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