/// <summary> /// The given node is defaultvalue(struct). /// Convert it to newobj /// </summary> internal static void ConvertDefaultValue(AstExpression callNode, XMethodDefinition defaultCtorDef) { var type = (XTypeReference)callNode.Operand; var defaultCtor = type.CreateReference(defaultCtorDef); var typeDef = defaultCtorDef.DeclaringType; if (typeDef.IsImmutableStruct) { var fieldDef = typeDef.Fields.SingleOrDefault(f => f.Name == NameConstants.Struct.DefaultFieldName); if (fieldDef != null) { // load the default field. callNode.Arguments.Clear(); callNode.Code = AstCode.Ldsfld; callNode.Operand = fieldDef; callNode.SetType(defaultCtor.DeclaringType); return; } } else { // Remove "this" argument callNode.Arguments.Clear(); callNode.Code = AstCode.Newobj; callNode.Operand = defaultCtor; callNode.SetType(defaultCtor.DeclaringType); } }
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); }
/// <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) && !typeDef.IsImmutableStruct) // TODO: check if this decision should be made based on the actual argument type, not the destination type. // this should be true at least for generic parameters, which might either take a ValueType or // a reference type. // Then again, maybe the struct argument should be cloned on an "box" instruction. { // 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> /// 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); var typeDef = defaultCtor.DeclaringType; if (typeDef.IsImmutableStruct) { var field = typeDef.Fields.SingleOrDefault(f => f.Name == NameConstants.Struct.DefaultFieldName); if (field != null) { newArrNode.Operand = field; } else { newArrNode.Operand = defaultCtor; } } else { newArrNode.Operand = defaultCtor; } }
/// <summary> /// Create the body of the ctor. /// </summary> private static MethodBody CreateCtorBody(XMethodDefinition calledMethod, FieldDefinition instanceField, ClassReference baseClass) { var body = new MethodBody(null); // Create code var ins = body.Instructions; var rthis = body.AllocateRegister(RCategory.Argument, RType.Object); // Call base ctor var baseCtorRef = new MethodReference(baseClass, "<init>", new Prototype(PrimitiveType.Void)); ins.Add(new Instruction(RCode.Invoke_direct, rthis) { Operand = baseCtorRef }); if (!calledMethod.IsStatic) { // load instance into field var rvalue = body.AllocateRegister(RCategory.Argument, RType.Object); ins.Add(new Instruction(RCode.Iput_object, rvalue, rthis) { Operand = instanceField }); } ins.Add(new Instruction(RCode.Return_void)); return(body); }
/// <summary> /// Default ctor /// </summary> public CompiledMethod(XMethodDefinition method) { if (method == null) { throw new ArgumentNullException("method"); } this.method = method; }
/// <summary> /// Java ctor /// </summary> public MethodSource(XMethodDefinition method, JavaMethodDefinition javaMethod) { if (javaMethod == null) { throw new ArgumentNullException(); } this.method = method; this.javaMethod = javaMethod; }
/// <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; }
/// <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> /// 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> /// 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> /// .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; }
/// <summary> /// Resolve this reference to it's definition. /// </summary> public override bool TryResolve(out XMethodDefinition method) { method = null; var declaringTypeRef = DeclaringType.IsArray ? Module.TypeSystem.Object : DeclaringType.GetElementType(); XTypeDefinition declaringType; if (!declaringTypeRef.TryResolve(out declaringType)) { return(false); } return(declaringType.TryGet(this, out method)); }
/// <summary> /// Get a compiled method info for the given method. /// Create if needed. /// </summary> internal CompiledMethod GetOrCreateCompileMethod(XMethodDefinition method) { CompiledMethod result; if (!xMethodMap.TryGetValue(method, out result)) { result = new CompiledMethod(method); compiledMethods.Add(result); xMethodMap.Add(method, result); } return(result); }
/// <summary> /// Generate an Invoke opcode. /// </summary> internal static RCode Invoke(this XMethodDefinition targetMethod, XMethodReference targetMethodRef, MethodSource currentMethod, bool isSpecial = false) { if (targetMethod != null) { if (targetMethod.DeclaringType.IsDelegate()) { return(RCode.Invoke_interface); } if (targetMethod.IsStatic || targetMethod.IsAndroidExtension) { return(RCode.Invoke_static); } if ((currentMethod != null) && targetMethod.UseInvokeSuper(currentMethod.Method)) { return(RCode.Invoke_super); } if (isSpecial && !targetMethod.IsConstructor && (currentMethod != null) && targetMethod.DeclaringType.IsBaseOf(currentMethod.Method.DeclaringType)) { return(RCode.Invoke_super); } if (targetMethod.UseInvokeInterface) { return(RCode.Invoke_interface); } if (targetMethod.IsDirect) { return(RCode.Invoke_direct); } if (targetMethod.DeclaringType.IsInterface) { return(RCode.Invoke_interface); } } if (targetMethodRef != null) { if (!targetMethodRef.HasThis) { return(RCode.Invoke_static); } switch (targetMethodRef.Name) { case "<init>": case "<clinit>": case ".ctor": case ".cctor": return(RCode.Invoke_direct); } } return(RCode.Invoke_virtual); }
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); }
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> /// Implement the class now that all classes have been created /// </summary> protected override void CreateMembers(DexTargetPackage targetPackage) { base.CreateMembers(targetPackage); // Build default ctor XTypeSystem typeSystem = Compiler.Module.TypeSystem; XSyntheticMethodDefinition ctor = XSyntheticMethodDefinition.Create(XType, XSyntheticMethodFlags.Constructor, "<init>", null, typeSystem.Void); ctor.Body = CreateCtorBody(); Class.Methods.Add(ctor.GetDexMethod(Class, targetPackage)); // Build Invoke method. XMethodDefinition sourceMethod = XType.Methods.Single(x => x.EqualsName("Invoke")); Prototype prototype = PrototypeBuilder.BuildPrototype(Compiler, targetPackage, Class, sourceMethod); MethodDefinition method = new MethodDefinition(Class, sourceMethod.Name, prototype) { AccessFlags = AccessFlags.Public | AccessFlags.Abstract, MapFileId = Compiler.GetNextMapFileId() }; Class.Methods.Add(method); // Find xSource method targetPackage.NameConverter.Record(sourceMethod, method); // If void() delegate, implement java.lang.Runnable if (sourceMethod.ReturnType.IsVoid() && (sourceMethod.Parameters.Count == 0)) { // Implement interface Class.Interfaces.Add(FrameworkReferences.Runnable); // Build run method var run = new MethodDefinition(Class, "run", new Prototype(PrimitiveType.Void)) { AccessFlags = AccessFlags.Public | AccessFlags.Final }; Class.Methods.Add(run); run.Body = new DexLib.Instructions.MethodBody(run, 1) { IncomingArguments = 1, OutgoingArguments = 1 }; var insList = run.Body.Instructions; var rThis = run.Body.Registers[0]; insList.Add(new DexLib.Instructions.Instruction(OpCodes.Invoke_virtual, method, rThis)); insList.Add(new DexLib.Instructions.Instruction(OpCodes.Return_void)); } }
/// <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> /// 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")); } }
public static MethodEntry RecordMapping(TypeEntry typeEntry, XMethodDefinition xMethod, MethodDefinition method, DexLib.MethodDefinition dmethod, CompiledMethod compiledMethod) { var scopeId = xMethod.ScopeId; StringBuilder netSignature = new StringBuilder(); method.MethodSignatureFullName(netSignature); var entry = new MethodEntry(method.OriginalName, netSignature.ToString(), dmethod.Name, dmethod.Prototype.ToSignature(), dmethod.MapFileId, scopeId); typeEntry.Methods.Add(entry); if (compiledMethod != null) { compiledMethod.RecordMapping(entry); } return(entry); }
/// <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> /// 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> /// Get a compiled method info for the given method. /// </summary> internal CompiledMethod GetMethod(XMethodDefinition method) { CompiledMethod result; return(xMethodMap.TryGetValue(method, out result) ? result : null); }
/// <summary> /// Record the given method mapping /// </summary> internal void Record(XMethodDefinition xMethod, MethodDefinition dMethod) { NameConverter.Record(xMethod, dMethod); GetOrCreateCompileMethod(xMethod).DexMethod = dMethod; }
/// <summary> /// Resolve this reference to it's definition. /// </summary> public override bool TryResolve(out XMethodDefinition method) { method = null; var declaringTypeRef = DeclaringType.IsArray ? Module.TypeSystem.Object : DeclaringType.GetElementType(); XTypeDefinition declaringType; if (!declaringTypeRef.TryResolve(out declaringType)) return false; return declaringType.TryGet(this, out method); }
/// <summary> /// Default ctor /// </summary> public DelegateInstanceType(XMethodDefinition calledMethod, ClassDefinition instanceDefinition, Dot42.DexLib.MethodDefinition instanceCtor) { this.calledMethod = calledMethod; this.instanceDefinition = instanceDefinition; this.instanceCtor = instanceCtor; }
/// <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); }