public static List <VarVersionPair> GetSyntheticParametersMask(ClassesProcessor.ClassNode node, string descriptor, int parameters) { List <VarVersionPair> mask = null; ClassWrapper wrapper = node.GetWrapper(); if (wrapper != null) { // own class MethodWrapper methodWrapper = wrapper.GetMethodWrapper(ICodeConstants.Init_Name, descriptor); if (methodWrapper == null) { if (DecompilerContext.GetOption(IFernflowerPreferences.Ignore_Invalid_Bytecode)) { return(null); } throw new Exception("Constructor " + node.classStruct.qualifiedName + "." + ICodeConstants .Init_Name + descriptor + " not found"); } mask = methodWrapper.synthParameters; } else if (parameters > 0 && node.type == ClassesProcessor.ClassNode.Class_Member && (node.access & ICodeConstants.Acc_Static) == 0) { // non-static member class mask = new List <VarVersionPair>(Enumerable.Repeat <VarVersionPair>(null, parameters)); mask[0] = new VarVersionPair(-1, 0); } return(mask); }
public virtual void PropagateMemberAccess(ClassesProcessor.ClassNode root) { if ((root.nested.Count == 0)) { return; } noSynthFlag = DecompilerContext.GetOption(IFernflowerPreferences.Synthetic_Not_Set ); ComputeMethodTypes(root); EliminateStaticAccess(root); }
private void AppendDefinitionType(TextBuffer buffer) { if (DecompilerContext.GetOption(IFernflowerPreferences.Use_Debug_Var_Names)) { MethodWrapper method = (MethodWrapper)DecompilerContext.GetProperty(DecompilerContext .Current_Method_Wrapper); if (method != null) { int?originalIndex = null; if (processor != null) { originalIndex = processor.GetVarOriginalIndex(index); } if (originalIndex != null) { // first try from signature if (DecompilerContext.GetOption(IFernflowerPreferences.Decompile_Generic_Signatures )) { StructLocalVariableTypeTableAttribute attr = method.methodStruct.GetAttribute(StructGeneralAttribute .Attribute_Local_Variable_Type_Table); if (attr != null) { string signature = attr.GetSignature(originalIndex, visibleOffset); if (signature != null) { GenericFieldDescriptor descriptor = GenericMain.ParseFieldSignature(signature); if (descriptor != null) { buffer.Append(GenericMain.GetGenericCastTypeName(descriptor.type)); return; } } } } // then try from descriptor StructLocalVariableTableAttribute attr_1 = method.methodStruct.GetLocalVariableAttr (); if (attr_1 != null) { string descriptor = attr_1.GetDescriptor(originalIndex, visibleOffset); if (descriptor != null) { buffer.Append(ExprProcessor.GetCastTypeName(new VarType(descriptor))); return; } } } } } buffer.Append(ExprProcessor.GetCastTypeName(GetVarType())); }
public virtual bool HasBooleanValue() { switch (constType.type) { case ICodeConstants.Type_Boolean: case ICodeConstants.Type_Char: case ICodeConstants.Type_Byte: case ICodeConstants.Type_Bytechar: case ICodeConstants.Type_Short: case ICodeConstants.Type_Shortchar: case ICodeConstants.Type_Int: { int value = (int)this.value; return(value == 0 || (DecompilerContext.GetOption(IFernflowerPreferences.Boolean_True_One ) && value == 1)); } } return(false); }
public virtual bool SimplifyStackVarsStatement(Statement stat, HashSet <int> setReorderedIfs , SSAConstructorSparseEx ssa, StructClass cl) { bool res = false; List <Exprent> expressions = stat.GetExprents(); if (expressions == null) { bool processClass14 = DecompilerContext.GetOption(IFernflowerPreferences.Decompile_Class_1_4 ); while (true) { bool changed = false; foreach (Statement st in stat.GetStats()) { res |= SimplifyStackVarsStatement(st, setReorderedIfs, ssa, cl); changed = IfHelper.MergeIfs(st, setReorderedIfs) || BuildIff(st, ssa) || processClass14 && CollapseInlinedClass14(st); // collapse composed if's // collapse iff ?: statement // collapse inlined .class property in version 1.4 and before if (changed) { break; } } res |= changed; if (!changed) { break; } } } else { res = SimplifyStackVarsExprents(expressions, cl); } return(res); }
public virtual void Init() { DecompilerContext.SetProperty(DecompilerContext.Current_Class, classStruct); DecompilerContext.SetProperty(DecompilerContext.Current_Class_Wrapper, this); DecompilerContext.GetLogger().StartClass(classStruct.qualifiedName); int maxSec = System.Convert.ToInt32(DecompilerContext.GetProperty(IFernflowerPreferences .Max_Processing_Method).ToString()); bool testMode = DecompilerContext.GetOption(IFernflowerPreferences.Unit_Test_Mode ); foreach (StructMethod mt in classStruct.GetMethods()) { DecompilerContext.GetLogger().StartMethod(mt.GetName() + " " + mt.GetDescriptor() ); MethodDescriptor md = MethodDescriptor.ParseDescriptor(mt.GetDescriptor()); VarProcessor varProc = new VarProcessor(mt, md); DecompilerContext.StartMethod(varProc); VarNamesCollector vc = varProc.GetVarNamesCollector(); CounterContainer counter = DecompilerContext.GetCounterContainer(); RootStatement root = null; bool isError = false; try { if (mt.ContainsCode()) { if (maxSec == 0 || testMode) { root = MethodProcessorRunnable.CodeToJava(mt, md, varProc); } else { MethodProcessorRunnable mtProc = new MethodProcessorRunnable(mt, md, varProc, DecompilerContext .GetCurrentContext()); Thread mtThread = new Thread(o => mtProc.Run()) { Name = "Java decompiler" }; long stopAt = Runtime.CurrentTimeMillis() + maxSec * 1000L; mtThread.Start(); while (!mtProc.IsFinished()) { try { lock (mtProc.Lock) { Thread.Sleep(200); } } catch (Exception e) { KillThread(mtThread); throw; } if (Runtime.CurrentTimeMillis() >= stopAt) { string message = "Processing time limit exceeded for method " + mt.GetName() + ", execution interrupted."; DecompilerContext.GetLogger().WriteMessage(message, IFernflowerLogger.Severity.Error ); KillThread(mtThread); isError = true; break; } } if (!isError) { root = mtProc.GetResult(); } } } else { bool thisVar = !mt.HasModifier(ICodeConstants.Acc_Static); int paramCount = 0; if (thisVar) { Sharpen.Collections.Put(varProc.GetThisVars(), new VarVersionPair(0, 0), classStruct .qualifiedName); paramCount = 1; } paramCount += [email protected]; int varIndex = 0; for (int i = 0; i < paramCount; i++) { varProc.SetVarName(new VarVersionPair(varIndex, 0), vc.GetFreeName(varIndex)); if (thisVar) { if (i == 0) { varIndex++; } else { varIndex += md.@params[i - 1].stackSize; } } else { varIndex += md.@params[i].stackSize; } } } } catch (Exception t) { string message = "Method " + mt.GetName() + " " + mt.GetDescriptor() + " couldn't be decompiled."; DecompilerContext.GetLogger().WriteMessage(message, IFernflowerLogger.Severity.Warn , t); isError = true; } MethodWrapper methodWrapper = new MethodWrapper(root, varProc, mt, counter); methodWrapper.decompiledWithErrors = isError; methods.AddWithKey(methodWrapper, InterpreterUtil.MakeUniqueKey(mt.GetName(), mt. GetDescriptor())); if (!isError) { // rename vars so that no one has the same name as a field VarNamesCollector namesCollector = new VarNamesCollector(); classStruct.GetFields().ForEach((StructField f) => namesCollector.AddName(f.GetName ())); varProc.RefreshVarNames(namesCollector); // if debug information present and should be used if (DecompilerContext.GetOption(IFernflowerPreferences.Use_Debug_Var_Names)) { StructLocalVariableTableAttribute attr = mt.GetLocalVariableAttr(); if (attr != null) { // only param names here varProc.SetDebugVarNames(attr.GetMapParamNames()); // the rest is here methodWrapper.GetOrBuildGraph().IterateExprents((Exprent exprent) => { List <Exprent> lst = exprent.GetAllExprents(true); lst.Add(exprent); lst.Where(e => e.type == Exprent.Exprent_Var).ToList().ForEach((Exprent e) => { VarExprent varExprent = (VarExprent)e; string name = varExprent.GetDebugName(mt); if (name != null) { varProc.SetVarName(varExprent.GetVarVersionPair(), name); } } ); return(0); } ); } } } DecompilerContext.GetLogger().EndMethod(); } DecompilerContext.GetLogger().EndClass(); }
private bool SimplifyStackVarsExprents(List <Exprent> list, StructClass cl) { bool res = false; int index = 0; while (index < list.Count) { Exprent current = list[index]; Exprent ret = IsSimpleConstructorInvocation(current); if (ret != null) { list[index] = ret; res = true; continue; } // lambda expression (Java 8) ret = IsLambda(current, cl); if (ret != null) { list[index] = ret; res = true; continue; } // remove monitor exit if (IsMonitorExit(current)) { list.RemoveAtReturningValue(index); res = true; continue; } // trivial assignment of a stack variable if (IsTrivialStackAssignment(current)) { list.RemoveAtReturningValue(index); res = true; continue; } if (index == list.Count - 1) { break; } Exprent next = list[index + 1]; // constructor invocation if (IsConstructorInvocationRemote(list, index)) { list.RemoveAtReturningValue(index); res = true; continue; } // remove getClass() invocation, which is part of a qualified new if (DecompilerContext.GetOption(IFernflowerPreferences.Remove_Get_Class_New)) { if (IsQualifiedNewGetClass(current, next)) { list.RemoveAtReturningValue(index); res = true; continue; } } // direct initialization of an array int arrCount = IsArrayInitializer(list, index); if (arrCount > 0) { for (int i = 0; i < arrCount; i++) { list.RemoveAtReturningValue(index + 1); } res = true; continue; } // add array initializer expression if (AddArrayInitializer(current, next)) { list.RemoveAtReturningValue(index + 1); res = true; continue; } // integer ++expr and --expr (except for vars!) Exprent func = IsPPIorMMI(current); if (func != null) { list[index] = func; res = true; continue; } // expr++ and expr-- if (IsIPPorIMM(current, next) || IsIPPorIMM2(current, next)) { list.RemoveAtReturningValue(index + 1); res = true; continue; } // assignment on stack if (IsStackAssignment(current, next)) { list.RemoveAtReturningValue(index + 1); res = true; continue; } if (!firstInvocation && IsStackAssignment2(current, next)) { list.RemoveAtReturningValue(index + 1); res = true; continue; } index++; } return(res); }
private static bool RemoveEmptyBlock(ControlFlowGraph graph, BasicBlock block, bool merging) { bool deletedRanges = false; if (block.GetSeq().IsEmpty()) { if (block.GetSuccs().Count > 1) { if (block.GetPreds().Count > 1) { // ambiguous block throw new Exception("ERROR: empty block with multiple predecessors and successors found" ); } else if (!merging) { throw new Exception("ERROR: empty block with multiple successors found"); } } HashSet <BasicBlock> setExits = new HashSet <BasicBlock>(graph.GetLast().GetPreds() ); if ((block.GetPredExceptions().Count == 0) && (!setExits.Contains(block) || block .GetPreds().Count == 1)) { if (setExits.Contains(block)) { BasicBlock pred = block.GetPreds()[0]; // FIXME: flag in the basic block if (pred.GetSuccs().Count != 1 || (!pred.GetSeq().IsEmpty() && pred.GetSeq().GetLastInstr ().group == ICodeConstants.Group_Switch)) { return(false); } } HashSet <BasicBlock> setPreds = new HashSet <BasicBlock>(block.GetPreds()); HashSet <BasicBlock> setSuccs = new HashSet <BasicBlock>(block.GetSuccs()); // collect common exception ranges of predecessors and successors HashSet <BasicBlock> setCommonExceptionHandlers = null; for (int i = 0; i < 2; ++i) { foreach (BasicBlock pred in i == 0 ? setPreds : setSuccs) { if (setCommonExceptionHandlers == null) { setCommonExceptionHandlers = new HashSet <BasicBlock>(pred.GetSuccExceptions()); } else { setCommonExceptionHandlers.IntersectWith(pred.GetSuccExceptions()); } } } // check the block to be in each of the common ranges if (setCommonExceptionHandlers != null && !(setCommonExceptionHandlers.Count == 0)) { foreach (BasicBlock handler in setCommonExceptionHandlers) { if (!block.GetSuccExceptions().Contains(handler)) { return(false); } } } // remove ranges consisting of this one block List <ExceptionRangeCFG> lstRanges = graph.GetExceptions(); for (int i = lstRanges.Count - 1; i >= 0; i--) { ExceptionRangeCFG range = lstRanges[i]; List <BasicBlock> lst = range.GetProtectedRange(); if (lst.Count == 1 && lst[0] == block) { if (DecompilerContext.GetOption(IFernflowerPreferences.Remove_Empty_Ranges)) { block.RemoveSuccessorException(range.GetHandler()); lstRanges.RemoveAtReturningValue(i); deletedRanges = true; } else { return(false); } } } // connect remaining nodes if (merging) { BasicBlock pred = block.GetPreds()[0]; pred.RemoveSuccessor(block); List <BasicBlock> lstSuccs = new List <BasicBlock>(block.GetSuccs()); foreach (BasicBlock succ in lstSuccs) { block.RemoveSuccessor(succ); pred.AddSuccessor(succ); } } else { foreach (BasicBlock pred in setPreds) { foreach (BasicBlock succ in setSuccs) { pred.ReplaceSuccessor(block, succ); } } } // finally exit edges HashSet <BasicBlock> setFinallyExits = graph.GetFinallyExits(); if (setFinallyExits.Contains(block)) { setFinallyExits.Remove(block); setFinallyExits.Add(new Sharpen.EnumeratorAdapter <BasicBlock>(setPreds.GetEnumerator()).Next()); } // replace first if necessary if (graph.GetFirst() == block) { if (setSuccs.Count != 1) { throw new Exception("multiple or no entry blocks!"); } else { graph.SetFirst(new Sharpen.EnumeratorAdapter <BasicBlock>(setSuccs.GetEnumerator()).Next()); } } // remove this block graph.RemoveBlock(block); if (deletedRanges) { RemoveDeadBlocks(graph); } } } return(deletedRanges); }
private bool ProcessStatementEx(StructMethod mt, RootStatement root, ControlFlowGraph graph) { int bytecode_version = mt.GetClassStruct().GetBytecodeVersion(); LinkedList <Statement> stack = new LinkedList <Statement>(); stack.AddLast(root); while (!(stack.Count == 0)) { Statement stat = Sharpen.Collections.RemoveLast(stack); Statement parent = stat.GetParent(); if (parent != null && parent.type == Statement.Type_Catchall && stat == parent.GetFirst () && !parent.IsCopied()) { CatchAllStatement fin = (CatchAllStatement)parent; BasicBlock head = fin.GetBasichead().GetBlock(); BasicBlock handler = fin.GetHandler().GetBasichead().GetBlock(); if (catchallBlockIDs.ContainsKey(handler.id)) { } else if (finallyBlockIDs.ContainsKey(handler.id)) { // do nothing fin.SetFinally(true); int?var = finallyBlockIDs.GetOrNullable(handler.id); fin.SetMonitor(var == null ? null : new VarExprent(var.Value, VarType.Vartype_Int , varProcessor)); } else { FinallyProcessor.Record inf = GetFinallyInformation(mt, root, fin); if (inf == null) { // inconsistent finally Sharpen.Collections.Put(catchallBlockIDs, handler.id, null); } else { if (DecompilerContext.GetOption(IFernflowerPreferences.Finally_Deinline) && VerifyFinallyEx (graph, fin, inf)) { Sharpen.Collections.Put(finallyBlockIDs, handler.id, null); } else { int varindex = DecompilerContext.GetCounterContainer().GetCounterAndIncrement(CounterContainer .Var_Counter); InsertSemaphore(graph, GetAllBasicBlocks(fin.GetFirst()), head, handler, varindex , inf, bytecode_version); Sharpen.Collections.Put(finallyBlockIDs, handler.id, varindex); } DeadCodeHelper.RemoveDeadBlocks(graph); // e.g. multiple return blocks after a nested finally DeadCodeHelper.RemoveEmptyBlocks(graph); DeadCodeHelper.MergeBasicBlocks(graph); } return(true); } } Sharpen.Collections.AddAll(stack, stat.GetStats()); } return(false); }
public override TextBuffer ToJava(int indent, BytecodeMappingTracer tracer) { bool literal = DecompilerContext.GetOption(IFernflowerPreferences.Literals_As_Is ); bool ascii = DecompilerContext.GetOption(IFernflowerPreferences.Ascii_String_Characters ); tracer.AddMapping(bytecode); if (constType.type != ICodeConstants.Type_Null && value == null) { return(new TextBuffer(ExprProcessor.GetCastTypeName(constType))); } switch (constType.type) { case ICodeConstants.Type_Boolean: { return(new TextBuffer(((int)value != 0).ToString())); } case ICodeConstants.Type_Char: { int val = (int)value; string ret = Char_Escapes.GetOrNull(val); if (ret == null) { char c = (char)val; if (IsPrintableAscii(c) || !ascii && TextUtil.IsPrintableUnicode(c)) { ret = c.ToString(); } else { ret = TextUtil.CharToUnicodeLiteral(c); } } return(new TextBuffer(ret).Enclose("'", "'")); } case ICodeConstants.Type_Byte: case ICodeConstants.Type_Bytechar: case ICodeConstants.Type_Short: case ICodeConstants.Type_Shortchar: case ICodeConstants.Type_Int: { int intVal = (int)value; if (!literal) { if (intVal == int.MaxValue) { return(new FieldExprent("MAX_VALUE", "java/lang/Integer", true, null, FieldDescriptor .Integer_Descriptor, bytecode).ToJava(0, tracer)); } else if (intVal == int.MinValue) { return(new FieldExprent("MIN_VALUE", "java/lang/Integer", true, null, FieldDescriptor .Integer_Descriptor, bytecode).ToJava(0, tracer)); } } return(new TextBuffer(value.ToString())); } case ICodeConstants.Type_Long: { long longVal = (long)value; if (!literal) { if (longVal == long.MaxValue) { return(new FieldExprent("MAX_VALUE", "java/lang/Long", true, null, FieldDescriptor .Long_Descriptor, bytecode).ToJava(0, tracer)); } else if (longVal == long.MinValue) { return(new FieldExprent("MIN_VALUE", "java/lang/Long", true, null, FieldDescriptor .Long_Descriptor, bytecode).ToJava(0, tracer)); } } return(new TextBuffer(value.ToString()).Append('L')); } case ICodeConstants.Type_Float: { float floatVal = (float)value; if (!literal) { if (float.IsNaN(floatVal)) { return(new FieldExprent("NaN", "java/lang/Float", true, null, FieldDescriptor.Float_Descriptor , bytecode).ToJava(0, tracer)); } else if (floatVal == float.PositiveInfinity) { return(new FieldExprent("POSITIVE_INFINITY", "java/lang/Float", true, null, FieldDescriptor .Float_Descriptor, bytecode).ToJava(0, tracer)); } else if (floatVal == float.NegativeInfinity) { return(new FieldExprent("NEGATIVE_INFINITY", "java/lang/Float", true, null, FieldDescriptor .Float_Descriptor, bytecode).ToJava(0, tracer)); } else if (floatVal == float.MaxValue) { return(new FieldExprent("MAX_VALUE", "java/lang/Float", true, null, FieldDescriptor .Float_Descriptor, bytecode).ToJava(0, tracer)); } else if (floatVal == float.MinValue) { return(new FieldExprent("MIN_VALUE", "java/lang/Float", true, null, FieldDescriptor .Float_Descriptor, bytecode).ToJava(0, tracer)); } } else if (float.IsNaN(floatVal)) { return(new TextBuffer("0.0F / 0.0")); } else if (floatVal == float.PositiveInfinity) { return(new TextBuffer("1.0F / 0.0")); } else if (floatVal == float.NegativeInfinity) { return(new TextBuffer("-1.0F / 0.0")); } return(new TextBuffer(value.ToString()).Append('F')); } case ICodeConstants.Type_Double: { double doubleVal = (double)value; if (!literal) { if (double.IsNaN(doubleVal)) { return(new FieldExprent("NaN", "java/lang/Double", true, null, FieldDescriptor.Double_Descriptor , bytecode).ToJava(0, tracer)); } else if (doubleVal == double.PositiveInfinity) { return(new FieldExprent("POSITIVE_INFINITY", "java/lang/Double", true, null, FieldDescriptor .Double_Descriptor, bytecode).ToJava(0, tracer)); } else if (doubleVal == double.NegativeInfinity) { return(new FieldExprent("NEGATIVE_INFINITY", "java/lang/Double", true, null, FieldDescriptor .Double_Descriptor, bytecode).ToJava(0, tracer)); } else if (doubleVal == double.MaxValue) { return(new FieldExprent("MAX_VALUE", "java/lang/Double", true, null, FieldDescriptor .Double_Descriptor, bytecode).ToJava(0, tracer)); } else if (doubleVal == double.MinValue) { return(new FieldExprent("MIN_VALUE", "java/lang/Double", true, null, FieldDescriptor .Double_Descriptor, bytecode).ToJava(0, tracer)); } } else if (double.IsNaN(doubleVal)) { return(new TextBuffer("0.0D / 0.0")); } else if (doubleVal == double.PositiveInfinity) { return(new TextBuffer("1.0D / 0.0")); } else if (doubleVal == double.NegativeInfinity) { return(new TextBuffer("-1.0D / 0.0")); } return(new TextBuffer(value.ToString()).Append('D')); } case ICodeConstants.Type_Null: { return(new TextBuffer("null")); } case ICodeConstants.Type_Object: { if (constType.Equals(VarType.Vartype_String)) { return(new TextBuffer(ConvertStringToJava(value.ToString(), ascii)).Enclose("\"", "\"")); } else if (constType.Equals(VarType.Vartype_Class)) { string stringVal = value.ToString(); VarType type = new VarType(stringVal, !stringVal.StartsWith("[")); return(new TextBuffer(ExprProcessor.GetCastTypeName(type)).Append(".class")); } break; } } throw new Exception("invalid constant type: " + constType); }
public override TextBuffer ToJava(int indent, BytecodeMappingTracer tracer) { TextBuffer buf = new TextBuffer(); string super_qualifier = null; bool isInstanceThis = false; tracer.AddMapping(bytecode); if (instance is InvocationExprent) { ((InvocationExprent)instance).MarkUsingBoxingResult(); } if (isStatic__) { if (IsBoxingCall() && canIgnoreBoxing) { // process general "boxing" calls, e.g. 'Object[] data = { true }' or 'Byte b = 123' // here 'byte' and 'short' values do not need an explicit narrowing type cast ExprProcessor.GetCastedExprent(lstParameters[0], descriptor.@params[0], buf, indent , false, false, false, false, tracer); return(buf); } ClassesProcessor.ClassNode node = (ClassesProcessor.ClassNode)DecompilerContext.GetProperty (DecompilerContext.Current_Class_Node); if (node == null || !classname.Equals(node.classStruct.qualifiedName)) { buf.Append(DecompilerContext.GetImportCollector().GetShortNameInClassContext(ExprProcessor .BuildJavaClassName(classname))); } } else { if (instance != null && instance.type == Exprent.Exprent_Var) { VarExprent instVar = (VarExprent)instance; VarVersionPair varPair = new VarVersionPair(instVar); VarProcessor varProc = instVar.GetProcessor(); if (varProc == null) { MethodWrapper currentMethod = (MethodWrapper)DecompilerContext.GetProperty(DecompilerContext .Current_Method_Wrapper); if (currentMethod != null) { varProc = currentMethod.varproc; } } string this_classname = null; if (varProc != null) { this_classname = varProc.GetThisVars().GetOrNull(varPair); } if (this_classname != null) { isInstanceThis = true; if (invocationTyp == Invoke_Special) { if (!classname.Equals(this_classname)) { // TODO: direct comparison to the super class? StructClass cl = DecompilerContext.GetStructContext().GetClass(classname); bool isInterface = cl != null && cl.HasModifier(ICodeConstants.Acc_Interface); super_qualifier = !isInterface ? this_classname : classname; } } } } if (functype == Typ_General) { if (super_qualifier != null) { TextUtil.WriteQualifiedSuper(buf, super_qualifier); } else if (instance != null) { TextBuffer res = instance.ToJava(indent, tracer); if (IsUnboxingCall()) { // we don't print the unboxing call - no need to bother with the instance wrapping / casting buf.Append(res); return(buf); } VarType rightType = instance.GetExprType(); VarType leftType = new VarType(ICodeConstants.Type_Object, 0, classname); if (rightType.Equals(VarType.Vartype_Object) && !leftType.Equals(rightType)) { buf.Append("((").Append(ExprProcessor.GetCastTypeName(leftType)).Append(")"); if (instance.GetPrecedence() >= FunctionExprent.GetPrecedence(FunctionExprent.Function_Cast )) { res.Enclose("(", ")"); } buf.Append(res).Append(")"); } else if (instance.GetPrecedence() > GetPrecedence()) { buf.Append("(").Append(res).Append(")"); } else { buf.Append(res); } } } } switch (functype) { case Typ_General: { if (VarExprent.Var_Nameless_Enclosure.Equals(buf.ToString())) { buf = new TextBuffer(); } if (buf.Length() > 0) { buf.Append("."); } buf.Append(name); if (invocationTyp == Invoke_Dynamic) { buf.Append("<invokedynamic>"); } buf.Append("("); break; } case Typ_Clinit: { throw new Exception("Explicit invocation of " + ICodeConstants.Clinit_Name); } case Typ_Init: { if (super_qualifier != null) { buf.Append("super("); } else if (isInstanceThis) { buf.Append("this("); } else if (instance != null) { buf.Append(instance.ToJava(indent, tracer)).Append(".<init>("); } else { throw new Exception("Unrecognized invocation of " + ICodeConstants.Init_Name); } break; } } List <VarVersionPair> mask = null; bool isEnum = false; if (functype == Typ_Init) { ClassesProcessor.ClassNode newNode = DecompilerContext.GetClassProcessor().GetMapRootClasses ().GetOrNull(classname); if (newNode != null) { mask = ExprUtil.GetSyntheticParametersMask(newNode, stringDescriptor, lstParameters .Count); isEnum = newNode.classStruct.HasModifier(ICodeConstants.Acc_Enum) && DecompilerContext .GetOption(IFernflowerPreferences.Decompile_Enum); } } BitSet setAmbiguousParameters = GetAmbiguousParameters(); // omit 'new Type[] {}' for the last parameter of a vararg method call if (lstParameters.Count == [email protected] && IsVarArgCall()) { Exprent lastParam = lstParameters[lstParameters.Count - 1]; if (lastParam.type == Exprent_New && lastParam.GetExprType().arrayDim >= 1) { ((NewExprent)lastParam).SetVarArgParam(true); } } bool firstParameter = true; int start = isEnum ? 2 : 0; for (int i = start; i < lstParameters.Count; i++) { if (mask == null || mask[i] == null) { TextBuffer buff = new TextBuffer(); bool ambiguous = setAmbiguousParameters.Get(i); // 'byte' and 'short' literals need an explicit narrowing type cast when used as a parameter ExprProcessor.GetCastedExprent(lstParameters[i], descriptor.@params[i], buff, indent , true, ambiguous, true, true, tracer); // the last "new Object[0]" in the vararg call is not printed if (buff.Length() > 0) { if (!firstParameter) { buf.Append(", "); } buf.Append(buff); } firstParameter = false; } } buf.Append(')'); return(buf); }
// precedence of new public override TextBuffer ToJava(int indent, BytecodeMappingTracer tracer) { TextBuffer buf = new TextBuffer(); if (anonymous) { ClassesProcessor.ClassNode child = DecompilerContext.GetClassProcessor().GetMapRootClasses ().GetOrNull(newType.value); // IDEA-204310 - avoid backtracking later on for lambdas (causes spurious imports) if (!enumConst && (!lambda || DecompilerContext.GetOption(IFernflowerPreferences .Lambda_To_Anonymous_Class))) { string enclosing = null; if (!lambda && constructor != null) { enclosing = GetQualifiedNewInstance(child.anonymousClassType.value, constructor.GetLstParameters (), indent, tracer); if (enclosing != null) { buf.Append(enclosing).Append('.'); } } buf.Append("new "); string typename = ExprProcessor.GetCastTypeName(child.anonymousClassType); if (enclosing != null) { ClassesProcessor.ClassNode anonymousNode = DecompilerContext.GetClassProcessor(). GetMapRootClasses().GetOrNull(child.anonymousClassType.value); if (anonymousNode != null) { typename = anonymousNode.simpleName; } else { typename = Sharpen.Runtime.Substring(typename, typename.LastIndexOf('.') + 1); } } GenericClassDescriptor descriptor = ClassWriter.GetGenericClassDescriptor(child.classStruct ); if (descriptor != null) { if ((descriptor.superinterfaces.Count == 0)) { buf.Append(GenericMain.GetGenericCastTypeName(descriptor.superclass)); } else { if (descriptor.superinterfaces.Count > 1 && !lambda) { DecompilerContext.GetLogger().WriteMessage("Inconsistent anonymous class signature: " + child.classStruct.qualifiedName, IFernflowerLogger.Severity.Warn); } buf.Append(GenericMain.GetGenericCastTypeName(descriptor.superinterfaces[0])); } } else { buf.Append(typename); } } buf.Append('('); if (!lambda && constructor != null) { List <Exprent> parameters = constructor.GetLstParameters(); List <VarVersionPair> mask = child.GetWrapper().GetMethodWrapper(ICodeConstants.Init_Name , constructor.GetStringDescriptor()).synthParameters; if (mask == null) { InvocationExprent superCall = child.superInvocation; mask = ExprUtil.GetSyntheticParametersMask(superCall.GetClassname(), superCall.GetStringDescriptor (), parameters.Count); } int start = enumConst ? 2 : 0; bool firstParam = true; for (int i = start; i < parameters.Count; i++) { if (mask == null || mask[i] == null) { if (!firstParam) { buf.Append(", "); } ExprProcessor.GetCastedExprent(parameters[i], constructor.GetDescriptor().@params [i], buf, indent, true, tracer); firstParam = false; } } } buf.Append(')'); if (enumConst && buf.Length() == 2) { buf.SetLength(0); } if (lambda) { if (!DecompilerContext.GetOption(IFernflowerPreferences.Lambda_To_Anonymous_Class )) { buf.SetLength(0); } // remove the usual 'new <class>()', it will be replaced with lambda style '() ->' Exprent methodObject = constructor == null ? null : constructor.GetInstance(); TextBuffer clsBuf = new TextBuffer(); new ClassWriter().ClassLambdaToJava(child, clsBuf, methodObject, indent, tracer); buf.Append(clsBuf); tracer.IncrementCurrentSourceLine(clsBuf.CountLines()); } else { TextBuffer clsBuf = new TextBuffer(); new ClassWriter().ClassToJava(child, clsBuf, indent, tracer); buf.Append(clsBuf); tracer.IncrementCurrentSourceLine(clsBuf.CountLines()); } } else if (directArrayInit) { VarType leftType = newType.DecreaseArrayDim(); buf.Append('{'); for (int i = 0; i < lstArrayElements.Count; i++) { if (i > 0) { buf.Append(", "); } ExprProcessor.GetCastedExprent(lstArrayElements[i], leftType, buf, indent, false, tracer); } buf.Append('}'); } else if (newType.arrayDim == 0) { if (!enumConst) { string enclosing = null; if (constructor != null) { enclosing = GetQualifiedNewInstance(newType.value, constructor.GetLstParameters() , indent, tracer); if (enclosing != null) { buf.Append(enclosing).Append('.'); } } buf.Append("new "); string typename = ExprProcessor.GetTypeName(newType); if (enclosing != null) { ClassesProcessor.ClassNode newNode = DecompilerContext.GetClassProcessor().GetMapRootClasses ().GetOrNull(newType.value); if (newNode != null) { typename = newNode.simpleName; } else { typename = Sharpen.Runtime.Substring(typename, typename.LastIndexOf('.') + 1); } } buf.Append(typename); } if (constructor != null) { List <Exprent> parameters = constructor.GetLstParameters(); List <VarVersionPair> mask = ExprUtil.GetSyntheticParametersMask(constructor.GetClassname (), constructor.GetStringDescriptor(), parameters.Count); int start = enumConst ? 2 : 0; if (!enumConst || start < parameters.Count) { buf.Append('('); bool firstParam = true; for (int i = start; i < parameters.Count; i++) { if (mask == null || mask[i] == null) { Exprent expr = parameters[i]; VarType leftType = constructor.GetDescriptor().@params[i]; if (i == parameters.Count - 1 && expr.GetExprType() == VarType.Vartype_Null && ProbablySyntheticParameter (leftType.value)) { break; } // skip last parameter of synthetic constructor call if (!firstParam) { buf.Append(", "); } ExprProcessor.GetCastedExprent(expr, leftType, buf, indent, true, false, true, true , tracer); firstParam = false; } } buf.Append(')'); } } } else if (isVarArgParam) { // just print the array elements VarType leftType = newType.DecreaseArrayDim(); for (int i = 0; i < lstArrayElements.Count; i++) { if (i > 0) { buf.Append(", "); } // new String[][]{{"abc"}, {"DEF"}} => new String[]{"abc"}, new String[]{"DEF"} Exprent element = lstArrayElements[i]; if (element.type == Exprent_New) { ((NewExprent)element).SetDirectArrayInit(false); } ExprProcessor.GetCastedExprent(element, leftType, buf, indent, false, tracer); } // if there is just one element of Object[] type it needs to be casted to resolve ambiguity if (lstArrayElements.Count == 1) { VarType elementType = lstArrayElements[0].GetExprType(); if (elementType.type == ICodeConstants.Type_Object && elementType.value.Equals("java/lang/Object" ) && elementType.arrayDim >= 1) { buf.Prepend("(Object)"); } } } else { buf.Append("new ").Append(ExprProcessor.GetTypeName(newType)); if ((lstArrayElements.Count == 0)) { for (int i = 0; i < newType.arrayDim; i++) { buf.Append('['); if (i < lstDims.Count) { buf.Append(lstDims[i].ToJava(indent, tracer)); } buf.Append(']'); } } else { for (int i = 0; i < newType.arrayDim; i++) { buf.Append("[]"); } VarType leftType = newType.DecreaseArrayDim(); buf.Append('{'); for (int i = 0; i < lstArrayElements.Count; i++) { if (i > 0) { buf.Append(", "); } ExprProcessor.GetCastedExprent(lstArrayElements[i], leftType, buf, indent, false, tracer); } buf.Append('}'); } } return(buf); }
public virtual void Save() { switch (type) { case Type_Folder: { // create folder resultSaver.SaveFolder(filename); // non-class files foreach (string[] pair in otherEntries) { resultSaver.CopyFile(pair[0], filename, pair[1]); } // classes for (int i = 0; i < classes.Count; i++) { StructClass cl = classes[i]; string entryName = decompiledData.GetClassEntryName(cl, classEntries[i]); if (entryName != null) { string content = decompiledData.GetClassContent(cl); if (content != null) { int[] mapping = null; if (DecompilerContext.GetOption(IFernflowerPreferences.Bytecode_Source_Mapping)) { mapping = DecompilerContext.GetBytecodeSourceMapper().GetOriginalLinesMapping(); } resultSaver.SaveClassFile(filename, cl.qualifiedName, entryName, content, mapping ); } } } break; } case Type_Jar: case Type_Zip: { // create archive file resultSaver.SaveFolder(archivePath); resultSaver.CreateArchive(archivePath, filename, manifest); // directory entries foreach (string dirEntry in dirEntries) { resultSaver.SaveDirEntry(archivePath, filename, dirEntry + "\\"); } // non-class entries foreach (string[] pair in otherEntries) { if (type != Type_Jar || !Sharpen.Runtime.EqualsIgnoreCase(Manifest_Name, pair[1])) { resultSaver.CopyEntry(pair[0], archivePath, filename, pair[1]); } } // classes for (int i = 0; i < classes.Count; i++) { StructClass cl = classes[i]; string entryName = decompiledData.GetClassEntryName(cl, classEntries[i]); if (entryName != null) { string content = decompiledData.GetClassContent(cl); resultSaver.SaveClassEntry(archivePath, filename, cl.qualifiedName, entryName, content ); } } resultSaver.CloseArchive(archivePath, filename); break; } } }
/// <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); }