void finalPass() {
void finalPass(boolean inlinedSomething) {
    void finalPass() {      TreeEnumerator e = TreeEnumerator.enumFromRoot(root);      OPT_BasicBlock cop = gc.prologue;      BasicBlockLE curr = getEntry();      BasicBlockLE next = null;    top:       while (true) {        // Step 0: If curr is the first block in a catch block,         // inject synthetic entry block too.        if (curr instanceof HandlerBlockLE) {          // tell our caller that we actually put a handler in the final CFG.          gc.generatedExceptionHandlers = true;           HandlerBlockLE hcurr = (HandlerBlockLE)curr;          if (DBG_FLATTEN) {            db("injecting handler entry block "+ hcurr.entryBlock+               " before "+hcurr);          }          gc.cfg.insertAfterInCodeOrder(cop, hcurr.entryBlock);          cop = hcurr.entryBlock;        }        // Step 1: Insert curr in the code order (after cop, updating cop).        if (DBG_FLATTEN) db("flattening: " + curr + " (" + curr.block + ")");        curr.setInCodeOrder();        gc.cfg.insertAfterInCodeOrder(cop, curr.block);        cop = curr.block;        if (DBG_FLATTEN) {          db("Current Code order for " + gc.method + "\n");          for (OPT_BasicBlock bb = gc.prologue; bb != null;                bb = (OPT_BasicBlock)bb.getNext()) {            VM.sysWrite(bb + "\n");          }        }        // Step 1.1 Sometimes (rarely) there will be an inscope         // exception handler that wasn't actually generated.  If this happens,         // make a new, filtered EHBBB to avoid later confusion.        if (curr.handlers != null) {          int notGenerated = 0;          for (int i = 0; i < curr.handlers.length; i++) {            if (!curr.handlers[i].isGenerated()) {              if (DBG_EX || DBG_FLATTEN) {                db("Will remove unreachable handler " + curr.handlers[i]                   + " from " + curr);              }              notGenerated++;            }          }          if (notGenerated > 0) {            if (notGenerated == curr.handlers.length) {              if (DBG_EX || DBG_FLATTEN) {                db("No (local) handlers were actually reachable for " +                    curr + "; setting to caller");              }              curr.block.exceptionHandlers =                curr.block.exceptionHandlers.getCaller();            } else {              OPT_ExceptionHandlerBasicBlock[] nlh =                 new OPT_ExceptionHandlerBasicBlock[curr.handlers.length -                                                   notGenerated];              for (int i = 0, j = 0; i < curr.handlers.length; i++) {                if (curr.handlers[i].isGenerated()) {                  nlh[j++] = curr.handlers[i].entryBlock;                } else {                  if (VM.VerifyAssertions) {                    VM._assert(curr.handlers[i].entryBlock.hasZeroIn(),                               "Non-generated handler with CFG edges");                  }                }              }              curr.block.exceptionHandlers =                 new OPT_ExceptionHandlerBasicBlockBag(nlh,                                                       curr.block.exceptionHandlers.getCaller());            }          }        }        // Step 2: Identify the next basic block to add to the code order.        // curr wants to fallthrough to an inlined method.          // Inject the entire inlined CFG in the code order.        // There's some fairly complicated coordination between this code,         // OPT_GenerationContext, and maybeInlineMethod.  Sorry, but you'll         // have to take a close look at all of these to see how it        // all fits together....--dave        if (curr.fallThrough != null &&             curr.fallThrough instanceof InliningBlockLE) {          InliningBlockLE icurr = (InliningBlockLE)curr.fallThrough;          OPT_BasicBlock forw = cop.nextBasicBlockInCodeOrder();          OPT_BasicBlock calleeEntry = icurr.gc.cfg.firstInCodeOrder();          OPT_BasicBlock calleeExit = icurr.gc.cfg.lastInCodeOrder();          gc.cfg.breakCodeOrder(cop, forw);          gc.cfg.linkInCodeOrder(cop, icurr.gc.cfg.firstInCodeOrder());          gc.cfg.linkInCodeOrder(icurr.gc.cfg.lastInCodeOrder(), forw);          if (DBG_CFG || DBG_SELECTED)            db("Added CFG edge from " + cop + " to " + calleeEntry);          if (icurr.epilogueBBLE != null) {            if (DBG_FLATTEN)              db("injected " + icurr + " between " + curr + " and " +                  icurr.epilogueBBLE.fallThrough);            if (VM.VerifyAssertions) {              VM._assert(icurr.epilogueBBLE.block ==                        icurr.gc.cfg.lastInCodeOrder());            }            curr = icurr.epilogueBBLE;            cop = curr.block;          } else {            if (DBG_FLATTEN) db("injected " + icurr + " after " + curr);            curr = icurr;            cop = calleeExit;          }        }        next = curr.fallThrough;        if (DBG_FLATTEN && next == null)          db(curr + " has no fallthrough case, getting next block");        if (next != null) {          if (DBG_CFG || DBG_SELECTED)            db("Added CFG edge from " + curr.block + " to " + next.block);          if (next.isInCodeOrder()) {            if (DBG_FLATTEN)              db("fallthrough " + next + " is already flattened, adding goto");            curr.block.appendInstruction(next.block.makeGOTO());            // set next to null to indicate no "real" fall through            next = null;          }        }        if (next == null) {          // Can't process fallthroughblock, so get next BBLE from enumeration          while (true) {            if (!e.hasMoreElements()) {              // all done.              if (DBG_FLATTEN) db("no more blocks! all done");              break  top;            }            next = e.next();            if (DBG_FLATTEN) db("looking at " + next);            if (!next.isGenerated()) {              if (DBG_FLATTEN) db("block " + next + " was not generated");              continue;            }            if (!next.isInCodeOrder())              break;          }          if (DBG_FLATTEN) db("found unflattened block: " + next);        }        curr = next;      }      // If the epilogue was unreachable, remove it from the code order and cfg      // and set gc.epilogue to null.      if (gc.epilogue.hasZeroIn()) {        if (DBG_FLATTEN || DBG_CFG)          db("Deleting unreachable epilogue " + gc.epilogue);        gc.cfg.removeFromCodeOrder(gc.epilogue);        // remove the node from the graph AND adjust its edge info        gc.epilogue.remove();        gc.epilogue.deleteIn();        gc.epilogue.deleteOut();        if (VM.VerifyAssertions) VM._assert(gc.epilogue.hasZeroOut());        gc.epilogue = null;      }      // if gc has an unlockAndRethrow block that was not used, then remove it      if (gc.unlockAndRethrow != null && gc.unlockAndRethrow.hasZeroIn()) {        gc.cfg.removeFromCFGAndCodeOrder(gc.unlockAndRethrow);        gc.enclosingHandlers.remove( gc.unlockAndRethrow );      }      if (DBG_FLATTEN) {        db("Current Code order for " + gc.method + "\n");        for (OPT_BasicBlock bb = gc.prologue;              bb != null;              bb = (OPT_BasicBlock)bb.getNext()) {          bb.printExtended();        }      }      if (DBG_FLATTEN) {        db("Final CFG for " + gc.method + "\n");        gc.cfg.printDepthFirst();      }    }