docs: public void inline(Context context) throws CFGBuilderException {
  
          CFG result = context.getResult();
  
          // Check to ensure we're not trying to inline something that is
          // recursive
          context.checkForRecursion();
  
          Subroutine subroutine = context.getSubroutine();
          CFG subCFG = subroutine.getCFG();
  
          while (context.hasMoreWork()) {
              BasicBlock subBlock = context.nextItem();
              BasicBlock resultBlock = context.getBlock(subBlock);
  
              // Mark blocks which are in JSR subroutines
              resultBlock.setInJSRSubroutine(context.getCaller() != null);
  
              // Copy instructions into the result block
              BasicBlock.InstructionIterator insIter = subBlock.instructionIterator();
              while (insIter.hasNext()) {
                  InstructionHandle handle = insIter.next();
                  resultBlock.addInstruction(handle);
              }
  
              // Set exception thrower status
              if (subBlock.isExceptionThrower()) {
                  resultBlock.setExceptionThrower(subBlock.getExceptionThrower());
              }
  
              // Set exception handler status
              if (subBlock.isExceptionHandler()) {
                  resultBlock.setExceptionGen(null, subBlock.getExceptionGen());
              }
  
              // Add control edges (including inlining JSR subroutines)
              Iterator<Edge> edgeIter = subCFG.outgoingEdgeIterator(subBlock);
              while (edgeIter.hasNext()) {
                  Edge edge = edgeIter.next();
                  int edgeType = edge.getType();
  
                  if (edgeType == JSR_EDGE) {
                      // Inline a JSR subroutine...
  
                      // Create a new Context
                      InstructionHandle jsrHandle = subBlock.getLastInstruction();
                      JsrInstruction jsr = (JsrInstruction) jsrHandle.getInstruction();
                      Subroutine jsrSub = jsrSubroutineMap.get(jsr.getTarget());
                      Context jsrContext = new Context(context, jsrSub, context.getResult());
  
                      // The start block in the JSR subroutine maps to the first
                      // inlined block in the result CFG.
                      BasicBlock resultJSRStartBlock = jsrContext.getBlock(jsrSub.getStartBlock());
                      result.createEdge(resultBlock, resultJSRStartBlock, GOTO_EDGE);
  
                      // The exit block in the JSR subroutine maps to the result
                      // block
                      // corresponding to the instruction following the JSR.
                      // (I.e., that is where control returns after the execution
                      // of
                      // the JSR subroutine.)
                      BasicBlock subJSRSuccessorBlock = subroutine.getBlock(jsrHandle.getNext());
                      BasicBlock resultJSRSuccessorBlock = context.getBlock(subJSRSuccessorBlock);
                      jsrContext.mapBlock(jsrSub.getExit(), resultJSRSuccessorBlock);
  
                      // Inline the JSR subroutine
                      inline(jsrContext);
                  } else {
                      // Ordinary control edge
                      BasicBlock resultTarget = context.getBlock(edge.getTarget());
                      result.createEdge(resultBlock, resultTarget, edge.getType());
                  }
              }
  
              // Add control edges for escape targets
              Iterator<EscapeTarget> escapeTargetIter = subroutine.escapeTargetIterator(subBlock);
              while (escapeTargetIter.hasNext()) {
                  EscapeTarget escapeTarget = escapeTargetIter.next();
                  InstructionHandle targetInstruction = escapeTarget.getTarget();
  
                  // Look for the calling context which has the target instruction
                  Context caller = context.getCaller();
                  while (caller != null) {
                      if (caller.getSubroutine().containsInstruction(targetInstruction)) {
                          break;
                      }
                      caller = caller.getCaller();
                  }
  
                  if (caller == null) {
                      throw new CFGBuilderException("Unknown caller for escape target " + targetInstruction + " referenced by "
                              + context.getSubroutine().getStartInstruction());
                  }
  
                  // Find result block in caller
                  BasicBlock subCallerTargetBlock = caller.getSubroutine().getBlock(targetInstruction);
                  BasicBlock resultCallerTargetBlock = caller.getBlock(subCallerTargetBlock);
  
                  // Add an edge to caller context
                  result.createEdge(resultBlock, resultCallerTargetBlock, escapeTarget.getEdgeType());
              }
  
              // If the block returns from the method, add a return edge
              if (subroutine.isReturnBlock(subBlock)) {
                  result.createEdge(resultBlock, result.getExit(), RETURN_EDGE);
              }
  
              // If the block calls System.exit(), add an exit edge
              if (subroutine.isExitBlock(subBlock)) {
                  result.createEdge(resultBlock, result.getExit(), EXIT_EDGE);
              }
  
              // If the block throws an unhandled exception, add an unhandled
              // exception edge
              if (subroutine.isUnhandledExceptionBlock(subBlock)) {
                  result.createEdge(resultBlock, result.getExit(), UNHANDLED_EXCEPTION_EDGE);
              }
  
          }
  
          /*
           * while (blocks are left) {
           *
           * get block from subroutine get corresponding block from result copy
           * instructions into result block
           *
           * if (block terminated by JSR) { get JSR subroutine create new context
           * create GOTO edge from current result block to start block of new
           * inlined context map subroutine exit block to result JSR successor
           * block inline (new context, result) } else { for each outgoing edge {
           * map each target to result blocks (add block to to work list if
           * needed) add edges to result }
           *
           * for each outgoing escape target { add edges into blocks in outer
           * contexts (adding those blocks to outer work list if needed) }
           *
           * if (block returns) { add return edge from result block to result CFG
           * exit block }
           *
           * if (block calls System.exit()) { add exit edge from result block to
           * result CFG exit block }
           *
           * if (block throws unhandled exception) { add unhandled exception edge
           * from result block to result CFG exit block } }
           *
           * }
           */
      }