/// <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> /// 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 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> /// 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> /// 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> /// 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 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 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; }
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> /// 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> /// 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 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> /// 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> /// 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); }
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; }