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

            ins.Add(new Instruction(RCode.Invoke_direct, rthis)
            {
                Operand = baseCtorRef
            });
            if (!calledMethod.IsStatic)
            {
                // load instance into field
                var rvalue = body.AllocateRegister(RCategory.Argument, RType.Object);
                ins.Add(new Instruction(RCode.Iput_object, rvalue, rthis)
                {
                    Operand = instanceField
                });
            }
            ins.Add(new Instruction(RCode.Return_void));
            return(body);
        }
Esempio n. 2
0
        /// <summary>
        /// Default ctor
        /// </summary>
        public RegisterMapper(MethodBody body, InvocationFrame frame)
        {
            this.frame = frame;
            // Select all non-argument registers that are in use.
            Dictionary<Register, RegisterFlags> used;
            int maxOutgoingRegisters;
            bool largeInvokeInsFound;
            GetUsedArgumentRegisters(body, out used, out maxOutgoingRegisters, out largeInvokeInsFound);
            //var used = body.Registers.Where(x => (x.Category != RCategory.Argument) && body.Instructions.Uses(x)).ToList();
            var sorted = used.OrderBy(x => x.Value).ThenBy(x => x.Key.Index).Select(x => x.Key).ToList();
            AddKeepWithNext(sorted, body);
            // Collect argument registers
            var arguments = body.Registers.Where(x => x.Category == RCategory.Argument).ToList();

            // Prepare various decisions
            //var maxOutgoingRegisters = body.Instructions.Max(x => x.Code.IsInvoke() ? x.Registers.Count : 0);
            var required = sorted.Count + arguments.Count;
            //var largeInvokeInsFound = body.Instructions.Any(x => x.Code.IsInvoke() && x.Registers.Count > 5);

            // Allocate Dex registers for each
            var index = 0;

            // Allocate spill registers (if needed)
            if ((required >= 16) || (largeInvokeInsFound && (required + maxOutgoingRegisters >= 16)))
            {
                spillRangeRegisters = new DexLib.Instructions.Register[MaxSpillRegisters];
                for (var i = 0; i < MaxSpillRegisters; i++)
                {
                    spillRangeRegisters[i] = new DexLib.Instructions.Register(index++);                    
                }
            }

            // Allocate Dex registers for each temp register.
            foreach (var r in sorted)
            {
                var dreg = new DexLib.Instructions.Register(index++);
                map[r] = dreg;
                dRegisterTypes[dreg] = r.Type;
            }

            // Allocate outgoing invocation frame (if needed)
            if ((required >= 16) || largeInvokeInsFound)
            {
                invokeRangeRegisters = new DexLib.Instructions.Register[maxOutgoingRegisters];
                for (var i = 0; i < maxOutgoingRegisters; i++)
                {
                    invokeRangeRegisters[i] = new DexLib.Instructions.Register(index++);
                }
            }

            // Allocate Dex registers for each argument
            foreach (var r in arguments)
            {
                var dreg = new DexLib.Instructions.Register(index++);
                map[r] = dreg;
                dRegisterTypes[dreg] = r.Type;
            }
            ArgumentCount = arguments.Count;
        }
Esempio n. 3
0
        /// <summary>
        /// Gets all registers of category!=Argument that are used in an instruction.
        /// </summary>
        private static void GetUsedArgumentRegisters(MethodBody body, out Dictionary <Register, RegisterFlags> used, out int maxOutgoingRegisters, out bool largeInvokeInsFound)
        {
            //maxOutgoingRegisters = body.Instructions.Max(x => x.Code.IsInvoke() ? x.Registers.Count : 0);
            //largeInvokeInsFound = body.Instructions.Any(x => x.Code.IsInvoke() && x.Registers.Count > 5);
            maxOutgoingRegisters = 0;
            largeInvokeInsFound  = false;

            used = new Dictionary <Register, RegisterFlags>();
            foreach (var ins in body.Instructions)
            {
                if (ins.Code.IsInvoke())
                {
                    maxOutgoingRegisters = Math.Max(maxOutgoingRegisters, ins.Registers.Count);
                    if (ins.Registers.Count > 5)
                    {
                        largeInvokeInsFound = true;
                    }
                }
                foreach (var reg in ins.Registers)
                {
                    if (reg.Category != RCategory.Argument)
                    {
                        var           lowestSize = GetLowestSize(ins, reg);
                        RegisterFlags currentLowestSize;
                        if (used.TryGetValue(reg, out currentLowestSize))
                        {
                            if (lowestSize < currentLowestSize)
                            {
                                used[reg] = lowestSize;
                            }
                        }
                        else
                        {
                            used.Add(reg, lowestSize);
                        }
                    }
                }
            }

            // Add second register of wide registers.
            Register prevReg = null;

            foreach (var reg in body.Registers)
            {
                if (prevReg != null)
                {
                    if (reg.Type == RType.Wide2)
                    {
                        RegisterFlags flags;
                        if (used.TryGetValue(prevReg, out flags))
                        {
                            used[reg] = flags;
                        }
                    }
                }
                prevReg = reg;
            }
        }
        /// <summary>
        /// Create the body of the equals method.
        /// </summary>
        private static MethodBody CreateEqualsBody(ISourceLocation sequencePoint, AssemblyCompiler compiler, DexTargetPackage targetPackage, XMethodDefinition equalsMethod, Prototype equalsPrototype, FieldDefinition instanceField, 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);

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

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

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

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

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

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

            // Load the instance fields.
            ins.Add(new Instruction(RCode.Iget_object, thisInstance, rthis)
            {
                Operand = instanceField
            });
            ins.Add(new Instruction(RCode.Iget_object, otherInstance, rother)
            {
                Operand = instanceField
            });

            // Compare the instance fields.
            ins.Add(new Instruction(RCode.If_eq, returnInstruction, new[] { thisInstance, otherInstance })); // compare instance members

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

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

            return(body);
        }
Esempio n. 5
0
        /// <summary>
        /// For each register in the given list, ensure that all keep-with-next registers are also added.
        /// </summary>
        private static void AddKeepWithNext(List <Register> registers, MethodBody body)
        {
            var i = 0;

            while (i < registers.Count)
            {
                var r = registers[i++];
                if ((r.Flags & RFlags.KeepWithNext) == 0)
                {
                    continue;
                }
                var next = body.Registers.First(x => x.Index == r.Index + 1);
                if (!registers.Contains(next))
                {
                    registers.Insert(i, next);
                }
            }
        }
Esempio n. 6
0
        /// <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>
        /// Create the body of the equals method.
        /// </summary>
        private static MethodBody CreateEqualsBody()
        {
            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);

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

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

            return(body);
        }
Esempio n. 8
0
        private readonly Stack <FinallyBlockState> tryCatchStack   = new Stack <FinallyBlockState>(); // holds the current finally target.

        /// <summary>
        /// Default ctor
        /// </summary>
        internal AstCompilerVisitor(AssemblyCompiler compiler, MethodSource source, DexTargetPackage targetPackage, MethodDefinition method, MethodBody body)
        {
            this.compiler      = compiler;
            currentMethod      = source;
            this.targetPackage = targetPackage;
            currentDexMethod   = method;
            this.body          = body;
            frame        = new AstInvocationFrame(targetPackage, method, source, body);
            instructions = body.Instructions;

            // Base class class ctor for structs
            if (source.IsDotNet && (source.Name == ".ctor") && (source.ILMethod.DeclaringType.IsValueType))
            {
                var ilMethod = source.ILMethod;
                if (!HasBaseOrThisClassCtorCall(ilMethod))
                {
                    // Add a call to the base class ctor now
                    var seqp     = SequencePointWrapper.Wrap(ilMethod.Body.Instructions.Select(x => x.SequencePoint(ilMethod.Body)).FirstOrDefault());
                    var baseCtor = new MethodReference(method.Owner.SuperClass, "<init>", new Prototype(PrimitiveType.Void));
                    this.Add(seqp, RCode.Invoke_direct, baseCtor, frame.ThisArgument);
                }
            }

            // Store any genericInstance argument

            /*if (source.Method.NeedsGenericInstanceTypeParameter && (source.Name == ".ctor"))
             * {
             *  var owner = method.Owner;
             *  var ilMethod = source.ILMethod;
             *  var giField = owner.GenericInstanceField;
             *  if (giField == null)
             *  {
             *      throw new CompilerException(string.Format("Expected GenericInstance field in {0}", ilMethod.FullName));
             *  }
             *  var seqp = SequencePointWrapper.Wrap(ilMethod.Body.Instructions.Select(x => x.SequencePoint).FirstOrDefault());
             *  this.Add(seqp, RCode.Iput_object, giField, frame.GenericInstanceTypeArgument, frame.ThisArgument);
             * }*/
        }
        /// <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;
        }
Esempio n. 10
0
        /// <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;
        }
        /// <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 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 code to load a value from an annotation interface.
        /// </summary>
        /// <returns>The register(s) holding the value</returns>
        private static Register[] CreateLoadValueSequence(
            ISourceLocation seqp,
            MethodBody body,
            XTypeReference valueType,
            Register annotationReg,
            MethodDefinition getter,
            AssemblyCompiler compiler,
            DexTargetPackage targetPackage,
            out Instruction branchIfNotSet)
        {
            // NOTE: It would be better if we wouldn't get the values as object arrays
            //       but as arrays of the actual type. 
            //       Apparently though the DexWriter will not write our attributes
            //       if they contain arrays not of type object[]. Therefore the 
            //       conversion code below.
            //       All in all it would be much cleaner if we could emit Ast code here
            //       instead of RL code.
            List<Register> result = new List<Register>();

            // get the array.
            Register regObject = body.AllocateRegister(RCategory.Temp, RType.Object);
            Register regIntVal = body.AllocateRegister(RCategory.Temp, RType.Value);
            
            body.Instructions.Add(seqp, RCode.Invoke_interface, getter, annotationReg);
            body.Instructions.Add(seqp, RCode.Move_result_object, regObject);

            // allocate result, initialize to default value.
            if (valueType.IsWide())
            {
                Tuple<Register, Register> regs = body.AllocateWideRegister(RCategory.Temp);
                body.Instructions.Add(seqp, RCode.Const_wide, 0, regs.Item1);
                result.Add(regs.Item1);
                result.Add(regs.Item2);
            }
            else if (valueType.IsPrimitive)
            {
                Register reg = body.AllocateRegister(RCategory.Temp, RType.Value);
                body.Instructions.Add(seqp, RCode.Const, 0, reg);
                result.Add(reg);
            }
            else // object 
            {
                Register reg = body.AllocateRegister(RCategory.Temp, RType.Object);
                body.Instructions.Add(seqp, RCode.Const, 0, reg);
                result.Add(reg);
            }

            // check if value is unset (array length 0) or null (array length 2)
            body.Instructions.Add(seqp, RCode.Array_length, regIntVal, regObject);
            branchIfNotSet = body.Instructions.Add(seqp, RCode.If_eqz, regIntVal);
            body.Instructions.Add(seqp, RCode.Rsub_int, 1, regIntVal, regIntVal);
            var branchOnNull = body.Instructions.Add(seqp, RCode.If_nez, regIntVal);

            // get the (boxed) value
            body.Instructions.Add(seqp, RCode.Const, 0, regIntVal);

            // convert to target type.
            if (valueType.IsArray)
            {
                Register regTmp = body.AllocateRegister(RCategory.Temp, RType.Object);
                Register regType = body.AllocateRegister(RCategory.Temp, RType.Object);
                
                var helper = compiler.GetDot42InternalType(InternalConstants.CompilerHelperName);
                var convertArray = helper.Resolve().Methods.First(p => p.Name == "ConvertArray" && p.Parameters.Count == 2)
                                         .GetReference(targetPackage);
                var underlying = valueType.ElementType.GetReference(targetPackage);

                body.Instructions.Add(seqp, RCode.Aget_object, regTmp, regObject, regIntVal);
                body.Instructions.Add(seqp, RCode.Const_class, underlying, regType);
                body.Instructions.Add(seqp, RCode.Invoke_static, convertArray, regTmp, regType);
                body.Instructions.Add(seqp, RCode.Move_result_object, result[0]);
                body.Instructions.Add(seqp, RCode.Check_cast, valueType.GetReference(targetPackage), result[0]);
            }
            else if (valueType.IsEnum())
            {
                Register regTmp = body.AllocateRegister(RCategory.Temp, RType.Object);
                Register regType = body.AllocateRegister(RCategory.Temp, RType.Object);
                
                var getFromObject = compiler.GetDot42InternalType("Enum").Resolve()
                                            .Methods.Single(p=>p.Name == "GetFromObject")
                                            .GetReference(targetPackage);

                body.Instructions.Add(seqp, RCode.Aget_object, regTmp, regObject, regIntVal);
                body.Instructions.Add(seqp, RCode.Const_class, valueType.GetReference(targetPackage), regType);
                body.Instructions.Add(seqp, RCode.Invoke_static, getFromObject, regType, regTmp);
                body.Instructions.Add(seqp, valueType.MoveResult(), result[0]);
                body.Instructions.Add(seqp, RCode.Check_cast, valueType.GetReference(targetPackage), result[0]);
            }
            else if(!valueType.IsPrimitive)
            {
                body.Instructions.Add(seqp, RCode.Aget_object, result[0], regObject, regIntVal);
                body.Instructions.Add(seqp, RCode.Check_cast, valueType.GetReference(targetPackage), result[0]);
            }
            else
            {
                Register regTmp = body.AllocateRegister(RCategory.Temp, RType.Object);
                // unbox and store
                RCode afterConvert;
                var unbox  = valueType.GetUnboxValueMethod(compiler, targetPackage, out afterConvert);
                body.Instructions.Add(seqp, RCode.Aget_object, regTmp, regObject, regIntVal);
                body.Instructions.Add(seqp, RCode.Invoke_static, unbox, regTmp);
                body.Instructions.Add(seqp, valueType.MoveResult(), result[0]);
                
                if (afterConvert != RCode.Nop)
                {
                    body.Instructions.Add(seqp, afterConvert, result[0], result[0]);
                }
            }

            // nop will be removed at some stage later.
            var nop = body.Instructions.Add(seqp, RCode.Nop);
            branchOnNull.Operand = nop;

            return result.ToArray();
        }
        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;
        }
Esempio n. 15
0
        /// <summary>
        /// Create the body of the equals method.
        /// </summary>
        private static MethodBody CreateEqualsBody()
        {
            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);

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

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

            return body;
        }
Esempio n. 16
0
        /// <summary>
        /// Create the body of the invoke method.
        /// </summary>
        private static MethodBody CreateInvokeBody(ISourceLocation sequencePoint, AssemblyCompiler compiler, DexTargetPackage targetPackage, XMethodDefinition calledMethod, XMethodDefinition invokeMethod, Prototype invokePrototype, Prototype calledMethodPrototype, FieldDefinition instanceField, ClassReference delegateClass)
        {
            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 instance = null;
            if (!calledMethod.IsStatic)
            {
                // load instance
                instance = body.AllocateRegister(RCategory.Temp, RType.Object);
                ins.Add(new Instruction(RCode.Iget_object, instance, rthis) { Operand = instanceField });
            }
            // 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(instance);
            }
            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++;
            }

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

            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);
                }
                else
                {
                    // Return wide
                    returnInstruction = new Instruction(RCode.Return_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);
                }
                else
                {
                    // Return 
                    returnInstruction = new Instruction(RCode.Return, 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);
                }
                else
                {
                    // Return 
                    returnInstruction = new Instruction(RCode.Return_object, r);
                }
            }

            // Call next delegate (if any)
            var next = body.AllocateRegister(RCategory.Temp, RType.Object);
            var multicastDelegateType = new ClassReference(targetPackage.NameConverter.GetConvertedFullName("System.MulticastDelegate"));
            var nextReference = new FieldReference(multicastDelegateType, "next", multicastDelegateType);
            ins.Add(new Instruction(RCode.Iget_object, nextReference, new[] { next, rthis })); // load this.next
            var afterCallNext = new Instruction(RCode.Nop);
            ins.Add(new Instruction(RCode.If_eqz, afterCallNext, new[] { next })); // if next == null, continue
            ins.Add(new Instruction(RCode.Check_cast, delegateClass, new[] { next }));
            var nextInvokeMethod = new MethodReference(delegateClass, "Invoke", invokePrototype);
            var nextInvokeArgs = new[] { next }.Concat(incomingMethodArgs.Skip(1)).ToArray();
            ins.Add(new Instruction(RCode.Invoke_virtual, nextInvokeMethod, nextInvokeArgs));
            ins.Add(afterCallNext);

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

            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;
        }
        private MethodBody CreateCctorBody()
        {
            MethodBody body = new MethodBody(null);

            Register methodInfoR = CallGetMethodInfo(body, calledMethod.GetReference(targetPackage));
            
            var ins = body.Instructions;
            ins.Add(new Instruction(RCode.Sput_object, methodInfoField, new[] { methodInfoR }));
            ins.Add(new Instruction(RCode.Return_void, null));
            return body;
        }
        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;
        }
 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;
 }
        /// <summary>
        /// Create the body of the invoke method.
        /// </summary>
        private static MethodBody CreateInvokeBody(ISourceLocation sequencePoint, AssemblyCompiler compiler, DexTargetPackage targetPackage, XMethodDefinition calledMethod, XMethodDefinition invokeMethod, Prototype invokePrototype, Prototype calledMethodPrototype, FieldDefinition instanceField, ClassReference delegateClass)
        {
            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 instance = null;

            if (!calledMethod.IsStatic)
            {
                // load instance
                instance = body.AllocateRegister(RCategory.Temp, RType.Object);
                ins.Add(new Instruction(RCode.Iget_object, instance, rthis)
                {
                    Operand = instanceField
                });
            }
            // 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(instance);
            }
            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++;
            }

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

            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);
                }
                else
                {
                    // Return wide
                    returnInstruction = new Instruction(RCode.Return_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);
                }
                else
                {
                    // Return
                    returnInstruction = new Instruction(RCode.Return, 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);
                }
                else
                {
                    // Return
                    returnInstruction = new Instruction(RCode.Return_object, r);
                }
            }

            // Call next delegate (if any)
            var next = body.AllocateRegister(RCategory.Temp, RType.Object);
            var multicastDelegateType = new ClassReference(targetPackage.NameConverter.GetConvertedFullName("System.MulticastDelegate"));
            var nextReference         = new FieldReference(multicastDelegateType, "next", multicastDelegateType);

            ins.Add(new Instruction(RCode.Iget_object, nextReference, new[] { next, rthis })); // load this.next
            var afterCallNext = new Instruction(RCode.Nop);

            ins.Add(new Instruction(RCode.If_eqz, afterCallNext, new[] { next })); // if next == null, continue
            ins.Add(new Instruction(RCode.Check_cast, delegateClass, new[] { next }));
            var nextInvokeMethod = new MethodReference(delegateClass, "Invoke", invokePrototype);
            var nextInvokeArgs = new[] { next }.Concat(incomingMethodArgs.Skip(1)).ToArray();

            ins.Add(new Instruction(RCode.Invoke_virtual, nextInvokeMethod, nextInvokeArgs));
            ins.Add(afterCallNext);

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

            return(body);
        }
Esempio n. 22
0
 /// <summary>
 /// For each register in the given list, ensure that all keep-with-next registers are also added.
 /// </summary>
 private static void AddKeepWithNext(List<Register> registers, MethodBody body)
 {
     var i = 0;
     while (i < registers.Count)
     {
         var r = registers[i++];
         if ((r.Flags & RFlags.KeepWithNext) == 0)
             continue;
         var next = body.Registers.First(x => x.Index == r.Index + 1);
         if (!registers.Contains(next))
         {
             registers.Insert(i, next);
         }
     }
 }
        /// <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;
        }
        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);
        }
Esempio n. 25
0
 /// <summary>
 /// Create the body of the ctor.
 /// </summary>
 private static MethodBody CreateCtorBody(XMethodDefinition calledMethod, FieldDefinition instanceField, ClassReference baseClass)
 {
     var body = new MethodBody(null);
     // Create code
     var ins = body.Instructions;
     var rthis = body.AllocateRegister(RCategory.Argument, RType.Object);
     // Call base ctor
     var baseCtorRef = new MethodReference(baseClass, "<init>", new Prototype(PrimitiveType.Void));
     ins.Add(new Instruction(RCode.Invoke_direct, rthis) { Operand = baseCtorRef });
     if (!calledMethod.IsStatic)
     {
         // load instance into field
         var rvalue = body.AllocateRegister(RCategory.Argument, RType.Object);
         ins.Add(new Instruction(RCode.Iput_object, rvalue, rthis) {Operand = instanceField});
     }
     ins.Add(new Instruction(RCode.Return_void));
     return body;
 }
        /// <summary>
        /// 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;
        }
Esempio n. 27
0
        /// <summary>
        /// Create the body of the equals method.
        /// </summary>
        private static MethodBody CreateEqualsBody(ISourceLocation sequencePoint, AssemblyCompiler compiler, DexTargetPackage targetPackage, XMethodDefinition equalsMethod, Prototype equalsPrototype, FieldDefinition instanceField, 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);

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

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

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

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

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

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

            // Load the instance fields.
            ins.Add(new Instruction(RCode.Iget_object, thisInstance, rthis) { Operand = instanceField });
            ins.Add(new Instruction(RCode.Iget_object, otherInstance, rother) { Operand = instanceField });

            // Compare the instance fields.
            ins.Add(new Instruction(RCode.If_eq, returnInstruction, new[] { thisInstance, otherInstance })); // compare instance members

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

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

            return body;
        }
Esempio n. 28
0
        /// <summary>
        /// Find all basic blocks in the given body.
        /// </summary>
        public static List<BasicBlock> Find(MethodBody body)
        {
            if (body.Instructions.Count == 0)
                return new List<BasicBlock>();

            // Tuple<int, Instruction>

            var targetInstructions = body.Instructions.Select(x => x.Operand).OfType<Instruction>().ToList();
            targetInstructions.AddRange(body.Instructions.Select(x => x.Operand).OfType<Instruction[]>().SelectMany(x => x));
            targetInstructions.AddRange(body.Instructions.Select(x => x.Operand).OfType<Tuple<int, Instruction>[]>().SelectMany(x => x).Select(x => x.Item2));
            targetInstructions.AddRange(body.Instructions.Where(x => x.Code.IsBranch() || x.Code.IsReturn()).Select(x => x.NextOrDefault));
            targetInstructions.AddRange(body.Exceptions.Select(x => x.TryStart));
            targetInstructions.AddRange(body.Exceptions.Select(x => x.TryEnd.Next));
            targetInstructions.AddRange(body.Exceptions.SelectMany(x => x.Catches, (h, y) => y.Instruction));
            targetInstructions.AddRange(body.Exceptions.Select(x => x.CatchAll));
            targetInstructions.Add(body.Instructions[0]);

            // Get sorted list with duplicates removed.
            var startInstructions = targetInstructions.Where(x => x != null).Distinct().OrderBy(x => x.Index).ToList();
            var result = new List<BasicBlock>();
            for (var i = 0; i < startInstructions.Count; i++)
            {
                var entry = startInstructions[i];
                var exit = (i + 1 < startInstructions.Count)
                               ? startInstructions[i + 1].Previous
                               : body.Instructions[body.Instructions.Count - 1];
                result.Add(new BasicBlock(body.Instructions, entry, exit));
            }
            return result;
        }
Esempio n. 29
0
        /// <summary>
        /// Create a frame for the given method
        /// </summary>
        internal AstInvocationFrame(DexTargetPackage targetPackage, MethodDefinition method, MethodSource source, MethodBody body) 
        {
            this.targetPackage = targetPackage;
            this.body = body;
            this.body = body;
            Debug.Assert(!body.Registers.Any());

            var prototypeParamOffset = 0;
            var prototype = method.Prototype;

            if (source.IsDotNet)
            {
                var ilMethod = source.ILMethod;

                // Allocate this
                if (!method.IsStatic)
                {
                    thisArgument = (ArgumentRegisterSpec) Allocate(method.Owner, true, RCategory.Argument, ilMethod.Body.ThisParameter);
                    arguments.Add(thisArgument);
                }
                else if (ilMethod.IsAndroidExtension() && !ilMethod.IsStatic)
                {
                    prototypeParamOffset++;
                    var type = ilMethod.DeclaringType.GetReference(targetPackage, source.Method.Module);
                    thisArgument = (ArgumentRegisterSpec) Allocate(type, true, RCategory.Argument, ilMethod.Body.ThisParameter);
                    arguments.Add(thisArgument);
                }
                // Allocate arguments
                var paramCount = ilMethod.Parameters.Count;
                for (var i = 0; i < paramCount; i++)
                {
                    var p = ilMethod.Parameters[i];
                    var type = prototype.Parameters[prototypeParamOffset++].Type;
                    arguments.Add((ArgumentRegisterSpec) Allocate(type, false, RCategory.Argument, p));
                }
            }
            else if (source.IsJava)
            {
                var javaMethod = source.JavaMethod;

                // Allocate this
                var code = javaMethod.Attributes.OfType<CodeAttribute>().First();
                if (!method.IsStatic)
                {
                    thisArgument = (ArgumentRegisterSpec)Allocate(method.Owner, true, RCategory.Argument, code.ThisParameter);
                    arguments.Add(thisArgument);
                }
                // Allocate arguments
                foreach (var p in code.Parameters)
                {
                    var type = prototype.Parameters[prototypeParamOffset++].Type;
                    arguments.Add((ArgumentRegisterSpec)Allocate(type, false, RCategory.Argument, p.Item2));
                }
            }
            else if (source.IsAst)
            {
                // Allocate this
                if (!method.IsStatic)
                {
                    thisArgument = (ArgumentRegisterSpec)Allocate(method.Owner, true, RCategory.Argument, null);
                    arguments.Add(thisArgument);
                }
                // Allocate arguments
                foreach (var p in ((XSyntheticMethodDefinition)source.Method).AstParameters)
                {
                    var type = prototype.Parameters[prototypeParamOffset++].Type;
                    arguments.Add((ArgumentRegisterSpec)Allocate(type, false, RCategory.Argument, p));
                }
            }
            else
            {
                throw new ArgumentException("Unknown source");
            }

            // Add GenericInstanceType parameter (if any)
            if (source.Method.NeedsGenericInstanceTypeParameter)
            {
                var type = prototype.GenericInstanceTypeParameter.Type;
                GenericInstanceTypeArgument = (ArgumentRegisterSpec) Allocate(type, false, RCategory.Argument, null);
                arguments.Add(GenericInstanceTypeArgument);                
            }
            // Add GenericInstanceMethod parameter (if any)
            if (source.Method.NeedsGenericInstanceMethodParameter)
            {
                var type = prototype.GenericInstanceMethodParameter.Type;
                GenericInstanceMethodArgument = (ArgumentRegisterSpec) Allocate(type, false, RCategory.Argument, null);
                arguments.Add(GenericInstanceMethodArgument);
            }
            // Check register count
            var expected = prototype.Parameters.Sum(x => x.Type.IsWide() ? 2 : 1);
            if (!method.IsStatic) expected++;
            if (expected != body.Registers.Count())
            {
                throw new ArgumentException(string.Format("Expected {0} registers, found {1} (in {2})", expected, body.Registers.Count(), method));
            }
        }
 /// <summary>
 /// Create 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 };
     }
 }
Esempio n. 31
0
        /// <summary>
        /// Gets all registers of category!=Argument that are used in an instruction.
        /// </summary>
        private static void GetUsedArgumentRegisters(MethodBody body, out Dictionary<Register, RegisterFlags> used, out int maxOutgoingRegisters, out bool largeInvokeInsFound)
        {
            //maxOutgoingRegisters = body.Instructions.Max(x => x.Code.IsInvoke() ? x.Registers.Count : 0);
            //largeInvokeInsFound = body.Instructions.Any(x => x.Code.IsInvoke() && x.Registers.Count > 5);
            maxOutgoingRegisters = 0;
            largeInvokeInsFound = false;

            used = new Dictionary<Register, RegisterFlags>();
            foreach (var ins in body.Instructions)
            {
                if (ins.Code.IsInvoke())
                {
                    maxOutgoingRegisters = Math.Max(maxOutgoingRegisters, ins.Registers.Count);
                    if (ins.Registers.Count > 5)
                    {
                        largeInvokeInsFound = true;
                    }
                }
                foreach (var reg in ins.Registers)
                {
                    if (reg.Category != RCategory.Argument)
                    {
                        var lowestSize = GetLowestSize(ins, reg);
                        RegisterFlags currentLowestSize;
                        if (used.TryGetValue(reg, out currentLowestSize))
                        {
                            if (lowestSize < currentLowestSize)
                            {
                                used[reg] = lowestSize;
                            }
                        }
                        else
                        {
                            used.Add(reg, lowestSize);
                        }
                    }
                }
            }

            // Add second register of wide registers.
            Register prevReg = null;
            foreach (var reg in body.Registers)
            {
                if (prevReg != null)
                {
                    if (reg.Type == RType.Wide2)
                    {
                        RegisterFlags flags;
                        if (used.TryGetValue(prevReg, out flags))
                        {
                            used[reg] = flags;
                        }
                    }
                }
                prevReg = reg;
            }
        }
        private static MethodDefinition CreateFactoryMethod(AssemblyCompiler compiler, DexTargetPackage targetPackage, CustomAttribute attribute, AttributeAnnotationMapping mapping)
        {
            var targetClass = mapping.AttributeClass; // is this really the right place for the factory methods?
            ISourceLocation seqp = null;
            var attributeTypeDef = attribute.AttributeType.Resolve();

            // create method
            string methodName = CreateAttributeFactoryMethodName(targetClass); 
            MethodDefinition method = new MethodDefinition(targetClass, methodName, new Prototype(mapping.AttributeClass));
            method.AccessFlags = AccessFlags.Public | AccessFlags.Static | AccessFlags.Synthetic;
            targetClass.Methods.Add(method);

            // create method body
            MethodBody body = new MethodBody(null);
            // Allocate attribute
            Register attributeReg = body.AllocateRegister(RCategory.Temp, RType.Object);
            body.Instructions.Add(seqp, RCode.New_instance, mapping.AttributeClass, attributeReg);

            // collect ctor arguments
            List<Register> ctorArgRegs = new List<Register>() { attributeReg };
            foreach (var p in attribute.ConstructorArguments)
            {
                XTypeReference xType = XBuilder.AsTypeReference(compiler.Module, p.Type);
                Register[] valueRegs = CreateInitializeValueInstructions(seqp, body, xType, p, compiler, targetPackage);
                ctorArgRegs.AddRange(valueRegs);
            }
            // Invoke ctor
            DexLib.MethodReference dctor = attribute.Constructor.GetReference(targetPackage, compiler.Module);
            body.Instructions.Add(seqp, RCode.Invoke_direct, dctor, ctorArgRegs.ToArray());

            // set field values
            foreach (var p in attribute.Fields)
            {
                var field = GetField(attributeTypeDef, p.Name);
                var xField = XBuilder.AsFieldReference(compiler.Module, field);

                Register[] valueRegs = CreateInitializeValueInstructions(seqp, body, xField.FieldType, p.Argument, compiler, targetPackage);
                body.Instructions.Add(seqp, xField.FieldType.IPut(), xField.GetReference(targetPackage),
                                                valueRegs[0], attributeReg);
            }

            // set property values
            foreach (var p in attribute.Properties)
            {
                PropertyDefinition property = GetSettableProperty(attributeTypeDef, p.Name);
                XTypeReference xType = XBuilder.AsTypeReference(compiler.Module, property.PropertyType);

                Register[] valueRegs = CreateInitializeValueInstructions(seqp, body, xType, p.Argument, compiler, targetPackage);
                XMethodDefinition xSetMethod = XBuilder.AsMethodDefinition(compiler.Module, property.SetMethod);
                body.Instructions.Add(seqp, xSetMethod.Invoke(xSetMethod, null), 
                                            xSetMethod.GetReference(targetPackage), 
                                            new[] { attributeReg }.Concat(valueRegs).ToArray());
            }

            // Return attribute
            body.Instructions.Add(seqp, RCode.Return_object, attributeReg);

            // Register method body
            targetPackage.Record(new CompiledMethod() { DexMethod = method, RLBody = body });

            // Return method
            return method;

        }
        /// <summary>
        /// Create 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;
        }
        /// <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. 35
0
 public RegisterUsageMap2(ControlFlowGraph2 graph)
 {
     _graph = graph;
     _usages = new Dictionary<Register, RegisterUsage>();
     _body = graph.Body;
     _basicBlocks = graph.BasicBlocks;
     CollectBasicUsages(_basicBlocks, _usages);
     // TODO: seperate independant usages.
 }
Esempio n. 36
0
 public RegisterUsageMap2(MethodBody body)
 {
     _body = body;
     _usages = new Dictionary<Register, RegisterUsage>();
     _basicBlocks = BasicBlock.Find(body);
     CollectBasicUsages(_basicBlocks, _usages);
     // TODO: seperate independant usages.
 }
Esempio n. 37
0
        /// <summary>
        /// Default ctor
        /// </summary>
        public RegisterMapper(MethodBody body, InvocationFrame frame)
        {
            this.frame = frame;
            // Select all non-argument registers that are in use.
            Dictionary <Register, RegisterFlags> used;
            int  maxOutgoingRegisters;
            bool largeInvokeInsFound;

            GetUsedArgumentRegisters(body, out used, out maxOutgoingRegisters, out largeInvokeInsFound);
            //var used = body.Registers.Where(x => (x.Category != RCategory.Argument) && body.Instructions.Uses(x)).ToList();
            var sorted = used.OrderBy(x => x.Value).ThenBy(x => x.Key.Index).Select(x => x.Key).ToList();

            AddKeepWithNext(sorted, body);
            // Collect argument registers
            var arguments = body.Registers.Where(x => x.Category == RCategory.Argument).ToList();

            // Prepare various decisions
            //var maxOutgoingRegisters = body.Instructions.Max(x => x.Code.IsInvoke() ? x.Registers.Count : 0);
            var required = sorted.Count + arguments.Count;
            //var largeInvokeInsFound = body.Instructions.Any(x => x.Code.IsInvoke() && x.Registers.Count > 5);

            // Allocate Dex registers for each
            var index = 0;

            // Allocate spill registers (if needed)
            if ((required >= 16) || (largeInvokeInsFound && (required + maxOutgoingRegisters >= 16)))
            {
                spillRangeRegisters = new DexLib.Instructions.Register[MaxSpillRegisters];
                for (var i = 0; i < MaxSpillRegisters; i++)
                {
                    spillRangeRegisters[i] = new DexLib.Instructions.Register(index++);
                }
            }

            // Allocate Dex registers for each temp register.
            foreach (var r in sorted)
            {
                var dreg = new DexLib.Instructions.Register(index++);
                map[r] = dreg;
                dRegisterTypes[dreg] = r.Type;
            }

            // Allocate outgoing invocation frame (if needed)
            if ((required >= 16) || largeInvokeInsFound)
            {
                invokeRangeRegisters = new DexLib.Instructions.Register[maxOutgoingRegisters];
                for (var i = 0; i < maxOutgoingRegisters; i++)
                {
                    invokeRangeRegisters[i] = new DexLib.Instructions.Register(index++);
                }
            }

            // Allocate Dex registers for each argument
            foreach (var r in arguments)
            {
                var dreg = new DexLib.Instructions.Register(index++);
                map[r] = dreg;
                dRegisterTypes[dreg] = r.Type;
            }
            ArgumentCount = arguments.Count;
        }
 private void AddMethod(ClassDefinition @class, string methodName, Prototype prototype, AccessFlags accessFlags, MethodBody body)
 {
     var method = new MethodDefinition(@class, methodName, prototype);
     method.AccessFlags = accessFlags;
     @class.Methods.Add(method);
     targetPackage.Record(new CompiledMethod { DexMethod = method, RLBody = body});
 }