public Frame<V>[] analyze(String owner, MethodNode m) throws AnalyzerException {
    if ((m.access & (ACC_ABSTRACT | ACC_NATIVE)) != 0) {
      frames = ASMUtils.newFrameArray(0);
      return frames;
    }

    @SuppressWarnings("unchecked") V refV = (V)BasicValue.REFERENCE_VALUE;

    int n = m.instructions.size();
    InsnList insns = m.instructions;
    List<TryCatchBlockNode>[] handlers = ASMUtils.newListArray(n);
    frames = ASMUtils.newFrameArray(n);
    queued = new boolean[n];
    queue = new int[n];
    top = 0;

    // computes exception handlers for each instruction
    for (int i = 0; i < m.tryCatchBlocks.size(); ++i) {
      TryCatchBlockNode tcb = m.tryCatchBlocks.get(i);
      int begin = insns.indexOf(tcb.start);
      int end = insns.indexOf(tcb.end);
      for (int j = begin; j < end; ++j) {
        List<TryCatchBlockNode> insnHandlers = handlers[j];
        if (insnHandlers == null) {
          insnHandlers = new ArrayList<>();
          handlers[j] = insnHandlers;
        }
        insnHandlers.add(tcb);
      }
    }

    // initializes the data structures for the control flow analysis
    Frame<V> current = newFrame(m.maxLocals, m.maxStack);
    Frame<V> handler = newFrame(m.maxLocals, m.maxStack);
    current.setReturn(interpreter.newReturnTypeValue(Type.getReturnType(m.desc)));
    Type[] args = Type.getArgumentTypes(m.desc);
    int local = 0;
    boolean isInstanceMethod = (m.access & ACC_STATIC) == 0;
    if (isInstanceMethod) {
      Type ctype = Type.getObjectType(owner);
      current.setLocal(local, interpreter.newParameterValue(true, local, ctype));
      local++;
    }
    for (Type arg : args) {
      current.setLocal(local, interpreter.newParameterValue(isInstanceMethod, local, arg));
      local++;
      if (arg.getSize() == 2) {
        current.setLocal(local, interpreter.newEmptyValue(local));
        local++;
      }
    }
    while (local < m.maxLocals) {
      current.setLocal(local, interpreter.newEmptyValue(local));
      local++;
    }

    interpreter.init(data[0]);
    merge(0, current);

    // control flow analysis
    while (top > 0) {
      int insn = queue[--top];
      Frame<V> f = frames[insn];
      queued[insn] = false;

      AbstractInsnNode insnNode = null;
      try {
        insnNode = m.instructions.get(insn);
        int insnOpcode = insnNode.getOpcode();
        int insnType = insnNode.getType();

        if (insnType == AbstractInsnNode.LABEL || insnType == AbstractInsnNode.LINE || insnType == AbstractInsnNode.FRAME) {
          interpreter.init(data[insn]);
          merge(insn + 1, f);
        }
        else {
          // delta
          interpreter.init(data[insn]);
          current.init(f).execute(insnNode, interpreter);

          if (insnNode instanceof JumpInsnNode j) {
            if (insnOpcode != GOTO && insnOpcode != JSR) {
              merge(insn + 1, current);
            }
            int jump = insns.indexOf(j.label);
            merge(jump, current);
          }
          else if (insnNode instanceof LookupSwitchInsnNode lsi) {
            int jump = insns.indexOf(lsi.dflt);
            merge(jump, current);
            for (int j = 0; j < lsi.labels.size(); ++j) {
              LabelNode label = lsi.labels.get(j);
              jump = insns.indexOf(label);
              merge(jump, current);
            }
          }
          else if (insnNode instanceof TableSwitchInsnNode tsi) {
            int jump = insns.indexOf(tsi.dflt);
            merge(jump, current);
            for (int j = 0; j < tsi.labels.size(); ++j) {
              LabelNode label = tsi.labels.get(j);
              jump = insns.indexOf(label);
              merge(jump, current);
            }
          }
          else if (insnOpcode != ATHROW
                   && (insnOpcode < IRETURN || insnOpcode > RETURN)) {
            merge(insn + 1, current);
          }
        }

        List<TryCatchBlockNode> insnHandlers = handlers[insn];
        if (insnHandlers != null) {
          for (TryCatchBlockNode tcb : insnHandlers) {
            int jump = insns.indexOf(tcb.handler);
            handler.init(f);
            handler.clearStack();
            handler.push(refV);
            merge(jump, handler);
          }
        }
      }
      catch (AnalyzerException e) {
        throw new AnalyzerException(e.node, "Error at instruction " + insn + ": " + e.getMessage(), e);
      }
      catch (Exception e) {
        throw new AnalyzerException(insnNode, "Error at instruction " + insn + ": " + e.getMessage(), e);
      }
    }

    return frames;
  }
public Frame<V>[] analyze(String owner, MethodNode m)