// for prefetching internal FieldDefinition(FieldReference fref) : this() { Owner = fref.Owner as ClassDefinition; Type = fref.Type; Name = fref.Name; }
private object ConvertFieldReference(FieldReference fieldRef, AssemblyCompiler compiler, DexTargetPackage targetPackage) { // We could also handle access to fields in the generated class; but see the coverage comment above. // It would require to map fields in the MapFile as well, at least for those in the __generated // class. I don't think its worth it. if (fieldRef.Owner.Descriptor == _map.GeneratedType.DexSignature) { throw new CompilerCacheResolveException("unable to resolve fields in __generated: " + fieldRef); } // I don't believe we have to protect ourselfs from field name changes. // Except for obfuscation, there is no reason to rename fields. They are // independent of other classes not in their class hierachy (of which we know // that it can not have changed) var classRef = ConvertClassReference(fieldRef.Owner, compiler, targetPackage); var typeRef = ConvertTypeReference(fieldRef.Type, compiler, targetPackage); return(new FieldReference(classRef, fieldRef.Name, typeRef)); }
private object ConvertFieldReference(FieldReference fieldRef, AssemblyCompiler compiler, DexTargetPackage targetPackage) { // We could also handle access to fields in the generated class; but see the coverage comment above. // It would require to map fields in the MapFile as well, at least for those in the __generated // class. I don't think its worth it. if (fieldRef.Owner.Descriptor == _map.GeneratedType.DexSignature) throw new CompilerCacheResolveException("unable to resolve fields in __generated: " + fieldRef); // I don't believe we have to protect ourselfs from field name changes. // Except for obfuscation, there is no reason to rename fields. They are // independent of other classes not in their class hierachy (of which we know // that it can not have changed) var classRef = ConvertClassReference(fieldRef.Owner, compiler, targetPackage); var typeRef = ConvertTypeReference(fieldRef.Type, compiler, targetPackage); return new FieldReference(classRef, fieldRef.Name, typeRef); }
/// <summary> /// Is other equal to this? /// </summary> public bool Equals(FieldReference other) { return (other != null) && Owner.Equals(other.Owner) && Name.Equals(other.Name) && Type.Equals(other.Type); }
/// <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> /// 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); } }
private MethodBody CreateCloneBody(MethodDefinition ctor, ClassDefinition @class) { MethodBody body = new MethodBody(null); var ins = body.Instructions; Register rthis = body.AllocateRegister(RCategory.Argument, RType.Object); Register rInvList = body.AllocateRegister(RCategory.Argument, RType.Object); Register rInvListLen = body.AllocateRegister(RCategory.Argument, RType.Value); Register result = body.AllocateRegister(RCategory.Temp, RType.Object); List<Register> ctorArgs = new List<Register> { result }; if (instanceField != null) { var rInstance = body.AllocateRegister(RCategory.Temp, RType.Object); ins.Add(new Instruction(RCode.Iget_object, instanceField, new[] {rInstance, rthis})); ctorArgs.Add(rInstance); } foreach (var field in GenericTypeFields) { var r = body.AllocateRegister(RCategory.Temp, RType.Object); ins.Add(new Instruction(RCode.Iget_object, field, new[] { r, rthis })); ctorArgs.Add(r); } ins.Add(new Instruction(RCode.New_instance, @class, new[] {result})); ins.Add(new Instruction(RCode.Invoke_direct, ctor, ctorArgs.ToArray())); var invListLengthReference = new FieldReference(multicastDelegateClass, "InvocationListLength", PrimitiveType.Int); var multicastDelegateArray = new ArrayType(multicastDelegateClass); var invListReference = new FieldReference(multicastDelegateClass, "InvocationList", multicastDelegateArray); ins.Add(new Instruction(RCode.Iput_object, invListReference, new []{ rInvList, result})); ins.Add(new Instruction(RCode.Iput, invListLengthReference, new[] { rInvListLen, result })); ins.Add(new Instruction(RCode.Return_object, null, new []{result})); return body; }
/// <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; }
/// <summary> /// Is other equal to this? /// </summary> public bool Equals(FieldReference other) { return((other != null) && Owner.Equals(other.Owner) && Name.Equals(other.Name) && Type.Equals(other.Type)); }