Ejemplo n.º 1
0
        /// <summary>
        /// Create code to box the given source value into the given type.
        /// </summary>
        public static RLRange Box(this IRLBuilder builder, ISourceLocation sequencePoint, RegisterSpec source, XTypeReference type, DexTargetPackage targetPackage, IRegisterAllocator frame)
        {
            if (type.IsPrimitive)
            {
                if (type.IsByte()) builder.Add(sequencePoint, RCode.Int_to_byte, source.Register, source.Register);
                else if (type.IsUInt16()) builder.Add(sequencePoint, RCode.Int_to_short, source.Register, source.Register);
                // Call appropriate valueOf method
                var boxedType = type.Module.TypeSystem.Object;
                var r = frame.AllocateTemp(boxedType.GetReference(targetPackage));
                var call = builder.Add(sequencePoint, RCode.Invoke_static, type.GetBoxValueOfMethod(), source.Registers);
                var last = builder.Add(sequencePoint, RCode.Move_result_object, r);
                return new RLRange(call, last, r);
            }
            if (type.IsGenericParameter)
            {
                var nop = builder.Add(sequencePoint, RCode.Nop);
                return new RLRange(nop, source);
            }
            XTypeDefinition typeDef ;
            if (type.TryResolve(out typeDef) && (typeDef.IsEnum))
            {
                // Call appropriate valueOf method
                /*var boxedType = type.Module.TypeSystem.Object;
                var r = frame.AllocateTemp(boxedType.GetReference(target, nsConverter));
                var call = builder.Add(sequencePoint, RCode.Invoke_static, typeDef.GetEnumUnderlyingType().GetBoxValueOfMethod(), source.Registers);
                var last = builder.Add(sequencePoint, RCode.Move_result_object, r);
                return new RLRange(call, last, r);*/
            }

            // Just cast
            var checkCast = builder.Add(sequencePoint, RCode.Check_cast, type.GetReference(targetPackage), source);
            return new RLRange(checkCast, source);
        }
Ejemplo n.º 2
0
 /// <summary>
 /// Default ctor
 /// </summary>
 public RLRange(RLRange prefix, Instruction first, Instruction last, RegisterSpec resultRegister) 
 {
     if ((prefix != null) && (prefix.first != null)) first = prefix.first;
     if ((last == null) && (prefix != null)) last = prefix.last;
     this.first = first;
     this.last = last;
     this.resultRegister = resultRegister;
     
 }
Ejemplo n.º 3
0
 /// <summary>
 /// Default ctor
 /// </summary>
 public RLRange(IEnumerable<RLRange> prefix, Instruction first, Instruction last, RegisterSpec resultRegister)
 {
     var prefixList = (prefix != null) ? prefix.Where(x => x != null).ToList() : null;
     var firstInPrefix = (prefixList != null) ? prefixList.Select(x => x.First).FirstOrDefault() : null;
     var lastInPrefix = (prefixList != null) ? prefixList.Select(x => x.Last).LastOrDefault() : null;
     if (firstInPrefix != null)
         first = firstInPrefix;
     if (last == null)
         last = lastInPrefix;
     this.first = first;
     this.last = last;
     this.resultRegister = resultRegister;
 }
Ejemplo n.º 4
0
 /// <summary>
 /// Default ctor
 /// </summary>
 public RLRange(RLRange prefix, Instruction first, Instruction last, RegisterSpec resultRegister)
 {
     if ((prefix != null) && (prefix.first != null))
     {
         first = prefix.first;
     }
     if ((last == null) && (prefix != null))
     {
         last = prefix.last;
     }
     this.first          = first;
     this.last           = last;
     this.resultRegister = resultRegister;
 }
Ejemplo n.º 5
0
        /// <summary>
        /// Default ctor
        /// </summary>
        public RLRange(IEnumerable <RLRange> prefix, Instruction first, Instruction last, RegisterSpec resultRegister)
        {
            var prefixList    = (prefix != null) ? prefix.Where(x => x != null).ToList() : null;
            var firstInPrefix = (prefixList != null) ? prefixList.Select(x => x.First).FirstOrDefault() : null;
            var lastInPrefix  = (prefixList != null) ? prefixList.Select(x => x.Last).LastOrDefault() : null;

            if (firstInPrefix != null)
            {
                first = firstInPrefix;
            }
            if (last == null)
            {
                last = lastInPrefix;
            }
            this.first          = first;
            this.last           = last;
            this.resultRegister = resultRegister;
        }
Ejemplo n.º 6
0
 /// <summary>
 /// Ensure the given value register is a temp register.
 /// If it is not, allocate a temp register an copy to it.
 /// </summary>
 public static RLRange EnsureTemp(this IRLBuilder builder, ISourceLocation sequencePoint, RegisterSpec value, IRegisterAllocator frame)
 {
     // Is temp?
     if (value.Register.Category == RCategory.Temp)
         return new RLRange(value);
     // No, allocate temp
     var tmp = frame.AllocateTemp(value.Type);
     Instruction ins;
     switch (value.Register.Type)
     {
         case RType.Object:
             ins = builder.Add(sequencePoint, RCode.Move_object, tmp.Register, value.Register);
             break;
         case RType.Wide:
             ins = builder.Add(sequencePoint, RCode.Move_wide, tmp.Register, value.Register);
             break;
         case RType.Value:
             ins = builder.Add(sequencePoint, RCode.Move, tmp.Register, value.Register);
             break;
         default:
             throw new ArgumentException("Unknown register type " + (int)value.Register.Type);
     }
     return new RLRange(ins, tmp);
 }
Ejemplo n.º 7
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;
        }
Ejemplo n.º 8
0
 /// <summary>
 /// No code, register only ctor
 /// </summary>
 public RLRange(RLRange prefix, RegisterSpec resultRegister)
     : this(prefix, null, null, resultRegister)
 {
 }
Ejemplo n.º 9
0
        /// <summary>
        /// Emit code (if needed) to convert a value from source type to destination type.
        /// This method is used in "store" opcodes such stloc, stfld, stsfld, call
        /// </summary>
        internal static RLRange ConvertTypeBeforeStore(this IRLBuilder builder, ISourceLocation sequencePoint, XTypeReference sourceType, XTypeReference destinationType, RegisterSpec source, DexTargetPackage targetPackage, IRegisterAllocator frame, AssemblyCompiler compiler, out bool converted)
        {
            converted = false;
            if (sourceType.IsSame(destinationType))
            {
                // Unsigned conversions
                if (sourceType.IsByte())
                {
                    var tmp = builder.EnsureTemp(sequencePoint, source, frame);
                    var ins = builder.Add(sequencePoint, RCode.Int_to_byte, tmp.Result, tmp.Result);
                    converted = true;
                    return(new RLRange(tmp, ins, tmp.Result));
                }
                else if (sourceType.IsUInt16())
                {
                    var tmp = builder.EnsureTemp(sequencePoint, source, frame);
                    var ins = builder.Add(sequencePoint, RCode.Int_to_short, tmp.Result, tmp.Result);
                    converted = true;
                    return(new RLRange(tmp, ins, tmp.Result));
                }
                return(new RLRange(source));
            }

            if (sourceType.IsArray)
            {
                var compilerHelper         = compiler.GetDot42InternalType(InternalConstants.CompilerHelperName).Resolve();
                var arrayType              = targetPackage.DexFile.GetClass(targetPackage.NameConverter.GetConvertedFullName(compilerHelper));
                var sourceArrayElementType = ((XArrayType)sourceType).ElementType;
                if (destinationType.ExtendsIList())
                {
                    // Use ArrayHelper.AsList to convert
                    var convertMethodName = "AsList";
                    var convertMethod     = arrayType.GetMethod(convertMethodName);
                    // Add code
                    var tmp = builder.EnsureTemp(sequencePoint, source, frame);
                    builder.Add(sequencePoint, RCode.Invoke_static, convertMethod, tmp.Result.Register);
                    var last = builder.Add(sequencePoint, RCode.Move_result_object, tmp.Result.Register);
                    converted = true;
                    return(new RLRange(tmp, last, tmp.Result));
                }
                if (destinationType.ExtendsICollection())
                {
                    // Use ArrayHelper.AsCollection to convert
                    var convertMethodName = "AsCollection";
                    var convertMethod     = arrayType.GetMethod(convertMethodName);
                    // Add code
                    var tmp = builder.EnsureTemp(sequencePoint, source, frame);
                    builder.Add(sequencePoint, RCode.Invoke_static, convertMethod, tmp.Result.Register);
                    var last = builder.Add(sequencePoint, RCode.Move_result_object, tmp.Result.Register);
                    converted = true;
                    return(new RLRange(tmp, last, tmp.Result));
                }
                if (destinationType.ExtendsIEnumerable())
                {
                    // Use ArrayHelper.As...Enumerable to convert
                    var convertMethodName = "AsObjectEnumerable";
                    if (sourceArrayElementType.IsPrimitive)
                    {
                        if (sourceArrayElementType.IsBoolean())
                        {
                            convertMethodName = "AsBoolEnumerable";
                        }
                        else if (sourceArrayElementType.IsByte())
                        {
                            convertMethodName = "AsByteEnumerable";
                        }
                        else if (sourceArrayElementType.IsSByte())
                        {
                            convertMethodName = "AsSByteEnumerable";
                        }
                        else if (sourceArrayElementType.IsChar())
                        {
                            convertMethodName = "AsCharEnumerable";
                        }
                        else if (sourceArrayElementType.IsInt16())
                        {
                            convertMethodName = "AsInt16Enumerable";
                        }
                        else if (sourceArrayElementType.IsUInt16())
                        {
                            convertMethodName = "AsUInt16Enumerable";
                        }
                        else if (sourceArrayElementType.IsInt32())
                        {
                            convertMethodName = "AsInt32Enumerable";
                        }
                        else if (sourceArrayElementType.IsUInt32())
                        {
                            convertMethodName = "AsUInt32Enumerable";
                        }
                        else if (sourceArrayElementType.IsInt64())
                        {
                            convertMethodName = "AsInt64Enumerable";
                        }
                        else if (sourceArrayElementType.IsFloat())
                        {
                            convertMethodName = "AsFloatEnumerable";
                        }
                        else if (sourceArrayElementType.IsDouble())
                        {
                            convertMethodName = "AsDoubleEnumerable";
                        }
                        else
                        {
                            throw new ArgumentOutOfRangeException("Unknown primitive array element type " + sourceArrayElementType);
                        }
                    }
                    var convertMethod = arrayType.GetMethod(convertMethodName);
                    // Add code
                    var tmp = builder.EnsureTemp(sequencePoint, source, frame);
                    builder.Add(sequencePoint, RCode.Invoke_static, convertMethod, tmp.Result.Register);
                    var last = builder.Add(sequencePoint, RCode.Move_result_object, tmp.Result.Register);
                    converted = true;
                    return(new RLRange(tmp, last, tmp.Result));
                }
            }

            // Do not convert
            return(new RLRange(source));
        }
Ejemplo n.º 10
0
        /// <summary>
        /// Create code to box the given source value into the given type.
        /// </summary>
        public static RLRange Box(this IRLBuilder builder, ISourceLocation sequencePoint, RegisterSpec source, XTypeReference type, DexTargetPackage targetPackage, IRegisterAllocator frame)
        {
            if (type.IsPrimitive)
            {
                if (type.IsByte())
                {
                    builder.Add(sequencePoint, RCode.Int_to_byte, source.Register, source.Register);
                }
                else if (type.IsUInt16())
                {
                    builder.Add(sequencePoint, RCode.Int_to_short, source.Register, source.Register);
                }
                // Call appropriate valueOf method
                var boxedType = type.Module.TypeSystem.Object;
                var r         = frame.AllocateTemp(boxedType.GetReference(targetPackage));
                var call      = builder.Add(sequencePoint, RCode.Invoke_static, type.GetBoxValueOfMethod(), source.Registers);
                var last      = builder.Add(sequencePoint, RCode.Move_result_object, r);
                return(new RLRange(call, last, r));
            }
            if (type.IsGenericParameter)
            {
                var nop = builder.Add(sequencePoint, RCode.Nop);
                return(new RLRange(nop, source));
            }
            XTypeDefinition typeDef;

            if (type.TryResolve(out typeDef) && (typeDef.IsEnum))
            {
                // Call appropriate valueOf method

                /*var boxedType = type.Module.TypeSystem.Object;
                 * var r = frame.AllocateTemp(boxedType.GetReference(target, nsConverter));
                 * var call = builder.Add(sequencePoint, RCode.Invoke_static, typeDef.GetEnumUnderlyingType().GetBoxValueOfMethod(), source.Registers);
                 * var last = builder.Add(sequencePoint, RCode.Move_result_object, r);
                 * return new RLRange(call, last, r);*/
            }

            // Just cast
            var checkCast = builder.Add(sequencePoint, RCode.Check_cast, type.GetReference(targetPackage), source);

            return(new RLRange(checkCast, source));
        }
Ejemplo n.º 11
0
        /// <summary>
        /// Emit code (if needed) to convert a value from source type to destination type.
        /// This method is used in "store" opcodes such stloc, stfld, stsfld, call
        /// </summary>
        internal static RLRange ConvertTypeBeforeStore(this IRLBuilder builder, ISourceLocation sequencePoint, XTypeReference sourceType, XTypeReference destinationType, RegisterSpec source, DexTargetPackage targetPackage, IRegisterAllocator frame, AssemblyCompiler compiler, out bool converted)
        {
            converted = false;
            if (sourceType.IsSame(destinationType))
            {
                // Unsigned conversions
                if (sourceType.IsByte())
                {
                    var tmp = builder.EnsureTemp(sequencePoint, source, frame);
                    var ins = builder.Add(sequencePoint, RCode.Int_to_byte, tmp.Result, tmp.Result);
                    converted = true;
                    return new RLRange(tmp, ins, tmp.Result);
                }
                else if (sourceType.IsUInt16())
                {
                    var tmp = builder.EnsureTemp(sequencePoint, source, frame);
                    var ins = builder.Add(sequencePoint, RCode.Int_to_short, tmp.Result, tmp.Result);
                    converted = true;
                    return new RLRange(tmp, ins, tmp.Result);
                }
                return new RLRange(source);
            }

            if (sourceType.IsArray)
            {
                var compilerHelper = compiler.GetDot42InternalType(InternalConstants.CompilerHelperName).Resolve();
                var arrayType = targetPackage.DexFile.GetClass(targetPackage.NameConverter.GetConvertedFullName(compilerHelper));
                var sourceArrayElementType = ((XArrayType)sourceType).ElementType;
                if (destinationType.ExtendsIList())
                {
                    // Use ArrayHelper.AsList to convert
                    var convertMethodName = "AsList";
                    var convertMethod = arrayType.GetMethod(convertMethodName);
                    // Add code
                    var tmp = builder.EnsureTemp(sequencePoint, source, frame);
                    builder.Add(sequencePoint, RCode.Invoke_static, convertMethod, tmp.Result.Register);
                    var last = builder.Add(sequencePoint, RCode.Move_result_object, tmp.Result.Register);
                    converted = true;
                    return new RLRange(tmp, last, tmp.Result);
                }
                if (destinationType.ExtendsICollection())
                {
                    // Use ArrayHelper.AsCollection to convert
                    var convertMethodName = "AsCollection";
                    var convertMethod = arrayType.GetMethod(convertMethodName);
                    // Add code
                    var tmp = builder.EnsureTemp(sequencePoint, source, frame);
                    builder.Add(sequencePoint, RCode.Invoke_static, convertMethod, tmp.Result.Register);
                    var last = builder.Add(sequencePoint, RCode.Move_result_object, tmp.Result.Register);
                    converted = true;
                    return new RLRange(tmp, last, tmp.Result);
                }
                if (destinationType.ExtendsIEnumerable())
                {
                    // Use ArrayHelper.As...Enumerable to convert
                    var convertMethodName = "AsObjectEnumerable";
                    if (sourceArrayElementType.IsPrimitive)
                    {
                        if (sourceArrayElementType.IsBoolean()) convertMethodName = "AsBoolEnumerable";
                        else if (sourceArrayElementType.IsByte()) convertMethodName = "AsByteEnumerable";
                        else if (sourceArrayElementType.IsSByte()) convertMethodName = "AsSByteEnumerable";
                        else if (sourceArrayElementType.IsChar()) convertMethodName = "AsCharEnumerable";
                        else if (sourceArrayElementType.IsInt16()) convertMethodName = "AsInt16Enumerable";
                        else if (sourceArrayElementType.IsUInt16()) convertMethodName = "AsUInt16Enumerable";
                        else if (sourceArrayElementType.IsInt32()) convertMethodName = "AsInt32Enumerable";
                        else if (sourceArrayElementType.IsUInt32()) convertMethodName = "AsUInt32Enumerable";
                        else if (sourceArrayElementType.IsInt64()) convertMethodName = "AsInt64Enumerable";
                        else if (sourceArrayElementType.IsFloat()) convertMethodName = "AsFloatEnumerable";
                        else if (sourceArrayElementType.IsDouble()) convertMethodName = "AsDoubleEnumerable";
                        else throw new ArgumentOutOfRangeException("Unknown primitive array element type " + sourceArrayElementType);
                    }
                    var convertMethod = arrayType.GetMethod(convertMethodName);
                    // Add code
                    var tmp = builder.EnsureTemp(sequencePoint, source, frame);
                    builder.Add(sequencePoint, RCode.Invoke_static, convertMethod, tmp.Result.Register);
                    var last = builder.Add(sequencePoint, RCode.Move_result_object, tmp.Result.Register);
                    converted = true;
                    return new RLRange(tmp, last, tmp.Result);
                }
            }

            // Do not convert
            return new RLRange(source);
        }
Ejemplo n.º 12
0
        /// <summary>
        /// Ensure the given value register is a temp register.
        /// If it is not, allocate a temp register an copy to it.
        /// </summary>
        public static RLRange EnsureTemp(this IRLBuilder builder, ISourceLocation sequencePoint, RegisterSpec value, IRegisterAllocator frame)
        {
            // Is temp?
            if (value.Register.Category == RCategory.Temp)
            {
                return(new RLRange(value));
            }
            // No, allocate temp
            var         tmp = frame.AllocateTemp(value.Type);
            Instruction ins;

            switch (value.Register.Type)
            {
            case RType.Object:
                ins = builder.Add(sequencePoint, RCode.Move_object, tmp.Register, value.Register);
                break;

            case RType.Wide:
                ins = builder.Add(sequencePoint, RCode.Move_wide, tmp.Register, value.Register);
                break;

            case RType.Value:
                ins = builder.Add(sequencePoint, RCode.Move, tmp.Register, value.Register);
                break;

            default:
                throw new ArgumentException("Unknown register type " + (int)value.Register.Type);
            }
            return(new RLRange(ins, tmp));
        }
Ejemplo n.º 13
0
        /// <summary>
        /// Create code to unbox the given source array of boxed type elements into an array of primitive elements.
        /// </summary>
        public static RLRange UnboxGenericArray(this IRLBuilder builder, ISourceLocation sequencePoint, RegisterSpec source, RegisterSpec boxedArray,
                                                XTypeReference type, DexTargetPackage targetPackage, IRegisterAllocator frame, AssemblyCompiler compiler)
        {
            var internalBoxingType = compiler.GetDot42InternalType("Boxing").Resolve();
            var ilUnboxMethod      = internalBoxingType.Methods.First(x => x.EqualsName("UnboxTo") && (x.Parameters.Count == 2) && (x.Parameters[1].ParameterType.IsSame(type, true)));
            var unboxMethod        = ilUnboxMethod.GetReference(targetPackage);
            var call = builder.Add(sequencePoint, RCode.Invoke_static, unboxMethod, boxedArray, source);

            return(new RLRange(call, null));
        }
Ejemplo n.º 14
0
 /// <summary>
 /// Default ctor
 /// </summary>
 public RLRange(Instruction first, Instruction last, RegisterSpec resultRegister)
     : this((RLRange)null, first, last, resultRegister)
 {
 }
Ejemplo n.º 15
0
 /// <summary>
 /// No code, register only ctor
 /// </summary>
 public RLRange(IEnumerable<RLRange> prefix, RegisterSpec resultRegister)
     : this(prefix, null, null, resultRegister)
 {
 }
Ejemplo n.º 16
0
 /// <summary>
 /// Default ctor
 /// </summary>
 public RLRange(Instruction first, Instruction last, RegisterSpec resultRegister)
     : this((RLRange)null, first, last, resultRegister)
 {
 }
Ejemplo n.º 17
0
 /// <summary>
 /// Single instruction range ctor
 /// </summary>
 public RLRange(Instruction single, RegisterSpec resultRegister)
     : this((RLRange)null, single, single, resultRegister)
 {
 }
Ejemplo n.º 18
0
 /// <summary>
 /// Single instruction range ctor
 /// </summary>
 public RLRange(RLRange prefix, Instruction single, RegisterSpec resultRegister)
     : this(prefix, single, single, resultRegister)
 {
 }
Ejemplo n.º 19
0
 /// <summary>
 /// Single instruction range ctor
 /// </summary>
 public RLRange(IEnumerable <RLRange> prefix, Instruction single, RegisterSpec resultRegister)
     : this(prefix, single, single, resultRegister)
 {
 }
Ejemplo n.º 20
0
 /// <summary>
 /// No code, register only ctor
 /// </summary>
 public RLRange(RegisterSpec resultRegister)
     : this((RLRange)null, null, null, resultRegister)
 {
 }
Ejemplo n.º 21
0
        /// <summary>
        /// Create code to unbox the given source value into the given type.
        /// </summary>
        public static RLRange Unbox(this IRLBuilder builder, ISourceLocation sequencePoint, RegisterSpec source, XTypeReference type, AssemblyCompiler compiler, DexTargetPackage targetPackage, IRegisterAllocator frame)
        {
            if (type.IsPrimitive)
            {
                RCode convertAfterCode;
                var   rUnboxed         = frame.AllocateTemp(type.GetReference(targetPackage));
                var   unboxValueMethod = type.GetUnboxValueMethod(compiler, targetPackage, out convertAfterCode);
                var   first            = builder.Add(sequencePoint, RCode.Invoke_static, unboxValueMethod, source);
                var   last             = builder.Add(sequencePoint, type.MoveResult(), rUnboxed);
                if (convertAfterCode != RCode.Nop)
                {
                    last = builder.Add(sequencePoint, convertAfterCode, rUnboxed, rUnboxed);
                }

                return(new RLRange(first, last, rUnboxed));
            }

            XTypeDefinition enumTypeDef;

            if (type.IsEnum(out enumTypeDef))
            {
                var rUnboxed         = frame.AllocateTemp(type.GetReference(targetPackage));
                var unboxValueMethod = enumTypeDef.Methods.First(x => x.Name == NameConstants.Enum.UnboxMethodName).GetReference(targetPackage);
                var first            = builder.Add(sequencePoint, RCode.Invoke_static, unboxValueMethod, source);
                var last             = builder.Add(sequencePoint, type.MoveResult(), rUnboxed);
                return(new RLRange(first, last, rUnboxed));
            }

            if (!type.IsGenericParameter)
            {
                // Just cast
                var checkCast = builder.Add(sequencePoint, RCode.Check_cast, type.GetReference(targetPackage), source);
                return(new RLRange(checkCast, source));
            }

            // Do nothing
            var nop = builder.Add(sequencePoint, RCode.Nop);

            return(new RLRange(nop, source));
        }
Ejemplo n.º 22
0
 /// <summary>
 /// No code, register only ctor
 /// </summary>
 public RLRange(RLRange prefix, RegisterSpec resultRegister)
     : this(prefix, null, null, resultRegister)
 {
 }
Ejemplo n.º 23
0
        /// <summary>
        /// Emit code (if needed) to convert a value from source type to destination type.
        /// This method is used in "store" opcodes such stloc, stfld, stsfld, call
        /// </summary>
        internal static RLRange ConvertTypeBeforeStore(this IRLBuilder builder, ISourceLocation sequencePoint, XTypeReference sourceType, XTypeReference destinationType, RegisterSpec source, DexTargetPackage targetPackage, IRegisterAllocator frame, AssemblyCompiler compiler, out bool converted)
        {
            converted = false;
            if (sourceType.IsSame(destinationType))
            {
                // Unsigned conversions
                if (sourceType.IsByte())
                {
                    var tmp = builder.EnsureTemp(sequencePoint, source, frame);
                    var ins = builder.Add(sequencePoint, RCode.Int_to_byte, tmp.Result, tmp.Result);
                    converted = true;
                    return(new RLRange(tmp, ins, tmp.Result));
                }
                else if (sourceType.IsUInt16())
                {
                    var tmp = builder.EnsureTemp(sequencePoint, source, frame);
                    var ins = builder.Add(sequencePoint, RCode.Int_to_short, tmp.Result, tmp.Result);
                    converted = true;
                    return(new RLRange(tmp, ins, tmp.Result));
                }
                return(new RLRange(source));
            }

            if (sourceType.IsArray)
            {
                var compilerHelper         = compiler.GetDot42InternalType(InternalConstants.CompilerHelperName).Resolve();
                var arrayType              = targetPackage.DexFile.GetClass(targetPackage.NameConverter.GetConvertedFullName(compilerHelper));
                var sourceArrayElementType = ((XArrayType)sourceType).ElementType;
                if (destinationType.ExtendsIList())
                {
                    // Use ArrayHelper.AsList to convert
                    var convertMethodName = "AsList";
                    var convertMethod     = arrayType.GetMethod(convertMethodName);
                    // Add code
                    var tmp = builder.EnsureTemp(sequencePoint, source, frame);
                    builder.Add(sequencePoint, RCode.Invoke_static, convertMethod, tmp.Result.Register);
                    var last = builder.Add(sequencePoint, RCode.Move_result_object, tmp.Result.Register);
                    converted = true;
                    return(new RLRange(tmp, last, tmp.Result));
                }
                if (destinationType.ExtendsICollection())
                {
                    // Use ArrayHelper.AsCollection to convert
                    var convertMethodName = "AsCollection";
                    var convertMethod     = arrayType.GetMethod(convertMethodName);
                    // Add code
                    var tmp = builder.EnsureTemp(sequencePoint, source, frame);
                    builder.Add(sequencePoint, RCode.Invoke_static, convertMethod, tmp.Result.Register);
                    var last = builder.Add(sequencePoint, RCode.Move_result_object, tmp.Result.Register);
                    converted = true;
                    return(new RLRange(tmp, last, tmp.Result));
                }
                if (destinationType.ExtendsIEnumerable())
                {
                    // Use ArrayHelper.As...Enumerable to convert
                    var convertMethodName = FrameworkReferences.GetAsEnumerableTMethodName(sourceArrayElementType);
                    var convertMethod     = arrayType.GetMethod(convertMethodName);
                    // Add code
                    var tmp = builder.EnsureTemp(sequencePoint, source, frame);
                    builder.Add(sequencePoint, RCode.Invoke_static, convertMethod, tmp.Result.Register);
                    var last = builder.Add(sequencePoint, RCode.Move_result_object, tmp.Result.Register);
                    converted = true;
                    return(new RLRange(tmp, last, tmp.Result));
                }
            }

            if (sourceType.IsGenericParameter && !destinationType.IsSystemObject())
            {
                var gp = (XGenericParameter)sourceType;
                if (gp.Constraints.Length > 0)
                {
                    // we could find the best matching constraint here, and check if we actually
                    // need to cast. This would probably allow us to skip some unneccesary casts.
                    // We would need some sort of IsAssignableFrom though, and I'm not sure we have
                    // this logic with XTypeDefinition implemented yet.
                    // Therefore, we just assume that the original compiler has done its job well,
                    // and always cast to the destination type.
                    // Apparently dex seems not to need a cast when destinationType is an interface.
                    // Since i'm not to sure about this, we nevertheless insert the cast here.
                    // [TODO: check if this is needed]
                    var tmp  = builder.EnsureTemp(sequencePoint, source, frame);
                    var cast = builder.Add(sequencePoint, RCode.Check_cast, destinationType.GetReference(targetPackage), tmp.Result);
                    converted = true;
                    return(new RLRange(tmp, cast, tmp.Result));
                }
            }

            // Do not convert
            return(new RLRange(source));
        }
Ejemplo n.º 24
0
 /// <summary>
 /// Create code to box the given source array of primitive type elements into an array of boxed elements.
 /// </summary>
 public static RLRange BoxGenericArray(this IRLBuilder builder, ISourceLocation sequencePoint, RegisterSpec source,
                                        XTypeReference type, DexTargetPackage targetPackage, IRegisterAllocator frame, AssemblyCompiler compiler)
 {
     var objectArrayType = new DexLib.ArrayType(new ClassReference("java.lang.Object"));
     var boxedArray = frame.AllocateTemp(objectArrayType);
     var internalBoxingType = compiler.GetDot42InternalType("Boxing").Resolve();
     var ilBoxMethod = internalBoxingType.Methods.First(x => x.EqualsName("Box") && (x.Parameters.Count == 1) && (x.Parameters[0].ParameterType.IsSame(type, true)));
     var boxMethod = ilBoxMethod.GetReference(targetPackage);
     var call = builder.Add(sequencePoint, RCode.Invoke_static, boxMethod, source);
     var saveArray = builder.Add(sequencePoint, RCode.Move_result_object, boxedArray);
     return new RLRange(call, saveArray, boxedArray);
 }
Ejemplo n.º 25
0
        /// <summary>
        /// Create code to box the given source array of primitive type elements into an array of boxed elements.
        /// </summary>
        public static RLRange BoxGenericArray(this IRLBuilder builder, ISourceLocation sequencePoint, RegisterSpec source,
                                              XTypeReference type, DexTargetPackage targetPackage, IRegisterAllocator frame, AssemblyCompiler compiler)
        {
            var objectArrayType    = new DexLib.ArrayType(new ClassReference("java.lang.Object"));
            var boxedArray         = frame.AllocateTemp(objectArrayType);
            var internalBoxingType = compiler.GetDot42InternalType("Boxing").Resolve();
            var ilBoxMethod        = internalBoxingType.Methods.First(x => x.EqualsName("Box") && (x.Parameters.Count == 1) && (x.Parameters[0].ParameterType.IsSame(type, true)));
            var boxMethod          = ilBoxMethod.GetReference(targetPackage);
            var call      = builder.Add(sequencePoint, RCode.Invoke_static, boxMethod, source);
            var saveArray = builder.Add(sequencePoint, RCode.Move_result_object, boxedArray);

            return(new RLRange(call, saveArray, boxedArray));
        }
Ejemplo n.º 26
0
 /// <summary>
 /// Create code to unbox the given source array of boxed type elements resulting from a call into an array of primitive elements.
 /// </summary>
 public static RLRange UnboxGenericArrayResult(this IRLBuilder builder, ISourceLocation sequencePoint, RegisterSpec boxedArray,
                                        XTypeReference type, DexTargetPackage targetPackage, IRegisterAllocator frame, AssemblyCompiler compiler)
 {
     var internalBoxingType = compiler.GetDot42InternalType("Boxing").Resolve();
     var primitiveArray = frame.AllocateTemp(type.GetReference(targetPackage));
     var ilUnboxMethod = internalBoxingType.Methods.First(x => x.Name.StartsWith("Unbox") && (x.Parameters.Count == 1) && (x.ReturnType.IsSame(type, true)));
     var unboxMethod = ilUnboxMethod.GetReference(targetPackage);
     var call = builder.Add(sequencePoint, RCode.Invoke_static, unboxMethod, boxedArray);
     var saveArray = builder.Add(sequencePoint, RCode.Move_result_object, primitiveArray);
     return new RLRange(call, saveArray, primitiveArray);
 }
Ejemplo n.º 27
0
        /// <summary>
        /// Create code to unbox the given source array of boxed type elements resulting from a call into an array of primitive elements.
        /// </summary>
        public static RLRange UnboxGenericArrayResult(this IRLBuilder builder, ISourceLocation sequencePoint, RegisterSpec boxedArray,
                                                      XTypeReference type, DexTargetPackage targetPackage, IRegisterAllocator frame, AssemblyCompiler compiler)
        {
            var internalBoxingType = compiler.GetDot42InternalType("Boxing").Resolve();
            var primitiveArray     = frame.AllocateTemp(type.GetReference(targetPackage));
            var ilUnboxMethod      = internalBoxingType.Methods.First(x => x.Name.StartsWith("Unbox") && (x.Parameters.Count == 1) && (x.ReturnType.IsSame(type, true)));
            var unboxMethod        = ilUnboxMethod.GetReference(targetPackage);
            var call      = builder.Add(sequencePoint, RCode.Invoke_static, unboxMethod, boxedArray);
            var saveArray = builder.Add(sequencePoint, RCode.Move_result_object, primitiveArray);

            return(new RLRange(call, saveArray, primitiveArray));
        }
Ejemplo n.º 28
0
        /// <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;
        }
Ejemplo n.º 29
0
        /// <summary>
        /// Create code to unbox the given source value into the given type.
        /// </summary>
        public static RLRange Unbox(this IRLBuilder builder, ISourceLocation sequencePoint, RegisterSpec source, XTypeReference type, AssemblyCompiler compiler, DexTargetPackage targetPackage, IRegisterAllocator frame)
        {
            if (type.IsPrimitive)
            {
                RCode convertAfterCode;
                var rUnboxed = frame.AllocateTemp(type.GetReference(targetPackage));
                var unboxValueMethod = type.GetUnboxValueMethod(compiler, targetPackage, out convertAfterCode);
                var first = builder.Add(sequencePoint, RCode.Invoke_static, unboxValueMethod, source);
                var last = builder.Add(sequencePoint, type.MoveResult(), rUnboxed);
                if (convertAfterCode != RCode.Nop)
                {
                    last = builder.Add(sequencePoint, convertAfterCode, rUnboxed, rUnboxed);
                }

                return new RLRange(first, last, rUnboxed);
            }

            XTypeDefinition enumTypeDef;
            if (type.IsEnum(out enumTypeDef))
            {
                var rUnboxed = frame.AllocateTemp(type.GetReference(targetPackage));
                var unboxValueMethod = enumTypeDef.Methods.First(x => x.Name == NameConstants.Enum.UnboxMethodName).GetReference(targetPackage);
                var first = builder.Add(sequencePoint, RCode.Invoke_static, unboxValueMethod, source);
                var last = builder.Add(sequencePoint, type.MoveResult(), rUnboxed);
                return new RLRange(first, last, rUnboxed);                
            }

            if (!type.IsGenericParameter)
            {
                // Just cast
                var checkCast = builder.Add(sequencePoint, RCode.Check_cast, type.GetReference(targetPackage), source);
                return new RLRange(checkCast, source);
            }

            // Do nothing
            var nop = builder.Add(sequencePoint, RCode.Nop);
            return new RLRange(nop, source);
        }
Ejemplo n.º 30
0
 /// <summary>
 /// Single instruction range ctor
 /// </summary>
 public RLRange(Instruction single, RegisterSpec resultRegister)
     : this((RLRange)null, single, single, resultRegister)
 {
 }
Ejemplo n.º 31
0
 /// <summary>
 /// No code, register only ctor
 /// </summary>
 public RLRange(RegisterSpec resultRegister)
     : this((RLRange)null, null, null, resultRegister)
 {
 }
Ejemplo n.º 32
0
 /// <summary>
 /// No code, register only ctor
 /// </summary>
 public RLRange(IEnumerable <RLRange> prefix, RegisterSpec resultRegister)
     : this(prefix, null, null, resultRegister)
 {
 }
Ejemplo n.º 33
0
 /// <summary>
 /// Create code to unbox the given source array of boxed type elements into an array of primitive elements.
 /// </summary>
 public static RLRange UnboxGenericArray(this IRLBuilder builder, ISourceLocation sequencePoint, RegisterSpec source, RegisterSpec boxedArray,
                                        XTypeReference type, DexTargetPackage targetPackage, IRegisterAllocator frame, AssemblyCompiler compiler)
 {
     var internalBoxingType = compiler.GetDot42InternalType("Boxing").Resolve();
     var ilUnboxMethod = internalBoxingType.Methods.First(x => x.EqualsName("UnboxTo") && (x.Parameters.Count == 2) && (x.Parameters[1].ParameterType.IsSame(type, true)));
     var unboxMethod = ilUnboxMethod.GetReference(targetPackage);
     var call = builder.Add(sequencePoint, RCode.Invoke_static, unboxMethod, boxedArray, source);
     return new RLRange(call, null);
 }
Ejemplo n.º 34
0
 /// <summary>
 /// Single instruction range ctor
 /// </summary>
 public RLRange(IEnumerable<RLRange> prefix, Instruction single, RegisterSpec resultRegister)
     : this(prefix, single, single, resultRegister)
 {
 }
Ejemplo n.º 35
0
 /// <summary>
 /// Single instruction range ctor
 /// </summary>
 public RLRange(RLRange prefix, Instruction single, RegisterSpec resultRegister)
     : this(prefix, single, single, resultRegister)
 {
 }
Ejemplo n.º 36
0
        /// <summary>
        /// Emit code (if needed) to convert a value from source type to destination type.
        /// This method is used in "store" opcodes such stloc, stfld, stsfld, call
        /// </summary>
        internal static RLRange ConvertTypeBeforeStore(this IRLBuilder builder, ISourceLocation sequencePoint, XTypeReference sourceType, XTypeReference destinationType, RegisterSpec source, DexTargetPackage targetPackage, IRegisterAllocator frame, AssemblyCompiler compiler, out bool converted)
        {
            converted = false;
            if (sourceType.IsSame(destinationType))
            {
                // Unsigned conversions
                if (sourceType.IsByte())
                {
                    var tmp = builder.EnsureTemp(sequencePoint, source, frame);
                    var ins = builder.Add(sequencePoint, RCode.Int_to_byte, tmp.Result, tmp.Result);
                    converted = true;
                    return new RLRange(tmp, ins, tmp.Result);
                }
                else if (sourceType.IsUInt16())
                {
                    var tmp = builder.EnsureTemp(sequencePoint, source, frame);
                    var ins = builder.Add(sequencePoint, RCode.Int_to_short, tmp.Result, tmp.Result);
                    converted = true;
                    return new RLRange(tmp, ins, tmp.Result);
                }
                return new RLRange(source);
            }

            if (sourceType.IsArray)
            {
                var compilerHelper = compiler.GetDot42InternalType(InternalConstants.CompilerHelperName).Resolve();
                var arrayType = targetPackage.DexFile.GetClass(targetPackage.NameConverter.GetConvertedFullName(compilerHelper));
                var sourceArrayElementType = ((XArrayType)sourceType).ElementType;
                if (destinationType.ExtendsIList())
                {
                    // Use ArrayHelper.AsList to convert
                    var convertMethodName = "AsList";
                    var convertMethod = arrayType.GetMethod(convertMethodName);
                    // Add code
                    var tmp = builder.EnsureTemp(sequencePoint, source, frame);
                    builder.Add(sequencePoint, RCode.Invoke_static, convertMethod, tmp.Result.Register);
                    var last = builder.Add(sequencePoint, RCode.Move_result_object, tmp.Result.Register);
                    converted = true;
                    return new RLRange(tmp, last, tmp.Result);
                }
                if (destinationType.ExtendsICollection())
                {
                    // Use ArrayHelper.AsCollection to convert
                    var convertMethodName = "AsCollection";
                    var convertMethod = arrayType.GetMethod(convertMethodName);
                    // Add code
                    var tmp = builder.EnsureTemp(sequencePoint, source, frame);
                    builder.Add(sequencePoint, RCode.Invoke_static, convertMethod, tmp.Result.Register);
                    var last = builder.Add(sequencePoint, RCode.Move_result_object, tmp.Result.Register);
                    converted = true;
                    return new RLRange(tmp, last, tmp.Result);
                }
                if (destinationType.ExtendsIEnumerable())
                {
                    // Use ArrayHelper.As...Enumerable to convert
                    var convertMethodName = "AsObjectEnumerable";
                    if (sourceArrayElementType.IsPrimitive)
                    {
                        if (sourceArrayElementType.IsBoolean()) convertMethodName = "AsBoolEnumerable";
                        else if (sourceArrayElementType.IsByte()) convertMethodName = "AsByteEnumerable";
                        else if (sourceArrayElementType.IsSByte()) convertMethodName = "AsSByteEnumerable";
                        else if (sourceArrayElementType.IsChar()) convertMethodName = "AsCharEnumerable";
                        else if (sourceArrayElementType.IsInt16()) convertMethodName = "AsInt16Enumerable";
                        else if (sourceArrayElementType.IsUInt16()) convertMethodName = "AsUInt16Enumerable";
                        else if (sourceArrayElementType.IsInt32()) convertMethodName = "AsInt32Enumerable";
                        else if (sourceArrayElementType.IsUInt32()) convertMethodName = "AsUInt32Enumerable";
                        else if (sourceArrayElementType.IsInt64()) convertMethodName = "AsInt64Enumerable";
                        else if (sourceArrayElementType.IsFloat()) convertMethodName = "AsFloatEnumerable";
                        else if (sourceArrayElementType.IsDouble()) convertMethodName = "AsDoubleEnumerable";
                        else throw new ArgumentOutOfRangeException("Unknown primitive array element type " + sourceArrayElementType);
                    }
                    var convertMethod = arrayType.GetMethod(convertMethodName);
                    // Add code
                    var tmp = builder.EnsureTemp(sequencePoint, source, frame);
                    builder.Add(sequencePoint, RCode.Invoke_static, convertMethod, tmp.Result.Register);
                    var last = builder.Add(sequencePoint, RCode.Move_result_object, tmp.Result.Register);
                    converted = true;
                    return new RLRange(tmp, last, tmp.Result);
                }
            }

            if (sourceType.IsGenericParameter && !destinationType.IsSystemObject())
            {
                var gp = (XGenericParameter) sourceType;
                if (gp.Constraints.Length > 0)
                {
                    // we could find the best matching constraint here, and check if we actually
                    // need to cast. This would probably allow us to skip some unneccesary casts.
                    // We would need some sort of IsAssignableFrom though, and I'm not sure we have
                    // this logic with XTypeDefinition implemented yet.
                    // Therefore, we just assume that the original compiler has done its job well,
                    // and always cast to the destination type.
                    // Apparently dex seems not to need a cast when destinationType is an interface. 
                    // Since i'm not to sure about this, we nevertheless insert the cast here. 
                    // [TODO: check if this is needed]
                    var tmp = builder.EnsureTemp(sequencePoint, source, frame);
                    var cast = builder.Add(sequencePoint, RCode.Check_cast, destinationType.GetReference(targetPackage), tmp.Result);
                    converted = true;
                    return new RLRange(tmp, cast, tmp.Result);
                }
            }

            // Do not convert
            return new RLRange(source);
        }