コード例 #1
0
ファイル: RLBuilder.cs プロジェクト: rfcclub/dot42
        /// <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);
        }
コード例 #2
0
ファイル: RLBuilder.cs プロジェクト: rfcclub/dot42
        /// <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);
        }
コード例 #3
0
ファイル: RLBuilder.cs プロジェクト: rfcclub/dot42
 /// <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);
 }
コード例 #4
0
        /// <summary>
        /// Create code to load a value from an annotation interface.
        /// </summary>
        /// <returns>The register(s) holding the value</returns>
        private static Register[] CreateLoadValueSequence(
            ISourceLocation seqp,
            MethodBody body,
            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();
        }
コード例 #5
0
ファイル: DexAnnotations.cs プロジェクト: jakesays/dot42
        public static Annotation GetGenericDefinitionAnnotationForType(XTypeReference xtype, bool forceTypeDefinition, AssemblyCompiler compiler, DexTargetPackage targetPackage)
        {
            var genericsDefAnnotationClass = compiler.GetDot42InternalType(InternalConstants.GenericDefinitionAnnotation)
                                                     .GetClassReference(targetPackage);
            var annotation = new Annotation {Type = genericsDefAnnotationClass, Visibility = AnnotationVisibility.Runtime};

            if (xtype.IsGenericInstance)
            {
                bool handled = false;
                List<object> genericArguments = new List<object>();

                if (xtype.GetElementType().IsNullableT())
                {
                    // privitives and enums are represented by their marker classes. 
                    // no annotation needed.
                    var argument = ((XGenericInstanceType) xtype).GenericArguments[0];
                    if (argument.IsEnum() || argument.IsPrimitive && !forceTypeDefinition)
                    {
                        return null;
                    }
                        
                    // structs have marker classes.
                    var classRef = xtype.GetReference(targetPackage) as ClassReference;
                    var @class = classRef == null ? null : targetPackage.DexFile.GetClass(classRef.Fullname);
                    if (@class != null && @class.NullableMarkerClass != null)
                    {
                        annotation.Arguments.Add(new AnnotationArgument("GenericInstanceType", @class.NullableMarkerClass));
                        handled = true;
                    }
                }

                if (!handled)
                {
                    foreach (var arg in ((XGenericInstanceType) xtype).GenericArguments)
                    {
                        if (arg.IsGenericParameter)
                        {
                            var gparm = (XGenericParameter) arg;

                            // TODO: if we wanted to annotate methods as well, we should differentiate 
                            //       between generic method arguments and generic type arguments.

                            genericArguments.Add(gparm.Position);
                        }
                        else if (arg.IsGenericInstance)
                        {
                            var giparm = GetGenericDefinitionAnnotationForType((XGenericInstanceType) arg, true,compiler, targetPackage);
                            genericArguments.Add(giparm);
                        }
                        else
                        {
                            genericArguments.Add(arg.GetReference(targetPackage));
                        }
                    }
                    annotation.Arguments.Add(new AnnotationArgument("GenericArguments", genericArguments.ToArray()));
                }
            }
            else // generic parameter
            {
                var parm = (XGenericParameter) xtype;
                annotation.Arguments.Add(new AnnotationArgument("GenericParameter", parm.Position));
            }

            if(forceTypeDefinition && annotation.Arguments.All(a => a.Name != "GenericInstanceType"))
                annotation.Arguments.Add(new AnnotationArgument("GenericTypeDefinition", xtype.ElementType.GetReference(targetPackage)));

            return annotation;
        }
コード例 #6
0
        /// <summary>
        /// Create code to initialize a value from an attribute.
        /// </summary>
        /// <returns>The register(s) holding the value</returns>
        private static Register[] CreateInitializeValueInstructions(ISourceLocation seqp, MethodBody body, XTypeReference targetType, CustomAttributeArgument value, AssemblyCompiler compiler, DexTargetPackage targetPackage)
        {
            List<Register> result = new List<Register>();

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

            // load data

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

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

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

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

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

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

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

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

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

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

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

            return result.ToArray();
        }
コード例 #7
0
        /// <summary>
        /// The syntax is experimental, and neither fully fixed nor officially defined.
        /// </summary>
        private static string GetDefinition(XTypeReference xtype, bool forceTypeDefinition, AssemblyCompiler compiler,
            DexTargetPackage targetPackage)
        {
            StringBuilder s = new StringBuilder();

            // TODO: reorganize, so that the syntax becomes clear.

            bool setGenericInstanceType = false;

            if (xtype.IsGenericInstance)
            {
                bool handled = false;

                if (xtype.GetElementType().IsNullableT())
                {
                    // privitives and enums are represented by their marker classes. 
                    // no annotation needed.
                    var argument = ((XGenericInstanceType) xtype).GenericArguments[0];
                    if (!forceTypeDefinition && (argument.IsEnum() || argument.IsPrimitive))
                    {
                        return "";
                    }

                    // structs have marker classes.
                    var classRef = xtype.GetReference(targetPackage) as ClassReference;
                    var @class = classRef == null ? null : targetPackage.DexFile.GetClass(classRef.Fullname);
                    if (@class != null && @class.NullableMarkerClass != null)
                    {
                        s.Append("@");
                        s.Append(GetClassName(@class.NullableMarkerClass));
                        setGenericInstanceType = true;
                        handled = true;
                    }
                }

                if (!handled)
                {
                    bool isFirst = true;
                    foreach (var arg in ((XGenericInstanceType) xtype).GenericArguments)
                    {
                        if (!isFirst) s.Append(",");
                        isFirst = false;

                        if (arg.IsGenericParameter)
                        {
                            var gparm = (XGenericParameter) arg;

                            // TODO: if we wanted to annotate methods as well, we should differentiate 
                            //       between generic method arguments and generic type arguments.
                            s.Append("!");
                            s.Append(gparm.Position);
                        }
                        else if (arg.IsGenericInstance)
                        {
                            var giparm = GetDefinition((XGenericInstanceType)arg, true, compiler, targetPackage);
                            s.Append("{");
                            s.Append(giparm);
                            s.Append("}");
                        }
                        else
                        {
                            s.Append(GetClassName(arg.GetReference(targetPackage)));
                        }
                    }
                }
            }
            else // generic parameter
            {
                var parm = (XGenericParameter) xtype;
                s.Append("!!");
                s.Append(parm.Position);
            }

            if (forceTypeDefinition && !setGenericInstanceType)
            {
                string def = GetClassName(xtype.ElementType.GetReference(targetPackage));
                s.Insert(0, def + "<");
                s.Append(">");
            }

            return s.ToString();
        }
コード例 #8
0
ファイル: RLBuilder.cs プロジェクト: jakesays/dot42
        /// <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);
        }