void InitObject(object data) { if (data is TypeReference typeRef) { var dataType = CilType.From(typeRef); var fromType = code.StackMap.PopStack(CilMain.Where); if (CodeSpan.Clear(fromType, dataType, code)) { return; } if (dataType.IsGenericParameter || (dataType.IsValueClass && dataType.Equals(fromType))) { if (dataType.IsGenericParameter) { code.NewInstruction(0xC0 /* checkcast */, CilType.SystemValueType, null); } code.NewInstruction(0xB6 /* invokevirtual */, CilType.SystemValueType, CilMethod.ValueClear); return; } } throw new InvalidProgramException(); }
void StoreObject(object data) { if (data is TypeReference typeRef) { var dataType = CilType.From(typeRef); var valueType = (CilType)code.StackMap.PopStack(CilMain.Where); var intoType = (CilType)code.StackMap.PopStack(CilMain.Where); if (CodeSpan.LoadStore(false, intoType, null, dataType, code)) { return; } if ((!dataType.IsReference) && intoType is BoxedType intoBoxedType && dataType.PrimitiveType == intoBoxedType.UnboxedType.PrimitiveType) { // 'stobj primitive' with a primitive value on the stack intoBoxedType.SetValueOV(code); return; } code.StackMap.PushStack(intoType); code.StackMap.PushStack(valueType); GenericUtil.ValueCopy(dataType, code, true); code.StackMap.PopStack(CilMain.Where); code.StackMap.PopStack(CilMain.Where); } else { throw new InvalidProgramException(); } }
static byte TestEq(JavaCode code, JavaType stackTop, JavaType stackTop2, Mono.Cecil.Cil.Instruction cilInst) { if (stackTop.IsReference || stackTop2.IsReference) { byte cmpOp = CodeSpan.CompareEq(stackTop, stackTop2, cilInst, code); if (cmpOp == 0) { cmpOp = 0xA5; // if_acmpeq (reference) } return(cmpOp); } if (stackTop2.IsIntLike && (stackTop.PrimitiveType == TypeCode.Int32 || stackTop.PrimitiveType == TypeCode.UInt32 || stackTop.PrimitiveType == TypeCode.Int16 || stackTop.PrimitiveType == TypeCode.UInt16 || stackTop.PrimitiveType == TypeCode.SByte || stackTop.PrimitiveType == TypeCode.Byte || stackTop.PrimitiveType == TypeCode.Char || stackTop.PrimitiveType == TypeCode.Boolean)) { return(0x9F); // if_icmpeq } byte op; if ((stackTop.PrimitiveType == TypeCode.Int64 || stackTop.PrimitiveType == TypeCode.UInt64) && (stackTop2.PrimitiveType == TypeCode.Int64 || stackTop2.PrimitiveType == TypeCode.UInt64)) { op = 0x94; // lcmp (long) } else if (stackTop.PrimitiveType == TypeCode.Single && stackTop2.PrimitiveType == TypeCode.Single) { op = 0x95; // fcmpl (float) } else if (stackTop.PrimitiveType == TypeCode.Double && stackTop2.PrimitiveType == TypeCode.Double) { op = 0x97; // dcmpl (double) } else { throw new Exception($"incompatible types '{stackTop}' and '{stackTop2}'"); } code.NewInstruction(op, null, null); return(0x99); // ifeq == zero }
void PopObjectAndLoadFromSpan(CilType fldClass) { var stackTop = stackMap.PopStack(CilMain.Where); stackMap.PushStack(stackTop); if (fldClass.IsValueClass && CodeSpan.LoadStore(true, (CilType)stackTop, null, fldClass, code)) { stackMap.PopStack(CilMain.Where); code.NewInstruction(0xC0 /* checkcast */, fldClass, null); } // pop object reference stackMap.PopStack(CilMain.Where); }
void LoadObject(Code cilOp, object data) { if (data is TypeReference typeRef) { var dataType = CilType.From(typeRef); var fromType = (CilType)code.StackMap.PopStack(CilMain.Where); if (CodeSpan.LoadStore(true, fromType, null, dataType, code)) { return; } if ((!dataType.IsReference) && cilOp == Code.Ldobj && fromType is BoxedType fromBoxedType && dataType.PrimitiveType == fromBoxedType.UnboxedType.PrimitiveType) { // 'ldobj primitive' with a corresponding boxed type on the stack. // we implement by unboxing the boxed type into a primitive value. fromBoxedType.GetValue(code); stackMap.PushStack(fromBoxedType.UnboxedType); return; } if (dataType.IsGenericParameter || (dataType.IsValueClass && dataType.Equals(fromType))) { code.StackMap.PushStack(dataType); if (SkipClone(cilInst.Next, fromType)) { // see below for the several cases where we determine // that we can safely avoid making a clone of the value code.NewInstruction(0x00 /* nop */, null, null); } else if (dataType.IsGenericParameter) { GenericUtil.ValueClone(code); } else if (cilOp == Code.Ldobj) { code.NewInstruction(0x00 /* nop */, null, null); } else { CilMethod.ValueMethod(CilMethod.ValueClone, code); } return; } if (dataType.IsReference && cilOp == Code.Box) { // 'box' is permitted on reference types, we treat it as a cast code.StackMap.PushStack(fromType); CastToClass(data); return; } if (!dataType.IsReference) { var boxedType = new BoxedType(dataType, false); code.StackMap.PushStack(boxedType); boxedType.BoxValue(code); return; } } throw new InvalidProgramException(); bool SkipClone(Mono.Cecil.Cil.Instruction next, CilType checkType) { if (checkType.IsByReference) { return(true); } if (next == null) { return(false); } var op = next.OpCode.Code; if (IsBrTrueBrFalseIsInst(op)) { // if 'ldobj' or 'box' is followed by a check for null, // we don't actually need to clone just for the test return(true); } if (op == Code.Box) { if (next.Operand is TypeReference nextTypeRef) { // 'ldobj' may be followed by 'box', to load the value // of a byref value type, and then box it into an object. // effectively we only need to clone once, in such a case. return(CilType.From(nextTypeRef).Equals(checkType)); } } var(storeType, _) = locals.GetLocalFromStoreInst(op, next.Operand); if (storeType != null) { // 'ldobj' or 'box' may be followed by a store instruction. // if storing into a variable of the same value type, the // next instruction will copy the value, so skip clone. return(storeType.Equals(checkType)); } if (op == Code.Ret && checkType.IsClonedAtTop) { // if the value on the stack was cloned/boxed at the top of // the method, then we can avoid clone and return it directly. // see also: CilType.MakeClonedAtTop and its callers. return(true); } if (op == Code.Unbox_Any) { if (next.Operand is TypeReference nextTypeRef) { // 'ldobj' or 'box' may be followed by 'unbox' and // then one of the instructions above, e.g. 'brtrue' // or 'stloc'. we still want to detect such a case // and prevent a needless clone. return(SkipClone(next.Next, CilType.From(nextTypeRef))); } } return(false); } }
void CallInstructionTranslator() { switch (cilOp) { case Code.Nop: case Code.Volatile: case Code.Constrained: case Code.Unaligned: case Code.Readonly: case Code.Tail: code.NewInstruction(0x00 /* nop */, null, null); break; case Code.Break: code.NewInstruction(0xCA /* debugger break */, null, null); break; case Code.Pop: case Code.Dup: PopOrDupStack(cilOp); break; case Code.Ldarg_0: case Code.Ldarg_1: case Code.Ldarg_2: case Code.Ldarg_3: case Code.Ldloc_0: case Code.Ldloc_1: case Code.Ldloc_2: case Code.Ldloc_3: case Code.Ldarg: case Code.Ldarg_S: case Code.Ldloc: case Code.Ldloc_S: locals.LoadValue(cilOp, cilInst.Operand); break; case Code.Stloc_0: case Code.Stloc_1: case Code.Stloc_2: case Code.Stloc_3: case Code.Starg: case Code.Starg_S: case Code.Stloc: case Code.Stloc_S: locals.StoreValue(cilOp, cilInst.Operand); break; case Code.Ldarga: case Code.Ldloca: case Code.Ldarga_S: case Code.Ldloca_S: locals.LoadAddress(cilInst.Operand); break; case Code.Ldc_I4_M1: case Code.Ldc_I4_0: case Code.Ldc_I4_1: case Code.Ldc_I4_2: case Code.Ldc_I4_3: case Code.Ldc_I4_4: case Code.Ldc_I4_5: case Code.Ldc_I4_6: case Code.Ldc_I4_7: case Code.Ldc_I4_8: case Code.Ldc_I4_S: case Code.Ldc_I4: case Code.Ldc_I8: case Code.Ldc_R4: case Code.Ldc_R8: case Code.Ldstr: case Code.Ldnull: LoadConstant(cilOp, cilInst); break; case Code.Ldfld: case Code.Ldflda: case Code.Stfld: case Code.Ldsfld: case Code.Ldsflda: case Code.Stsfld: LoadStoreField(cilOp, cilInst.Operand); break; case Code.Initobj: InitObject(cilInst.Operand); break; case Code.Newobj: case Code.Call: case Code.Callvirt: case Code.Ret: CallMethod(cilOp, cilInst.Operand); break; case Code.Castclass: CastToClass(cilInst.Operand); break; case Code.Ldtoken: LoadToken(); break; case Code.Unbox: case Code.Unbox_Any: UnboxObject(cilOp, cilInst.Operand); break; case Code.Ldobj: case Code.Box: LoadObject(cilOp, cilInst.Operand); break; case Code.Stobj: StoreObject(cilInst.Operand); break; case Code.Br: case Code.Br_S: case Code.Brtrue: case Code.Brtrue_S: case Code.Beq: case Code.Beq_S: case Code.Bgt: case Code.Bgt_S: case Code.Bgt_Un: case Code.Bgt_Un_S: case Code.Blt: case Code.Blt_S: case Code.Blt_Un: case Code.Blt_Un_S: CodeCompare.Straight(code, cilOp, locals, cilInst); break; case Code.Brfalse: case Code.Brfalse_S: case Code.Bne_Un: case Code.Bne_Un_S: case Code.Ble: case Code.Ble_S: case Code.Ble_Un: case Code.Ble_Un_S: case Code.Bge: case Code.Bge_S: case Code.Bge_Un: case Code.Bge_Un_S: CodeCompare.Opposite(code, cilOp, locals, cilInst); break; case Code.Cgt: case Code.Cgt_Un: case Code.Ceq: case Code.Clt: case Code.Clt_Un: CodeCompare.Compare(code, cilOp, cilInst); break; case Code.Switch: CodeCompare.Switch(code, cilInst); break; case Code.Isinst: CodeCompare.Instance(code, locals, cilInst); break; case Code.Conv_I1: case Code.Conv_Ovf_I1: case Code.Conv_Ovf_I1_Un: case Code.Conv_I2: case Code.Conv_Ovf_I2: case Code.Conv_Ovf_U2_Un: case Code.Conv_I4: case Code.Conv_Ovf_I4: case Code.Conv_Ovf_I4_Un: case Code.Conv_I8: case Code.Conv_Ovf_I8: case Code.Conv_Ovf_I8_Un: case Code.Conv_U1: case Code.Conv_Ovf_U1: case Code.Conv_Ovf_U1_Un: case Code.Conv_U2: case Code.Conv_Ovf_U2: case Code.Conv_Ovf_I2_Un: case Code.Conv_U4: case Code.Conv_Ovf_U4: case Code.Conv_Ovf_U4_Un: case Code.Conv_U8: case Code.Conv_Ovf_U8: case Code.Conv_Ovf_U8_Un: case Code.Conv_I: case Code.Conv_Ovf_I: case Code.Conv_Ovf_I_Un: case Code.Conv_U: case Code.Conv_Ovf_U: case Code.Conv_Ovf_U_Un: case Code.Conv_R4: case Code.Conv_R8: case Code.Conv_R_Un: CodeNumber.Conversion(code, cilOp, cilInst); break; case Code.Add: case Code.Sub: case Code.Mul: case Code.Neg: case Code.Div: case Code.Div_Un: case Code.Rem: case Code.Rem_Un: case Code.And: case Code.Or: case Code.Xor: case Code.Not: case Code.Shl: case Code.Shr: case Code.Shr_Un: case Code.Add_Ovf: case Code.Add_Ovf_Un: case Code.Sub_Ovf: case Code.Sub_Ovf_Un: case Code.Mul_Ovf: case Code.Mul_Ovf_Un: CodeNumber.Calculation(code, cilOp, cilInst); break; case Code.Ldind_I1: case Code.Ldind_U1: case Code.Ldind_I2: case Code.Ldind_U2: case Code.Ldind_I4: case Code.Ldind_U4: case Code.Ldind_I8: case Code.Ldind_I: case Code.Ldind_R4: case Code.Ldind_R8: case Code.Ldind_Ref: case Code.Stind_I1: case Code.Stind_I2: case Code.Stind_I4: case Code.Stind_I8: case Code.Stind_I: case Code.Stind_R4: case Code.Stind_R8: case Code.Stind_Ref: CodeNumber.Indirection(code, cilOp); break; case Code.Throw: case Code.Rethrow: case Code.Leave: case Code.Leave_S: case Code.Endfinally: case Code.Endfilter: exceptions.Translate(cilInst); break; case Code.Newarr: arrays.New(cilInst.Operand); break; case Code.Ldlen: arrays.Length(); break; case Code.Ldelema: arrays.Address(null, cilInst); break; case Code.Ldelem_I1: case Code.Ldelem_U1: case Code.Ldelem_I2: case Code.Ldelem_U2: case Code.Ldelem_I4: case Code.Ldelem_U4: case Code.Ldelem_I8: case Code.Ldelem_I: case Code.Ldelem_R4: case Code.Ldelem_R8: case Code.Ldelem_Ref: case Code.Ldelem_Any: arrays.Load(cilOp, cilInst.Operand, cilInst); break; case Code.Stelem_I1: case Code.Stelem_I2: case Code.Stelem_I4: case Code.Stelem_I8: case Code.Stelem_I: case Code.Stelem_R4: case Code.Stelem_R8: case Code.Stelem_Any: case Code.Stelem_Ref: arrays.Store(cilOp, cilInst); break; case Code.Ldftn: case Code.Ldvirtftn: Delegate.LoadFunction(code, cilInst); break; case Code.Sizeof: CodeSpan.Sizeof(cilInst.Operand, code); break; case Code.Localloc: CodeSpan.Localloc(code); break; /* instructions not handled: * Jmp, Calli, Cpobj, Refanyval, Ckfinite, Mkrefany, Arglist, * Tail, Cpblk, Initblk, No, Refanytype, */ default: throw new InvalidProgramException(); } }
static byte TestGtLt(JavaCode code, JavaType stackTop, JavaType stackTop2, bool greater, bool unsigned_unordered) { byte op; // // for floating point, normal comparison returns 0 if either value // is NaN, while unordered comparison returns 1. we have fcmp/dcmp // variants which return either 1 or -1. following the comparison, // we have ifgt/iflt to check if the result is either greater than // or less than 0. we consider all this when picking the opcode: // // test normal compare unordered compare // greater than ifgt xcmpl xcmpg // less than iflt xcmpg xcmpl // if (stackTop.PrimitiveType == TypeCode.Single) { op = (byte)((greater != unsigned_unordered) ? 0x95 // fcmpl : 0x96); // fcmpg } else if (stackTop.PrimitiveType == TypeCode.Double) { op = (byte)((greater != unsigned_unordered) ? 0x97 // dcmpl : 0x98); // dcmpg } // // for unsigned integer comparison, we use library function // system.UInt{32,64}.CompareTo, followed by ifgt/iflt // else if (unsigned_unordered && stackTop.PrimitiveType != TypeCode.Char) { char typeChar; int typeBits; string typeName = null; if (stackTop.PrimitiveType == TypeCode.SByte || stackTop.PrimitiveType == TypeCode.Byte) { typeChar = 'B'; typeBits = 0; typeName = "Byte"; } else if (stackTop.PrimitiveType == TypeCode.Int16 || stackTop.PrimitiveType == TypeCode.UInt16) { typeChar = 'S'; typeBits = 16; } else if (stackTop.PrimitiveType == TypeCode.Int32 || stackTop.PrimitiveType == TypeCode.UInt32) { typeChar = 'I'; typeBits = 32; } else if (stackTop.PrimitiveType == TypeCode.Int64 || stackTop.PrimitiveType == TypeCode.UInt64) { typeChar = 'J'; typeBits = 64; } else if (greater && stackTop.Equals(JavaStackMap.Null)) { // per MS CLI Partition III table 4 note 2, 'cgt.un' // can be used to check for a non-null reference return(0xA6); // if_acmpne } else { if (CodeSpan.CompareGtLt(stackTop, stackTop2, code)) { return((byte)(greater ? 0x9D // ifgt : 0x9B)); // iflt } throw new InvalidProgramException(); } if (typeBits != 0) { typeName = "UInt" + typeBits.ToString(); } code.NewInstruction(0xB8 /* invokestatic */, new JavaType(0, 0, $"system.{typeName}"), new JavaMethodRef("CompareTo", $"({typeChar}{typeChar})I", CilMain.Where)); /* * new JavaType(0, 0, $"java.lang.{typeName}"), * new JavaMethodRef("compareUnsigned", * $"({typeChar}{typeChar})I", CilMain.Where));*/ op = 0; } // // for signed long comparison, we use lcmp followed by ifgt/iflt // else if (stackTop.PrimitiveType == TypeCode.Int64 || stackTop.PrimitiveType == TypeCode.UInt64) { op = 0x94; // lcmp (long) } // // for signed integer comparison, we have if_icmplt/if_icmpgt // which directly compare two integers and branch // else if (stackTop.PrimitiveType == TypeCode.Int32 || stackTop.PrimitiveType == TypeCode.UInt32 || stackTop.PrimitiveType == TypeCode.Int16 || stackTop.PrimitiveType == TypeCode.UInt16 || stackTop.PrimitiveType == TypeCode.SByte || stackTop.PrimitiveType == TypeCode.Byte || stackTop.PrimitiveType == TypeCode.Char || stackTop.PrimitiveType == TypeCode.Boolean) { return((byte)(greater ? 0xA3 // if_icmpgt : 0xA1)); // if_icmplt } else { throw new InvalidProgramException(); } // // return the selected opcode // if (op != 0) { code.NewInstruction(op, null, null); } return((byte)(greater ? 0x9D // ifgt : 0x9B)); // iflt }
public static void Indirection(JavaCode code, Code cilOp) { var(name, opcodeType) = IndirectOpCodeToNameAndType(cilOp); bool isRef = opcodeType.Equals(JavaType.ObjectType); bool isLoad; if (cilOp >= Code.Ldind_I1 && cilOp <= Code.Ldind_Ref) { isLoad = true; } else { isLoad = false; var valueType = code.StackMap.PopStack(CilMain.Where); if (valueType.IsReference != isRef) { throw new InvalidProgramException(); } } var stackTop = (CilType)code.StackMap.PopStack(CilMain.Where); if (stackTop.IsGenericParameter) { if (isLoad) { var resultType = GenericUtil.CastMaybeGeneric(stackTop, false, code); if (resultType == stackTop && (!stackTop.Equals(JavaType.ObjectType))) { code.NewInstruction(0xC0 /* checkcast */, stackTop.AsWritableClass, null); resultType = stackTop; } code.StackMap.PushStack(resultType); } else { code.NewInstruction(0x5F /* swap */, null, null); GenericUtil.ValueCopy(stackTop, code); } return; } // // non-generic object reference // var boxedType = stackTop as BoxedType; if (boxedType == null || boxedType.IsBoxedReference != isRef) { if (CodeSpan.LoadStore(isLoad, stackTop, opcodeType, null, code)) { return; } if (object.ReferenceEquals(stackTop, CodeArrays.GenericArrayType)) { // a byref parameter T[] gets translated to java.lang.Object, // so we have to explicitly cast it to system.Reference boxedType = new BoxedType(stackTop, false); code.NewInstruction(0x5F /* swap */, null, null); code.NewInstruction(0xC0 /* checkcast */, boxedType.AsWritableClass, null); code.NewInstruction(0x5F /* swap */, null, null); } else { throw new ArgumentException($"incompatible type '{stackTop}'"); } } var unboxedType = boxedType.UnboxedType; var unboxedTypeCode = unboxedType.IsReference ? 0 : unboxedType.PrimitiveType; JavaMethodRef method; if (CompareIndirectTypes(unboxedTypeCode, opcodeType.PrimitiveType)) { // indirect access to a primitive or reference type, with a // reference type that represents the boxed form of the same type. if (isLoad) { boxedType.GetValue(code); if (unboxedType.IsReference) { // if we know the type of indirected value, cast to it if (!unboxedType.Equals(JavaType.ObjectType)) { code.NewInstruction(0xC0 /* checkcast */, unboxedType.AsWritableClass, null); } } else { unboxedType = CilType.From(opcodeType); } code.StackMap.PushStack(unboxedType); } else { // if we are storing a real array into a boxed reference of // e.g., system.Array, then we have to create an array proxy CodeArrays.MaybeGetProxy(CodeArrays.GenericArrayType, unboxedType, code); boxedType.SetValueOV(code); } return; } // indirect access to a primitive value from a reference type that // represents some other a primitive value; for example ldind.r4 // from a system.Int32. we call the "CodeNumber.Indirection methods" // helpers, defined in all baselib primitives, to assist. if (opcodeType.IsIntLike) { opcodeType = JavaType.IntegerType; } if (isLoad) { method = new JavaMethodRef("Get_" + name, opcodeType); code.StackMap.PushStack(CilType.From(opcodeType)); } else { method = new JavaMethodRef("Set_" + name, JavaType.VoidType, opcodeType); } code.NewInstruction(0xB6 /* invokevirtual */, boxedType, method); }
public static void Calculation(JavaCode code, Code cilOp, Mono.Cecil.Cil.Instruction cilInst) { if (cilOp == Code.And && CodeBuilder.IsAndBeforeShift(cilInst.Previous, code)) { // jvm shift instructions mask the shift count, so // eliminate AND-ing with 31 and 63 prior to a shift code.NewInstruction(0x00 /* nop */, null, null); return; } var stackTop1 = code.StackMap.PopStack(CilMain.Where); if (cilOp == Code.Sub && CodeSpan.SubOffset(stackTop1, code)) { return; } var type1 = GetNumericTypeCode(stackTop1); if (cilOp == Code.Not) { BitwiseNot(code, type1); return; } byte op; if (cilOp == Code.Neg) { op = 0x74; // ineg } else { var stackTop2 = code.StackMap.PopStack(CilMain.Where); if ((cilOp == Code.Add || cilOp == Code.Add_Ovf_Un) && CodeSpan.AddOffset(stackTop1, stackTop2, code)) { return; } char kind; var type2 = type1; type1 = GetNumericTypeCode(stackTop2); switch (cilOp) { case Code.Add: op = 0x60; kind = 'A'; break; // iadd case Code.Sub: op = 0x64; kind = 'A'; break; // isub case Code.Mul: op = 0x68; kind = 'A'; break; // imul case Code.Div: op = 0x6C; kind = 'A'; break; // idiv case Code.Rem: op = 0x70; kind = 'A'; break; // irem case Code.And: op = 0x7E; kind = 'L'; break; // iand case Code.Or: op = 0x80; kind = 'L'; break; // ior case Code.Xor: op = 0x82; kind = 'L'; break; // ixor case Code.Shl: op = 0x78; kind = 'S'; break; // ishl case Code.Shr: op = 0x7A; kind = 'S'; break; // ishr case Code.Shr_Un: op = 0x7C; kind = 'S'; break; // iushr case Code.Div_Un: case Code.Rem_Un: op = 0x00; kind = 'U'; break; case Code.Add_Ovf: case Code.Sub_Ovf: case Code.Mul_Ovf: case Code.Add_Ovf_Un: case Code.Sub_Ovf_Un: case Code.Mul_Ovf_Un: op = 0x00; kind = 'A'; break; default: throw new InvalidProgramException(); } bool ok = true; if (kind == 'S') { // second operand must be integer shift count if (type2 != TypeCode.Int32) { ok = false; } } else { // logical and arithmetic operands must be same type if (type1 != type2) { if (kind == 'A' && type1 == TypeCode.Int64 && type2 == TypeCode.Int32) { // special case: convert the second operand to Int64 code.NewInstruction(0x85 /* i2l */, null, null); code.StackMap.PushStack(JavaType.LongType); code.StackMap.PushStack(JavaType.LongType); code.StackMap.PopStack(CilMain.Where); code.StackMap.PopStack(CilMain.Where); } else if (kind == 'A' && type1 == TypeCode.Int32 && type2 == TypeCode.Int64) { // special case: convert the second operand to Int32 code.NewInstruction(0x88 /* l2i */, null, null); } else { ok = false; } } if (kind == 'L') { // logical operation requires integer operands if (type1 != TypeCode.Int32 && type1 != TypeCode.Int64) { ok = false; } } } if (!ok) { throw new Exception($"unexpected opcode or operands ({type1} and {type2})"); } if (kind == 'A' && op == 0) { OverflowArithmetic(code, type1, cilOp); return; } if (kind == 'U') { UnsignedDivide(code, type1, (cilOp == Code.Rem_Un)); return; } } if (type1 == TypeCode.Int64) { op++; // ixxx -> lxxx } else if (type1 == TypeCode.Single) { op += 2; // ixxx -> fxxx } else if (type1 == TypeCode.Double) { op += 3; // ixxx -> dxxx } code.NewInstruction(op, null, null); code.StackMap.PushStack(CilType.From(new JavaType(type1, 0, null))); }
public void Address(CilType arrayType, Mono.Cecil.Cil.Instruction inst) { stackMap.PopStack(CilMain.Where); // index if (arrayType == null) { arrayType = (CilType)stackMap.PopStack(CilMain.Where); } else { stackMap.PopStack(CilMain.Where); // array } var elemType = arrayType.AdjustRank(-arrayType.ArrayRank); if (inst != null && inst.Next != null) { var(spanType, _) = locals.GetLocalFromStoreInst( inst.Next.OpCode.Code, inst.Next.Operand); if (CodeSpan.AddressArray(elemType, spanType, code)) { return; } } if (elemType.IsReference) { if (elemType.IsGenericParameter) { // call system.Array.Box(object array, int index) code.NewInstruction(0xB8 /* invokestatic */, SystemArrayType, new JavaMethodRef("Box", CilType.SystemValueType, JavaType.ObjectType, JavaType.IntegerType)); } else if (elemType.IsValueClass) { code.NewInstruction(0x32 /* aaload */, null, null); } else { // call system.Reference.Box(object a, int i) elemType = new BoxedType(elemType, false); code.NewInstruction(0xB8 /* invokestatic */, elemType, new JavaMethodRef("Box", elemType, JavaType.ObjectType, JavaType.IntegerType)); } stackMap.PushStack(elemType); } else { // call system.(PrimitiveType).Box(primitiveType[] a, int i) var typeCode = elemType.PrimitiveType; stackMap.PushStack(new BoxedType(elemType, false)); arrayType = elemType.AdjustRank(1); elemType = elemType.AsWritableClass; code.NewInstruction(0xB8 /* invokestatic */, elemType, new JavaMethodRef("Box", elemType, arrayType, JavaType.IntegerType)); } }