/// <exception cref="IOException"/> public virtual void ProcessClass(ClassesProcessor.ClassNode node) { foreach (ClassesProcessor.ClassNode child in node.nested) { ProcessClass(child); } ClassesProcessor clProcessor = DecompilerContext.GetClassProcessor(); StructClass cl = node.classStruct; if (cl.GetBytecodeVersion() < ICodeConstants.Bytecode_Java_8) { // lambda beginning with Java 8 return; } StructBootstrapMethodsAttribute bootstrap = cl.GetAttribute(StructGeneralAttribute .Attribute_Bootstrap_Methods); if (bootstrap == null || bootstrap.GetMethodsNumber() == 0) { return; } // no bootstrap constants in pool BitSet lambda_methods = new BitSet(); // find lambda bootstrap constants for (int i = 0; i < bootstrap.GetMethodsNumber(); ++i) { LinkConstant method_ref = bootstrap.GetMethodReference(i); // method handle // FIXME: extend for Eclipse etc. at some point if (Javac_Lambda_Class.Equals(method_ref.classname) && (Javac_Lambda_Method.Equals (method_ref.elementname) || Javac_Lambda_Alt_Method.Equals(method_ref.elementname ))) { lambda_methods.Set(i); } } if (lambda_methods.IsEmpty()) { return; } // no lambda bootstrap constant found Dictionary <string, string> mapMethodsLambda = new Dictionary <string, string>(); // iterate over code and find invocations of bootstrap methods. Replace them with anonymous classes. foreach (StructMethod mt in cl.GetMethods()) { mt.ExpandData(); InstructionSequence seq = mt.GetInstructionSequence(); if (seq != null && seq.Length() > 0) { int len = seq.Length(); for (int i = 0; i < len; ++i) { Instruction instr = seq.GetInstr(i); if (instr.opcode == ICodeConstants.opc_invokedynamic) { LinkConstant invoke_dynamic = cl.GetPool().GetLinkConstant(instr.Operand(0)); if (lambda_methods.Get(invoke_dynamic.index1)) { // lambda invocation found List <PooledConstant> bootstrap_arguments = bootstrap.GetMethodArguments(invoke_dynamic .index1); MethodDescriptor md = MethodDescriptor.ParseDescriptor(invoke_dynamic.descriptor); string lambda_class_name = md.ret.value; string lambda_method_name = invoke_dynamic.elementname; string lambda_method_descriptor = ((PrimitiveConstant)bootstrap_arguments[2]).GetString (); // method type LinkConstant content_method_handle = (LinkConstant)bootstrap_arguments[1]; ClassesProcessor.ClassNode node_lambda = new ClassesProcessor.ClassNode(content_method_handle .classname, content_method_handle.elementname, content_method_handle.descriptor, content_method_handle.index1, lambda_class_name, lambda_method_name, lambda_method_descriptor , cl); node_lambda.simpleName = cl.qualifiedName + "##Lambda_" + invoke_dynamic.index1 + "_" + invoke_dynamic.index2; node_lambda.enclosingMethod = InterpreterUtil.MakeUniqueKey(mt.GetName(), mt.GetDescriptor ()); node.nested.Add(node_lambda); node_lambda.parent = node; Sharpen.Collections.Put(clProcessor.GetMapRootClasses(), node_lambda.simpleName, node_lambda); if (!node_lambda.lambdaInformation.is_method_reference) { Sharpen.Collections.Put(mapMethodsLambda, node_lambda.lambdaInformation.content_method_key , node_lambda.simpleName); } } } } } mt.ReleaseResources(); } // build class hierarchy on lambda foreach (ClassesProcessor.ClassNode nd in node.nested) { if (nd.type == ClassesProcessor.ClassNode.Class_Lambda) { string parent_class_name = mapMethodsLambda.GetOrNull(nd.enclosingMethod); if (parent_class_name != null) { ClassesProcessor.ClassNode parent_class = clProcessor.GetMapRootClasses().GetOrNull (parent_class_name); parent_class.nested.Add(nd); nd.parent = parent_class; } } } }
/// <exception cref="System.IO.IOException"/> public static RootStatement CodeToJava(StructMethod mt, MethodDescriptor md, VarProcessor varProc) { StructClass cl = mt.GetClassStruct(); bool isInitializer = ICodeConstants.Clinit_Name.Equals(mt.GetName()); // for now static initializer only mt.ExpandData(); InstructionSequence seq = mt.GetInstructionSequence(); ControlFlowGraph graph = new ControlFlowGraph(seq); DeadCodeHelper.RemoveDeadBlocks(graph); graph.InlineJsr(mt); // TODO: move to the start, before jsr inlining DeadCodeHelper.ConnectDummyExitBlock(graph); DeadCodeHelper.RemoveGotos(graph); 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, cl.GetBytecodeVersion ()); } RootStatement root = DomHelper.ParseGraph(graph); FinallyProcessor fProc = new FinallyProcessor(md, varProc); while (fProc.IterateGraph(mt, root, graph)) { root = DomHelper.ParseGraph(graph); } // remove synchronized exception handler // not until now because of comparison between synchronized statements in the finally cycle DomHelper.RemoveSynchronizedHandler(root); // LabelHelper.lowContinueLabels(root, new HashSet<StatEdge>()); SequenceHelper.CondenseSequences(root); ClearStructHelper.ClearStatements(root); ExprProcessor proc = new ExprProcessor(md, varProc); proc.ProcessStatement(root, cl); SequenceHelper.CondenseSequences(root); StackVarsProcessor stackProc = new StackVarsProcessor(); do { stackProc.SimplifyStackVars(root, mt, cl); varProc.SetVarVersions(root); }while (new PPandMMHelper().FindPPandMM(root)); 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); stackProc.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; //} ExitHelper.RemoveRedundantReturns(root); SecondaryFunctionsHelper.IdentifySecondaryFunctions(root, varProc); varProc.SetVarDefinitions(root); // must be the last invocation, because it makes the statement structure inconsistent // FIXME: new edge type needed LabelHelper.ReplaceContinueWithBreak(root); mt.ReleaseResources(); return(root); }