/// <summary> /// Java ctor /// </summary> public MethodSource(XMethodDefinition method, JavaMethodDefinition javaMethod) { if (javaMethod == null) throw new ArgumentNullException(); this.method = method; this.javaMethod = javaMethod; }
/// <summary> /// AST ctor /// </summary> public MethodSource(XMethodDefinition method, AstBlock ast) { if (ast == null) throw new ArgumentNullException(); this.method = method; this.ast = ast; }
/// <summary> /// IL ctor /// </summary> public MethodSource(XMethodDefinition method, ILMethodDefinition ilMethod) { if (ilMethod == null) throw new ArgumentNullException(); this.method = method; this.ilMethod = ilMethod; }
/// <summary> /// Should invoke_super be used to call this method from the given method? /// </summary> public bool UseInvokeSuper(XMethodDefinition currentlyCompiledMethod) { if (IsConstructor) { return(false); } if (this == currentlyCompiledMethod) { return(false); } if (!DeclaringType.IsBaseOf(currentlyCompiledMethod.DeclaringType)) { return(false); } // Check if this method is a direct base method of the currently compiled method var iterator = currentlyCompiledMethod; while (true) { var baseMethod = iterator.GetBaseMethod(true); if ((baseMethod == null) || (baseMethod == iterator)) { break; } if ((baseMethod.IsSame(this)) && (baseMethod != currentlyCompiledMethod)) { return(true); } // Keep the order or baseMethod.IsSame(..) iterator = baseMethod; } // Check if this method is a direct base method of any of the methods in the declaring type of the currently compiled method. var sameInCurrentType = currentlyCompiledMethod.DeclaringType.Methods.FirstOrDefault(x => x.IsSameExceptDeclaringType(this)); if (sameInCurrentType != null) { iterator = sameInCurrentType; while (true) { var baseMethod = iterator.GetBaseMethod(true); if ((baseMethod == null) || (baseMethod == iterator)) { break; } if ((baseMethod.IsSame(this)) && (baseMethod != currentlyCompiledMethod)) { return(true); } // Keep the order or baseMethod.IsSame(..) iterator = baseMethod; } } return(false); }
/// <summary> /// Default ctor /// </summary> public DelegateType(AssemblyCompiler compiler, XTypeDefinition delegateType, ClassDefinition interfaceClass, Dex target, NameConverter nsConverter) { this.compiler = compiler; this.delegateType = delegateType; this.interfaceClass = interfaceClass; // Build invoke prototype invokeMethod = delegateType.Methods.First(x => x.EqualsName("Invoke")); }
/// <summary> /// .NET ctor /// </summary> public DecompilerContext(XMethodDefinition currentMethod) { if (currentMethod == null) throw new ArgumentNullException("currentMethod"); name = currentMethod.Name; declaringTypeName = currentMethod.DeclaringType.Name; declaringType = currentMethod.DeclaringType; returnType = currentMethod.ReturnType; currentModule = currentMethod.Module; }
public MethodBody GetMethodBody(MethodDefinition targetMethod, XMethodDefinition sourceMethod) { var javaType = (XBuilder.JavaTypeDefinition) sourceMethod.DeclaringType; var className = javaType.ClassFile.ClassName; var source = javaType.ClassFile.Loader.TryGetClassSource(className); if (source == null) return null; DexLookup dex = GetOrCreateDex(source, waitForResult: true); var methodDef = dex.GetMethod(targetMethod.Owner.Fullname, targetMethod.Name, targetMethod.Prototype.ToSignature()); return methodDef == null ? null : methodDef.Body; }
/// <summary> /// Create the current type as class definition. /// </summary> internal DelegateInstanceTypeBuilder( ISourceLocation sequencePoint, AssemblyCompiler compiler, DexTargetPackage targetPackage, ClassDefinition delegateClass, XMethodDefinition invokeMethod, Prototype invokePrototype, XMethodDefinition calledMethod) { this.sequencePoint = sequencePoint; this.compiler = compiler; this.targetPackage = targetPackage; this.delegateClass = delegateClass; this.invokeMethod = invokeMethod; this.invokePrototype = invokePrototype; this.calledMethod = calledMethod; this.multicastDelegateClass = compiler.GetDot42InternalType("System", "MulticastDelegate").GetClassReference(targetPackage); }
/// <summary> /// Resolve this reference to it's definition. /// </summary> public override bool TryResolve(out XMethodDefinition method) { string methodName; string descriptor; string className; if (TryGetJavaImportNames(out methodName, out descriptor, out className)) { // Resolve to java method definition var declaringType = Java.XBuilder.AsTypeReference(Module, className, XTypeUsageFlags.DeclaringType); var methodRef = Java.XBuilder.AsMethodReference(Module, methodName, descriptor, declaringType, className, HasThis); return(methodRef.TryResolve(out method)); } method = this; return(true); }
/// <summary> /// Create the current type as class definition. /// </summary> public void Create(ClassDefinition declaringClass, DexTargetPackage targetPackage) { // Find xMethod xMethod = XBuilder.AsMethodDefinition(compiler.Module, method); // Create method definition dmethod = new DexLib.MethodDefinition(); dmethod.Name = GetMethodName(method, targetPackage); dmethod.MapFileId = compiler.GetNextMapFileId(); AddMethodToDeclaringClass(declaringClass, dmethod, targetPackage); targetPackage.Record(xMethod, dmethod); // Set access flags SetAccessFlags(dmethod, method); // Create prototype dmethod.Prototype = PrototypeBuilder.BuildPrototype(compiler, targetPackage, declaringClass, xMethod); }
/// <summary> /// Try to get a method with given reference in this type. /// The declaring type of the method reference is assumed to refer to this type. /// </summary> public bool TryGet(XMethodReference methodRef, out XMethodDefinition method) { // Look in my own methods method = Methods.FirstOrDefault(x => x.IsSameExceptDeclaringType(methodRef)); if (method != null) { return(true); } // Look in base type XTypeDefinition baseTypeDef; if ((BaseType != null) && BaseType.TryResolve(out baseTypeDef)) { return(baseTypeDef.TryGet(methodRef, out method)); } return(false); }
/// <summary> /// Resolve this reference to it's definition. /// </summary> public virtual bool TryResolve(out XMethodDefinition method) { if (resolvedMethod != null) { method = resolvedMethod; return true; } method = null; XTypeDefinition declaringType; if (!DeclaringType.GetElementType().TryResolve(out declaringType)) return false; if (!declaringType.TryGet(this, out method)) return false; // Cache for later resolvedMethod = method; declaringType.AddFlushAction(() => resolvedMethod = null); return true; }
/// <summary> /// Default ctor /// </summary> public DelegateType(AssemblyCompiler compiler, XTypeDefinition delegateType, ClassDefinition interfaceClass, Dex target, NameConverter nsConverter) { this.compiler = compiler; this.delegateType = delegateType; this.interfaceClass = interfaceClass; // Build invoke prototype invokeMethod = delegateType.Methods.First(x => x.EqualsName("Invoke")); XTypeDefinition baseType = delegateType; while ((null != baseType) && !baseType.Methods.Any(x => x.EqualsName("Equals"))) { baseType = baseType.BaseType as XTypeDefinition; } if (null != baseType) { equalsMethod = baseType.Methods.First(x => x.EqualsName("Equals")); } }
/// <summary> /// Add generic parameters to the prototype based on the given XMethodDefinition /// </summary> public static void AddGenericParameters(AssemblyCompiler compiler, DexTargetPackage targetPackage, XMethodDefinition method, Prototype result) { if (method.NeedsGenericInstanceTypeParameter) { var annType = compiler.GetDot42InternalType(InternalConstants.GenericTypeParameterAnnotation).GetClassReference(targetPackage); int numParameters = method.DeclaringType.GenericParameters.Count; var buildAsArray = numParameters > InternalConstants.GenericTypeParametersAsArrayThreshold; var parameterArray = result.GenericInstanceTypeParameters; AddGenericParameterArguments(result, buildAsArray, numParameters, "__$$git", annType, parameterArray); } if (method.NeedsGenericInstanceMethodParameter) { // Add GenericInstance parameter var annType = compiler.GetDot42InternalType(InternalConstants.GenericMethodParameterAnnotation).GetClassReference(targetPackage); int numParameters = method.GenericParameters.Count; var buildAsArray = numParameters > InternalConstants.GenericMethodParametersAsArrayThreshold; var parameterArray = result.GenericInstanceMethodParameters; AddGenericParameterArguments(result, buildAsArray, numParameters, "__$$gim", annType, parameterArray); } }
/// <summary> /// Gets the instance type that calls the given method. /// Create if needed. /// </summary> public DelegateInstanceType GetOrCreateInstance(ISourceLocation sequencePoint, DexTargetPackage targetPackage, XMethodDefinition calledMethod) { DelegateInstanceType result; if (instances.TryGetValue(calledMethod, out result)) return result; // Ensure prototype exists if (invokePrototype == null) { invokePrototype = PrototypeBuilder.BuildPrototype(compiler, targetPackage, interfaceClass, invokeMethod); } // Not found, build it. var builder = new DelegateInstanceTypeBuilder(sequencePoint, compiler, targetPackage, InterfaceClass, invokeMethod, invokePrototype, calledMethod); result = builder.Create(); instances.Add(calledMethod, result); return result; }
/// <summary> /// Create a prototype for the given methods signature /// </summary> internal static Prototype BuildPrototype(AssemblyCompiler compiler, DexTargetPackage targetPackage, ClassDefinition declaringClass, XMethodDefinition method) { var result = new Prototype(); result.ReturnType = method.ReturnType.GetReference(targetPackage); if (method.IsAndroidExtension && !method.IsStatic) { // Add "this" parameter var dparameter = new Parameter(method.DeclaringType.GetReference(targetPackage), "this"); result.Parameters.Add(dparameter); } foreach (var p in method.Parameters) { var dparameter = new Parameter(p.ParameterType.GetReference(targetPackage), p.Name); result.Parameters.Add(dparameter); } AddGenericParameters(compiler, targetPackage, method, result); result.Freeze(); return result; }
/// <summary> /// Resolve this reference to it's definition. /// </summary> public virtual bool TryResolve(out XMethodDefinition method) { if (resolvedMethod != null) { method = resolvedMethod; return(true); } method = null; XTypeDefinition declaringType; if (!DeclaringType.GetElementType().TryResolve(out declaringType)) { return(false); } if (!declaringType.TryGet(this, out method)) { return(false); } // Cache for later resolvedMethod = method; declaringType.AddFlushAction(() => resolvedMethod = null); return(true); }
/// <summary> /// Create a prototype for the given methods signature /// </summary> internal static Prototype BuildPrototype(AssemblyCompiler compiler, DexTargetPackage targetPackage, ClassDefinition declaringClass, XMethodDefinition method) { var result = new Prototype(); result.ReturnType = method.ReturnType.GetReference(targetPackage); if (method.IsAndroidExtension && !method.IsStatic) { // Add "this" parameter var dparameter = new Parameter(method.DeclaringType.GetReference(targetPackage), "this"); result.Parameters.Add(dparameter); } foreach (var p in method.Parameters) { var dparameter = new Parameter(p.ParameterType.GetReference(targetPackage), p.Name); result.Parameters.Add(dparameter); } if (method.NeedsGenericInstanceTypeParameter) { // Add GenericInstance parameter (to pass the generic instance array of the declaring type) var paramType = FrameworkReferences.ClassArray; var dparameter = new Parameter(paramType, "__$$git"); var annType = compiler.GetDot42InternalType(InternalConstants.GenericTypeParameterAnnotation).GetClassReference(targetPackage); dparameter.Annotations.Add(new Annotation(annType, AnnotationVisibility.Runtime)); result.Parameters.Add(dparameter); result.GenericInstanceTypeParameter = dparameter; } if (method.NeedsGenericInstanceMethodParameter) { // Add GenericInstance parameter var paramType = FrameworkReferences.ClassArray; var dparameter = new Parameter(paramType, "__$$gim"); var annType = compiler.GetDot42InternalType(InternalConstants.GenericMethodParameterAnnotation).GetClassReference(targetPackage); dparameter.Annotations.Add(new Annotation(annType, AnnotationVisibility.Runtime)); result.Parameters.Add(dparameter); result.GenericInstanceMethodParameter = dparameter; } return result; }
private void DecompileMethod(XMethodDefinition xMethod, ITextOutput output, int indentation=0) { var indent = new string(Enumerable.Repeat('\t', indentation).ToArray()); var ilMethod = xMethod as XBuilder.ILMethodDefinition; if (ilMethod == null || !ilMethod.OriginalMethod.HasBody) { output.Write(indent); output.WriteLine("// not an il method or method without body."); return; } var methodSource = new MethodSource(xMethod, ilMethod.OriginalMethod); var node = MethodBodyCompiler.CreateOptimizedAst(AssemblyCompiler, methodSource, GenerateSetNextInstructionCode, StopConversion); if (StopConversion != StopAstConversion.None) { output.Write(indent); output.Write("// Stop " + StopConversion); output.WriteLine(); output.WriteLine(); } var bridge = new TextOutputBridge(output); for(int i = 0; i < indentation; ++i) bridge.Indent(); FormattingOptions formattingOptions; if (StopConversion == StopAstConversion.AfterILConversion || !BreakExpressionLines) formattingOptions = FormattingOptions.Default; else formattingOptions = FormattingOptions.BreakExpressions; if(!ShowFullNames) formattingOptions |= FormattingOptions.SimpleNames; if(ShowHasSeqPoint) formattingOptions |= FormattingOptions.ShowHasSeqPoint; node.WriteTo(bridge, formattingOptions); for (int i = 0; i < indentation; ++i) bridge.Unindent(); }
private bool IsUnderlyingCodeModified(XMethodDefinition sourceMethod) { var ilMethod = sourceMethod as XModel.DotNet.XBuilder.ILMethodDefinition; var javaMethod = sourceMethod as XModel.Java.XBuilder.JavaMethodDefinition; if (ilMethod != null) { var assembly = ilMethod.OriginalMethod.DeclaringType.Module.Assembly; if (_modifiedDetector.IsModified(assembly)) return true; } else if (javaMethod != null) { var javaType = (XModel.Java.XBuilder.JavaTypeDefinition)javaMethod.DeclaringType; var classFile = (ClassFile) javaType.OriginalTypeDefinition; var loader = classFile.Loader as AssemblyClassLoader; var assembly = loader == null ? null : loader.GetAssembly(classFile); if (assembly == null || _modifiedDetector.IsModified(assembly)) return true; } else { // TODO: synthetic methods could be resolved from the cache as well. // check if this would bring any performance benefits. return true; } return false; }
public CacheEntry GetFromCacheImpl(MethodDefinition targetMethod, XMethodDefinition sourceMethod, AssemblyCompiler compiler, DexTargetPackage targetPackage) { if (_initialize == null) return null; _initialize.Wait(); if (!IsEnabled) return null; if (sourceMethod.ScopeId == null || sourceMethod.ScopeId == "(none)") { return null; } if (IsUnderlyingCodeModified(sourceMethod)) return null; Tuple<TypeEntry, MethodEntry> entry; string typeScopeId = sourceMethod.DeclaringType.ScopeId; string methodScopeId = sourceMethod.ScopeId; MethodDefinition cachedMethod; if (_methodsByScopeId.TryGetValue(Tuple.Create(typeScopeId, methodScopeId), out entry)) { cachedMethod = _dexLookup.GetMethod(entry.Item1.DexName, entry.Item2.DexName, entry.Item2.DexSignature); } else { // try directly in the dexlookup, for jar imports cachedMethod = _dexLookup.GetMethod(typeScopeId.Replace("/", "."), targetMethod.Name, targetMethod.Prototype.ToSignature()); } if (cachedMethod == null) return null; if (cachedMethod.Body == null) { // I believe there is a bug in MethodExplicitInterfaceConverter generating // stubs for interfaces if they derive from an imported interface. // Bail out for now until this is fixed. DLog.Debug(DContext.CompilerCodeGenerator, "Compiler cache: no method body found on cached version of {0}, even though one was expected.", sourceMethod); return null; } try { if (!Equals(cachedMethod.Prototype,targetMethod.Prototype)) { throw new Exception("internal error, got the wrong method."); } var body = DexMethodBodyCloner.Clone(targetMethod, cachedMethod); FixReferences(body, compiler, targetPackage); string className = entry != null ? entry.Item1.DexName : body.Owner.Owner.Fullname; var @class = _dexLookup.GetClass(className); return new CacheEntry(body, entry != null ? entry.Item2 : null, entry != null ? _map.GetSourceCodePositions(entry.Item2) : null, @class.SourceFile); } catch (CompilerCacheResolveException ex) { // This happens at the moment for methods using fields in the __generated class, // as well as for references to generated methods (mostly explicit interfac stubs) // during the IL conversion phase. // This also seems to happen for Framework-nested classes, maybe because these do // not get an entry in the map file. This should be fixed. // The number of these failures in my test is 890 out of ~12000. We gracefully // handle errors by re-compiling the method body. Debug.WriteLine(string.Format("Compiler cache: error while converting cached body: {0}: {1}. Not using cached body.", sourceMethod, ex.Message)); return null; } catch (Exception ex) { DLog.Warning(DContext.CompilerCodeGenerator, "Compiler cache: exception while converting cached body: {0}: {1}. Not using cached body.", sourceMethod, ex.Message); Trace.WriteLine(string.Format("Compiler cache: error while converting cached body: {0}: {1}. Not using cached body.", sourceMethod, ex.Message)); return null; } }
public CacheEntry GetFromCache(MethodDefinition targetMethod, XMethodDefinition sourceMethod, AssemblyCompiler compiler, DexTargetPackage targetPackage) { var ret = GetFromCacheImpl(targetMethod, sourceMethod, compiler, targetPackage); if (ret != null) Interlocked.Increment(ref statCacheHits); else Interlocked.Increment(ref statCacheMisses); return ret; }
/// <summary> /// Default ctor /// </summary> public CompiledMethod(XMethodDefinition method) { if (method == null) throw new ArgumentNullException("method"); this.method = method; }
/// <summary> /// Resolve this reference to it's definition. /// </summary> public override bool TryResolve(out XMethodDefinition method) { return ElementMethod.TryResolve(out method); }
/// <summary> /// Create a method reference for the given method using this this as declaring type. /// Usually the method will be returned, unless this type is a generic instance type. /// </summary> public override XMethodReference CreateReference(XMethodDefinition method) { return(new XMethodReference.Simple(method.Name, method.HasThis, method.ReturnType, this, method.Parameters, method.GenericParameters.Select(x => x.Name))); }
/// <summary> /// Create a method reference for the given method using this this as declaring type. /// Usually the method will be returned, unless this type is a generic instance type. /// </summary> public virtual XMethodReference CreateReference(XMethodDefinition method) { return(method); }
/// <summary> /// Try to get a method with given reference in this type. /// The declaring type of the method reference is assumed to refer to this type. /// </summary> public bool TryGet(XMethodReference methodRef, out XMethodDefinition method) { // Look in my own methods method = Methods.FirstOrDefault(x => x.IsSameExceptDeclaringType(methodRef)); if (method != null) return true; // Look in base type XTypeDefinition baseTypeDef; if ((BaseType != null) && BaseType.TryResolve(out baseTypeDef)) { return baseTypeDef.TryGet(methodRef, out method); } return false; }
/// <summary> /// Process an argument of the given call node. /// </summary> private static void CloneStructArgument(AstExpression callNode, XMethodDefinition method, int argumentIndex) { // Clone structs var paramIndex = method.IsStatic ? argumentIndex : argumentIndex - 1; if ((paramIndex >= 0) && (method.Name != NameConstants.Struct.CloneMethodName) && (method.Name != NameConstants.Struct.CopyFromMethodName)) { var paramType = method.Parameters[paramIndex].ParameterType; XTypeDefinition typeDef; if (paramType.IsStruct(out typeDef)) { // Call $Clone var argNode = callNode.Arguments[argumentIndex]; if (IsCloneNeeded(argNode)) { var cloneMethod = GetCloneMethod(typeDef); var clone = new AstExpression(argNode.SourceLocation, AstCode.Call, paramType.CreateReference(cloneMethod), argNode); callNode.Arguments[argumentIndex] = clone; } } } }
/// <summary> /// Process an argument of the given call node. /// </summary> private static void ProcessArgument(AstExpression callNode, XMethodDefinition method, int argumentIndex, XModule assembly) { var argNode = callNode.Arguments[argumentIndex]; // Process argument switch (argNode.Code) { case AstCode.Ldloca: // Parameter argNode.Code = AstCode.Ldloc; break; case AstCode.Ldflda: // Instance field argNode.Code = AstCode.Ldfld; break; case AstCode.Ldsflda: // Static field argNode.Code = AstCode.Ldsfld; break; case AstCode.Ldelema: // Array element argNode.Code = AstCode.Ldelem_Any; break; case AstCode.Ldobj: // Load object if ((argumentIndex == 0) && !method.IsStatic) { AstVariable variable; if ((argNode.Arguments.Count == 1) && (argNode.Arguments[0].Match(AstCode.Ldloc, out variable)) && variable.Type.IsByReference) { argNode.Code = AstCode.Ldloc; argNode.Operand = variable; argNode.InferredType = variable.Type.ElementType; argNode.Arguments.Clear(); } } break; } }
/// <summary> /// Resolve this reference to it's definition. /// </summary> public override bool TryResolve(out XMethodDefinition method) { return(ElementMethod.TryResolve(out method)); }
/// <summary> /// Record the given method mapping /// </summary> internal DexLib.MethodDefinition GetMethod(XMethodDefinition xMethod) { DexLib.MethodDefinition dmethod; if (xMethodMap.TryGetValue(xMethod, out dmethod)) return dmethod; /*var javaImportAttr = ilMethod.GetJavaImportAttribute(); if (javaImportAttr != null) { string memberName; string descriptor; string className; javaImportAttr.GetDexOrJavaImportNames(ilMethod, out memberName, out descriptor, out className); var javaMethod = javaMethodMap.Keys.FirstOrDefault(x => (x.Name == memberName) && (x.Descriptor == descriptor) && (x.DeclaringClass.ClassName == className)); if (javaMethod != null) { return GetMethod(javaMethod); } }*/ throw new ArgumentException(string.Format("Method {0} not found", xMethod)); }
/// <summary> /// Create a method reference for the given method using this this as declaring type. /// Usually the method will be returned, unless this type is a generic instance type. /// </summary> public override XMethodReference CreateReference(XMethodDefinition method) { return new XMethodReference.Simple(method.Name, method.HasThis, method.ReturnType, this, method.Parameters, method.GenericParameters.Select(x => x.Name)); }
internal CompiledMethod GetCompiledMethod(XMethodDefinition method) { return ((Target.Dex.DexTargetPackage) targetPackage).GetMethod(method); }
/// <summary> /// Record the given method mapping /// </summary> internal void Record(XMethodDefinition xMethod, DexLib.MethodDefinition dMethod) { xMethodMap.Add(xMethod, dMethod); }
/// <summary> /// The given node is defaultvalue(struct). /// Convert it to newobj /// </summary> private static void ConvertDefaultValue(AstExpression callNode, XMethodDefinition defaultCtorDef) { var type = (XTypeReference) callNode.Operand; var defaultCtor = type.CreateReference(defaultCtorDef); // Remove "this" argument callNode.Arguments.Clear(); callNode.Code = AstCode.Newobj; callNode.Operand = defaultCtor; callNode.SetType(defaultCtor.DeclaringType); }
/// <summary> /// Default ctor /// </summary> public DelegateInstanceType(XMethodDefinition calledMethod, ClassDefinition instanceDefinition, Dot42.DexLib.MethodDefinition instanceCtor) { this.calledMethod = calledMethod; this.instanceDefinition = instanceDefinition; this.instanceCtor = instanceCtor; }
/// <summary> /// The given node is newarr(struct). /// Convert it to initStructArray(newarr(struct)) /// </summary> private static void ConvertNewArrStruct(AstExpression newArrNode, XMethodDefinition defaultCtor) { var newArrClone = new AstExpression(newArrNode); newArrNode.Code = AstCode.InitStructArray; newArrNode.Arguments.Clear(); newArrNode.Arguments.Add(newArrClone); newArrNode.Operand = defaultCtor; }