public static RootStatement codeToJava()

in src/org/jetbrains/java/decompiler/main/rels/MethodProcessorRunnable.java [77:261]


  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);
    DecompilerContext.getLimitContainer().incrementAndCheckDirectNodeCount(graph);

    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.duplicateMergedMatchedExceptionCatchBlocks(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, mt);

    cancellationManager.checkCanceled();

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

    // 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(varProc).findPPandMM(root));

    cancellationManager.checkCanceled();

    if (cl.isVersion9()) {
      ConcatenationHelper.simplifyStringConcat(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);
      }
    }

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

      while (true) {
        if (EliminateLoopsHelper.eliminateLoops(root, mt, cl)) {
          continue;
        }

        MergeHelper.enhanceLoops(root);

        if (LoopExtractHelper.extractLoops(root)) {
          continue;
        }

        if (!IfHelper.mergeAllIfs(root)) {
          break;
        }
      }


      LabelHelper.identifyLabels(root);

      if (TryHelper.enhanceTryStats(root, graph, mt)) {
        continue;
      }

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

      // this has to be done last so it does not screw up the formation of for loops
      if (MergeHelper.makeDoWhileLoops(root)) {
        LabelHelper.cleanUpEdges(root);
        LabelHelper.identifyLabels(root);
      }

      // 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);

    cleanSynchronizedVar(root);

    varProc.setVarDefinitions(root);

    cancellationManager.checkCanceled();
    SecondaryFunctionsHelper.updateAssignments(root);

    // 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;
  }