public static RootStatement codeToJava(StructClass cl, StructMethod mt, MethodDescriptor md, VarProcessor varProc) throws IOException {
    CancellationManager cancellationManager = DecompilerContext.getCancellationManager();
    cancellationManager.checkCanceled();
    boolean isInitializer = CodeConstants.CLINIT_NAME.equals(mt.getName()); // for now static initializer only

    mt.expandData(cl);
    InstructionSequence seq = mt.getInstructionSequence();
    ControlFlowGraph graph = new ControlFlowGraph(seq);

    DeadCodeHelper.removeDeadBlocks(graph);

    //
    // According to the JVMS11 4.9.1:
    //   If the class file version number is 51.0 or above,
    //   then neither the jsr opcode or the jsr_w opcode may appear in the code array
    //
    // Since jsr instruction is forbidden for class files version 51.0 (Java 7) or above
    // call to inlineJsr() is only meaningful for class files prior to the Java 7.
    //
    cancellationManager.checkCanceled();
    if (!cl.isVersion7()) {
      graph.inlineJsr(cl, mt);
    }

    // TODO: move to the start, before jsr inlining
    DeadCodeHelper.connectDummyExitBlock(graph);

    DeadCodeHelper.removeGoTos(graph);

    ExceptionDeobfuscator.duplicateMergedCatchBlocks(graph, cl);

    ExceptionDeobfuscator.removeCircularRanges(graph);

    ExceptionDeobfuscator.restorePopRanges(graph);

    if (DecompilerContext.getOption(IFernflowerPreferences.REMOVE_EMPTY_RANGES)) {
      ExceptionDeobfuscator.removeEmptyRanges(graph);
    }

    if (DecompilerContext.getOption(IFernflowerPreferences.ENSURE_SYNCHRONIZED_MONITOR)) {
      // special case: search for 'synchronized' ranges w/o monitorexit instruction (as generated by Kotlin and Scala)
      DeadCodeHelper.extendSynchronizedRangeToMonitorExit(graph);
    }

    if (DecompilerContext.getOption(IFernflowerPreferences.NO_EXCEPTIONS_RETURN)) {
      // special case: single return instruction outside of a protected range
      DeadCodeHelper.incorporateValueReturns(graph);
    }

    //		ExceptionDeobfuscator.restorePopRanges(graph);
    ExceptionDeobfuscator.insertEmptyExceptionHandlerBlocks(graph);

    DeadCodeHelper.mergeBasicBlocks(graph);

    DecompilerContext.getCounterContainer().setCounter(CounterContainer.VAR_COUNTER, mt.getLocalVariables());

    if (ExceptionDeobfuscator.hasObfuscatedExceptions(graph)) {
      DecompilerContext.getLogger().writeMessage("Heavily obfuscated exception ranges found!", IFernflowerLogger.Severity.WARN);
      if (!ExceptionDeobfuscator.handleMultipleEntryExceptionRanges(graph)) {
        DecompilerContext.getLogger().writeMessage("Found multiple entry exception ranges which could not be splitted", IFernflowerLogger.Severity.WARN);
      }
      ExceptionDeobfuscator.insertDummyExceptionHandlerBlocks(graph, mt.getBytecodeVersion());
    }
    cancellationManager.checkCanceled();
    RootStatement root = DomHelper.parseGraph(graph);

    cancellationManager.checkCanceled();

    FinallyProcessor fProc = new FinallyProcessor(md, varProc);
    while (fProc.iterateGraph(cl, mt, root, graph)) {
      cancellationManager.checkCanceled();
      root = DomHelper.parseGraph(graph);
    }

    // remove synchronized exception handler
    // not until now because of comparison between synchronized statements in the finally cycle
    DomHelper.removeSynchronizedHandler(root);
    cancellationManager.checkCanceled();

    //		LabelHelper.lowContinueLabels(root, new HashSet<StatEdge>());

    SequenceHelper.condenseSequences(root);

    ClearStructHelper.clearStatements(root);
    cancellationManager.checkCanceled();

    ExprProcessor proc = new ExprProcessor(md, varProc);
    proc.processStatement(root, cl);
    cancellationManager.checkCanceled();

    SequenceHelper.condenseSequences(root);

    do {
      StackVarsProcessor.simplifyStackVars(root, mt, cl);
      varProc.setVarVersions(root);
    }
    while (new PPandMMHelper().findPPandMM(root));

    cancellationManager.checkCanceled();

    while (true) {
      LabelHelper.cleanUpEdges(root);

      do {
        MergeHelper.enhanceLoops(root);
      }
      while (LoopExtractHelper.extractLoops(root) || IfHelper.mergeAllIfs(root));

      if (DecompilerContext.getOption(IFernflowerPreferences.IDEA_NOT_NULL_ANNOTATION)) {
        if (IdeaNotNullHelper.removeHardcodedChecks(root, mt)) {
          SequenceHelper.condenseSequences(root);
          StackVarsProcessor.simplifyStackVars(root, mt, cl);
          varProc.setVarVersions(root);
        }
      }

      LabelHelper.identifyLabels(root);

      if (InlineSingleBlockHelper.inlineSingleBlocks(root)) {
        continue;
      }

      // initializer may have at most one return point, so no transformation of method exits permitted
      if (isInitializer || !ExitHelper.condenseExits(root)) {
        break;
      }

      // FIXME: !!
      //if(!EliminateLoopsHelper.eliminateLoops(root)) {
      //  break;
      //}
    }
    cancellationManager.checkCanceled();

    ExitHelper.removeRedundantReturns(root);

    SecondaryFunctionsHelper.identifySecondaryFunctions(root, varProc);

    varProc.setVarDefinitions(root);

    cancellationManager.checkCanceled();

    // must be the last invocation, because it makes the statement structure inconsistent
    // FIXME: new edge type needed
    LabelHelper.replaceContinueWithBreak(root);

    SwitchHelper.simplifySwitchesOnReferences(root, cl);
    SwitchHelper.prepareForRules(root, cl);
    PatternHelper.replaceAssignmentsWithPatternVariables(root, cl);
    cancellationManager.checkCanceled();

    mt.releaseResources();

    return root;
  }
public static RootStatement codeToJava(StructClass cl, StructMethod mt, MethodDescriptor md, VarProcessor varProc)