Example #1
0
 internal ClassDefinition(ClassReference cref)
     : this()
 {
     fullNameCache = cref.Fullname;
     ns            = cref.Namespace;
     name          = cref.Name;
 }
Example #2
0
 internal ClassDefinition(ClassReference cref)
     : this()
 {
     fullNameCache = cref.Fullname;
     ns = cref.Namespace;
     name = cref.Name;
 }
Example #3
0
 internal ClassDefinition(ClassReference cref)
     : this()
 {
     Fullname  = cref.Fullname;
     Namespace = cref.Namespace;
     Name      = cref.Name;
 }
Example #4
0
 internal ClassDefinition(ClassReference cref)
     : this()
 {
     Fullname = cref.Fullname;
     Namespace = cref.Namespace;
     Name = cref.Name;
 }
Example #5
0
 /// <summary>
 /// Default ctor
 /// </summary>
 private BoxInfo(XTypeReferenceKind metadataType, ClassReference boxedClass, PrimitiveType primitiveType,
                 string unboxMethodName, RCode convertAfterCode)
 {
     this.metadataType = metadataType;
     this.boxedClass = boxedClass;
     this.primitiveType = primitiveType;
     this.unboxMethodName = unboxMethodName;
     this.convertAfterCode = convertAfterCode;
 }
Example #6
0
        public MethodDefinition GetMethod(ClassReference ownerRef, string methodName, Prototype prototype)
        {
            // TODO: check in profiler if we should optimize this as well.
            var owner = GetClass(ownerRef.Fullname);

            if (owner == null)
            {
                return(null);
            }
            return(owner.Methods.SingleOrDefault(x => (x.Name == methodName) && (x.Prototype.Equals(prototype))));
        }
 /// <summary>
 /// Create the current type as class definition.
 /// </summary>
 internal DelegateInstanceTypeBuilder(
     ISourceLocation sequencePoint,
     AssemblyCompiler compiler, DexTargetPackage targetPackage,
     ClassDefinition delegateClass,
     XMethodDefinition invokeMethod, Prototype invokePrototype,
     XMethodDefinition calledMethod)
 {
     this.sequencePoint = sequencePoint;
     this.compiler = compiler;
     this.targetPackage = targetPackage;
     this.delegateClass = delegateClass;
     this.invokeMethod = invokeMethod;
     this.invokePrototype = invokePrototype;
     this.calledMethod = calledMethod;
     this.multicastDelegateClass = compiler.GetDot42InternalType("System", "MulticastDelegate").GetClassReference(targetPackage);
 }
Example #8
0
 private static void AddGenericParameterArguments(Prototype result, bool buildAsArray, int numParameters, string parameterBaseName, ClassReference annType, IList<Parameter> parameterArray)
 {
     if (buildAsArray)
     {
         // Add GenericInstance parameter (to pass the generic instance array of the declaring type)
         var paramType = FrameworkReferences.ClassArray;
         var dparameter = new Parameter(paramType, parameterBaseName);
         dparameter.Annotations.Add(new Annotation(annType, AnnotationVisibility.Runtime));
         result.Parameters.Add(dparameter);
         parameterArray.Add(dparameter);
     }
     else
     {
         for (int i = 0; i < numParameters; ++i)
         {
             var dparameter = new Parameter(FrameworkReferences.Class, parameterBaseName + (i + 1));
             dparameter.Annotations.Add(new Annotation(annType, AnnotationVisibility.Runtime));
             result.Parameters.Add(dparameter);
             parameterArray.Add(dparameter);
         }
     }
 }
Example #9
0
 /// <summary>
 /// Create an android EnclosingClass annotation and attach it to the given provider.
 /// </summary>
 public static void AddEnclosingClassAnnotation(this IAnnotationProvider provider, ClassReference @class)
 {
     var annotation = new Annotation { Type = new ClassReference("dalvik/annotation/EnclosingClass"), Visibility = AnnotationVisibility.System };
     annotation.Arguments.Add(new AnnotationArgument("value", @class));
     provider.Annotations.Add(annotation);
 }
        /// <summary>
        /// Delegate methods are created unfortunately during the compilation phase in AstCompiler.VisitExpression.
        /// Model this behaviour here.
        /// </summary>
        private DelegateInstanceType GetDelegateInstanceType(TypeEntry typeEntry, ClassReference classRef, AssemblyCompiler compiler, DexTargetPackage targetPackage)
        {
            var scopeIds = typeEntry.ScopeId.Split(new[] { ":delegate:" }, StringSplitOptions.None);

            var typeScopId = scopeIds[0];
            var xTypeDef = compiler.Module.GetTypeByScopeID(GetTypeScopeId(typeEntry.Scope, typeScopId, typeEntry.Name));
            var delegateType = compiler.GetDelegateType(xTypeDef);
            
            var calledMethodId = scopeIds[1];
            var calledTypeScopeId = calledMethodId.Split('|')[0];
            var calledMethodScope = calledMethodId.Split('|')[1];

            var calledTypeDef = compiler.Module.GetTypeByScopeID(calledTypeScopeId);
            var calledMethod = calledTypeDef.GetMethodByScopeId(calledMethodScope);

            // NOTE: we are loosing the SequencePoint (DebugInfo) here. I'm not sure if this
            //       was ever valuable anyways.
            var delInstanceType = delegateType.GetOrCreateInstance(null, targetPackage, calledMethod);
            return delInstanceType;
        }
Example #11
0
 /// <summary>
 /// Is other equal to this?
 /// </summary>
 public bool Equals(ClassReference other)
 {
     return base.Equals(other) && Fullname == other.Fullname;
 }
 /// <summary>
 /// Generate code for a call or callvirtual opcode.
 /// </summary>
 private RLRange VisitDexNativeCall(AstExpression node, List<RLRange> args, AstNode parent, XMethodDefinition ilMethod)
 {
     var fullName = ilMethod.DeclaringType.FullName;
     switch (fullName)
     {
         case "System.Threading.Monitor":
             {
                 if (ilMethod.Parameters.Count == 1)
                 {
                     switch (ilMethod.Name)
                     {
                         case "Enter":
                             return new RLRange(this.Add(node.SourceLocation, RCode.Monitor_enter, args[0].Result), null);
                         case "Exit":
                             return new RLRange(this.Add(node.SourceLocation, RCode.Monitor_exit, args[0].Result), null);
                     }
                 }
             }
             break;
         case "System.Object":
             {
                 if ((ilMethod.Parameters.Count == 2) && (ilMethod.Name == "ReferenceEquals"))
                 {
                     var r = frame.AllocateTemp(PrimitiveType.Int);
                     var start = this.Add(node.SourceLocation, RCode.Const, 0, r);
                     var test = this.Add(node.SourceLocation, AstCode.Ceq.Reverse().ToIfTest(), args[0].Result, args[1].Result);
                     this.Add(node.SourceLocation, RCode.Const, 1, r);
                     var end = this.Add(node.SourceLocation, RCode.Nop, null);
                     test.Operand = end;
                     return new RLRange(args, start, end, r);                           
                 }
             }
             break;
         case "System.Array":
             {
                 if ((args.Count == 1) && (ilMethod.Name == "get_Length"))
                 {
                     var r = frame.AllocateTemp(PrimitiveType.Int);
                     var argType = node.Arguments[0].GetResultType();
                     if (argType.IsArray)
                     {
                         // Standard array
                         var first = this.Add(node.SourceLocation, RCode.Array_length, r, args[0].Result);
                         return new RLRange(args, first, r);
                     }
                     {
                         // Object, call via java.lang.reflect.Array.getLength
                         var getLength = FrameworkReferences.ArrayGetLength;
                         var first = this.Add(node.SourceLocation, RCode.Invoke_static, getLength, args[0].Result);
                         var last = this.Add(node.SourceLocation, RCode.Move_result, r);
                         return new RLRange(args, first, last, r);
                     }
                 }                        
             }
             break;
         case "System.Nullable`1":
             {
                 if ((args.Count == 1) && (ilMethod.Name == "get_RawValue"))
                 {
                     return (RLRange) node.Arguments[0].Result;
                 }
             }
             break;
         case "Dot42.Internal.TypeHelper":
             {
                 string typeName = null;
                 switch (ilMethod.Name)
                 {
                     case "BooleanType":
                         typeName = "java.lang.Boolean";
                         break;
                     case "ByteType":
                         typeName = "java.lang.Byte";
                         break;
                     case "CharacterType":
                         typeName = "java.lang.Character";
                         break;
                     case "ShortType":
                         typeName = "java.lang.Short";
                         break;
                     case "IntegerType":
                         typeName = "java.lang.Integer";
                         break;
                     case "LongType":
                         typeName = "java.lang.Long";
                         break;
                     case "FloatType":
                         typeName = "java.lang.Float";
                         break;
                     case "DoubleType":
                         typeName = "java.lang.Double";
                         break;
                 }
                 if (typeName != null)
                 {
                     var typeRef = new ClassReference(typeName);
                     var r = frame.AllocateTemp(new ClassReference("java.lang.Class"));
                     var constClass = this.Add(node.SourceLocation, RCode.Const_class, typeRef, r);
                     return new RLRange(args, constClass, r);
                 }
             }
             break;
     }
     throw new ArgumentException(string.Format("Unknown extern method {0} at {1}", ilMethod.FullName, FormatSource(node)));
 }
        /// <summary>
        /// Create the body of the equals method.
        /// </summary>
        private static MethodBody CreateEqualsCheckTypeOnlyBody(ClassReference delegateClass)
        {
            MethodBody body = new MethodBody(null);

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

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

            var ins = body.Instructions;

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

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

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

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

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

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

            var hashCodeMethod = compiler.GetDot42InternalType("Java.Lang", "System")
                                         .Resolve()
                                         .Methods.First(m => m.Name == "IdentityHashCode")
                                         .GetReference(targetPackage);
            
            // Check if other object can be casted.
            ins.Add(new Instruction(RCode.Const_class, delegateInstance, new[] { tempObj }));
            ins.Add(new Instruction(RCode.Invoke_static, hashCodeMethod, new[] { tempObj }));
            ins.Add(new Instruction(RCode.Move_result, null, new[] { result }));

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

            return body;
        }
Example #16
0
 public MethodDefinition GetMethod(ClassReference ownerRef, string methodName, Prototype prototype)
 {
     // TODO: check in profiler if we should optimize this as well.
     var owner = GetClass(ownerRef.Fullname);
     if (owner == null) return null;
     return owner.Methods.SingleOrDefault(x => (x.Name == methodName) && (x.Prototype.Equals(prototype)));
 }
Example #17
0
 public FieldReference(ClassReference owner, string name, TypeReference fieldType)
 {
     Owner = owner;
     Type  = fieldType;
     Name  = name;
 }
        /// <summary>
        /// Generate code for the given expression.
        /// </summary>
        private RLRange VisitExpression(AstExpression node, List<RLRange> args, AstNode parent)
        {

            switch (node.Code)
            {
                case AstCode.Nop:
                case AstCode.Endfinally:
                case AstCode.Endfilter:
                    return new RLRange(this.Add(node.SourceLocation, RCode.Nop), null);
                case AstCode.Ldexception:
                    throw new InvalidOperationException("ldexception should not occur");
                case AstCode.Dup:
                    return new RLRange(this.Add(node.SourceLocation, RCode.Nop), args[0].Result);

                    #region Constants

                case AstCode.Ldc_I4:
                case AstCode.Ldc_R4:
                    {
                        var type = node.GetResultType();
                        var converter = type.ConstValueConverter(true);
                        var value = converter(node.Operand);
                        var r = frame.AllocateTemp(type.IsFloat() ? PrimitiveType.Float : PrimitiveType.Int);
                        var first = this.Add(node.SourceLocation, RCode.Const, value, r);
                        return new RLRange(first, r);
                    }
                case AstCode.Ldc_I8:
                case AstCode.Ldc_R8:
                    {
                        var type = node.GetResultType();
                        var converter = type.ConstValueConverter(false);
                        var value = converter(node.Operand);
                        var r = frame.AllocateTemp(type.IsDouble() ? PrimitiveType.Double : PrimitiveType.Long);
                        return new RLRange(args, this.Add(node.SourceLocation, RCode.Const_wide, value, r), r);
                    }
                case AstCode.Ldnull:
                    {
                        //Debugger.Launch();
                        var r = frame.AllocateTemp(node.GetResultType().GetReference(targetPackage));
                        return new RLRange(args, this.Add(node.SourceLocation, RCode.Const, 0, r), r);
                    }
                case AstCode.Ldstr:
                    {
                        var str = (string) node.Operand;
                        var r = frame.AllocateTemp(node.GetResultType().GetReference(targetPackage));
                        return new RLRange(args, this.Add(node.SourceLocation, RCode.Const_string, str, r), r);
                    }
                case AstCode.DefaultValue:
                    {
                        var type = (XTypeReference) node.Operand;
                        if (type.IsPrimitive)
                        {
                            var r = frame.AllocateTemp(type.GetReference(targetPackage));
                            return new RLRange(args, this.Add(node.SourceLocation, node.Arguments[0].Const(), 0, r), r);
                        }
                        if (type.IsEnum())
                        {
                            var r = frame.AllocateTemp(type.GetReference(targetPackage));
                            var denumType = type.GetClassReference(targetPackage);
                            var defaultField = new FieldReference(denumType, NameConstants.Enum.DefaultFieldName, denumType);
                            return new RLRange(this.Add(node.SourceLocation, RCode.Sget_object, defaultField, r), r);
                        }
                        else
                        {
                            var r = frame.AllocateTemp(type.GetReference(targetPackage));
                            return new RLRange(args, this.Add(node.SourceLocation, RCode.Const, 0, r), r);
                        }
                    }
                case AstCode.TypeOf:
                    {
                        var type = (XTypeReference) node.Operand;
                        var dtype = type.IsVoid() ? PrimitiveType.Void : type.GetReference(targetPackage);
                        var typeReg = frame.AllocateTemp(FrameworkReferences.Class);
                        var first = this.Add(node.SourceLocation, RCode.Const_class, dtype, typeReg);
                        return new RLRange(first, typeReg);
                    }
                case AstCode.BoxedTypeOf:
                    {
                        var type = (XTypeReference) node.Operand;
                        var typeReg = frame.AllocateTemp(FrameworkReferences.Class);
                        var first = this.Add(node.SourceLocation, RCode.Const_class, type.GetBoxedType(), typeReg);
                        return new RLRange(first, typeReg);
                    }

                    #endregion

                    #region Arithmetic

                case AstCode.Neg:
                    {
                        var tmp = this.EnsureTemp(node.SourceLocation, args[0].Result, frame);
                        return new RLRange(args, this.Add(node.SourceLocation, node.Neg(), tmp.Result, tmp.Result),
                                           tmp.Result);
                    }
                case AstCode.Not:
                    {
                        var tmp = this.EnsureTemp(node.SourceLocation, args[0].Result, frame);
                        return new RLRange(args, this.Add(node.SourceLocation, node.Not(), tmp.Result, tmp.Result),
                                           tmp.Result);
                    }
                case AstCode.Add:
                    {
                        if (args[0].Result.Register.IsTemp)
                            return new RLRange(args,
                                               this.Add(node.SourceLocation, node.Add2Addr(), args[0].Result,
                                                        args[1].Result), args[0].Result);
                        var tmp = frame.AllocateTemp(args[0].Result.Type);
                        return new RLRange(args,
                                           this.Add(node.SourceLocation, node.Add(), tmp, args[0].Result, args[1].Result),
                                           tmp);
                    }
                case AstCode.Add_Ovf:
                    {
                        var isLong = node.Arguments[0].IsInt64();
                        var addMethods =
                            compiler.GetDot42InternalType("Checked").Resolve().Methods.Where(x => x.Name == "Add");
                        var ilMethod = addMethods.First(x => isLong ? x.ReturnType.IsInt64() : x.ReturnType.IsInt32());
                        var method = ilMethod.GetReference(targetPackage);
                        var tmp = this.EnsureTemp(node.SourceLocation, args[0].Result, frame);
                        var registers = tmp.Result.Registers.Concat(args[1].Result.Registers);
                        this.Add(node.SourceLocation, RCode.Invoke_static, method, registers);
                        return new RLRange(args,
                                           this.Add(node.SourceLocation,
                                                    isLong ? RCode.Move_result_wide : RCode.Move_result, tmp.Result),
                                           tmp.Result);
                    }
                case AstCode.CompoundAdd:
                    {
                        var localReg = frame.GetArgument((AstVariable) node.Operand);
                        return new RLRange(args,
                                           this.Add(node.SourceLocation, node.Add2Addr(), localReg, args[0].Result),
                                           localReg);
                    }
                case AstCode.Sub:
                    {
                        if (args[0].Result.Register.IsTemp)
                            return new RLRange(args,
                                               this.Add(node.SourceLocation, node.Sub2Addr(), args[0].Result,
                                                        args[1].Result), args[0].Result);
                        var tmp = frame.AllocateTemp(args[0].Result.Type);
                        return new RLRange(args,
                                           this.Add(node.SourceLocation, node.Sub(), tmp, args[0].Result, args[1].Result),
                                           tmp);
                    }
                case AstCode.Sub_Ovf:
                    {
                        var isLong = node.Arguments[0].IsInt64();
                        var addMethods =
                            compiler.GetDot42InternalType("Checked").Resolve().Methods.Where(x => x.Name == "Sub");
                        var ilMethod = addMethods.First(x => isLong ? x.ReturnType.IsInt64() : x.ReturnType.IsInt32());
                        var method = ilMethod.GetReference(targetPackage);
                        var tmp = this.EnsureTemp(node.SourceLocation, args[0].Result, frame);
                        var registers = tmp.Result.Registers.Concat(args[1].Result.Registers);
                        this.Add(node.SourceLocation, RCode.Invoke_static, method, registers);
                        return new RLRange(args,
                                           this.Add(node.SourceLocation,
                                                    isLong ? RCode.Move_result_wide : RCode.Move_result, tmp.Result),
                                           tmp.Result);
                    }
                case AstCode.CompoundSub:
                    {
                        var localReg = frame.GetArgument((AstVariable) node.Operand);
                        return new RLRange(args,
                                           this.Add(node.SourceLocation, node.Sub2Addr(), localReg, args[0].Result),
                                           localReg);
                    }
                case AstCode.Mul:
                    {
                        if (args[0].Result.Register.IsTemp)
                            return new RLRange(args,
                                               this.Add(node.SourceLocation, node.Mul2Addr(), args[0].Result,
                                                        args[1].Result), args[0].Result);
                        var tmp = frame.AllocateTemp(args[0].Result.Type);
                        return new RLRange(args,
                                           this.Add(node.SourceLocation, node.Mul(), tmp, args[0].Result, args[1].Result),
                                           tmp);
                    }
                case AstCode.Mul_Ovf:
                    {
                        var isLong = node.Arguments[0].IsInt64();
                        var addMethods =
                            compiler.GetDot42InternalType("Checked").Resolve().Methods.Where(x => x.Name == "Mul");
                        var ilMethod = addMethods.First(x => isLong ? x.ReturnType.IsInt64() : x.ReturnType.IsInt32());
                        var method = ilMethod.GetReference(targetPackage);
                        var tmp = this.EnsureTemp(node.SourceLocation, args[0].Result, frame);
                        var registers = tmp.Result.Registers.Concat(args[1].Result.Registers);
                        this.Add(node.SourceLocation, RCode.Invoke_static, method, registers);
                        return new RLRange(args,
                                           this.Add(node.SourceLocation,
                                                    isLong ? RCode.Move_result_wide : RCode.Move_result, tmp.Result),
                                           tmp.Result);
                    }
                case AstCode.CompoundMul:
                    {
                        var localReg = frame.GetArgument((AstVariable) node.Operand);
                        return new RLRange(args,
                                           this.Add(node.SourceLocation, node.Mul2Addr(), localReg, args[0].Result),
                                           localReg);
                    }
                case AstCode.Div:
                case AstCode.Div_Un:
                    {
                        if (args[0].Result.Register.IsTemp)
                            return new RLRange(args,
                                               this.Add(node.SourceLocation, node.Div2Addr(), args[0].Result,
                                                        args[1].Result), args[0].Result);
                        var tmp = frame.AllocateTemp(args[0].Result.Type);
                        return new RLRange(args,
                                           this.Add(node.SourceLocation, node.Div(), tmp, args[0].Result, args[1].Result),
                                           tmp);
                    }
                case AstCode.CompoundDiv:
                    {
                        var localReg = frame.GetArgument((AstVariable) node.Operand);
                        return new RLRange(args,
                                           this.Add(node.SourceLocation, node.Div2Addr(), localReg, args[0].Result),
                                           localReg);
                    }
                case AstCode.Rem:
                case AstCode.Rem_Un:
                    {
                        if (args[0].Result.Register.IsTemp)
                            return new RLRange(args,
                                               this.Add(node.SourceLocation, node.Rem2Addr(), args[0].Result,
                                                        args[1].Result), args[0].Result);
                        var tmp = frame.AllocateTemp(args[0].Result.Type);
                        return new RLRange(args,
                                           this.Add(node.SourceLocation, node.Rem(), tmp, args[0].Result, args[1].Result),
                                           tmp);
                    }
                case AstCode.CompoundRem:
                    {
                        var localReg = frame.GetArgument((AstVariable) node.Operand);
                        return new RLRange(args,
                                           this.Add(node.SourceLocation, node.Rem2Addr(), localReg, args[0].Result),
                                           localReg);
                    }
                case AstCode.And:
                    {
                        if (args[0].Result.Register.IsTemp)
                            return new RLRange(args,
                                               this.Add(node.SourceLocation, node.And2Addr(), args[0].Result,
                                                        args[1].Result), args[0].Result);
                        var tmp = frame.AllocateTemp(args[0].Result.Type);
                        return new RLRange(args,
                                           this.Add(node.SourceLocation, node.And(), tmp, args[0].Result, args[1].Result),
                                           tmp);
                    }
                case AstCode.CompoundAnd:
                    {
                        var localReg = frame.GetArgument((AstVariable) node.Operand);
                        return new RLRange(args,
                                           this.Add(node.SourceLocation, node.And2Addr(), localReg, args[0].Result),
                                           localReg);
                    }
                case AstCode.Or:
                    {
                        if (args[0].Result.Register.IsTemp)
                            return new RLRange(args,
                                               this.Add(node.SourceLocation, node.Or2Addr(), args[0].Result,
                                                        args[1].Result), args[0].Result);
                        var tmp = frame.AllocateTemp(args[0].Result.Type);
                        return new RLRange(args,
                                           this.Add(node.SourceLocation, node.Or(), tmp, args[0].Result, args[1].Result),
                                           tmp);
                    }
                case AstCode.CompoundOr:
                    {
                        var localReg = frame.GetArgument((AstVariable) node.Operand);
                        return new RLRange(args, this.Add(node.SourceLocation, node.Or2Addr(), localReg, args[0].Result),
                                           localReg);
                    }
                case AstCode.Xor:
                    {
                        if (args[0].Result.Register.IsTemp)
                            return new RLRange(args,
                                               this.Add(node.SourceLocation, node.Xor2Addr(), args[0].Result,
                                                        args[1].Result), args[0].Result);
                        var tmp = frame.AllocateTemp(args[0].Result.Type);
                        return new RLRange(args,
                                           this.Add(node.SourceLocation, node.Xor(), tmp, args[0].Result, args[1].Result),
                                           tmp);
                    }
                case AstCode.CompoundXor:
                    {
                        var localReg = frame.GetArgument((AstVariable) node.Operand);
                        return new RLRange(args,
                                           this.Add(node.SourceLocation, node.Xor2Addr(), localReg, args[0].Result),
                                           localReg);
                    }
                case AstCode.Shl:
                    {
                        var r = frame.AllocateTemp(args[0].Result.Type);
                        return new RLRange(args,
                                           this.Add(node.SourceLocation, node.Shl(), r, args[0].Result, args[1].Result),
                                           r);
                    }
                case AstCode.CompoundShl:
                    {
                        var localReg = frame.GetArgument((AstVariable) node.Operand);
                        return new RLRange(args,
                                           this.Add(node.SourceLocation, node.Shl2Addr(), localReg, args[0].Result),
                                           localReg);
                    }
                case AstCode.Shr:
                    {
                        var r = frame.AllocateTemp(args[0].Result.Type);
                        return new RLRange(args,
                                           this.Add(node.SourceLocation, node.Shr(), r, args[0].Result, args[1].Result),
                                           r);
                    }
                case AstCode.CompoundShr:
                    {
                        var localReg = frame.GetArgument((AstVariable) node.Operand);
                        return new RLRange(args,
                                           this.Add(node.SourceLocation, node.Shr2Addr(), localReg, args[0].Result),
                                           localReg);
                    }
                case AstCode.Shr_Un:
                    {
                        var r = frame.AllocateTemp(args[0].Result.Type);
                        return new RLRange(args,
                                           this.Add(node.SourceLocation, node.UShr(), r, args[0].Result, args[1].Result),
                                           r);
                    }
                case AstCode.CompoundShr_Un:
                    {
                        var localReg = frame.GetArgument((AstVariable) node.Operand);
                        return new RLRange(args,
                                           this.Add(node.SourceLocation, node.UShr2Addr(), localReg, args[0].Result),
                                           localReg);
                    }
                case AstCode.Conditional: // arg[0] ? arg[1] : arg[2]
                    {
                        var valueType = (XTypeReference) node.Operand;
                        var result = frame.AllocateTemp(valueType.GetReference(targetPackage));
                        var move = node.Arguments[1].Move();
                        var move2 = node.Arguments[2].Move();
                        if (move2 == RCode.Move_object) move = move2;

                        // condition
                        var gotoArg2 = this.Add(node.SourceLocation, RCode.If_eqz, null, args[0].Result.Registers);

                        // Generate code for arg[1]
                        var arg1 = node.Arguments[1].Accept(this, node);
                        this.Add(node.SourceLocation, move, result, arg1.Result);
                        var gotoEnd = this.Add(node.SourceLocation, RCode.Goto, null);

                        // Generate code for arg[2]
                        var arg2Start = this.Add(node.SourceLocation, RCode.Nop);
                        var arg2 = node.Arguments[2].Accept(this, node);
                        this.Add(node.SourceLocation, move, result, arg2.Result);

                        var end = this.Add(node.SourceLocation, RCode.Nop);
                        // Set branch targets
                        gotoArg2.Operand = arg2Start;
                        gotoEnd.Operand = end;

                        return new RLRange(gotoArg2, end, result);
                    }

                    #endregion

                    #region Conversion

                    /*case AstCode.Conv_U4:
                case AstCode.Conv_Ovf_U4:
                    {
                        return new RLRange(this.Add(node.SourceLocation, RCode.Nop), args[0].Result);
                    }*/
                case AstCode.Conv_I1:
                case AstCode.Conv_Ovf_I1:
                case AstCode.Conv_Ovf_I1_Un:
                    return ConvX(node.SourceLocation, RCode.Int_to_byte, PrimitiveType.Byte,
                                 ConvToInt(node.SourceLocation, args[0]));
                case AstCode.Conv_U1:
                case AstCode.Conv_Ovf_U1:
                case AstCode.Conv_Ovf_U1_Un:
                    {
                        var result = ConvX(node.SourceLocation, RCode.Int_to_byte, PrimitiveType.Byte,
                                           ConvToInt(node.SourceLocation, args[0]));
                        var last = this.Add(node.SourceLocation, RCode.And_int_lit, 0xFF, result.Result, result.Result);
                        return new RLRange(result.First, last, result.Result);
                    }
                case AstCode.Conv_I2:
                case AstCode.Conv_Ovf_I2:
                case AstCode.Conv_Ovf_I2_Un:
                    return ConvX(node.SourceLocation, RCode.Int_to_short, PrimitiveType.Short,
                                 ConvToInt(node.SourceLocation, args[0]));
                case AstCode.Conv_U2:
                case AstCode.Conv_Ovf_U2:
                case AstCode.Conv_Ovf_U2_Un:
                    {
                        if (node.GetResultType().IsUInt16())
                        {
                            var result = ConvX(node.SourceLocation, RCode.Int_to_short, PrimitiveType.Short,
                                               ConvToInt(node.SourceLocation, args[0]));
                            var r2 = frame.AllocateTemp(PrimitiveType.Int);
                            this.Add(node.SourceLocation, RCode.Const, 0xFFFF, r2);
                            var last = this.Add(node.SourceLocation, RCode.And_int_2addr, result.Result, r2);
                            return new RLRange(result.First, last, result.Result);
                        }
                        else
                        {
                            return ConvX(node.SourceLocation, RCode.Int_to_char, PrimitiveType.Char,
                                         ConvToInt(node.SourceLocation, args[0]));
                        }
                    }
                case AstCode.Conv_I4:
                case AstCode.Conv_Ovf_I4:
                case AstCode.Conv_Ovf_I4_Un:
                case AstCode.Conv_I: // Convert to native int
                case AstCode.Conv_Ovf_I: // Convert to native with overflow check
                case AstCode.Conv_Ovf_I_Un: // Convert to native without overflow check
                case AstCode.Conv_U: // Convert to native uint
                case AstCode.Conv_Ovf_U: // Convert to native uint with overflow check
                case AstCode.Conv_Ovf_U_Un: // Convert to native uint without overflow check
                case AstCode.Conv_U4:
                case AstCode.Conv_Ovf_U4:
                case AstCode.Conv_Ovf_U4_Un:
                    return ConvX(node.SourceLocation, node.Arguments[0].ConvI4(), PrimitiveType.Int, args[0]);
                case AstCode.Conv_I8:
                case AstCode.Conv_Ovf_I8:
                case AstCode.Conv_Ovf_I8_Un:
                case AstCode.Conv_U8:
                case AstCode.Conv_Ovf_U8:
                case AstCode.Conv_Ovf_U8_Un:
                    return ConvX(node.SourceLocation, node.Arguments[0].ConvI8(), PrimitiveType.Long, args[0]);
                case AstCode.Conv_R4:
                    return ConvX(node.SourceLocation, node.Arguments[0].ConvR4(), PrimitiveType.Float, args[0]);
                case AstCode.Conv_R8:
                case AstCode.Conv_R_Un:
                    return ConvX(node.SourceLocation, node.Arguments[0].ConvR8(), PrimitiveType.Double, args[0]);
                case AstCode.Int_to_ubyte:
                    {
                        var tmp = this.EnsureTemp(node.SourceLocation, args[0].Result, frame);
                        var last = this.Add(node.SourceLocation, RCode.And_int_lit, 0xFF, tmp.Result, tmp.Result);
                        return new RLRange(args, tmp.First, last, tmp.Result);
                    }
                case AstCode.Int_to_ushort:
                    {
                        var tmp = this.EnsureTemp(node.SourceLocation, args[0].Result, frame);
                        var r2 = frame.AllocateTemp(PrimitiveType.Int);
                        this.Add(node.SourceLocation, RCode.Const, 0xFFFF, r2);
                        var last = this.Add(node.SourceLocation, RCode.And_int_2addr, tmp.Result, r2);
                        return new RLRange(args, tmp.First, last, tmp.Result);
                    }
                case AstCode.Box:
                    {
                        var type = (XTypeReference) node.Operand;
                        var tmp = this.EnsureTemp(node.SourceLocation, args[0].Result, frame);
                        return this.Box(node.SourceLocation, tmp.Result, type, targetPackage, frame);
                    }
                case AstCode.Unbox:
                case AstCode.Unbox_Any:
                    {
                        var type = (XTypeReference) node.Operand;
                        var tmp = this.EnsureTemp(node.SourceLocation, args[0].Result, frame);
                        return this.Unbox(node.SourceLocation, tmp.Result, type, compiler, targetPackage, frame);
                    }
                case AstCode.AddressOf:
                    {
                        return args[0];
                    }
                case AstCode.Enum_to_int:
                case AstCode.Enum_to_long:
                    {
                        var enumType = node.Arguments[0].GetResultType().Resolve();
                        var isWide = enumType.GetEnumUnderlyingType().IsWide();
                        var internalEnumType = compiler.GetDot42InternalType("Enum").GetClassReference(targetPackage);
                        var methodName = isWide ? "LongValue" : "IntValue";
                        var enumNumericType = isWide ? PrimitiveType.Long : PrimitiveType.Int;
                        var rvalue = frame.AllocateTemp(enumNumericType);
                        var convMethodDex = new MethodReference(internalEnumType, methodName,
                                                                new Prototype(enumNumericType));
                        var call = this.Add(node.SourceLocation, RCode.Invoke_virtual, convMethodDex, args[0].Result);
                        var last = this.Add(node.SourceLocation, isWide ? RCode.Move_result_wide : RCode.Move_result,
                                            rvalue);
                        return new RLRange(call, last, rvalue);
                    }

                case AstCode.Int_to_enum:
                case AstCode.Long_to_enum:
                    {
                        var enumType = node.GetResultType().Resolve();
                        var denumType = enumType.GetClassReference(targetPackage);
                        var isWide = enumType.GetEnumUnderlyingType().IsWide();
                        var literalIsWide = node.Arguments[0].GetResultType().IsWide();
                        var internalEnumType = compiler.GetDot42InternalType("Enum").GetClassReference(targetPackage);
                        var internalEnumInfoType = compiler.GetDot42InternalType("EnumInfo").GetClassReference(targetPackage);
                        var enumNumericType = isWide ? PrimitiveType.Long : PrimitiveType.Int;
                        var getValueMethod = new MethodReference(internalEnumInfoType, "GetValue",
                                                                 new Prototype(internalEnumType,
                                                                               new Parameter(enumNumericType, "value")));
                        var rinfo = frame.AllocateTemp(internalEnumInfoType);
                        var infoField = new FieldReference(denumType, NameConstants.Enum.InfoFieldName,
                                                           internalEnumInfoType);
                        var getInfo = this.Add(node.SourceLocation, RCode.Sget_object, infoField, rinfo);
                        var valueR = args[0].Result;
                        if (isWide != literalIsWide)
                        {
                            var convValueR = frame.AllocateTemp(isWide ? PrimitiveType.Long : PrimitiveType.Int);
                            var convCode = isWide ? RCode.Int_to_long : RCode.Long_to_int;
                            this.Add(node.SourceLocation, convCode, convValueR, valueR);
                            valueR = convValueR;
                        }
                        this.Add(node.SourceLocation, RCode.Invoke_virtual, getValueMethod,
                                 rinfo.Registers.Concat(valueR.Registers));
                        var renum = frame.AllocateTemp(denumType);
                        this.Add(node.SourceLocation, RCode.Move_result_object, renum);
                        var castClass = this.Add(node.SourceLocation, RCode.Check_cast, denumType, renum);
                        return new RLRange(getInfo, castClass, renum);
                    }

                    #endregion

                    #region Branching

                case AstCode.Cle:
                case AstCode.Cle_Un:
                case AstCode.Clt:
                case AstCode.Clt_Un:
                case AstCode.Ceq:
                case AstCode.Cne:
                case AstCode.Cgt:
                case AstCode.Cgt_Un:
                case AstCode.Cge:
                case AstCode.Cge_Un:
                    {
                        var r = frame.AllocateTemp(PrimitiveType.Int);
                        var start = this.Add(node.SourceLocation, RCode.Const, 0, r);
                        Instruction test;
                        var narg0 = node.Arguments[0];
                        var narg1 = node.Arguments[1];
                        if (narg0.IsWide() || narg1.IsWide())
                        {
                            var r2 = frame.AllocateTemp(PrimitiveType.Int);
                            var code = narg0.IsDouble() ? RCode.Cmpg_double : RCode.Cmp_long;
                            this.Add(node.SourceLocation, code, r2, args[0].Result, args[1].Result);
                            test = this.Add(node.SourceLocation, node.Code.Reverse().ToIfTestZ(), r2);
                        }
                        else if (narg0.IsFloat() || narg1.IsFloat())
                        {
                            var r2 = frame.AllocateTemp(PrimitiveType.Int);
                            this.Add(node.SourceLocation, RCode.Cmpg_float, r2, args[0].Result, args[1].Result);
                            test = this.Add(node.SourceLocation, node.Code.Reverse().ToIfTestZ(), r2);
                        }
                        else
                        {
                            test = this.Add(node.SourceLocation, node.Code.Reverse().ToIfTest(), args[0].Result,
                                            args[1].Result);
                        }
                        this.Add(node.SourceLocation, RCode.Const, 1, r);
                        var end = this.Add(node.SourceLocation, RCode.Nop, null);
                        test.Operand = end;
                        return new RLRange(args, start, end, r);
                    }
                case AstCode.CmpLFloat:
                case AstCode.CmpGFloat:
                case AstCode.CmpLong:
                    {
                        var r = frame.AllocateTemp(PrimitiveType.Int);
                        var code = node.CmpFloatOrLong();
                        var test = this.Add(node.SourceLocation, code, r, args[0].Result, args[1].Result);
                        return new RLRange(args, test, r);
                    }
                case AstCode.CIsNotNull:
                case AstCode.CIsNull:
                    {
                        var r = frame.AllocateTemp(PrimitiveType.Int);
                        var start = this.Add(node.SourceLocation, RCode.Const, 0, r);
                        var test = this.Add(node.SourceLocation, node.Code.Reverse().ToIfTestZ(), args[0].Result);
                        this.Add(node.SourceLocation, RCode.Const, 1, r);
                        var end = this.Add(node.SourceLocation, RCode.Nop, null);
                        test.Operand = end;
                        return new RLRange(args, start, end, r);
                    }
                case AstCode.Brtrue:
                case AstCode.Brfalse:
                case AstCode.BrIfEq:
                case AstCode.BrIfNe:
                case AstCode.BrIfGe:
                case AstCode.BrIfGt:
                case AstCode.BrIfLe:
                case AstCode.BrIfLt:
                    {
                        var label = (AstLabel) node.Operand;
                        var opcode = node.Code.ToIfTestZ();
                        var branch = this.Add(node.SourceLocation, opcode, args[0].Result);
                        labelManager.AddResolveAction(label, x => branch.Operand = x);
                        return new RLRange(branch, null);
                    }
                case AstCode.__Beq:
                case AstCode.__Bne_Un:
                case AstCode.__Ble:
                case AstCode.__Ble_Un:
                case AstCode.__Blt:
                case AstCode.__Blt_Un:
                case AstCode.__Bgt:
                case AstCode.__Bgt_Un:
                case AstCode.__Bge:
                case AstCode.__Bge_Un:
                    {
                        var label = (AstLabel) node.Operand;
                        var opcode = node.Code.ToIfTest();
                        var branch = this.Add(node.SourceLocation, opcode, args[0].Result, args[1].Result);
                        labelManager.AddResolveAction(label, x => branch.Operand = x);
                        return new RLRange(branch, null);
                    }
                case AstCode.Br:
                    {
                        var label = (AstLabel) node.Operand;
                        var branch = this.Add(node.SourceLocation, RCode.Goto, null);
                        labelManager.AddResolveAction(label, x => branch.Operand = x);
                        return new RLRange(branch, null);
                    }
                case AstCode.Leave:
                    {
                        var label = (AstLabel) node.Operand;
                        var branch = this.Add(node.SourceLocation, RCode.Leave, null);
                        labelManager.AddResolveAction(label, x => branch.Operand = x);
                        return new RLRange(branch, null);
                    }
                case AstCode.Switch:
                    {
                        var labels = (AstLabel[]) node.Operand;
                        var targets = new Instruction[labels.Length];
                        for (var i = 0; i < labels.Length; i++)
                        {
                            var index = i;
                            labelManager.AddResolveAction(labels[i], x => targets[index] = x);
                        }
                        var @switch = this.Add(node.SourceLocation, RCode.Packed_switch, targets, args[0].Result);
                        return new RLRange(@switch, null);
                    }
                case AstCode.LookupSwitch:
                    {
                        var labelKeyPairs = (AstLabelKeyPair[]) node.Operand;
                        var targetPairs = new Tuple<int, Instruction>[labelKeyPairs.Length];
                        for (var i = 0; i < labelKeyPairs.Length; i++)
                        {
                            var index = i;
                            var key = labelKeyPairs[i].Key;
                            var label = labelKeyPairs[i].Label;
                            labelManager.AddResolveAction(label, x => targetPairs[index] = Tuple.Create(key, x));
                        }
                        var @switch = this.Add(node.SourceLocation, RCode.Sparse_switch, targetPairs, args[0].Result);
                        return new RLRange(@switch, null);
                    }
                case AstCode.NullCoalescing:
                    {
                        var r = frame.AllocateTemp(node.InferredType.GetReference(targetPackage));
                        var first = this.Add(node.SourceLocation, RCode.Move_object, r, args[0].Result);
                        // r := leftExpr
                        var if_nez = this.Add(node.SourceLocation, RCode.If_nez, r); // if r not null, skip
                        this.Add(node.SourceLocation, RCode.Move_object, r, args[1].Result); // r := rightExpr
                        var end = this.Add(node.SourceLocation, RCode.Nop);
                        if_nez.Operand = end;
                        return new RLRange(first, end, r);
                    }

                    #endregion

                    #region Call

                case AstCode.Call:
                case AstCode.Callvirt:
                case AstCode.CallIntf:
                case AstCode.CallSpecial:
                    {
                        return VisitCallExpression(node, args, parent);
                    }
                case AstCode.Ret:
                    if (currentMethod.ReturnsVoid)
                        return new RLRange(args, this.Add(node.SourceLocation, RCode.Return_void), null);
                    return new RLRange(args, this.Add(node.SourceLocation, node.Return(currentMethod), args[0].Result),
                                       null);

                    #endregion

                    #region Array

                case AstCode.Newarr:
                    {
                        var type = (XTypeReference) node.Operand;
                        var dType = new ArrayType(type.GetReference(targetPackage));
                        var r = frame.AllocateTemp(dType);
                        var newArray = this.Add(node.SourceLocation, RCode.New_array, dType, r, args[0].Result);
                        return new RLRange(newArray, r);
                    }
                case AstCode.ArrayNewInstance:
                    {
                        // Resolve type to a Class<?>
                        var newInstance = FrameworkReferences.ArrayNewInstance;
                        var first = this.Add(node.SourceLocation, RCode.Invoke_static, newInstance, args[0].Result,
                                             args[1].Result);
                        var r = frame.AllocateTemp(newInstance.Prototype.ReturnType);
                        var last = this.Add(node.SourceLocation, RCode.Move_result_object, r);
                        return new RLRange(first, last, r);
                    }
                case AstCode.ArrayNewInstance2:
                    {
                        // Call java.lang.reflect.Array.newInstance(type, int[])
                        var newInstance = FrameworkReferences.ArrayNewInstance2;
                        var first = this.Add(node.SourceLocation, RCode.Invoke_static, newInstance, args[0].Result,
                                             args[1].Result);
                        var resultReg = frame.AllocateTemp(FrameworkReferences.Object);
                        var last = this.Add(node.SourceLocation, RCode.Move_result_object, resultReg);
                        return new RLRange(args, first, last, resultReg);
                    }
                case AstCode.InitEnumArray:
                    {
                        var type = (XTypeReference) node.Operand;
                        var typeDef = type.Resolve();
                        // Initialize array
                        var fillMethod = FrameworkReferences.ArraysFillObject;
                        var denumType = typeDef.GetClassReference(targetPackage);
                        var defaultField = new FieldReference(denumType, NameConstants.Enum.DefaultFieldName, denumType);
                        var rdefault = frame.AllocateTemp(denumType);
                        var first = this.Add(node.SourceLocation, RCode.Sget_object, defaultField, rdefault);
                        var arrayR = args[0].Result;
                        var last = this.Add(node.SourceLocation, RCode.Invoke_static, fillMethod, arrayR, rdefault);
                        return new RLRange(first, last, arrayR);
                    }
                case AstCode.InitStructArray:
                    {
                        var defaultCtor = (XMethodReference) node.Operand;
                        var dDefaultCtor = defaultCtor.GetReference(targetPackage);
                        var arrayR = args[0].Result;
                        var indexR = frame.AllocateTemp(PrimitiveType.Int);
                        var oneR = frame.AllocateTemp(PrimitiveType.Int);
                        var elementR = frame.AllocateTemp(dDefaultCtor.Owner);
                        var first = this.Add(node.SourceLocation, RCode.Array_length, indexR, arrayR);
                        this.Add(node.SourceLocation, RCode.Const, 1, oneR);
                        var ifZero = this.Add(node.SourceLocation, RCode.If_eqz, indexR);
                            // if (index == 0) goto end;  (Operand set later)
                        this.Add(node.SourceLocation, RCode.Sub_int_2addr, indexR, oneR); // index--;
                        this.Add(node.SourceLocation, RCode.New_instance, dDefaultCtor.Owner, elementR);
                            // element = new Struct;
                        this.Add(node.SourceLocation, RCode.Invoke_direct, dDefaultCtor, elementR);
                            // invoke element.ctor()
                        this.Add(node.SourceLocation, RCode.Aput_object, elementR, arrayR, indexR);
                            // Store element in array
                        this.Add(node.SourceLocation, RCode.Goto, ifZero); // End of loop
                        var end = this.Add(node.SourceLocation, RCode.Nop);
                        ifZero.Operand = end;
                        return new RLRange(first, end, arrayR);
                    }
                case AstCode.MultiNewarr:
                    {
                        var arrType = (XTypeReference) node.Operand;
                        var darrType = arrType.GetReference(targetPackage);
                        var compType = arrType;
                        // Unwind array type to component type
                        for (var i = 0; i < node.Arguments.Count; i++)
                        {
                            compType = compType.ElementType;
                        }
                        var dcompType = new ArrayType(compType.GetReference(targetPackage));
                        var dimArrayR = frame.AllocateTemp(new ArrayType(PrimitiveType.Int));
                        var lengthR = frame.AllocateTemp(PrimitiveType.Int);
                        var first = this.Add(node.SourceLocation, RCode.Nop);
                        // Allocate dimensions array
                        this.Add(node.SourceLocation, RCode.Const, node.Arguments.Count, lengthR);
                        this.Add(node.SourceLocation, RCode.New_array, PrimitiveType.Int, dimArrayR, lengthR);
                        var indexR = lengthR;
                        // Initialize dimensions array
                        for (var i = 0; i < node.Arguments.Count; i++)
                        {
                            this.Add(node.SourceLocation, RCode.Const, i, indexR);
                            this.Add(node.SourceLocation, RCode.Aput, args[i], dimArrayR, indexR);
                        }

                        // Load component type
                        var compTypeR = frame.AllocateTemp(new ClassReference("java/lang/Class"));
                        this.Add(node.SourceLocation, RCode.Const_class, dcompType, compTypeR);

                        // Call java/lang/reflect/Array/newInstance
                        var reflectArrayType = new ClassReference("java/lang/reflect/Array");
                        var prototype = PrototypeBuilder.ParseMethodSignature("(Ljava/lang/Class;[I)Ljava/lang/Object;");
                        var methodRef = new MethodReference(reflectArrayType, "newInstance", prototype);
                        var arrayR = frame.AllocateTemp(darrType);
                        this.Add(node.SourceLocation, RCode.Invoke_static, methodRef, compTypeR, dimArrayR);
                        var last = this.Add(node.SourceLocation, RCode.Move_result_object, arrayR);

                        return new RLRange(first, last, arrayR);
                    }
                case AstCode.ByRefArray:
                case AstCode.ByRefOutArray:
                    {
                        // Create array
                        var type = (XTypeReference) node.Operand;
                        var dType = new ArrayType(type.GetReference(targetPackage));
                        var arrayR = frame.AllocateTemp(dType);
                        var lengthR = frame.AllocateTemp(PrimitiveType.Int);
                        // length=1
                        var initLength = this.Add(node.SourceLocation, RCode.Const, 1, lengthR);
                        // newarray
                        this.Add(node.SourceLocation, RCode.New_array, dType, arrayR, lengthR);
                        if (node.Code == AstCode.ByRefArray)
                        {
                            var valueR = args[0].Result;
                            var arrayType = node.InferredType;

                            // Perform type conversion if needed
                            bool isConverted;
                            var converted = this.ConvertTypeBeforeStore(node.SourceLocation, type, arrayType.ElementType,
                                                                        valueR, targetPackage, frame, compiler,
                                                                        out isConverted);
                            if (isConverted) valueR = converted.Result;

                            // array[0]=value
                            var indexR = frame.AllocateTemp(PrimitiveType.Int);
                            this.Add(node.SourceLocation, RCode.Const, 0, indexR);
                            this.Add(node.SourceLocation, arrayType.APut(), valueR, arrayR, indexR);
                        }
                        var end = this.Add(node.SourceLocation, RCode.Nop);
                        return new RLRange(initLength, end, arrayR);
                    }
                case AstCode.Ldlen:
                    {
                        var r = frame.AllocateTemp(PrimitiveType.Int);
                        return new RLRange(this.Add(node.SourceLocation, RCode.Array_length, r, args[0].Result), r);
                    }
                case AstCode.Stelem_I:
                case AstCode.Stelem_I1:
                case AstCode.Stelem_I2:
                case AstCode.Stelem_I4:
                case AstCode.Stelem_I8:
                case AstCode.Stelem_R4:
                case AstCode.Stelem_R8:
                case AstCode.Stelem_Ref:
                case AstCode.Stelem_Any:
                    {
                        var first = this.Add(node.SourceLocation, RCode.Nop);
                        var arrayR = args[0].Result;
                        var indexR = args[1].Result;
                        var valueR = args[2].Result;
                        var valueType = node.Arguments[2].GetResultType();
                        var arrayType = node.Arguments[0].GetResultType();

                        // Perform type conversion if needed
                        bool isConverted;
                        var converted = this.ConvertTypeBeforeStore(node.SourceLocation, valueType,
                                                                    arrayType.ElementType, valueR, targetPackage,
                                                                    frame, compiler, out isConverted);
                        if (isConverted) valueR = converted.Result;

                        // Store in array
                        var aput = this.Add(node.SourceLocation, node.APut(), valueR, arrayR, indexR);
                        return new RLRange(first, aput, valueR);
                    }
                case AstCode.Ldelem_I:
                case AstCode.Ldelem_I1:
                case AstCode.Ldelem_I2:
                case AstCode.Ldelem_I4:
                case AstCode.Ldelem_I8:
                case AstCode.Ldelem_R4:
                case AstCode.Ldelem_R8:
                case AstCode.Ldelem_U1:
                case AstCode.Ldelem_U2:
                case AstCode.Ldelem_U4:
                case AstCode.Ldelem_Ref:
                case AstCode.Ldelem_Any:
                    {
                        var arrayR = args[0].Result;
                        var indexR = args[1].Result;
                        var arrayType = node.Arguments[0].GetResultType();
                        var elementType = arrayType.ElementType;

                        // Allocate registry for value
                        var valueR = frame.AllocateTemp(elementType.GetReference(targetPackage));

                        // Get from array
                        var first = this.Add(node.SourceLocation, node.AGet(), valueR, arrayR, indexR);
                        return new RLRange(first, valueR);
                    }

                    #endregion

                    #region Local variables / arguments

                case AstCode.Ldloc:
                    {
                        var variable = (AstVariable) node.Operand;
                        var valueR = frame.GetArgument(variable);
                        return new RLRange(args, valueR);
                    }
                case AstCode.Ldthis:
                    if (frame.ThisArgument == null)
                        throw new ArgumentException("No this in current method");
                    return new RLRange(args, frame.ThisArgument);
                case AstCode.Stloc:
                    {
                        var variable = (AstVariable) node.Operand;
                        var resultType = node.Arguments[0].GetResultType();
                        var valueR = args[0].Result;
                        var first = this.Add(node.SourceLocation, RCode.Nop);
                        // Convert value if needed
                        bool isConverted;
                        var converted = this.ConvertTypeBeforeStore(node.SourceLocation, resultType, variable.Type,
                                                                    valueR, targetPackage, frame, compiler,
                                                                    out isConverted);
                        if (isConverted) valueR = converted.Result;
                        // Store in variable
                        var variableR = frame.GetArgument(variable);
                        return new RLRange(args, first, this.Add(node.SourceLocation, node.Move(), variableR, valueR),
                                           variableR);
                    }

                    #endregion

                    #region Fields

                case AstCode.Ldfld:
                    {
                        var fieldRef = (XFieldReference) node.Operand;
                        var field = fieldRef.Resolve();
                        var dField = field.GetReference(targetPackage);
                        var fieldType = field.FieldType;
                        // Allocate register
                        var valueR = frame.AllocateTemp(fieldType.GetReference(targetPackage));
                        // Get from field
                        var iget = this.Add(node.SourceLocation, field.IGet(), dField, valueR, args[0].Result);
                        return new RLRange(iget, valueR);
                    }
                case AstCode.Stfld:
                    {
                        var fieldRef = (XFieldReference) node.Operand;
                        var field = fieldRef.Resolve();
                        var dField = field.GetReference(targetPackage);
                        var type = node.InferredType;
                        var first = this.Add(node.SourceLocation, RCode.Nop);
                        var valueR = args[1].Result;

                        // Perform type conversion if needed
                        bool isConverted;
                        var converted = this.ConvertTypeBeforeStore(node.SourceLocation, type, field.FieldType, valueR,
                                                                    targetPackage, frame, compiler,
                                                                    out isConverted);
                        if (isConverted) valueR = converted.Result;

                        // Store in field
                        var iput = this.Add(node.SourceLocation, field.IPut(), dField, valueR, args[0].Result);
                        return new RLRange(first, iput, valueR);
                    }
                case AstCode.Ldsfld:
                    {
                        var field = (XFieldReference) node.Operand;
                        XFieldDefinition fieldDef;
                        field.TryResolve(out fieldDef);
                        var fieldType = field.FieldType;
                        // Allocate register
                        var valueR = frame.AllocateTemp(fieldType.GetReference(targetPackage));

                        string resourceName;
                        if ((fieldDef != null) && fieldDef.TryGetResourceIdAttribute(out resourceName))
                        {
                            // Replace by resource id.
                            var id = FindResourceId(compiler.ResourceTable, resourceName);
                            return new RLRange(args, this.Add(node.SourceLocation, RCode.Const, id, valueR), valueR);
                        }
                        else
                        {
                            // Normal get from field
                            var dField = field.GetReference(targetPackage);
                            var iget = this.Add(node.SourceLocation, node.SGet(), dField, valueR);
                            return new RLRange(iget, valueR);
                        }
                    }
                case AstCode.Stsfld:
                    {
                        var field = (XFieldReference) node.Operand;
                        var dField = field.GetReference(targetPackage);
                        var type = node.InferredType;
                        var first = this.Add(node.SourceLocation, RCode.Nop);
                        var valueR = args[0].Result;

                        // Perform type conversion if needed
                        bool isConverted;
                        var converted = this.ConvertTypeBeforeStore(node.SourceLocation, type, field.FieldType, valueR,
                                                                    targetPackage, frame, compiler,
                                                                    out isConverted);
                        if (isConverted) valueR = converted.Result;

                        // Store in field
                        var sput = this.Add(node.SourceLocation, node.SPut(), dField, valueR);
                        return new RLRange(first, sput, valueR);
                    }

                    #endregion

                    #region Object model

                case AstCode.Newobj: // IL new
                    {
                        var ilCtorRef = (XMethodReference) node.Operand;
                        var ilType = ilCtorRef.DeclaringType;

                        // New normal object
                        var ilCtor = ilCtorRef.Resolve();
                        var dCtor = ilCtor.GetReference(targetPackage);
                        var dType = ilType.GetReference(targetPackage);

                        // Create instance
                        var r = frame.AllocateTemp(dType);
                        var first = this.Add(node.SourceLocation, RCode.New_instance, dType, r);

                        // Prepare arguments
                        int argsOffset;
                        List<RLRange> originalArgs;
                        ConvertParametersBeforeCall(node, args, ilCtor, out argsOffset, out originalArgs);

                        // Collect arguments
                        var arguments = args.SelectMany(x => x.Result.Registers).ToList();
                        // Insert this argument
                        arguments.Insert(0, r);

                        // Invoke ctor
                        this.Add(node.SourceLocation, RCode.Invoke_direct, dCtor, arguments);

                        // Post process arguments
                        ConvertParametersAfterCall(node, args, ilCtor, argsOffset, originalArgs);
                        var last = this.Add(node.SourceLocation, RCode.Nop);
                        return new RLRange(args, first, last, r);
                    }
                case AstCode.New: // Java new
                    {
                        var ilType = (XTypeReference) node.Operand;
                        // New normal object
                        var dType = ilType.GetReference(targetPackage);
                        // Create instance
                        var r = frame.AllocateTemp(dType);
                        var first = this.Add(node.SourceLocation, RCode.New_instance, dType, r);
                        return new RLRange(args, first, r);
                    }
                case AstCode.CallBaseCtor:
                    {
                        var dtype = currentDexMethod.Owner;
                        var dBaseType = dtype.SuperClass as ClassDefinition;
                        if (dBaseType == null)
                            throw new CompilerException(string.Format("Type {0} base no superclass as definition", dtype.Fullname));
                        var paramCount = node.Arguments.Count - 1;
                        var baseCtor = dBaseType.Methods.Single(x => x.IsConstructor && (x.Prototype.Parameters.Count == paramCount));
                        var call = this.Add(node.SourceLocation, RCode.Invoke_direct, baseCtor, args.SelectMany(x => x.Result.Registers));
                        return new RLRange(call, args[0].Result);
                    }
            case AstCode.Castclass:
                    {
                        throw new NotSupportedException("castclass is not supported");
                    }
                case AstCode.SimpleCastclass:
                    {
                        var type = (XTypeReference) node.Operand;
                        var dType = type.GetReference(targetPackage);
                        if (type.IsPrimitive)
                        {
                            // Convert type to boxed type
                            dType = BoxInfo.GetBoxedType(type);
                        }

                        // Normal cast
                        var tmp = this.EnsureTemp(node.SourceLocation, args[0].Result, frame);
                        var checkCast = this.Add(node.SourceLocation, RCode.Check_cast, dType, tmp.Result);
                        return new RLRange(tmp, checkCast, tmp.Result);
                    }
                case AstCode.Isinst: // "as" operator
                    {
                        throw new NotSupportedException("isinst is not supported");
                    }
                case AstCode.InstanceOf: // "is" operator
                    {
                        throw new NotSupportedException("instanceof is not supported");
                    }
                case AstCode.SimpleInstanceOf: // "is" operator
                    {
                        var type = (XTypeReference) node.Operand;
                        var dType = type.GetReference(targetPackage);
                        if (type.IsPrimitive)
                        {
                            // Convert type to boxed type
                            dType = BoxInfo.GetBoxedType(type);
                        }
                        // Normal "is"
                        var rResult = frame.AllocateTemp(PrimitiveType.Boolean);
                        var instanceOf = this.Add(node.SourceLocation, RCode.Instance_of, dType, rResult, args[0].Result);
                        return new RLRange(instanceOf, rResult);
                    }

                    #endregion

#region Generics
                case AstCode.LdGenericInstanceField:
                    {
                        var giField = GetGenericInstanceField();
                        var r = frame.AllocateTemp(FrameworkReferences.ClassArray);
                        var iget = this.Add(node.SourceLocation, RCode.Iget_object, giField, r, frame.ThisArgument);
                        return new RLRange(iget, r);
                    }
                case AstCode.StGenericInstanceField:
                    {
                        var giField = GetGenericInstanceField();
                        var r = args[0].Result;
                        var iput = this.Add(node.SourceLocation, RCode.Iput_object, giField, r, frame.ThisArgument);
                        return new RLRange(iput, r);
                    }
                case AstCode.LdGenericInstanceTypeArgument:
                    {
                        if (frame.GenericInstanceTypeArgument == null)
                        {
                            throw new CompilerException(string.Format("Method {0} has no generic instance type argument", currentMethod.FullName));
                        }
                        return new RLRange(frame.GenericInstanceTypeArgument);
                    }
                case AstCode.LdGenericInstanceMethodArgument:
                    {
                        if (frame.GenericInstanceMethodArgument == null)
                        {
                            throw new CompilerException(string.Format("Method {0} has no generic instance method argument", currentMethod.FullName));
                        }
                        return new RLRange(frame.GenericInstanceMethodArgument);
                    }
                case AstCode.UnboxFromGeneric:
                    {
                        // Get result
                        var elementType = (XTypeReference) node.Operand;
                        var r = args[0].Result;
                        var start = this.Add(node.SourceLocation, RCode.Nop);
                        var last = start;

                        // Convert result when needed
                        if (elementType.IsGenericParameter)
                        {
                            var returnType = node.GetResultType();
                            var tmp = this.Unbox(node.SourceLocation, r, returnType, compiler, targetPackage, frame);
                            last = tmp.Last;
                            r = tmp.Result;
                        }
                        else if (elementType.IsGenericParameterArray())
                        {
                            var returnType = node.GetResultType();
                            if (returnType.IsPrimitiveArray())
                            {
                                var tmp = this.UnboxGenericArrayResult(node.SourceLocation, r, returnType, targetPackage, frame, compiler);
                                last = tmp.Last;
                                r = tmp.Result;
                            }
                            else
                            {
                                var tmp = this.Unbox(node.SourceLocation, r, returnType, compiler, targetPackage, frame);
                                last = tmp.Last;
                                r = tmp.Result;
                            }
                        }
                        return new RLRange(start, last, r);
                    }
#endregion

                case AstCode.Throw:
                    {
                        var @throw = this.Add(node.SourceLocation, RCode.Throw, args[0].Result);
                        return new RLRange(@throw, null);
                    }
                case AstCode.Rethrow:
                    {
                        if (currentExceptionRegister == null)
                            throw new CompilerException("retrow outside catch block");
                        var @throw = this.Add(node.SourceLocation, RCode.Throw, currentExceptionRegister);
                        return new RLRange(@throw, null);                        
                    }
                case AstCode.Delegate:
                    {
                        //Debugger.Launch();
                        var delegateInfo = (Tuple<XTypeDefinition, XMethodDefinition>)node.Operand;
                        var delegateType = compiler.GetDelegateType(delegateInfo.Item1);
                        var delegateInstanceType = delegateType.GetOrCreateInstance(node.SourceLocation, targetPackage, delegateInfo.Item2);

                        // Create instance
                        var r = frame.AllocateTemp(delegateInstanceType.InstanceDefinition);
                        var newobj = this.Add(node.SourceLocation, RCode.New_instance, delegateInstanceType.InstanceDefinition, r);
                        // Call ctor
                        if (delegateInstanceType.CalledMethodIsStatic)
                        {
                            // Call without instance argument
                            var invokeCtor = this.Add(node.SourceLocation, RCode.Invoke_direct, delegateInstanceType.InstanceCtor, r);
                            return new RLRange(newobj, invokeCtor, r);
                        }
                        else
                        {
                            // Call with instance argument
                            var invokeCtor = this.Add(node.SourceLocation, RCode.Invoke_direct, delegateInstanceType.InstanceCtor, r, args[0].Result);
                            return new RLRange(newobj, invokeCtor, r);
                        }
                    }
                case AstCode.InitArray:
                    {
                        var arrayData = (InitArrayData) node.Operand;
                        var size = arrayData.Length;
                        var type = arrayData.ArrayType;
                        var dType = type.GetReference(targetPackage);

                        // Allocate new array
                        var rArray = frame.AllocateTemp(dType);
                        var rSize = frame.AllocateTemp(PrimitiveType.Int);
                        var start = this.Add(node.SourceLocation, RCode.Const, size, rSize);
                        this.Add(node.SourceLocation, RCode.New_array, dType, rArray, rSize);

                        // Initialize array
                        if (arrayData.IsSupportedByFillArrayData())
                        {
                            // Use fill-array-data
                            this.Add(node.SourceLocation, RCode.Fill_array_data, arrayData.Values, rArray);
                        }
                        else
                        {
                            // Use const/aput sequence
                            var rValue = frame.AllocateTemp(arrayData.ArrayType.ElementType.GetReference(targetPackage));
                            var rIndex = frame.AllocateTemp(PrimitiveType.Int);
                            var isWide = arrayData.ArrayType.ElementType.IsWide();
                            var constCode = isWide ? RCode.Const_wide : RCode.Const;
                            var aputCode = arrayData.ArrayType.APut();
                            var convertCode = arrayData.ArrayType.AConstConvertBeforePut();
                            var valueConverter = arrayData.ArrayType.ElementType.ConstValueConverter(false);

                            // Initialize index
                            this.Add(node.SourceLocation, RCode.Const, 0, rIndex);

                            // aput for each
                            for (var i = 0; i < arrayData.Length; i++)
                            {
                                var value = valueConverter(arrayData.Values.GetValue(i));
                                this.Add(node.SourceLocation, constCode, value, rValue);
                                if (convertCode != RCode.Nop)
                                {
                                    this.Add(node.SourceLocation, convertCode, rValue, rValue);                                    
                                }
                                this.Add(node.SourceLocation, aputCode, rValue, rArray, rIndex);
                                if (i + 1 < arrayData.Length)
                                {
                                    // Increment index
                                    this.Add(node.SourceLocation, RCode.Add_int_lit, 1, rIndex, rIndex);
                                }
                            }
                        }


                        //throw new NotImplementedException();
                        return new RLRange(this.Add(node.SourceLocation, RCode.Nop), rArray);
                    }
                case AstCode.InitArrayFromArguments:
                    {
                        var size = args.Count;
                        var type = (XArrayType) node.Operand;
                        var dType = type.GetReference(targetPackage);

                        // Allocate new array
                        var rArray = frame.AllocateTemp(dType);
                        var rSize = frame.AllocateTemp(PrimitiveType.Int);
                        var start = this.Add(node.SourceLocation, RCode.Nop);
                        this.Add(node.SourceLocation, RCode.Const, size, rSize);
                        this.Add(node.SourceLocation, RCode.New_array, dType, rArray, rSize);

                        // Use const/aput sequence
                        var rIndex = frame.AllocateTemp(PrimitiveType.Int);
                        var aputCode = type.APut();

                        // Initialize index
                        this.Add(node.SourceLocation, RCode.Const, 0, rIndex);

                        // aput for each
                        for (var i = 0; i < size; i++)
                        {
                            this.Add(node.SourceLocation, aputCode, args[i].Result, rArray, rIndex);
                            if (i + 1 < size)
                            {
                                // Increment index
                                this.Add(node.SourceLocation, RCode.Add_int_lit, 1, rIndex, rIndex);
                            }
                        }
                        return new RLRange(start, this.Add(node.SourceLocation, RCode.Nop), rArray);
                    }
                case AstCode.LdClass:
                    {
                        var ilType = (XTypeReference)node.Operand;
                        var dType = ilType.GetReference(targetPackage);
                        // Load type
                        var r = frame.AllocateTemp(FrameworkReferences.Class);
                        var first = this.Add(node.SourceLocation, RCode.Const_class, dType, r);
                        return new RLRange(args, first, r);                        
                    }
                case AstCode.Ldtoken:
                    {
                        throw new NotSupportedException("ldtoken is not supported");
                    }
                default:
                    string opcodeName;
#if DEBUG
                    //Debugger.Launch();
                    opcodeName = node.Code.ToString();
#else
                    opcodeName = ((int)node.Code).ToString();
#endif
                    var source = FormatSource(node);
                    var msg = string.Format("Unexpected opcode {0} in {1}.", opcodeName, source);
                    throw new ArgumentException(msg);
            }
        }
Example #19
0
 public Annotation(ClassReference type, AnnotationVisibility visibility, params AnnotationArgument[] arguments)
 {
     Type       = type;
     Visibility = visibility;
     Arguments  = arguments.ToList();
 }
Example #20
0
 /// <summary>
 /// Is other equal to this?
 /// </summary>
 public bool Equals(ClassReference other)
 {
     return(base.Equals(other) && Fullname == other.Fullname);
 }
Example #21
0
 public FieldReference(ClassReference owner, string name, TypeReference fieldType)
 {
     Owner = owner;
     Type = fieldType;
     Name = name;
 }
 /// <summary>
 /// Create the body of the ctor.
 /// </summary>
 private static MethodBody CreateCtorBody(XMethodDefinition calledMethod, FieldDefinition instanceField, ClassReference baseClass)
 {
     var body = new MethodBody(null);
     // Create code
     var ins = body.Instructions;
     var rthis = body.AllocateRegister(RCategory.Argument, RType.Object);
     // Call base ctor
     var baseCtorRef = new MethodReference(baseClass, "<init>", new Prototype(PrimitiveType.Void));
     ins.Add(new Instruction(RCode.Invoke_direct, rthis) { Operand = baseCtorRef });
     if (!calledMethod.IsStatic)
     {
         // load instance into field
         var rvalue = body.AllocateRegister(RCategory.Argument, RType.Object);
         ins.Add(new Instruction(RCode.Iput_object, rvalue, rthis) {Operand = instanceField});
     }
     ins.Add(new Instruction(RCode.Return_void));
     return body;
 }
        private ClassReference ConvertClassReference(ClassReference sourceRef, AssemblyCompiler compiler, DexTargetPackage targetPackage)
        {
            TypeEntry type = _map.GetTypeBySignature(sourceRef.Descriptor);

            if (IsDelegateInstance(type))
            {
                // special delegate handling.
                return GetDelegateInstanceType(type, sourceRef, compiler, targetPackage).InstanceDefinition;
            }
            else
            {
                var xTypeDef = ResolveToType(type, sourceRef, compiler);
                return xTypeDef.GetClassReference(targetPackage);
            }
        }
        /// <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;
        }
        /// <summary>
        /// will throw if type is not found.
        /// </summary>
        private static XTypeDefinition ResolveToType(TypeEntry type, ClassReference sourceRef, AssemblyCompiler compiler)
        {
            XTypeDefinition xTypeDef = null;

            if (type != null)
            {
                string scopeId = GetTypeScopeId(type);
                xTypeDef = compiler.Module.GetTypeByScopeID(scopeId);
            }
            else
            {
                string scopeId = sourceRef.Descriptor.Substring(1,sourceRef.Descriptor.Length-2);
                xTypeDef = compiler.Module.GetTypeByScopeID(scopeId);
            }

            if (xTypeDef == null)
            {
                throw new CompilerCacheResolveException("unable to resolve " + sourceRef);
            }
            return xTypeDef;
        }
        /// <summary>
        /// Create the body of the equals method.
        /// </summary>
        private static MethodBody CreateEqualsBody(ISourceLocation sequencePoint, AssemblyCompiler compiler, DexTargetPackage targetPackage, XMethodDefinition equalsMethod, Prototype equalsPrototype, FieldDefinition instanceField, ClassReference delegateClass)
        {
            MethodBody body = new MethodBody(null);

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

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

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

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

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

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

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

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

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

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

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

            return body;
        }
Example #27
0
 /// <summary>
 /// Create an android MemberClasses annotation and attach it to the given provider.
 /// </summary>
 public static void AddMemberClassesAnnotation(this IAnnotationProvider provider, ClassReference[] classes)
 {
     var annotation = new Annotation { Type = new ClassReference("dalvik/annotation/MemberClasses"), Visibility = AnnotationVisibility.System };
     annotation.Arguments.Add(new AnnotationArgument("value", classes));
     provider.Annotations.Add(annotation);
 }
        /// <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;
        }