/// <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 TypeReference ConvertTypeReference(TypeReference sourceRef, AssemblyCompiler compiler, DexTargetPackage targetPackage) { if (sourceRef is PrimitiveType) { return(sourceRef); } if (sourceRef is ByReferenceType) { var type = (ByReferenceType)sourceRef; var elementType = ConvertTypeReference(type.ElementType, compiler, targetPackage); return(new ByReferenceType(elementType)); } if (sourceRef is ArrayType) { var arrayType = (ArrayType)sourceRef; var elementType = ConvertTypeReference(arrayType.ElementType, compiler, targetPackage); return(new ArrayType(elementType)); } // must be ClassReference return(ConvertClassReference((ClassReference)sourceRef, compiler, targetPackage)); }
private TypeReference ConvertTypeReference(TypeReference sourceRef, AssemblyCompiler compiler, DexTargetPackage targetPackage) { if (sourceRef is PrimitiveType) { return sourceRef; } if (sourceRef is ByReferenceType) { var type = (ByReferenceType) sourceRef; var elementType = ConvertTypeReference(type.ElementType, compiler, targetPackage); return new ByReferenceType(elementType); } if (sourceRef is ArrayType) { var arrayType = (ArrayType) sourceRef; var elementType = ConvertTypeReference(arrayType.ElementType,compiler, targetPackage); return new ArrayType(elementType); } // must be ClassReference return ConvertClassReference((ClassReference)sourceRef, compiler, targetPackage); }
/// <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> /// 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 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 }; } }
public Parameter(TypeReference type, string name) : this() { Type = type; Name = name; }