Esempio n. 1
0
 /// <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 CreateGetTargetImplBody()
        {
            MethodBody body   = new MethodBody(null);
            var        ins    = body.Instructions;
            Register   rthis  = body.AllocateRegister(RCategory.Argument, RType.Object);
            Register   result = body.AllocateRegister(RCategory.Temp, RType.Object);

            ins.Add(new Instruction(RCode.Iget_object, instanceField, new[] { result, rthis }));
            ins.Add(new Instruction(RCode.Return_object, null, new[] { result }));
            return(body);
        }
        private static void CreateCompareArrayInstructions(InstructionList ins, MethodBody body, Register rthis, Register rother, FieldDefinition field, Register rThisValue, Register rOtherValue, Instruction returnFalseInstruction)
        {
            Instruction done = new Instruction(RCode.Nop);

            // Load the instance fields.
            ins.Add(new Instruction(RCode.Iget_object, rThisValue, rthis)
            {
                Operand = field
            });
            ins.Add(new Instruction(RCode.Iget_object, rOtherValue, rother)
            {
                Operand = field
            });

            var rThisLen  = body.AllocateRegister(RCategory.Temp, RType.Value);
            var rOtherLen = body.AllocateRegister(RCategory.Temp, RType.Value);

            // load length
            ins.Add(new Instruction(RCode.Array_length, rThisLen, rThisValue));
            ins.Add(new Instruction(RCode.Array_length, rOtherLen, rOtherValue));

            // Compare the length
            ins.Add(new Instruction(RCode.If_ne, returnFalseInstruction, new[] { rThisLen, rOtherLen }));
            ins.Add(new Instruction(RCode.If_eqz, done, new[] { rThisLen }));

            // now iterate over all elements in the array.
            var thisType  = body.AllocateRegister(RCategory.Temp, RType.Object);
            var otherType = body.AllocateRegister(RCategory.Temp, RType.Object);
            var counter   = body.AllocateRegister(RCategory.Temp, RType.Object);

            ins.Add(new Instruction(RCode.Const, 0, new[] { counter }));

            var loadThisVal = new Instruction(RCode.Aget_object, thisType, rThisValue, counter);

            ins.Add(loadThisVal);
            ins.Add(new Instruction(RCode.Aget_object, otherType, rOtherValue, counter));

            // compare types.
            ins.Add(new Instruction(RCode.If_ne, returnFalseInstruction, new[] { thisType, otherType }));

            ins.Add(new Instruction(RCode.Add_int_lit8, 1, new[] { counter, counter }));
            ins.Add(new Instruction(RCode.If_ne, loadThisVal, new[] { counter, rThisLen }));

            ins.Add(done);
        }
        private MethodBody CreateGetMethodInfoImplBody()
        {
            // TODO: For methods taking generic parameters we want to lazy initialize a
            //       non-static volatile MethodInfo register.

            MethodBody body   = new MethodBody(null);
            var        ins    = body.Instructions;
            Register   rthis  = body.AllocateRegister(RCategory.Argument, RType.Object);
            Register   result = body.AllocateRegister(RCategory.Temp, RType.Object);

            if (methodInfoField.IsStatic)
            {
                ins.Add(new Instruction(RCode.Sget_object, methodInfoField, new[] { result }));
            }
            else
            {
                ins.Add(new Instruction(RCode.Iget_object, methodInfoField, new[] { result, rthis }));
            }
            ins.Add(new Instruction(RCode.Return_object, null, new[] { result }));
            return(body);
        }
        /// <summary>
        /// Create the body of the equals method.
        /// </summary>
        private static MethodBody CreateEqualsCheckTypeOnlyBody(ClassReference delegateClass)
        {
            MethodBody body = new MethodBody(null);

            // This pointer and method argument.
            Register rthis  = body.AllocateRegister(RCategory.Argument, RType.Object);
            Register rother = body.AllocateRegister(RCategory.Argument, RType.Object);

            // result register
            Register result = body.AllocateRegister(RCategory.Temp, RType.Value);

            var ins = body.Instructions;

            // Check if other object can be casted.
            ins.Add(new Instruction(RCode.Instance_of, delegateClass, new[] { result, rother }));

            // Add return instructions
            ins.Add(new Instruction(RCode.Return, result));

            return(body);
        }
        /// <summary>
        /// Create the body of the ctor.
        /// </summary>
        private MethodBody CreateCtorBody()
        {
            var body = new MethodBody(null);
            // Create code
            var ins   = body.Instructions;
            var rthis = body.AllocateRegister(RCategory.Argument, RType.Object);
            // Call base ctor
            var baseCtorRef = new MethodReference(delegateClass, "<init>", new Prototype(PrimitiveType.Void));

            ins.Add(new Instruction(RCode.Invoke_direct, rthis)
            {
                Operand = baseCtorRef
            });


            if (instanceField != null)
            {
                // load instance into field
                var rInstanceArg = body.AllocateRegister(RCategory.Argument, RType.Object);
                ins.Add(new Instruction(RCode.Iput_object, rInstanceArg, rthis)
                {
                    Operand = instanceField
                });
            }

            foreach (var field in GenericTypeFields)
            {
                var rArg = body.AllocateRegister(RCategory.Argument, RType.Object);
                ins.Add(new Instruction(RCode.Iput_object, rArg, rthis)
                {
                    Operand = field
                });
            }

            ins.Add(new Instruction(RCode.Return_void));
            return(body);
        }
        /// <summary>
        /// Create the body of the ctor.
        /// </summary>
        private MethodBody CreateCtorBody(Prototype prototype)
        {
            var body = new MethodBody(null);
            // Create code
            var ins   = body.Instructions;
            var rthis = body.AllocateRegister(RCategory.Argument, RType.Object);
            // Add parameters
            var paramRegs = new List <Register> {
                rthis
            };

            foreach (var p in prototype.Parameters)
            {
                if (p.Type.IsWide())
                {
                    var pair = body.AllocateWideRegister(RCategory.Argument);
                    paramRegs.Add(pair.Item1);
                    paramRegs.Add(pair.Item2);
                }
                else
                {
                    var reg = body.AllocateRegister(RCategory.Argument, p.Type.IsPrimitive() ? RType.Value : RType.Object);
                    paramRegs.Add(reg);
                }
            }

            // Call base ctor
            var baseCtorRef = new MethodReference(Class.SuperClass, "<init>", prototype);

            ins.Add(new Instruction(RCode.Invoke_direct, paramRegs.ToArray())
            {
                Operand = baseCtorRef
            });
            ins.Add(new Instruction(RCode.Return_void));
            return(body);
        }
Esempio n. 8
0
        /// <summary>
        /// Allocate a register for the given type.
        /// </summary>
        protected override RegisterSpec Allocate(TypeReference type, bool forceObject, RCategory category, object parameter)
        {
            var isWide = !forceObject && type.IsWide();

            if (isWide)
            {
                var pair = body.AllocateWideRegister(category);
                switch (category)
                {
                case RCategory.Temp:
                    return(new RegisterSpec(pair.Item1, pair.Item2, type));

                case RCategory.Variable:
                case RCategory.VariablePreventOptimization:
                case RCategory.TempVariable:
                    return(new VariableRegisterSpec(pair.Item1, pair.Item2, type, (AstVariable)parameter));

                case RCategory.Argument:
                    return(new ArgumentRegisterSpec(pair.Item1, pair.Item2, type, ParameterWrapper.Wrap(parameter)));

                default:
                    throw new ArgumentException("Unknown category " + category);
                }
            }
            var isPrimitive = !forceObject && (type is PrimitiveType);
            var register    = body.AllocateRegister(category, isPrimitive ? RType.Value : RType.Object);

            switch (category)
            {
            case RCategory.Temp:
                return(new RegisterSpec(register, null, type));

            case RCategory.Variable:
            case RCategory.VariablePreventOptimization:
            case RCategory.TempVariable:
                return(new VariableRegisterSpec(register, null, type, (AstVariable)parameter));

            case RCategory.Argument:
                return(new ArgumentRegisterSpec(register, null, type, ParameterWrapper.Wrap(parameter)));

            default:
                throw new ArgumentException("Unknown category " + category);
            }
        }
        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);
        }
        private Register CallGetMethodInfo(MethodBody body, MethodReference methodRef)
        {
            // >> var method = TypeHelper.GetMethodInfo(typeof(CalledClass), methodName, new[] { paramType1, ...}, null, null);

            var ins = body.Instructions;

            Register classR        = body.AllocateRegister(RCategory.Temp, RType.Object);
            Register methodNameR   = body.AllocateRegister(RCategory.Temp, RType.Object);
            Register methodParamsR = body.AllocateRegister(RCategory.Temp, RType.Object);
            Register idxR          = body.AllocateRegister(RCategory.Temp, RType.Value);
            var      resultR       = body.AllocateRegister(RCategory.Temp, RType.Object);
            var      nullR         = body.AllocateRegister(RCategory.Temp, RType.Object);

            var parameters = methodRef.Prototype.Parameters;

            ins.Add(new Instruction(RCode.Const_class, methodRef.Owner, new[] { classR }));
            ins.Add(new Instruction(RCode.Const_string, methodRef.Name, new[] { methodNameR }));

            ins.Add(new Instruction(RCode.Const, parameters.Count, new[] { idxR }));
            ins.Add(new Instruction(RCode.New_array, FrameworkReferences.ClassArray, new[] { methodParamsR, idxR }));

            for (int i = 0; i < parameters.Count; ++i)
            {
                ins.Add(new Instruction(RCode.Const, i, new[] { idxR }));
                ins.Add(new Instruction(RCode.Const_class, parameters[i].Type, new[] { resultR }));
                ins.Add(new Instruction(RCode.Aput_object, null, new[] { resultR, methodParamsR, idxR }));
            }

            ins.Add(new Instruction(RCode.Const, 0, new[] { nullR }));

            var xGetMethodInfo = compiler.GetDot42InternalType(InternalConstants.TypeHelperName).Resolve().Methods.First(m => m.Name == "GetMethodInfo");
            var getMethodInfo  = xGetMethodInfo.GetReference(targetPackage);

            // TODO: make this work with generic parameters as well.
            ins.Add(new Instruction(RCode.Invoke_virtual, getMethodInfo, new[] { classR, methodNameR, methodParamsR, nullR, nullR }));
            ins.Add(new Instruction(RCode.Move_result_object, null, new[] { resultR }));
            return(resultR);
        }
Esempio n. 11
0
        /// <summary>
        /// Create code to initialize a value from an attribute.
        /// </summary>
        /// <returns>The register(s) holding the value</returns>
        private static Register[] CreateInitializeValueInstructions(ISourceLocation seqp, MethodBody body, XTypeReference targetType, CustomAttributeArgument value, AssemblyCompiler compiler, DexTargetPackage targetPackage)
        {
            List <Register> result = new List <Register>();

            // allocate result, initialize to default value.
            if (targetType.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 (targetType.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);
            }

            // load data

            if (value.Value == null) // must be a reference type
            {
                body.Instructions.Add(seqp, RCode.Const, 0, result[0]);
                body.Instructions.Add(seqp, RCode.Check_cast, targetType.GetReference(targetPackage), result[0]);
                return(result.ToArray());
            }

            var valueType = XBuilder.AsTypeReference(compiler.Module, value.Type);

            if (value.Value is CustomAttributeArgument)
            {
                // this happens if a type conversion is neccessary
                var nestedValue = (CustomAttributeArgument)value.Value;
                valueType = XBuilder.AsTypeReference(compiler.Module, nestedValue.Type);

                var rOrigValue = CreateInitializeValueInstructions(seqp, body, valueType, nestedValue, compiler, targetPackage);

                if (!nestedValue.Type.IsPrimitive)
                {
                    body.Instructions.Add(seqp, RCode.Move_object, result[0], rOrigValue[0]);
                    body.Instructions.Add(seqp, RCode.Check_cast, targetType.GetReference(targetPackage), result[0]);
                }
                else if (!targetType.IsPrimitive)
                {
                    body.Instructions.Add(seqp, RCode.Invoke_static, valueType.GetBoxValueOfMethod(), rOrigValue);
                    body.Instructions.Add(seqp, RCode.Move_result_object, result[0]);
                    body.Instructions.Add(seqp, RCode.Check_cast, targetType.GetReference(targetPackage), result[0]);
                }
                else
                {
                    throw new Exception(string.Format("type converstion in attribute {0}=>{1} not yet supported", valueType.FullName, targetType.FullName));
                }
            }
            else if (valueType.IsArray)
            {
                var array       = (CustomAttributeArgument[])value.Value;
                var elementType = valueType.ElementType;

                Register rIndex = body.AllocateRegister(RCategory.Temp, RType.Value);
                body.Instructions.Add(seqp, RCode.Const, array.Length, rIndex);
                body.Instructions.Add(seqp, RCode.New_array, valueType.GetReference(targetPackage), result[0], rIndex);

                // iterate through each value
                for (int i = 0; i < array.Length; i++)
                {
                    Register rLoaded = CreateInitializeValueInstructions(seqp, body, elementType, array[i], compiler, targetPackage)[0];

                    body.Instructions.Add(seqp, RCode.Const, i, rIndex);
                    body.Instructions.Add(seqp, valueType.APut(), rLoaded, result[0], rIndex);
                }
            }
            else if (targetType.IsEnum())
            {
                var enumClass = (targetType.IsEnum()? targetType:valueType).GetReference(targetPackage);

                Register rEnumClass = body.AllocateRegister(RCategory.Temp, RType.Object);
                body.Instructions.Add(seqp, RCode.Const_class, enumClass, rEnumClass);

                long lVal = Convert.ToInt64(value.Value);
                if (lVal <= int.MaxValue && lVal >= int.MinValue)
                {
                    Register regTmp = body.AllocateRegister(RCategory.Temp, RType.Value);
                    body.Instructions.Add(seqp, RCode.Const, (int)lVal, regTmp);
                    var get = compiler.GetDot42InternalType("Enum").Resolve()
                              .Methods.Single(p => p.Name == "Get" && p.Parameters.Count == 2 && !p.Parameters[1].ParameterType.IsWide())
                              .GetReference(targetPackage);
                    body.Instructions.Add(seqp, RCode.Invoke_static, get, rEnumClass, regTmp);
                    body.Instructions.Add(seqp, targetType.MoveResult(), result[0]);
                }
                else
                {
                    var regTmp = body.AllocateWideRegister(RCategory.Temp);
                    body.Instructions.Add(seqp, RCode.Const, (long)lVal, regTmp.Item1);
                    var get = compiler.GetDot42InternalType("Enum").Resolve()
                              .Methods.Single(p => p.Name == "Get" && p.Parameters.Count == 2 && p.Parameters[1].ParameterType.IsWide())
                              .GetReference(targetPackage);
                    body.Instructions.Add(seqp, RCode.Invoke_static, get, rEnumClass, regTmp.Item1);
                    body.Instructions.Add(seqp, targetType.MoveResult(), result[0]);
                }
                body.Instructions.Add(seqp, RCode.Check_cast, targetType.GetReference(targetPackage), result[0]);
            }
            else if (valueType.IsSystemString())
            {
                body.Instructions.Add(seqp, RCode.Const_string, (string)value.Value, result[0]);
            }
            else if (valueType.IsSystemType())
            {
                var type = XBuilder.AsTypeReference(compiler.Module, (TypeReference)value.Value);
                // TODO: this might not work with typeof(void) on ART runtime.
                body.Instructions.Add(seqp, RCode.Const_class, type.GetReference(targetPackage), result[0]);
            }
            else if (!valueType.IsPrimitive)
            {
                // can this happen?
                throw new Exception("invalid value type in attribute: " + targetType.FullName);
            }
            else
            {
                if (targetType.IsSystemObject())
                {
                    // can this happen? or is this always handled above?

                    // boxing required.
                    var rUnboxed = CreateInitializeValueInstructions(seqp, body, valueType, value, compiler, targetPackage);
                    body.Instructions.Add(seqp, RCode.Invoke_static, valueType.GetBoxValueOfMethod(), rUnboxed);
                    body.Instructions.Add(seqp, RCode.Move_result_object, result[0]);
                }
                else if (targetType.IsDouble())
                {
                    body.Instructions.Add(seqp, RCode.Const_wide, Convert.ToDouble(value.Value), result[0]);
                }
                else if (targetType.IsWide() && valueType.IsUInt64())
                {
                    body.Instructions.Add(seqp, RCode.Const_wide, (long)Convert.ToUInt64(value.Value), result[0]);
                }
                else if (targetType.IsWide())
                {
                    body.Instructions.Add(seqp, RCode.Const_wide, Convert.ToInt64(value.Value), result[0]);
                }
                else if (targetType.IsFloat())
                {
                    body.Instructions.Add(seqp, RCode.Const, Convert.ToSingle(value.Value), result[0]);
                }
                else
                {
                    body.Instructions.Add(seqp, RCode.Const, (int)Convert.ToInt64(value.Value), result[0]);
                }
            }

            return(result.ToArray());
        }
Esempio n. 12
0
        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);
        }
Esempio n. 13
0
        /// <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 body of the equals method.
        /// </summary>
        private MethodBody CreateHashCodeBody(ClassReference delegateInstance)
        {
            MethodBody body = new MethodBody(null);

            // This pointer and method argument.
            Register rthis   = body.AllocateRegister(RCategory.Argument, RType.Object);
            Register tempObj = body.AllocateRegister(RCategory.Temp, RType.Object);
            Register tempInt = body.AllocateRegister(RCategory.Temp, RType.Value);

            Register tempArray       = body.AllocateRegister(RCategory.Temp, RType.Object);
            Register tempIdx         = body.AllocateRegister(RCategory.Temp, RType.Value);
            Register tempArrayLength = body.AllocateRegister(RCategory.Temp, RType.Value);

            // Create code.
            var ins = body.Instructions;

            // Temporary parameter result.
            Register result = body.AllocateRegister(RCategory.Temp, RType.Value);

            var hashCodeMethod = compiler.GetDot42InternalType("Java.Lang", "System")
                                 .Resolve()
                                 .Methods.First(m => m.Name == "IdentityHashCode")
                                 .GetReference(targetPackage);

            // Check if other object can be casted.
            ins.Add(new Instruction(RCode.Const_class, delegateInstance, new[] { tempObj }));
            ins.Add(new Instruction(RCode.Invoke_static, hashCodeMethod, new[] { tempObj }));
            ins.Add(new Instruction(RCode.Move_result, null, new[] { result }));

            if (instanceField != null)
            {
                ins.Add(new Instruction(RCode.Mul_int_lit, 397, new[] { result, result }));
                ins.Add(new Instruction(RCode.Iget_object, tempObj, rthis)
                {
                    Operand = instanceField
                });
                ins.Add(new Instruction(RCode.Invoke_static, tempObj)
                {
                    Operand = hashCodeMethod
                });
                ins.Add(new Instruction(RCode.Move_result, tempInt));
                ins.Add(new Instruction(RCode.Xor_int_2addr, result, tempInt));
            }

            foreach (var field in GenericTypeFields)
            {
                if (field.Type.Equals(FrameworkReferences.Class))
                {
                    ins.Add(new Instruction(RCode.Iget_object, tempObj, rthis)
                    {
                        Operand = field
                    });
                    ins.Add(new Instruction(RCode.Invoke_static, hashCodeMethod, new[] { tempObj }));
                    ins.Add(new Instruction(RCode.Move_result, null, new[] { tempInt }));
                    ins.Add(new Instruction(RCode.Xor_int_2addr, null, new[] { result, tempInt }));
                }
                else // array
                {
                    ins.Add(new Instruction(RCode.Iget_object, tempArray, rthis)
                    {
                        Operand = field
                    });
                    ins.Add(new Instruction(RCode.Array_length, tempArrayLength, rthis));
                    ins.Add(new Instruction(RCode.Const, tempIdx)
                    {
                        Operand = 0
                    });

                    Instruction loop;
                    ins.Add(loop = new Instruction());
                    ins.Add(new Instruction(RCode.Mul_int_lit, 397, new[] { result, result }));
                    ins.Add(new Instruction(RCode.Aget_object, tempObj, tempArray, tempIdx));
                    ins.Add(new Instruction(RCode.Invoke_static, hashCodeMethod, new[] { tempObj }));
                    ins.Add(new Instruction(RCode.Move_result, null, new[] { tempInt }));
                    ins.Add(new Instruction(RCode.Xor_int_2addr, null, new[] { result, tempInt }));

                    ins.Add(new Instruction(RCode.Add_int_lit8, 1, new[] { tempIdx, tempIdx }));
                    ins.Add(new Instruction(RCode.If_ltz, tempIdx, tempArrayLength)
                    {
                        Operand = loop
                    });
                }
            }

            // Add return instructions
            ins.Add(new Instruction(RCode.Return, null, new[] { result }));

            return(body);
        }
        /// <summary>
        /// Create the body of the equals method.
        /// </summary>
        private MethodBody CreateEqualsBody(ClassReference delegateInstance)
        {
            MethodBody body = new MethodBody(null);

            // This pointer and method argument.
            Register rthis  = body.AllocateRegister(RCategory.Argument, RType.Object);
            Register rother = body.AllocateRegister(RCategory.Argument, RType.Object);

            // Create code.
            var ins = body.Instructions;

            // Temporary parameter result.
            Register result = body.AllocateRegister(RCategory.Temp, RType.Value);

            // Prepare the return instruction.
            Instruction returnFalseInstruction = new Instruction(RCode.Return, result);


            // Check if other object can be casted.
            ins.Add(new Instruction(RCode.Instance_of, delegateInstance, new[] { result, rother }));
            ins.Add(new Instruction(RCode.If_eqz, returnFalseInstruction, new[] { result }));

            // Set result to false on default.
            ins.Add(new Instruction(RCode.Const, 0, new[] { result }));

            // Cast of the other object.
            ins.Add(new Instruction(RCode.Check_cast, delegateInstance, new[] { rother }));

            // Get instance fields of this and other.
            var rThisValue  = body.AllocateRegister(RCategory.Temp, RType.Object);
            var rOtherValue = body.AllocateRegister(RCategory.Temp, RType.Object);

            if (instanceField != null)
            {
                // Load the instance fields.
                ins.Add(new Instruction(RCode.Iget_object, rThisValue, rthis)
                {
                    Operand = instanceField
                });
                ins.Add(new Instruction(RCode.Iget_object, rOtherValue, rother)
                {
                    Operand = instanceField
                });

                // Compare the instance fields.
                ins.Add(new Instruction(RCode.If_ne, returnFalseInstruction, new[] { rThisValue, rOtherValue }));
            }

            foreach (var field in GenericTypeFields)
            {
                if (field.Type.Equals(FrameworkReferences.Class))
                {
                    // simply load and compare the fields.
                    ins.Add(new Instruction(RCode.Iget_object, rThisValue, rthis)
                    {
                        Operand = field
                    });
                    ins.Add(new Instruction(RCode.Iget_object, rOtherValue, rother)
                    {
                        Operand = field
                    });
                    ins.Add(new Instruction(RCode.If_ne, returnFalseInstruction, new[] { rThisValue, rOtherValue }));
                }
                else // array
                {
                    CreateCompareArrayInstructions(ins, body, rthis, rother, field, rThisValue, rOtherValue, returnFalseInstruction);
                }
            }

            // return true, if we made it so far
            ins.Add(new Instruction(RCode.Const, 1, new[] { result }));

            // Add return instructions
            ins.Add(returnFalseInstruction);

            return(body);
        }
        /// <summary>
        /// Create the body of the invoke method.
        /// </summary>
        /// <param name="calledMethodPrototype"></param>
        private MethodBody CreateInvokeBody(Prototype calledMethodPrototype)
        {
            var body  = new MethodBody(null);
            var rthis = body.AllocateRegister(RCategory.Argument, RType.Object);

            foreach (var p in invokePrototype.Parameters)
            {
                if (p.Type.IsWide())
                {
                    body.AllocateWideRegister(RCategory.Argument);
                }
                else
                {
                    var type = (p.Type is PrimitiveType) ? RType.Value : RType.Object;
                    body.AllocateRegister(RCategory.Argument, type);
                }
            }
            var incomingMethodArgs = body.Registers.ToArray();

            // Create code
            var      ins         = body.Instructions;
            Register instanceReg = null;

            if (!calledMethod.IsStatic)
            {
                // load instance
                instanceReg = body.AllocateRegister(RCategory.Temp, RType.Object);
                ins.Add(new Instruction(RCode.Iget_object, instanceReg, rthis)
                {
                    Operand = instanceField
                });
            }

            List <Register> genericTypeParameterRegs = new List <Register>();

            foreach (var field in GenericTypeFields)
            {
                var r = body.AllocateRegister(RCategory.Temp, RType.Object);
                ins.Add(new Instruction(RCode.Iget_object, r, rthis)
                {
                    Operand = field
                });
                genericTypeParameterRegs.Add(r);
            }

            // Invoke
            var calledMethodRef = calledMethod.GetReference(targetPackage);
            var inputArgs       = calledMethod.IsStatic ? incomingMethodArgs.Skip(1).ToArray() : incomingMethodArgs;

            // Cast arguments (if needed)
            var outputArgs = new List <Register>();

            if (!calledMethod.IsStatic)
            {
                outputArgs.Add(instanceReg);
            }
            var parameterIndex = 0;

            for (var i = calledMethod.IsStatic ? 0 : 1; i < inputArgs.Length;)
            {
                var invokeType  = invokePrototype.Parameters[parameterIndex].Type;
                var inputIsWide = invokeType.IsWide();
                var calledType  = calledMethodPrototype.Parameters[parameterIndex].Type;
                if (!invokeType.Equals(calledType))
                {
                    // Add cast / unbox
                    var source = inputIsWide
                                     ? new RegisterSpec(inputArgs[i], inputArgs[i + 1], invokeType)
                                     : new RegisterSpec(inputArgs[i], null, invokeType);
                    var tmp = ins.Unbox(sequencePoint, source, calledMethod.Parameters[parameterIndex].ParameterType, compiler, targetPackage, body);
                    outputArgs.Add(tmp.Result.Register);
                    if (calledType.IsWide())
                    {
                        outputArgs.Add(tmp.Result.Register2);
                    }
                }
                else
                {
                    outputArgs.Add(inputArgs[i]);
                    if (calledType.IsWide())
                    {
                        outputArgs.Add(inputArgs[i + 1]);
                    }
                }
                i += inputIsWide ? 2 : 1;
                parameterIndex++;
            }

            outputArgs.AddRange(genericTypeParameterRegs);

            // Actual call
            ins.Add(new Instruction(calledMethod.Invoke(calledMethod, null), calledMethodRef, outputArgs.ToArray()));

            // Collect return value
            var         invokeReturnType = invokePrototype.ReturnType;
            var         calledReturnType = calledMethodPrototype.ReturnType;
            var         needsBoxing      = !invokeReturnType.Equals(calledReturnType);
            Instruction returnInstruction;
            Instruction nextMoveResultInstruction = null;

            if (calledReturnType.IsWide())
            {
                var r = body.AllocateWideRegister(RCategory.Temp);
                ins.Add(new Instruction(RCode.Move_result_wide, r.Item1));
                if (needsBoxing)
                {
                    // Box
                    var source = new RegisterSpec(r.Item1, r.Item2, calledReturnType);
                    var tmp    = ins.Box(sequencePoint, source, calledMethod.ReturnType, targetPackage, body);
                    returnInstruction         = new Instruction(RCode.Return_object, tmp.Result.Register);
                    nextMoveResultInstruction = new Instruction(RCode.Move_result_object, tmp.Result.Register);
                }
                else
                {
                    // Return wide
                    returnInstruction         = new Instruction(RCode.Return_wide, r.Item1);
                    nextMoveResultInstruction = new Instruction(RCode.Move_result_wide, r.Item1);
                }
            }
            else if (calledMethod.ReturnType.IsVoid())
            {
                // Void return
                returnInstruction = new Instruction(RCode.Return_void);
            }
            else if (calledReturnType is PrimitiveType)
            {
                // Single register return
                var r = body.AllocateRegister(RCategory.Temp, RType.Value);
                ins.Add(new Instruction(RCode.Move_result, r));
                if (needsBoxing)
                {
                    // Box
                    var source = new RegisterSpec(r, null, invokeReturnType);
                    var tmp    = ins.Box(sequencePoint, source, calledMethod.ReturnType, targetPackage, body);
                    returnInstruction         = new Instruction(RCode.Return_object, tmp.Result.Register);
                    nextMoveResultInstruction = new Instruction(RCode.Move_result_object, tmp.Result.Register);
                }
                else
                {
                    // Return
                    returnInstruction         = new Instruction(RCode.Return, r);
                    nextMoveResultInstruction = new Instruction(RCode.Move_result, r);
                }
            }
            else
            {
                var r = body.AllocateRegister(RCategory.Temp, RType.Object);
                ins.Add(new Instruction(RCode.Move_result_object, r));
                if (needsBoxing)
                {
                    // Box
                    var source = new RegisterSpec(r, null, invokeReturnType);
                    var tmp    = ins.Box(sequencePoint, source, invokeMethod.ReturnType, targetPackage, body);
                    returnInstruction         = new Instruction(RCode.Return_object, tmp.Result.Register);
                    nextMoveResultInstruction = new Instruction(RCode.Move_result_object, tmp.Result.Register);
                }
                else
                {
                    // Return
                    returnInstruction         = new Instruction(RCode.Return_object, r);
                    nextMoveResultInstruction = new Instruction(RCode.Move_result_object, r);
                }
            }

            // Call delegate list
            var multicastDelegateType  = new ClassReference(targetPackage.NameConverter.GetConvertedFullName("System.MulticastDelegate"));
            var invListLengthReference = new FieldReference(multicastDelegateType, "InvocationListLength", PrimitiveType.Int);
            var multicastDelegateArray = new ArrayType(multicastDelegateType);
            var invListReference       = new FieldReference(multicastDelegateType, "InvocationList", multicastDelegateArray);

            var index   = body.AllocateRegister(RCategory.Temp, RType.Value);
            var count   = body.AllocateRegister(RCategory.Temp, RType.Value);
            var next    = body.AllocateRegister(RCategory.Temp, RType.Object);
            var invList = body.AllocateRegister(RCategory.Temp, RType.Object);

            var done = new Instruction(RCode.Nop);

            var nextInvokeMethod = new MethodReference(delegateClass, "Invoke", invokePrototype);
            var nextInvokeArgs = new[] { next }.Concat(incomingMethodArgs.Skip(1)).ToArray();

            ins.Add(new Instruction(RCode.Iget, invListLengthReference, new[] { count, rthis }));
            ins.Add(new Instruction(RCode.If_eqz, done, new[] { count }));
            ins.Add(new Instruction(RCode.Const, 0, new[] { index }));
            ins.Add(new Instruction(RCode.Iget_object, invListReference, new[] { invList, rthis }));

            var getNext = new Instruction(RCode.Aget_object, null, new[] { next, invList, index });

            ins.Add(getNext);
            ins.Add(new Instruction(RCode.Check_cast, delegateClass, new [] { next }));
            ins.Add(new Instruction(RCode.Invoke_virtual, nextInvokeMethod, nextInvokeArgs));

            if (nextMoveResultInstruction != null)
            {
                ins.Add(nextMoveResultInstruction);
            }

            ins.Add(new Instruction(RCode.Add_int_lit8, 1, new[] { index, index }));
            ins.Add(new Instruction(RCode.If_lt, getNext, new[] { index, count }));

            ins.Add(done);

            // Add return instructions
            ins.Add(returnInstruction);

            return(body);
        }