/** Return a description of the local variables (one per line) */
  public static String local_var_descr(MethodGen mg) {

    String out = String.format("Locals for %s [cnt %d]\n", mg, mg.getMaxLocals());
    LocalVariableGen[] lvgs = mg.getLocalVariables();
    if ((lvgs != null) && (lvgs.length > 0)) {
      for (LocalVariableGen lvg : lvgs)
        out += String.format("  %s [index %d]\n", lvg, lvg.getIndex());
    }
    return (out);
  }
  /**
   * Pass 3b implements the data flow analysis as described in the Java Virtual Machine
   * Specification, Second Edition. Later versions will use LocalVariablesInfo objects to verify if
   * the verifier-inferred types and the class file's debug information (LocalVariables attributes)
   * match [TODO].
   *
   * @see org.apache.bcel.verifier.statics.LocalVariablesInfo
   * @see org.apache.bcel.verifier.statics.Pass2Verifier#getLocalVariablesInfo(int)
   */
  @Override
  public VerificationResult do_verify() {
    if (!myOwner.doPass3a(method_no).equals(VerificationResult.VR_OK)) {
      return VerificationResult.VR_NOTYET;
    }

    // Pass 3a ran before, so it's safe to assume the JavaClass object is
    // in the BCEL repository.
    JavaClass jc;
    try {
      jc = Repository.lookupClass(myOwner.getClassName());
    } catch (ClassNotFoundException e) {
      // FIXME: maybe not the best way to handle this
      throw new AssertionViolatedException("Missing class: " + e, e);
    }

    ConstantPoolGen constantPoolGen = new ConstantPoolGen(jc.getConstantPool());
    // Init Visitors
    InstConstraintVisitor icv = new InstConstraintVisitor();
    icv.setConstantPoolGen(constantPoolGen);

    ExecutionVisitor ev = new ExecutionVisitor();
    ev.setConstantPoolGen(constantPoolGen);

    Method[] methods = jc.getMethods(); // Method no "method_no" exists, we ran Pass3a before on it!

    try {

      MethodGen mg = new MethodGen(methods[method_no], myOwner.getClassName(), constantPoolGen);

      icv.setMethodGen(mg);

      ////////////// DFA BEGINS HERE ////////////////
      if (!(mg.isAbstract() || mg.isNative())) { // IF mg HAS CODE (See pass 2)

        ControlFlowGraph cfg = new ControlFlowGraph(mg);

        // Build the initial frame situation for this method.
        Frame f = new Frame(mg.getMaxLocals(), mg.getMaxStack());
        if (!mg.isStatic()) {
          if (mg.getName().equals(Constants.CONSTRUCTOR_NAME)) {
            Frame._this = new UninitializedObjectType(ObjectType.getInstance(jc.getClassName()));
            f.getLocals().set(0, Frame._this);
          } else {
            Frame._this = null;
            f.getLocals().set(0, ObjectType.getInstance(jc.getClassName()));
          }
        }
        Type[] argtypes = mg.getArgumentTypes();
        int twoslotoffset = 0;
        for (int j = 0; j < argtypes.length; j++) {
          if (argtypes[j] == Type.SHORT
              || argtypes[j] == Type.BYTE
              || argtypes[j] == Type.CHAR
              || argtypes[j] == Type.BOOLEAN) {
            argtypes[j] = Type.INT;
          }
          f.getLocals().set(twoslotoffset + j + (mg.isStatic() ? 0 : 1), argtypes[j]);
          if (argtypes[j].getSize() == 2) {
            twoslotoffset++;
            f.getLocals().set(twoslotoffset + j + (mg.isStatic() ? 0 : 1), Type.UNKNOWN);
          }
        }
        circulationPump(mg, cfg, cfg.contextOf(mg.getInstructionList().getStart()), f, icv, ev);
      }
    } catch (VerifierConstraintViolatedException ce) {
      ce.extendMessage("Constraint violated in method '" + methods[method_no] + "':\n", "");
      return new VerificationResult(VerificationResult.VERIFIED_REJECTED, ce.getMessage());
    } catch (RuntimeException re) {
      // These are internal errors

      StringWriter sw = new StringWriter();
      PrintWriter pw = new PrintWriter(sw);
      re.printStackTrace(pw);

      throw new AssertionViolatedException(
          "Some RuntimeException occured while verify()ing class '"
              + jc.getClassName()
              + "', method '"
              + methods[method_no]
              + "'. Original RuntimeException's stack trace:\n---\n"
              + sw
              + "---\n",
          re);
    }
    return VerificationResult.VR_OK;
  }