public MethodDisassembly(MethodDefinition methodDef, MapFileLookup mapFile = null, TypeEntry typeEntry = null, MethodEntry methodEntry = null) { _typeEntry = typeEntry; _methodEntry = methodEntry; _methodDef = methodDef; _mapFile = mapFile; JumpTargetOffsets=new HashSet<int>(); ExceptionHandlerOffsets = new HashSet<int>(); if (methodDef.Body != null) { foreach (var i in methodDef.Body.Instructions) { var op = i.Operand as Instruction; if (op != null) JumpTargetOffsets.Add(op.Offset); } foreach (var e in methodDef.Body.Exceptions) { foreach(var c in e.Catches) ExceptionHandlerOffsets.Add(c.Instruction.Offset); if (e.CatchAll != null) ExceptionHandlerOffsets.Add(e.CatchAll.Offset); } } Format = FormatOptions.Default; }
/// <summary> /// Create code to load a value from an annotation interface. /// </summary> /// <returns>The register(s) holding the value</returns> private static Register[] CreateLoadValueSequence( ISourceLocation seqp, MethodBody body, TypeReference valueType, Register annotationReg, MethodDefinition getter) { if (valueType.IsWide()) { Tuple <Register, Register> regs = body.AllocateWideRegister(RCategory.Temp); body.Instructions.Add(seqp, RCode.Invoke_interface, getter, annotationReg); body.Instructions.Add(seqp, RCode.Move_result_wide, regs.Item1); return(new[] { regs.Item1, regs.Item2 }); } if (valueType is PrimitiveType) { Register reg = body.AllocateRegister(RCategory.Temp, RType.Value); body.Instructions.Add(seqp, RCode.Invoke_interface, getter, annotationReg); body.Instructions.Add(seqp, RCode.Move_result, reg); return(new[] { reg }); } else { Register reg = body.AllocateRegister(RCategory.Temp, RType.Object); body.Instructions.Add(seqp, RCode.Invoke_interface, getter, annotationReg); body.Instructions.Add(seqp, RCode.Move_result_object, reg); return(new[] { reg }); } }
/// <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>", 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 }; 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)); } }
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> /// Implement the class now that all classes have been created /// </summary> protected override void CreateMembers(DexTargetPackage targetPackage) { // Build ctors foreach (var baseCtor in GetBaseClassCtors()) { // Build ctor var prototype = PrototypeBuilder.BuildPrototype(Compiler, targetPackage, null, baseCtor); var ctor = new MethodDefinition(Class, "<init>", prototype); ctor.AccessFlags = AccessFlags.Public | AccessFlags.Constructor; Class.Methods.Add(ctor); // Create ctor body var ctorBody = CreateCtorBody(prototype); targetPackage.Record(new CompiledMethod { DexMethod = ctor, RLBody = ctorBody }); } }
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> /// 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> /// Implement the class now that all classes have been created /// </summary> protected override void CreateMembers(DexTargetPackage targetPackage) { // Build ctors foreach (var baseCtor in GetBaseClassCtors()) { // Build ctor var prototype = PrototypeBuilder.BuildPrototype(Compiler, targetPackage, null, baseCtor); var ctor = new MethodDefinition(Class, "<init>", prototype); ctor.AccessFlags = AccessFlags.Public | AccessFlags.Constructor; Class.Methods.Add(ctor); // Create ctor body var ctorBody = CreateCtorBody(prototype); targetPackage.Record(new CompiledMethod { DexMethod = ctor, RLBody = ctorBody }); } }
/// <summary> /// Create a method body for the given method. /// </summary> internal static MethodBody TranslateToRL(AssemblyCompiler compiler, DexTargetPackage targetPackage, MethodSource source, MethodDefinition dmethod, bool generateSetNextInstructionCode, out CompiledMethod compiledMethod) { try { #if DEBUG //Debugger.Launch(); if ((source.Method != null) && (source.Method.Name == "test6")) { //Debugger.Launch(); } #endif // Create Ast var optimizedAst = CreateOptimizedAst(compiler, source, generateSetNextInstructionCode); // Generate RL code var rlBody = new MethodBody(source); var rlGenerator = new AstCompilerVisitor(compiler, source, targetPackage, dmethod, rlBody); optimizedAst.Accept(rlGenerator, null); rlGenerator.Complete(); // Should we add return_void? if (source.ReturnsVoid) { var instructions = rlBody.Instructions; if ((instructions.Count == 0) || (instructions.Last().Code != RCode.Return_void && instructions.Last().Code != RCode.Throw)) { instructions.Add(new RL.Instruction(RCode.Return_void) { SequencePoint = source.GetLastSourceLine() }); } } // Record results compiledMethod = targetPackage.Record(source, rlBody, rlGenerator.Frame); return rlBody; } catch (Exception ex) { // Forward exception with more information var msg = string.Format("Error while compiling {0} in {1}: {2}", source.FullName, source.DeclaringTypeFullName, ex.Message); throw new CompilerException(msg, ex); } }
/// <summary> /// Verify the given method /// </summary> private void VerifyMethod(MethodDefinition method) { if (method.Body == null) { if (method.IsConstructor) { onError(string.Format("Constructor has no body: {0}", method)); } } else { foreach (var handler in method.Body.Exceptions) { if (handler.TryEnd.Offset < handler.TryStart.Offset) { onError(string.Format("Invalid exception handler 0x{0:X4}-0x{1:X4} in {2}", handler.TryStart.Offset, handler.TryEnd.Offset, method.Name)); } } } }
/// <summary> /// Implement the class now that all classes have been created /// </summary> protected override void CreateMembers(DexTargetPackage targetPackage) { // Build ctors foreach (var baseCtor in GetBaseClassCtors()) { // TODO: does this make sense? after all, we derive from object. // probalby one should just remove this code, and generate a // defaul constructor. var prototype = PrototypeBuilder.BuildPrototype(Compiler, targetPackage, null, baseCtor); var ctor = new MethodDefinition(Class, "<init>", prototype); ctor.AccessFlags = AccessFlags.Public | AccessFlags.Constructor; Class.Methods.Add(ctor); // Create ctor body var ctorBody = CreateCtorBody(prototype); targetPackage.Record(new CompiledMethod { DexMethod = ctor, RLBody = ctorBody }); } // build original type field // Create field definition // NOTE: at the moment the underlying type is both defined as a type and in the annotation. // remove one or the other when we have determined which is the better way. var dfield = new Dot42.DexLib.FieldDefinition(); dfield.Owner = Class; dfield.Name = "underlying$"; dfield.IsSynthetic = true; dfield.IsFinal = true; dfield.IsStatic = true; dfield.IsPublic = true; dfield.Type = Compiler.Module.TypeSystem.Type.GetClassReference(targetPackage); dfield.Value = _underlyingBuilder.Class; Class.Fields.Add(dfield); }
/// <summary> /// Implement the class now that all classes have been created /// </summary> protected override void CreateMembers(DexTargetPackage targetPackage) { // Build ctors foreach (var baseCtor in GetBaseClassCtors()) { // Build ctor var prototype = PrototypeBuilder.BuildPrototype(Compiler, targetPackage, null, baseCtor); var ctor = new MethodDefinition(Class, "<init>", prototype); ctor.AccessFlags = AccessFlags.Public | AccessFlags.Constructor; Class.Methods.Add(ctor); // Create ctor body var ctorBody = CreateCtorBody(prototype); targetPackage.Record(new CompiledMethod { DexMethod = ctor, RLBody = ctorBody }); } // build original type field // Create field definition var dfield = new Dot42.DexLib.FieldDefinition(); dfield.Owner = Class; dfield.Name = "underlying$"; dfield.IsSynthetic = true; dfield.IsFinal = true; dfield.IsStatic = true; dfield.IsPublic = true; dfield.Type = Compiler.Module.TypeSystem.Type.GetClassReference(targetPackage); // not sure if GetClassReference is the best way to go forward here. // might depend on the sort order of the class builders. var underlyingType = XBuilder.AsTypeReference(Compiler.Module, Type); dfield.Value = underlyingType.GetClassReference(targetPackage); Class.Fields.Add(dfield); }
public MethodBodyDisassemblyFormatter(MethodDefinition methodDef, MapFileLookup mapFile) { _methodDef = methodDef; _mapFile = mapFile; TypeEntry typeEntry = null; MethodEntry methodEntry = null; if (mapFile != null) { typeEntry = mapFile.GetTypeByNewName(methodDef.Owner.Fullname); if (typeEntry != null) { methodEntry = typeEntry.FindDexMethod(methodDef.Name, methodDef.Prototype.ToSignature()); } } _dissassembly = new MethodDisassembly(methodDef, mapFile, typeEntry, methodEntry); _sourceDocument = new Lazy<string[]>(() => { if (_dissassembly.MethodEntry == null) return null; var pos = _mapFile.GetSourceCodePositions(_dissassembly.MethodEntry).FirstOrDefault(); if (pos == null) return null; try { return File.ReadAllLines(pos.Document.Path); } catch (Exception) { return null; } }); }
private static MethodDefinition CreateFactoryMethod(AssemblyCompiler compiler, DexTargetPackage targetPackage, CustomAttribute attribute, AttributeAnnotationMapping mapping) { var targetClass = mapping.AttributeClass; // is this really the right place for the factory methods? ISourceLocation seqp = null; var attributeTypeDef = attribute.AttributeType.Resolve(); // create method string methodName = CreateAttributeFactoryMethodName(targetClass); MethodDefinition method = new MethodDefinition(targetClass, methodName, new Prototype(mapping.AttributeClass)); method.AccessFlags = AccessFlags.Public | AccessFlags.Static | AccessFlags.Synthetic; targetClass.Methods.Add(method); // create method body MethodBody body = new MethodBody(null); // Allocate attribute Register attributeReg = body.AllocateRegister(RCategory.Temp, RType.Object); body.Instructions.Add(seqp, RCode.New_instance, mapping.AttributeClass, attributeReg); // collect ctor arguments List <Register> ctorArgRegs = new List <Register>() { attributeReg }; foreach (var p in attribute.ConstructorArguments) { XTypeReference xType = XBuilder.AsTypeReference(compiler.Module, p.Type); Register[] valueRegs = CreateInitializeValueInstructions(seqp, body, xType, p, compiler, targetPackage); ctorArgRegs.AddRange(valueRegs); } // Invoke ctor DexLib.MethodReference dctor = attribute.Constructor.GetReference(targetPackage, compiler.Module); body.Instructions.Add(seqp, RCode.Invoke_direct, dctor, ctorArgRegs.ToArray()); // set field values foreach (var p in attribute.Fields) { var field = GetField(attributeTypeDef, p.Name); var xField = XBuilder.AsFieldReference(compiler.Module, field); Register[] valueRegs = CreateInitializeValueInstructions(seqp, body, xField.FieldType, p.Argument, compiler, targetPackage); body.Instructions.Add(seqp, xField.FieldType.IPut(), xField.GetReference(targetPackage), valueRegs[0], attributeReg); } // set property values foreach (var p in attribute.Properties) { PropertyDefinition property = GetSettableProperty(attributeTypeDef, p.Name); XTypeReference xType = XBuilder.AsTypeReference(compiler.Module, property.PropertyType); Register[] valueRegs = CreateInitializeValueInstructions(seqp, body, xType, p.Argument, compiler, targetPackage); XMethodDefinition xSetMethod = XBuilder.AsMethodDefinition(compiler.Module, property.SetMethod); body.Instructions.Add(seqp, xSetMethod.Invoke(xSetMethod, null), xSetMethod.GetReference(targetPackage), new[] { attributeReg }.Concat(valueRegs).ToArray()); } // Return attribute body.Instructions.Add(seqp, RCode.Return_object, attributeReg); // Register method body targetPackage.Record(new CompiledMethod() { DexMethod = method, RLBody = body }); // Return method return(method); }
/// <summary> /// Default ctor /// </summary> internal AttributeCtorMapping(MethodDefinition builder, List<MethodDefinition> argumentGetters) { this.Builder = builder; ArgumentGetters = argumentGetters; }
/// <summary> /// Create a frame for the given method /// </summary> internal AstInvocationFrame(DexTargetPackage targetPackage, MethodDefinition method, MethodSource source, MethodBody body) { this.targetPackage = targetPackage; this.body = body; this.body = body; Debug.Assert(!body.Registers.Any()); var prototypeParamOffset = 0; var prototype = method.Prototype; if (source.IsDotNet) { var ilMethod = source.ILMethod; // Allocate this if (!method.IsStatic) { thisArgument = (ArgumentRegisterSpec) Allocate(method.Owner, true, RCategory.Argument, ilMethod.Body.ThisParameter); arguments.Add(thisArgument); } else if (ilMethod.IsAndroidExtension() && !ilMethod.IsStatic) { prototypeParamOffset++; var type = ilMethod.DeclaringType.GetReference(targetPackage, source.Method.Module); thisArgument = (ArgumentRegisterSpec) Allocate(type, true, RCategory.Argument, ilMethod.Body.ThisParameter); arguments.Add(thisArgument); } // Allocate arguments var paramCount = ilMethod.Parameters.Count; for (var i = 0; i < paramCount; i++) { var p = ilMethod.Parameters[i]; var type = prototype.Parameters[prototypeParamOffset++].Type; arguments.Add((ArgumentRegisterSpec) Allocate(type, false, RCategory.Argument, p)); } } else if (source.IsJava) { var javaMethod = source.JavaMethod; // Allocate this var code = javaMethod.Attributes.OfType<CodeAttribute>().First(); if (!method.IsStatic) { thisArgument = (ArgumentRegisterSpec)Allocate(method.Owner, true, RCategory.Argument, code.ThisParameter); arguments.Add(thisArgument); } // Allocate arguments foreach (var p in code.Parameters) { var type = prototype.Parameters[prototypeParamOffset++].Type; arguments.Add((ArgumentRegisterSpec)Allocate(type, false, RCategory.Argument, p.Item2)); } } else if (source.IsAst) { // Allocate this if (!method.IsStatic) { thisArgument = (ArgumentRegisterSpec)Allocate(method.Owner, true, RCategory.Argument, null); arguments.Add(thisArgument); } // Allocate arguments foreach (var p in ((XSyntheticMethodDefinition)source.Method).AstParameters) { var type = prototype.Parameters[prototypeParamOffset++].Type; arguments.Add((ArgumentRegisterSpec)Allocate(type, false, RCategory.Argument, p)); } } else { throw new ArgumentException("Unknown source"); } // Add GenericInstanceType parameter (if any) if (source.Method.NeedsGenericInstanceTypeParameter) { var type = prototype.GenericInstanceTypeParameter.Type; GenericInstanceTypeArgument = (ArgumentRegisterSpec) Allocate(type, false, RCategory.Argument, null); arguments.Add(GenericInstanceTypeArgument); } // Add GenericInstanceMethod parameter (if any) if (source.Method.NeedsGenericInstanceMethodParameter) { var type = prototype.GenericInstanceMethodParameter.Type; GenericInstanceMethodArgument = (ArgumentRegisterSpec) Allocate(type, false, RCategory.Argument, null); arguments.Add(GenericInstanceMethodArgument); } // Check register count var expected = prototype.Parameters.Sum(x => x.Type.IsWide() ? 2 : 1); if (!method.IsStatic) expected++; if (expected != body.Registers.Count()) { throw new ArgumentException(string.Format("Expected {0} registers, found {1} (in {2})", expected, body.Registers.Count(), method)); } }
/// <summary> /// Create the current type as class definition. /// </summary> internal static DelegateInstanceType Create( ISourceLocation sequencePoint, AssemblyCompiler compiler, DexTargetPackage targetPackage, ClassDefinition delegateClass, XMethodDefinition invokeMethod, Prototype invokePrototype, XMethodDefinition equalsMethod, Prototype equalsPrototype, XMethodDefinition calledMethod) { // Prepare called method var target = targetPackage.DexFile; var owner = target.GetClass(calledMethod.DeclaringType.GetClassReference(targetPackage).Fullname) ?? targetPackage.GetOrCreateGeneratedCodeClass(); var calledMethodPrototype = PrototypeBuilder.BuildPrototype(compiler, targetPackage, owner, calledMethod); var calledMethodRef = calledMethod.GetReference(targetPackage); if (calledMethod.DeclaringType.HasDexImportAttribute()) { // Delegate method is a Dex import method } else { // Delegate method is a .NET method var calledDexMethod = owner.Methods.Single(x => (x.Name == calledMethodRef.Name) && (x.Prototype.Equals(calledMethodRef.Prototype))); if (calledDexMethod.IsPrivate) { calledDexMethod.IsPrivate = false; calledDexMethod.IsProtected = true; } } var @class = new ClassDefinition(); @class.Name = CreateInstanceTypeName(owner); @class.Namespace = owner.Namespace; @class.AccessFlags = AccessFlags.Public | AccessFlags.Final; owner.InnerClasses.Add(@class); // Set super class @class.SuperClass = delegateClass; // Implement delegate interface //@class.Interfaces.Add(delegateInterface); // Get type of instance XTypeDefinition instanceType = calledMethod.DeclaringType; TypeReference instanceTypeRef = instanceType.GetReference(targetPackage); // Add instance field FieldDefinition instanceField = null; if (!calledMethod.IsStatic) { instanceField = new FieldDefinition(); instanceField.Name = "instance"; instanceField.Owner = @class; instanceField.Type = instanceTypeRef; instanceField.AccessFlags = AccessFlags.Private | AccessFlags.Final; @class.Fields.Add(instanceField); } // Add ctor var ctor = new Dot42.DexLib.MethodDefinition(); ctor.Owner = @class; ctor.Name = "<init>"; ctor.AccessFlags = AccessFlags.Public | AccessFlags.Constructor; ctor.Prototype = new Prototype(PrimitiveType.Void); if (!calledMethod.IsStatic) { ctor.Prototype.Parameters.Add(new Parameter(instanceTypeRef, "this")); } @class.Methods.Add(ctor); // Create ctor body var ctorBody = CreateCtorBody(calledMethod, instanceField, delegateClass); targetPackage.Record(new CompiledMethod() { DexMethod = ctor, RLBody = ctorBody }); // Add Invoke method var invoke = new Dot42.DexLib.MethodDefinition(@class, "Invoke", invokePrototype) { AccessFlags = AccessFlags.Public }; @class.Methods.Add(invoke); // Create body var invokeBody = CreateInvokeBody(sequencePoint, compiler, targetPackage, calledMethod, invokeMethod, invokePrototype, calledMethodPrototype, instanceField, delegateClass); targetPackage.Record(new CompiledMethod() { DexMethod = invoke, RLBody = invokeBody }); // Add Equals method if (null != equalsMethod) { var equals = new Dot42.DexLib.MethodDefinition(@class, "equals", equalsPrototype) { AccessFlags = AccessFlags.Public }; @class.Methods.Add(equals); // Create body if (!calledMethod.IsStatic) { var equalsBody = CreateEqualsBody(sequencePoint, compiler, targetPackage, equalsMethod, equalsPrototype, instanceField, @class); targetPackage.Record(new CompiledMethod() { DexMethod = equals, RLBody = equalsBody }); } else { var equalsBody = CreateEqualsBody(); targetPackage.Record(new CompiledMethod() { DexMethod = equals, RLBody = equalsBody }); } } return new DelegateInstanceType(calledMethod, @class, ctor); }
/// <summary> /// Create an annotation interface. /// </summary> internal static AttributeAnnotationInterface Create( ISourceLocation sequencePoint, AssemblyCompiler compiler, DexTargetPackage targetPackage, TypeDefinition attributeType, ClassDefinition attributeClass) { // Create class ClassDefinition @interface = new ClassDefinition(); @interface.Name = CreateAnnotationTypeName(attributeClass); @interface.Namespace = attributeClass.Namespace; @interface.AccessFlags = AccessFlags.Public | AccessFlags.Abstract | AccessFlags.Interface | AccessFlags.Annotation; @interface.Owner = attributeClass; attributeClass.InnerClasses.Add(@interface); // Set super class @interface.SuperClass = new ClassReference("java/lang/Object"); // Implement Dot42.Internal.IAttribute @interface.Interfaces.Add(new ClassReference("java/lang/annotation/Annotation")); // Prepare result AttributeAnnotationInterface result = new AttributeAnnotationInterface(@interface); // Add methods from IAttribute XModel.XTypeDefinition baseIntfType = compiler.GetDot42InternalType("IAttribute").Resolve(); foreach (XModel.XMethodDefinition imethod in baseIntfType.Methods) { if (imethod.Parameters.Count > 0) { throw new CompilerException(string.Format("Invalid IAttribute method {0}", imethod)); } string methodName = NameConverter.GetConvertedName(imethod); TypeReference dfieldType = imethod.ReturnType.GetReference(targetPackage); MethodDefinition method = new MethodDefinition(@interface, methodName, new Prototype(dfieldType)); method.AccessFlags = AccessFlags.Public | AccessFlags.Abstract; @interface.Methods.Add(method); } // Add field mapping foreach (var field in attributeType.Fields.Where(x => x.IsReachable && x.IsPublic)) { string methodName = CreateGetMethodName(NameConverter.GetConvertedName(field), result); TypeReference dfieldType = field.FieldType.GetReference(targetPackage, compiler.Module); MethodDefinition method = new MethodDefinition(@interface, methodName, new Prototype(dfieldType)); method.AccessFlags = AccessFlags.Public | AccessFlags.Abstract; result.FieldToGetMethodMap.Add(field, method); @interface.Methods.Add(method); } // Add property mapping foreach (var property in attributeType.Properties.Where(x => x.IsReachable && (x.SetMethod != null) && (x.SetMethod.IsPublic) && x.SetMethod.IsReachable)) { string methodName = CreateGetMethodName(NameConverter.GetConvertedName(property), result); TypeReference dpropType = property.PropertyType.GetReference(targetPackage, compiler.Module); MethodDefinition method = new MethodDefinition(@interface, methodName, new Prototype(dpropType)); method.AccessFlags = AccessFlags.Public | AccessFlags.Abstract; result.PropertyToGetMethodMap.Add(property, method); @interface.Methods.Add(method); } // Add ctor mapping var argIndex = 0; foreach (var ctor in attributeType.Methods.Where(x => (x.Name == ".ctor") && x.IsReachable)) { // Add methods for the ctor arguments List <MethodDefinition> paramGetMethods = new List <MethodDefinition>(); foreach (ParameterDefinition p in ctor.Parameters) { string methodName = CreateGetMethodName("c" + argIndex++, result); TypeReference dparamType = p.ParameterType.GetReference(targetPackage, compiler.Module); MethodDefinition method = new MethodDefinition(@interface, methodName, new Prototype(dparamType)); method.AccessFlags = AccessFlags.Public | AccessFlags.Abstract; @interface.Methods.Add(method); paramGetMethods.Add(method); } // Add a builder method MethodDefinition buildMethod = CreateBuildMethod(sequencePoint, ctor, paramGetMethods, compiler, targetPackage, attributeClass, result); result.CtorMap.Add(ctor, new AttributeCtorMapping(buildMethod, paramGetMethods)); } // Create default values annotation Annotation defAnnotation = CreateDefaultAnnotation(result); result.AnnotationInterfaceClass.Annotations.Add(defAnnotation); return(result); }
/// <summary> /// Note that referencing operands, i.e. TypeReferences, FieldReference or /// MethodRefrences are not cloned, but only shallow copied. /// If you indend to modify those operand values themself, be sure to clone /// them beforehand. /// </summary> public static MethodBody Clone(MethodDefinition targetMethod, MethodDefinition sourceMethod) { var sourceBody = sourceMethod.Body; MethodBody body = new MethodBody(targetMethod, sourceBody.Registers.Count) { IncomingArguments = sourceBody.IncomingArguments, OutgoingArguments = sourceBody.OutgoingArguments }; foreach (var sourceIns in sourceBody.Instructions) { var ins = new Instruction(sourceIns.OpCode); foreach (var r in sourceIns.Registers) ins.Registers.Add(body.Registers[r.Index]); ins.Offset = sourceIns.Offset; ins.SequencePoint = ins.SequencePoint; ins.Operand = sourceIns.Operand; body.Instructions.Add(ins); } // fix instruction references var insByOffset = body.Instructions.ToDictionary(i => i.Offset); foreach (var ins in body.Instructions) { var targetIns = ins.Operand as Instruction; var packedSwitch = ins.Operand as PackedSwitchData; var sparseSwitch = ins.Operand as SparseSwitchData; if (targetIns != null) { ins.Operand = insByOffset[targetIns.Offset]; } else if (packedSwitch != null) { var ps = new PackedSwitchData(packedSwitch.Targets.Select(si => insByOffset[si.Offset])); ps.FirstKey = packedSwitch.FirstKey; ins.Operand = ps; } else if (sparseSwitch != null) { var ss = new SparseSwitchData(); foreach (var ssd in sparseSwitch.Targets) { ss.Targets.Add(ssd.Key, insByOffset[ssd.Value.Offset]); } ins.Operand = ss; } } foreach (var sourceEx in sourceBody.Exceptions) { var ex = new ExceptionHandler(); if (sourceEx.TryStart != null) ex.TryStart = insByOffset[sourceEx.TryStart.Offset]; if (sourceEx.TryEnd != null) ex.TryEnd = insByOffset[sourceEx.TryEnd.Offset]; if (sourceEx.CatchAll != null) ex.CatchAll = insByOffset[sourceEx.CatchAll.Offset]; foreach (var sourceCatch in sourceEx.Catches) { var c = new Catch { Type = sourceCatch.Type, Instruction = insByOffset[sourceCatch.Instruction.Offset] }; ex.Catches.Add(c); } body.Exceptions.Add(ex); } if (sourceBody.DebugInfo != null) { var di = body.DebugInfo = new DebugInfo(body); di.LineStart = sourceBody.DebugInfo.LineStart; di.Parameters = sourceBody.DebugInfo.Parameters.ToList(); foreach (var sourceInstruction in sourceBody.DebugInfo.DebugInstructions) { di.DebugInstructions.Add(new DebugInstruction(sourceInstruction.OpCode, sourceInstruction.Operands.ToList())); } } return body; }
/// <summary> /// Implement the class now that all classes have been created /// </summary> protected override void CreateMembers(DexTargetPackage targetPackage) { // Build ctors foreach (var baseCtor in GetBaseClassCtors()) { // TODO: does this make sense? after all, we derive from object. // probalby one should just remove this code, and generate a // defaul constructor. var prototype = PrototypeBuilder.BuildPrototype(Compiler, targetPackage, null, baseCtor); var ctor = new MethodDefinition(Class, "<init>", prototype); ctor.AccessFlags = AccessFlags.Public | AccessFlags.Constructor; Class.Methods.Add(ctor); // Create ctor body var ctorBody = CreateCtorBody(prototype); targetPackage.Record(new CompiledMethod { DexMethod = ctor, RLBody = ctorBody }); } // build original type field // Create field definition // NOTE: at the moment the underlying type is both defined as a type and in the annotation. // remove one or the other when we have determined which is the better way. var dfield = new Dot42.DexLib.FieldDefinition(); dfield.Owner = Class; dfield.Name = "underlying$"; dfield.IsSynthetic = true; dfield.IsFinal = true; dfield.IsStatic= true; dfield.IsPublic = true; dfield.Type = Compiler.Module.TypeSystem.Type.GetClassReference(targetPackage); dfield.Value = _underlyingBuilder.Class; Class.Fields.Add(dfield); }
/// <summary> /// Is other equal to this? /// </summary> public bool Equals(MethodDefinition other) { // Should be enough (ownership) return base.Equals(other); }
/// <summary> /// Create an annotation interface. /// </summary> internal static AttributeAnnotationInterface Create( ISourceLocation sequencePoint, AssemblyCompiler compiler, DexTargetPackage targetPackage, TypeDefinition attributeType, ClassDefinition attributeClass) { // Create class ClassDefinition @interface = new ClassDefinition(); @interface.Name = CreateAnnotationTypeName(attributeClass); @interface.Namespace = attributeClass.Namespace; @interface.AccessFlags = AccessFlags.Public | AccessFlags.Abstract | AccessFlags.Interface | AccessFlags.Annotation; @interface.Owner = attributeClass; attributeClass.AddInnerClass(@interface); // Set super class @interface.SuperClass = FrameworkReferences.Object; // Implement Dot42.Internal.IAttribute @interface.Interfaces.Add(new ClassReference("java/lang/annotation/Annotation")); // Prepare result AttributeAnnotationInterface result = new AttributeAnnotationInterface(@interface); // Add methods from IAttribute XModel.XTypeDefinition baseIntfType = compiler.GetDot42InternalType("IAttribute").Resolve(); foreach (XModel.XMethodDefinition imethod in baseIntfType.Methods) { if (imethod.Parameters.Count > 0) throw new CompilerException(string.Format("Invalid IAttribute method {0}", imethod)); string methodName = NameConverter.GetConvertedName(imethod); TypeReference dfieldType = imethod.ReturnType.GetReference(targetPackage); MethodDefinition method = new MethodDefinition(@interface, methodName, new Prototype(dfieldType)); method.AccessFlags = AccessFlags.Public | AccessFlags.Abstract; @interface.Methods.Add(method); } TypeDefinition currentType = attributeType; while (currentType != null && currentType.FullName != typeof(Attribute).FullName) { // Add field mapping foreach (var field in currentType.Fields.Where(x => x.IsReachable && x.IsPublic)) { string methodName = CreateGetMethodName(NameConverter.GetConvertedName(field), result); MethodDefinition method = new MethodDefinition(@interface, methodName, MakePrototype(field.FieldType, targetPackage, compiler.Module)); method.AccessFlags = AccessFlags.Public | AccessFlags.Abstract; result.FieldToGetMethodMap.Add(field, method); @interface.Methods.Add(method); } // Add property mapping foreach (var property in currentType.Properties.Where( x => x.IsReachable && (x.SetMethod != null) && x.SetMethod.IsPublic && x.SetMethod.IsReachable)) { // ignore properties with same name [might be overriden] if (result.PropertyToGetMethodMap.Keys.Any(k => k.Name == property.Name)) continue; string methodName = CreateGetMethodName(NameConverter.GetConvertedName(property), result); Mono.Cecil.TypeReference propType = property.PropertyType; MethodDefinition method = new MethodDefinition(@interface, methodName, MakePrototype(propType, targetPackage, compiler.Module)); method.AccessFlags = AccessFlags.Public | AccessFlags.Abstract; result.PropertyToGetMethodMap.Add(property, method); @interface.Methods.Add(method); } if (currentType.BaseType == null || currentType.BaseType.IsSystemObject()) break; currentType = currentType.BaseType.Resolve(); } // Add ctor mapping var argIndex = 0; foreach (var ctor in attributeType.Methods.Where(x => (x.Name == ".ctor") && x.IsReachable)) { // Add methods for the ctor arguments List<Tuple<MethodDefinition, Mono.Cecil.TypeReference>> paramGetMethods = new List<Tuple<MethodDefinition, Mono.Cecil.TypeReference>>(); foreach (ParameterDefinition p in ctor.Parameters) { string methodName = CreateGetMethodName("c" + argIndex++, result); MethodDefinition method = new MethodDefinition(@interface, methodName, MakePrototype(p.ParameterType, targetPackage, compiler.Module)); method.AccessFlags = AccessFlags.Public | AccessFlags.Abstract; @interface.Methods.Add(method); paramGetMethods.Add(Tuple.Create(method, p.ParameterType)); } // Add a builder method MethodDefinition buildMethod = CreateBuildMethod(sequencePoint, ctor, paramGetMethods, compiler, targetPackage, attributeClass, result); result.CtorMap.Add(ctor, new AttributeCtorMapping(buildMethod, paramGetMethods.Select(p=>p.Item1).ToList())); } // Create default values annotation Annotation defAnnotation = CreateDefaultAnnotation(result); result.AnnotationInterfaceClass.Annotations.Add(defAnnotation); return result; }
/// <summary> /// Create a method definition for the builder method that builds a custom attribute from an annotation. /// </summary> private static MethodDefinition CreateBuildMethod( ISourceLocation seqp, Mono.Cecil.MethodDefinition ctor, List<Tuple<MethodDefinition, Mono.Cecil.TypeReference>> paramGetMethods, AssemblyCompiler compiler, DexTargetPackage targetPackage, ClassDefinition attributeClass, AttributeAnnotationInterface mapping) { // Create method definition string name = CreateBuildMethodName(attributeClass); TypeReference attributeTypeRef = ctor.DeclaringType.GetReference(targetPackage, compiler.Module); MethodDefinition method = new MethodDefinition(attributeClass, name, new Prototype(attributeTypeRef, new Parameter(mapping.AnnotationInterfaceClass, "ann"))); method.AccessFlags = AccessFlags.Public | AccessFlags.Static | AccessFlags.Synthetic; attributeClass.Methods.Add(method); // Create method body MethodBody body = new MethodBody(null); Register annotationReg = body.AllocateRegister(RCategory.Argument, RType.Object); //body.Instructions.Add(seqp, RCode.Check_cast, mapping.AnnotationInterfaceClass, annotationReg); // Allocate attribute Register attributeReg = body.AllocateRegister(RCategory.Temp, RType.Object); body.Instructions.Add(seqp, RCode.New_instance, attributeClass, attributeReg); // Get ctor arguments List<Register> ctorArgRegs = new List<Register>(); foreach (var p in paramGetMethods) { Instruction branchIfNotSet; // this can not happen, but lets keep the code below simple. XModel.XTypeReference xType = XBuilder.AsTypeReference(compiler.Module, p.Item2); Register[] valueRegs = CreateLoadValueSequence(seqp, body, xType, annotationReg, p.Item1, compiler, targetPackage, out branchIfNotSet); branchIfNotSet.Operand = body.Instructions.Add(seqp, RCode.Nop); ctorArgRegs.AddRange(valueRegs); } // Invoke ctor DexLib.MethodReference dctor = ctor.GetReference(targetPackage, compiler.Module); body.Instructions.Add(seqp, RCode.Invoke_direct, dctor, new[] { attributeReg }.Concat(ctorArgRegs).ToArray()); // Get field values foreach (var fieldMap in mapping.FieldToGetMethodMap) { var field = fieldMap.Key; XModel.XTypeReference xFieldType = XBuilder.AsTypeReference(compiler.Module, field.FieldType); MethodDefinition getter = fieldMap.Value; Instruction branchIfNotSet; Register[] valueRegs = CreateLoadValueSequence(seqp, body, xFieldType, annotationReg, getter, compiler, targetPackage, out branchIfNotSet); var put = body.Instructions.Add(seqp, xFieldType.IPut(), valueRegs[0], attributeReg); mapping.FixOperands.Add(Tuple.Create(put, (MemberReference)field)); branchIfNotSet.Operand = body.Instructions.Add(seqp, RCode.Nop); } // Get property values foreach (var propertyMap in mapping.PropertyToGetMethodMap) { PropertyDefinition property = propertyMap.Key; XTypeReference xType = XBuilder.AsTypeReference(compiler.Module, property.PropertyType); MethodDefinition getter = propertyMap.Value; Instruction branchIfNotSet; Register[] valueRegs = CreateLoadValueSequence(seqp, body, xType, annotationReg, getter, compiler, targetPackage, out branchIfNotSet); XModel.XMethodDefinition xSetMethod = XBuilder.AsMethodDefinition(compiler.Module, property.SetMethod); var set = body.Instructions.Add(seqp, xSetMethod.Invoke(xSetMethod, null), null, new[] { attributeReg }.Concat(valueRegs).ToArray()); mapping.FixOperands.Add(Tuple.Create(set, (MemberReference)property.SetMethod)); branchIfNotSet.Operand = body.Instructions.Add(seqp, RCode.Nop); } // Return attribute body.Instructions.Add(seqp, RCode.Return_object, attributeReg); // Register method body targetPackage.Record(new CompiledMethod() { DexMethod = method, RLBody = body }); // Return method return method; }
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> /// Create code to load a value from an annotation interface. /// </summary> /// <returns>The register(s) holding the value</returns> private static Register[] CreateLoadValueSequence( ISourceLocation seqp, MethodBody body, TypeReference valueType, Register annotationReg, MethodDefinition getter) { if (valueType.IsWide()) { Tuple<Register, Register> regs = body.AllocateWideRegister(RCategory.Temp); body.Instructions.Add(seqp, RCode.Invoke_interface, getter, annotationReg); body.Instructions.Add(seqp, RCode.Move_result_wide, regs.Item1); return new[] { regs.Item1, regs.Item2 }; } if (valueType is PrimitiveType) { Register reg = body.AllocateRegister(RCategory.Temp, RType.Value); body.Instructions.Add(seqp, RCode.Invoke_interface, getter, annotationReg); body.Instructions.Add(seqp, RCode.Move_result, reg); return new[] { reg }; } else { Register reg = body.AllocateRegister(RCategory.Temp, RType.Object); body.Instructions.Add(seqp, RCode.Invoke_interface, getter, annotationReg); body.Instructions.Add(seqp, RCode.Move_result_object, reg); return new[] { reg }; } }
private MethodBody CreateCloneBody(MethodDefinition ctor, ClassDefinition @class) { MethodBody body = new MethodBody(null); var ins = body.Instructions; Register rthis = body.AllocateRegister(RCategory.Argument, RType.Object); Register rInvList = body.AllocateRegister(RCategory.Argument, RType.Object); Register rInvListLen = body.AllocateRegister(RCategory.Argument, RType.Value); Register result = body.AllocateRegister(RCategory.Temp, RType.Object); List<Register> ctorArgs = new List<Register> { result }; if (instanceField != null) { var rInstance = body.AllocateRegister(RCategory.Temp, RType.Object); ins.Add(new Instruction(RCode.Iget_object, instanceField, new[] {rInstance, rthis})); ctorArgs.Add(rInstance); } foreach (var field in GenericTypeFields) { var r = body.AllocateRegister(RCategory.Temp, RType.Object); ins.Add(new Instruction(RCode.Iget_object, field, new[] { r, rthis })); ctorArgs.Add(r); } ins.Add(new Instruction(RCode.New_instance, @class, new[] {result})); ins.Add(new Instruction(RCode.Invoke_direct, ctor, ctorArgs.ToArray())); var invListLengthReference = new FieldReference(multicastDelegateClass, "InvocationListLength", PrimitiveType.Int); var multicastDelegateArray = new ArrayType(multicastDelegateClass); var invListReference = new FieldReference(multicastDelegateClass, "InvocationList", multicastDelegateArray); ins.Add(new Instruction(RCode.Iput_object, invListReference, new []{ rInvList, result})); ins.Add(new Instruction(RCode.Iput, invListLengthReference, new[] { rInvListLen, result })); ins.Add(new Instruction(RCode.Return_object, null, new []{result})); return body; }
public DelegateInstanceType Create() { instanceField = null; // actually at the momennt, we are not called multiple times... genericMethodTypeFields.Clear(); genericInstanceTypeFields.Clear(); // Prepare called method var target = targetPackage.DexFile; var owner = target.GetClass(calledMethod.DeclaringType.GetClassReference(targetPackage).Fullname) ?? targetPackage.GetOrCreateGeneratedCodeClass(); var calledMethodPrototype = PrototypeBuilder.BuildPrototype(compiler, targetPackage, owner, calledMethod); var calledMethodRef = calledMethod.GetReference(targetPackage); if (calledMethod.DeclaringType.HasDexImportAttribute()) { // Delegate method is a Dex import method } else { // Delegate method is a .NET method var calledDexMethod = owner.Methods.Single(x => (x.Name == calledMethodRef.Name) && (x.Prototype.Equals(calledMethodRef.Prototype))); if (calledDexMethod.IsPrivate) { calledDexMethod.IsPrivate = false; calledDexMethod.IsProtected = true; } } var @class = new ClassDefinition { Name = CreateInstanceTypeName(owner), Namespace = owner.Namespace, AccessFlags = AccessFlags.Public | AccessFlags.Final, MapFileId = compiler.GetNextMapFileId(), }; owner.AddInnerClass(@class); // Set super class @class.SuperClass = delegateClass; // Implement delegate interface //@class.Interfaces.Add(delegateInterface); // Get type of instance XTypeDefinition instanceType = calledMethod.DeclaringType; TypeReference instanceTypeRef = instanceType.GetReference(targetPackage); // Add ctor var ctor = new MethodDefinition { Owner = @class, Name = "<init>", AccessFlags = AccessFlags.Public | AccessFlags.Constructor, Prototype = new Prototype(PrimitiveType.Void), }; ctor.Prototype.Unfreeze(); if (!calledMethod.IsStatic) { ctor.Prototype.Parameters.Add(new Parameter(instanceTypeRef, "this")); } PrototypeBuilder.AddGenericParameters(compiler, targetPackage, calledMethod, ctor.Prototype); ctor.Prototype.Freeze(); @class.Methods.Add(ctor); // Add methodInfo field methodInfoField = new FieldDefinition(); methodInfoField.Name = "methodInfo"; methodInfoField.Owner = @class; methodInfoField.Type = compiler.GetDot42InternalType("System.Reflection", "MethodInfo").GetReference(targetPackage); methodInfoField.AccessFlags = AccessFlags.Private | AccessFlags.Final | AccessFlags.Static; @class.Fields.Add(methodInfoField); // Add instance field & getTargetImpl method if (!calledMethod.IsStatic) { instanceField = new FieldDefinition(); instanceField.Name = "instance"; instanceField.Owner = @class; instanceField.Type = instanceTypeRef; instanceField.AccessFlags = AccessFlags.Private | AccessFlags.Final; @class.Fields.Add(instanceField); AddMethod(@class, "GetTargetImpl", new Prototype(FrameworkReferences.Object), AccessFlags.Protected, CreateGetTargetImplBody()); } // Add generic instance type and method fields var gtpa = compiler.GetDot42InternalType(InternalConstants.GenericTypeParameterAnnotation).GetClassReference(targetPackage); var gmpa = compiler.GetDot42InternalType(InternalConstants.GenericMethodParameterAnnotation).GetClassReference(targetPackage); foreach (var parameter in ctor.Prototype.Parameters) { bool isGtpa = parameter.Annotations.Any(a => a.Type.Equals(gtpa)); bool isGmpa = parameter.Annotations.Any(a => a.Type.Equals(gmpa)); if (isGmpa || isGtpa) { var list = isGtpa ? genericInstanceTypeFields : genericMethodTypeFields; var field = new FieldDefinition(); field.Name = isGtpa ? "$git" : "$gmt"; if (parameter.Type.Equals(FrameworkReferences.Class)) field.Name += list.Count + 1; field.Owner = @class; field.Type = parameter.Type; field.AccessFlags = AccessFlags.Private | AccessFlags.Final; @class.Fields.Add(field); list.Add(field); } } // Create ctor body var ctorBody = CreateCtorBody(); targetPackage.Record(new CompiledMethod() { DexMethod = ctor, RLBody = ctorBody }); // add class static ctor AddMethod(@class, "<clinit>", new Prototype(PrimitiveType.Void), AccessFlags.Public | AccessFlags.Constructor | AccessFlags.Static, CreateCctorBody()); // Add Invoke method AddMethod(@class, "Invoke", invokePrototype, AccessFlags.Public, CreateInvokeBody(calledMethodPrototype)); // Add Equals method var typeOnlyEqualsSuffices = calledMethod.IsStatic && !calledMethod.NeedsGenericInstanceTypeParameter && !calledMethod.NeedsGenericInstanceMethodParameter; var equalsBody = typeOnlyEqualsSuffices ? CreateEqualsCheckTypeOnlyBody(@class) : CreateEqualsBody(@class); var equalsPrototype = new Prototype(PrimitiveType.Boolean, new Parameter(multicastDelegateClass, "other")); AddMethod(@class, "EqualsWithoutInvocationList", equalsPrototype, AccessFlags.Protected, equalsBody); if (!typeOnlyEqualsSuffices) { var hashCodePrototype = new Prototype(PrimitiveType.Int); AddMethod(@class, "HashCodeWithoutInvocationList", hashCodePrototype, AccessFlags.Protected, CreateHashCodeBody(@class)); } var clonePrototype = new Prototype(multicastDelegateClass, new Parameter(new ArrayType(multicastDelegateClass), "invocationList"), new Parameter(PrimitiveType.Int, "invocationListLength")); AddMethod(@class, "CloneWithNewInvocationList", clonePrototype, AccessFlags.Protected, CreateCloneBody(ctor, @class)); AddMethod(@class, "GetMethodInfoImpl", new Prototype(methodInfoField.Type),AccessFlags.Protected, CreateGetMethodInfoImplBody()); return new DelegateInstanceType(calledMethod, @class, ctor); }
/// <summary> /// Create an annotation interface. /// </summary> internal static AttributeAnnotationInterface Create( ISourceLocation sequencePoint, AssemblyCompiler compiler, DexTargetPackage targetPackage, TypeDefinition attributeType, ClassDefinition attributeClass) { // Create class ClassDefinition @interface = new ClassDefinition(); @interface.Name = CreateAnnotationTypeName(attributeClass); @interface.Namespace = attributeClass.Namespace; @interface.AccessFlags = AccessFlags.Public | AccessFlags.Abstract | AccessFlags.Interface | AccessFlags.Annotation; @interface.Owner = attributeClass; attributeClass.InnerClasses.Add(@interface); // Set super class @interface.SuperClass = new ClassReference("java/lang/Object"); // Implement Dot42.Internal.IAttribute @interface.Interfaces.Add(new ClassReference("java/lang/annotation/Annotation")); // Prepare result AttributeAnnotationInterface result = new AttributeAnnotationInterface(@interface); // Add methods from IAttribute XModel.XTypeDefinition baseIntfType = compiler.GetDot42InternalType("IAttribute").Resolve(); foreach (XModel.XMethodDefinition imethod in baseIntfType.Methods) { if (imethod.Parameters.Count > 0) throw new CompilerException(string.Format("Invalid IAttribute method {0}", imethod)); string methodName = NameConverter.GetConvertedName(imethod); TypeReference dfieldType = imethod.ReturnType.GetReference(targetPackage); MethodDefinition method = new MethodDefinition(@interface, methodName, new Prototype(dfieldType)); method.AccessFlags = AccessFlags.Public | AccessFlags.Abstract; @interface.Methods.Add(method); } // Add field mapping foreach (var field in attributeType.Fields.Where(x => x.IsReachable && x.IsPublic)) { string methodName = CreateGetMethodName(NameConverter.GetConvertedName(field), result); TypeReference dfieldType = field.FieldType.GetReference(targetPackage, compiler.Module); MethodDefinition method = new MethodDefinition(@interface, methodName, new Prototype(dfieldType)); method.AccessFlags = AccessFlags.Public | AccessFlags.Abstract; result.FieldToGetMethodMap.Add(field, method); @interface.Methods.Add(method); } // Add property mapping foreach (var property in attributeType.Properties.Where(x => x.IsReachable && (x.SetMethod != null) && (x.SetMethod.IsPublic) && x.SetMethod.IsReachable)) { string methodName = CreateGetMethodName(NameConverter.GetConvertedName(property), result); TypeReference dpropType = property.PropertyType.GetReference(targetPackage, compiler.Module); MethodDefinition method = new MethodDefinition(@interface, methodName, new Prototype(dpropType)); method.AccessFlags = AccessFlags.Public | AccessFlags.Abstract; result.PropertyToGetMethodMap.Add(property, method); @interface.Methods.Add(method); } // Add ctor mapping var argIndex = 0; foreach (var ctor in attributeType.Methods.Where(x => (x.Name == ".ctor") && x.IsReachable)) { // Add methods for the ctor arguments List<MethodDefinition> paramGetMethods = new List<MethodDefinition>(); foreach (ParameterDefinition p in ctor.Parameters) { string methodName = CreateGetMethodName("c" + argIndex++, result); TypeReference dparamType = p.ParameterType.GetReference(targetPackage, compiler.Module); MethodDefinition method = new MethodDefinition(@interface, methodName, new Prototype(dparamType)); method.AccessFlags = AccessFlags.Public | AccessFlags.Abstract; @interface.Methods.Add(method); paramGetMethods.Add(method); } // Add a builder method MethodDefinition buildMethod = CreateBuildMethod(sequencePoint, ctor, paramGetMethods, compiler, targetPackage, attributeClass, result); result.CtorMap.Add(ctor, new AttributeCtorMapping(buildMethod, paramGetMethods)); } // Create default values annotation Annotation defAnnotation = CreateDefaultAnnotation(result); result.AnnotationInterfaceClass.Annotations.Add(defAnnotation); return result; }
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 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; } }
private static MethodDefinition CreateFactoryMethod(AssemblyCompiler compiler, DexTargetPackage targetPackage, CustomAttribute attribute, AttributeAnnotationMapping mapping) { var targetClass = mapping.AttributeClass; // is this really the right place for the factory methods? ISourceLocation seqp = null; var attributeTypeDef = attribute.AttributeType.Resolve(); // create method string methodName = CreateAttributeFactoryMethodName(targetClass); MethodDefinition method = new MethodDefinition(targetClass, methodName, new Prototype(mapping.AttributeClass)); method.AccessFlags = AccessFlags.Public | AccessFlags.Static | AccessFlags.Synthetic; targetClass.Methods.Add(method); // create method body MethodBody body = new MethodBody(null); // Allocate attribute Register attributeReg = body.AllocateRegister(RCategory.Temp, RType.Object); body.Instructions.Add(seqp, RCode.New_instance, mapping.AttributeClass, attributeReg); // collect ctor arguments List<Register> ctorArgRegs = new List<Register>() { attributeReg }; foreach (var p in attribute.ConstructorArguments) { XTypeReference xType = XBuilder.AsTypeReference(compiler.Module, p.Type); Register[] valueRegs = CreateInitializeValueInstructions(seqp, body, xType, p, compiler, targetPackage); ctorArgRegs.AddRange(valueRegs); } // Invoke ctor DexLib.MethodReference dctor = attribute.Constructor.GetReference(targetPackage, compiler.Module); body.Instructions.Add(seqp, RCode.Invoke_direct, dctor, ctorArgRegs.ToArray()); // set field values foreach (var p in attribute.Fields) { var field = GetField(attributeTypeDef, p.Name); var xField = XBuilder.AsFieldReference(compiler.Module, field); Register[] valueRegs = CreateInitializeValueInstructions(seqp, body, xField.FieldType, p.Argument, compiler, targetPackage); body.Instructions.Add(seqp, xField.FieldType.IPut(), xField.GetReference(targetPackage), valueRegs[0], attributeReg); } // set property values foreach (var p in attribute.Properties) { PropertyDefinition property = GetSettableProperty(attributeTypeDef, p.Name); XTypeReference xType = XBuilder.AsTypeReference(compiler.Module, property.PropertyType); Register[] valueRegs = CreateInitializeValueInstructions(seqp, body, xType, p.Argument, compiler, targetPackage); XMethodDefinition xSetMethod = XBuilder.AsMethodDefinition(compiler.Module, property.SetMethod); body.Instructions.Add(seqp, xSetMethod.Invoke(xSetMethod, null), xSetMethod.GetReference(targetPackage), new[] { attributeReg }.Concat(valueRegs).ToArray()); } // Return attribute body.Instructions.Add(seqp, RCode.Return_object, attributeReg); // Register method body targetPackage.Record(new CompiledMethod() { DexMethod = method, RLBody = body }); // Return method return method; }
/// <summary> /// Create code to load a value from an annotation interface. /// </summary> /// <returns>The register(s) holding the value</returns> private static Register[] CreateLoadValueSequence( ISourceLocation seqp, MethodBody body, XTypeReference valueType, Register annotationReg, MethodDefinition getter, AssemblyCompiler compiler, DexTargetPackage targetPackage, out Instruction branchIfNotSet) { // NOTE: It would be better if we wouldn't get the values as object arrays // but as arrays of the actual type. // Apparently though the DexWriter will not write our attributes // if they contain arrays not of type object[]. Therefore the // conversion code below. // All in all it would be much cleaner if we could emit Ast code here // instead of RL code. List<Register> result = new List<Register>(); // get the array. Register regObject = body.AllocateRegister(RCategory.Temp, RType.Object); Register regIntVal = body.AllocateRegister(RCategory.Temp, RType.Value); body.Instructions.Add(seqp, RCode.Invoke_interface, getter, annotationReg); body.Instructions.Add(seqp, RCode.Move_result_object, regObject); // allocate result, initialize to default value. if (valueType.IsWide()) { Tuple<Register, Register> regs = body.AllocateWideRegister(RCategory.Temp); body.Instructions.Add(seqp, RCode.Const_wide, 0, regs.Item1); result.Add(regs.Item1); result.Add(regs.Item2); } else if (valueType.IsPrimitive) { Register reg = body.AllocateRegister(RCategory.Temp, RType.Value); body.Instructions.Add(seqp, RCode.Const, 0, reg); result.Add(reg); } else // object { Register reg = body.AllocateRegister(RCategory.Temp, RType.Object); body.Instructions.Add(seqp, RCode.Const, 0, reg); result.Add(reg); } // check if value is unset (array length 0) or null (array length 2) body.Instructions.Add(seqp, RCode.Array_length, regIntVal, regObject); branchIfNotSet = body.Instructions.Add(seqp, RCode.If_eqz, regIntVal); body.Instructions.Add(seqp, RCode.Rsub_int, 1, regIntVal, regIntVal); var branchOnNull = body.Instructions.Add(seqp, RCode.If_nez, regIntVal); // get the (boxed) value body.Instructions.Add(seqp, RCode.Const, 0, regIntVal); // convert to target type. if (valueType.IsArray) { Register regTmp = body.AllocateRegister(RCategory.Temp, RType.Object); Register regType = body.AllocateRegister(RCategory.Temp, RType.Object); var helper = compiler.GetDot42InternalType(InternalConstants.CompilerHelperName); var convertArray = helper.Resolve().Methods.First(p => p.Name == "ConvertArray" && p.Parameters.Count == 2) .GetReference(targetPackage); var underlying = valueType.ElementType.GetReference(targetPackage); body.Instructions.Add(seqp, RCode.Aget_object, regTmp, regObject, regIntVal); body.Instructions.Add(seqp, RCode.Const_class, underlying, regType); body.Instructions.Add(seqp, RCode.Invoke_static, convertArray, regTmp, regType); body.Instructions.Add(seqp, RCode.Move_result_object, result[0]); body.Instructions.Add(seqp, RCode.Check_cast, valueType.GetReference(targetPackage), result[0]); } else if (valueType.IsEnum()) { Register regTmp = body.AllocateRegister(RCategory.Temp, RType.Object); Register regType = body.AllocateRegister(RCategory.Temp, RType.Object); var getFromObject = compiler.GetDot42InternalType("Enum").Resolve() .Methods.Single(p=>p.Name == "GetFromObject") .GetReference(targetPackage); body.Instructions.Add(seqp, RCode.Aget_object, regTmp, regObject, regIntVal); body.Instructions.Add(seqp, RCode.Const_class, valueType.GetReference(targetPackage), regType); body.Instructions.Add(seqp, RCode.Invoke_static, getFromObject, regType, regTmp); body.Instructions.Add(seqp, valueType.MoveResult(), result[0]); body.Instructions.Add(seqp, RCode.Check_cast, valueType.GetReference(targetPackage), result[0]); } else if(!valueType.IsPrimitive) { body.Instructions.Add(seqp, RCode.Aget_object, result[0], regObject, regIntVal); body.Instructions.Add(seqp, RCode.Check_cast, valueType.GetReference(targetPackage), result[0]); } else { Register regTmp = body.AllocateRegister(RCategory.Temp, RType.Object); // unbox and store RCode afterConvert; var unbox = valueType.GetUnboxValueMethod(compiler, targetPackage, out afterConvert); body.Instructions.Add(seqp, RCode.Aget_object, regTmp, regObject, regIntVal); body.Instructions.Add(seqp, RCode.Invoke_static, unbox, regTmp); body.Instructions.Add(seqp, valueType.MoveResult(), result[0]); if (afterConvert != RCode.Nop) { body.Instructions.Add(seqp, afterConvert, result[0], result[0]); } } // nop will be removed at some stage later. var nop = body.Instructions.Add(seqp, RCode.Nop); branchOnNull.Operand = nop; return result.ToArray(); }
/// <summary> /// Implement the class now that all classes have been created /// </summary> protected override void CreateMembers(DexTargetPackage targetPackage) { // Build ctors foreach (var baseCtor in GetBaseClassCtors()) { // Build ctor var prototype = PrototypeBuilder.BuildPrototype(Compiler, targetPackage, null, baseCtor); var ctor = new MethodDefinition(Class, "<init>", prototype); ctor.AccessFlags = AccessFlags.Public | AccessFlags.Constructor; Class.Methods.Add(ctor); // Create ctor body var ctorBody = CreateCtorBody(prototype); targetPackage.Record(new CompiledMethod { DexMethod = ctor, RLBody = ctorBody }); } // build original type field // Create field definition var dfield = new Dot42.DexLib.FieldDefinition(); dfield.Owner = Class; dfield.Name = "underlying$"; dfield.IsSynthetic = true; dfield.IsFinal = true; dfield.IsStatic= true; dfield.IsPublic = true; dfield.Type = Compiler.Module.TypeSystem.Type.GetClassReference(targetPackage); // not sure if GetClassReference is the best way to go forward here. // might depend on the sort order of the class builders. var underlyingType = XBuilder.AsTypeReference(Compiler.Module, Type); dfield.Value = underlyingType.GetClassReference(targetPackage); Class.Fields.Add(dfield); }
/// <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 method definition for the builder method that builds a custom attribute from an annotation. /// </summary> private static MethodDefinition CreateBuildMethod( ISourceLocation seqp, Mono.Cecil.MethodDefinition ctor, List <MethodDefinition> paramGetMethods, AssemblyCompiler compiler, DexTargetPackage targetPackage, ClassDefinition attributeClass, AttributeAnnotationInterface mapping) { // Create method definition string name = CreateBuildMethodName(attributeClass); TypeReference attributeTypeRef = ctor.DeclaringType.GetReference(targetPackage, compiler.Module); MethodDefinition method = new MethodDefinition(attributeClass, name, new Prototype(attributeTypeRef, new Parameter(mapping.AnnotationInterfaceClass, "ann"))); method.AccessFlags = AccessFlags.Public | AccessFlags.Static | AccessFlags.Synthetic; attributeClass.Methods.Add(method); // Create method body MethodBody body = new MethodBody(null); Register annotationReg = body.AllocateRegister(RCategory.Argument, RType.Object); //body.Instructions.Add(seqp, RCode.Check_cast, mapping.AnnotationInterfaceClass, annotationReg); // Allocate attribute Register attributeReg = body.AllocateRegister(RCategory.Temp, RType.Object); body.Instructions.Add(seqp, RCode.New_instance, attributeClass, attributeReg); // Get ctor arguments List <Register> ctorArgRegs = new List <Register>(); foreach (MethodDefinition p in paramGetMethods) { TypeReference paramType = p.Prototype.ReturnType; Register[] valueRegs = CreateLoadValueSequence(seqp, body, paramType, annotationReg, p); ctorArgRegs.AddRange(valueRegs); } // Invoke ctor DexLib.MethodReference dctor = ctor.GetReference(targetPackage, compiler.Module); body.Instructions.Add(seqp, RCode.Invoke_direct, dctor, new[] { attributeReg }.Concat(ctorArgRegs).ToArray()); // Get field values foreach (var fieldMap in mapping.FieldToGetMethodMap) { Mono.Cecil.FieldDefinition field = fieldMap.Key; MethodDefinition getter = fieldMap.Value; Register[] valueRegs = CreateLoadValueSequence(seqp, body, getter.Prototype.ReturnType, annotationReg, getter); DexLib.FieldReference dfield = field.GetReference(targetPackage, compiler.Module); XModel.XTypeReference xFieldType = XBuilder.AsTypeReference(compiler.Module, field.FieldType); body.Instructions.Add(seqp, xFieldType.IPut(), dfield, valueRegs[0], attributeReg); } // Get property values foreach (var propertyMap in mapping.PropertyToGetMethodMap) { PropertyDefinition property = propertyMap.Key; MethodDefinition getter = propertyMap.Value; Register[] valueRegs = CreateLoadValueSequence(seqp, body, getter.Prototype.ReturnType, annotationReg, getter); DexLib.MethodReference dmethod = property.SetMethod.GetReference(targetPackage, compiler.Module); XModel.XMethodDefinition xSetMethod = XBuilder.AsMethodDefinition(compiler.Module, property.SetMethod); body.Instructions.Add(seqp, xSetMethod.Invoke(xSetMethod, null), dmethod, new[] { attributeReg }.Concat(valueRegs).ToArray()); } // Return attribute body.Instructions.Add(seqp, RCode.Return_object, attributeReg); // Register method body targetPackage.Record(new CompiledMethod() { DexMethod = method, RLBody = body }); // Return method return(method); }
/// <summary> /// Default ctor /// </summary> public DexMethodDefinitionNode(MethodDefinition methodDef) { this._methodDef = methodDef; Text = methodDef.Name; ImageIndex = 6; }
private void AddMethod(ClassDefinition @class, string methodName, Prototype prototype, AccessFlags accessFlags, MethodBody body) { var method = new MethodDefinition(@class, methodName, prototype); method.AccessFlags = accessFlags; @class.Methods.Add(method); targetPackage.Record(new CompiledMethod { DexMethod = method, RLBody = body}); }
/// <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 the current type as class definition. /// </summary> internal static DelegateInstanceType Create( ISourceLocation sequencePoint, AssemblyCompiler compiler, DexTargetPackage targetPackage, ClassDefinition delegateClass, XMethodDefinition invokeMethod, Prototype invokePrototype, XMethodDefinition equalsMethod, Prototype equalsPrototype, XMethodDefinition calledMethod) { // Prepare called method var target = targetPackage.DexFile; var owner = target.GetClass(calledMethod.DeclaringType.GetClassReference(targetPackage).Fullname) ?? targetPackage.GetOrCreateGeneratedCodeClass(); var calledMethodPrototype = PrototypeBuilder.BuildPrototype(compiler, targetPackage, owner, calledMethod); var calledMethodRef = calledMethod.GetReference(targetPackage); if (calledMethod.DeclaringType.HasDexImportAttribute()) { // Delegate method is a Dex import method } else { // Delegate method is a .NET method var calledDexMethod = owner.Methods.Single(x => (x.Name == calledMethodRef.Name) && (x.Prototype.Equals(calledMethodRef.Prototype))); if (calledDexMethod.IsPrivate) { calledDexMethod.IsPrivate = false; calledDexMethod.IsProtected = true; } } var @class = new ClassDefinition(); @class.Name = CreateInstanceTypeName(owner); @class.Namespace = owner.Namespace; @class.AccessFlags = AccessFlags.Public | AccessFlags.Final; owner.InnerClasses.Add(@class); // Set super class @class.SuperClass = delegateClass; // Implement delegate interface //@class.Interfaces.Add(delegateInterface); // Get type of instance XTypeDefinition instanceType = calledMethod.DeclaringType; TypeReference instanceTypeRef = instanceType.GetReference(targetPackage); // Add instance field FieldDefinition instanceField = null; if (!calledMethod.IsStatic) { instanceField = new FieldDefinition(); instanceField.Name = "instance"; instanceField.Owner = @class; instanceField.Type = instanceTypeRef; instanceField.AccessFlags = AccessFlags.Private | AccessFlags.Final; @class.Fields.Add(instanceField); } // Add ctor var ctor = new Dot42.DexLib.MethodDefinition(); ctor.Owner = @class; ctor.Name = "<init>"; ctor.AccessFlags = AccessFlags.Public | AccessFlags.Constructor; ctor.Prototype = new Prototype(PrimitiveType.Void); if (!calledMethod.IsStatic) { ctor.Prototype.Parameters.Add(new Parameter(instanceTypeRef, "this")); } @class.Methods.Add(ctor); // Create ctor body var ctorBody = CreateCtorBody(calledMethod, instanceField, delegateClass); targetPackage.Record(new CompiledMethod() { DexMethod = ctor, RLBody = ctorBody }); // Add Invoke method var invoke = new Dot42.DexLib.MethodDefinition(@class, "Invoke", invokePrototype) { AccessFlags = AccessFlags.Public }; @class.Methods.Add(invoke); // Create body var invokeBody = CreateInvokeBody(sequencePoint, compiler, targetPackage, calledMethod, invokeMethod, invokePrototype, calledMethodPrototype, instanceField, delegateClass); targetPackage.Record(new CompiledMethod() { DexMethod = invoke, RLBody = invokeBody }); // Add Equals method if (null != equalsMethod) { var equals = new Dot42.DexLib.MethodDefinition(@class, "equals", equalsPrototype) { AccessFlags = AccessFlags.Public }; @class.Methods.Add(equals); // Create body if (!calledMethod.IsStatic) { var equalsBody = CreateEqualsBody(sequencePoint, compiler, targetPackage, equalsMethod, equalsPrototype, instanceField, @class); targetPackage.Record(new CompiledMethod() { DexMethod = equals, RLBody = equalsBody }); } else { var equalsBody = CreateEqualsBody(); targetPackage.Record(new CompiledMethod() { DexMethod = equals, RLBody = equalsBody }); } } return(new DelegateInstanceType(calledMethod, @class, ctor)); }