public static void CompareEq(JavaType stackTop, JavaType stackTop2, Mono.Cecil.Cil.Instruction cilInst, JavaCode code) { if (stackTop.Equals(SpanType) && (stackTop2.PrimitiveType == TypeCode.Int64 || stackTop2.PrimitiveType == TypeCode.UInt64)) { // compare Span with long throw new InvalidProgramException(); } if (stackTop2.Equals(SpanType) && (stackTop.PrimitiveType == TypeCode.Int64 || stackTop.PrimitiveType == TypeCode.UInt64)) { if (cilInst.Previous == null || cilInst.Previous.OpCode.Code != Code.Conv_U || cilInst.Previous.Previous == null || cilInst.Previous.Previous.OpCode.Code != Code.Ldc_I4_0) { // make sure the program is comparing the span address against // a zero value, which we can convert to a null reference. // ldarg.1 (span argument) // ldc.i4.0 // conv.u // bne.un label throw new InvalidProgramException(); } // compare long with Span code.NewInstruction(0x58 /* pop2 */, null, null); code.NewInstruction(0x01 /* aconst_null */, null, null); } }
static int ConvertToLong(JavaCode code, TypeCode oldType, TypeCode newType) { if (oldType == TypeCode.Int64 || oldType == TypeCode.UInt64) { return(0x00); // nop } if (oldType == TypeCode.Double) { return(0x8F); // d2l } if (oldType == TypeCode.Single) { return(0x8C); // f2l } if (newType == TypeCode.UInt64) { code.NewInstruction(0x85 /* i2l */, null, null); code.StackMap.PushStack(JavaType.LongType); long maskValue = (oldType == TypeCode.Byte) ? 0xFF : (oldType == TypeCode.UInt16) ? 0xFFFF : 0xFFFFFFFF; code.NewInstruction(0x12 /* ldc */, null, (long)maskValue); code.StackMap.PushStack(JavaType.LongType); code.StackMap.PopStack(CilMain.Where); code.StackMap.PopStack(CilMain.Where); return(0x7F); // land } CilMain.MakeRoomForCategory2ValueOnStack(code); return(0x85); // i2l }
public static void Instance(JavaCode code, CodeLocals locals, Mono.Cecil.Cil.Instruction cilInst) { if (cilInst.Operand is TypeReference cilType && cilInst.Next != null) { var stackTop = (CilType)code.StackMap.PopStack(CilMain.Where); if (!stackTop.IsReference) { throw new InvalidProgramException(); // top of stack is a primitive type } var castType = (CilType)CilType.From(cilType); JavaType castClass = CilType.From(cilType).AsWritableClass; if (GenericUtil.ShouldCallGenericCast(stackTop, castType) || castType.IsGenericParameter) { code.StackMap.PushStack(stackTop); // casting to a generic type is done via GenericType.TestCast GenericUtil.CastToGenericType(cilType, 0, code); code.StackMap.PopStack(CilMain.Where); // stackTop if (!castType.IsGenericParameter) { code.NewInstruction(0xC0 /* checkcast */, castClass, null); } code.StackMap.PushStack(castClass); } else if (CodeArrays.CheckCast(castType, false, code)) { // if casting to Object[], ValueType[], to an array of // interface type, or to an array of a generic parameter, // then CodeArrays.CheckCast already generated a call to // system.Array.CheckCast in baselib, and we are done here if (!castType.IsGenericParameter) { // avoid cast since T[] might be a primitive array code.NewInstruction(0xC0 /* checkcast */, castClass, null); } code.StackMap.PushStack(castClass); } // // the cil 'isinst' casts the operand to the requested class, // but the jvm 'instanceof' only returns zero or one. so we // also use 'checkcast' to get the jvm to acknowledge the cast // // however, if the cil 'isinst' is immediately followed by // 'brtrue' or 'brfalse' then we don't have to actually cast // else if (!TestForBranch(code, castClass, cilInst.Next)) { ushort nextLabel = (ushort)cilInst.Next.Offset; int localIndex = locals.GetTempIndex(stackTop); TestAndCast(code, castClass, stackTop, nextLabel, localIndex); locals.FreeTempIndex(localIndex); } }
static void LoadGeneric(CilType loadType, int loadIndex, JavaCode code) { if (loadIndex < 0) { // generic type is accessible through the generic-type member field code.NewInstruction(0x19 /* aload */, null, (int)0); code.NewInstruction(0xB4 /* getfield */, loadType, ConcreteTypeField); code.StackMap.PushStack(ConcreteTypeField.Type); code.NewInstruction(0x12 /* ldc */, null, -loadIndex - 1); code.StackMap.PushStack(JavaType.IntegerType); // call system.RuntimeType.Argument(int typeArgumentIndex) code.NewInstruction(0xB6 /* invokevirtual */, CilType.SystemRuntimeTypeType, new JavaMethodRef("Argument", CilType.SystemTypeType, JavaType.IntegerType)); code.StackMap.PopStack(CilMain.Where); // integer code.StackMap.PopStack(CilMain.Where); // generic type field code.StackMap.PushStack(CilType.SystemTypeType); // type result } else if (loadIndex > 0) { // generic type is accessible through a parameter code.NewInstruction(0x19 /* aload */, null, (int)(loadIndex - 1)); code.StackMap.PushStack(CilType.SystemTypeType); } else { // generic type is known to be a constant LoadMaybeGeneric(loadType, code); } }
public static void LoadParameterlessGeneric(CilType loadType, JavaCode code) { code.NewInstruction(0x12 /* ldc */, loadType.AsWritableClass, null); code.NewInstruction(0xB8 /* invokestatic */, CilType.SystemRuntimeTypeType, new JavaMethodRef("GetType", CilType.SystemTypeType, JavaType.ClassType)); code.StackMap.PushStack(CilType.SystemTypeType); }
static byte TestBool(JavaCode code, JavaType stackTop) { if (stackTop.IsReference) { return(0xC7); // ifnonnull } if (stackTop.PrimitiveType == TypeCode.Int64 || stackTop.PrimitiveType == TypeCode.UInt64 || 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) { if (stackTop.PrimitiveType == TypeCode.Int64 || stackTop.PrimitiveType == TypeCode.UInt64) { code.NewInstruction(0x09 /* lconst_0 (long) */, null, null); code.NewInstruction(0x94 /* lcmp (long) */, null, null); } return(0x9A); // ifne != zero } throw new InvalidProgramException(); }
public static bool LoadStore(bool isLoad, CilType stackTop, JavaType opcodeType, CilType dataType, JavaCode code) { if (stackTop.Equals(SpanType) && code.Method.Class.Name != SpanType.ClassName) { string opcodeDescr; if (opcodeType == null) { opcodeType = CilType.SystemValueType; opcodeDescr = ""; // at this point we should have been called from LoadObject or // StoreObject in CodeMisc to handle a ldobj/stobj instruction, // so make sure the pointer-span element is a value type if (dataType.IsGenericParameter || (!dataType.IsValueClass)) { throw new InvalidProgramException(); } code.NewInstruction(0x12 /* ldc */, dataType.AsWritableClass, null); // make sure the stack has room for three parameters: // 'this', value reference (in case of Store), and class code.StackMap.PushStack(JavaType.ObjectType); code.StackMap.PushStack(JavaType.ObjectType); code.StackMap.PushStack(JavaType.ObjectType); code.StackMap.PopStack(CilMain.Where); code.StackMap.PopStack(CilMain.Where); code.StackMap.PopStack(CilMain.Where); } else { if (opcodeType.Equals(JavaType.ShortType) && stackTop.GenericParameters != null && stackTop.GenericParameters[0].Equals(JavaType.CharacterType)) { opcodeType = JavaType.CharacterType; } opcodeDescr = opcodeType.ToDescriptor(); } var voidType = JavaType.VoidType; var spanMethod = isLoad ? (new JavaMethodRef("Load" + opcodeDescr, opcodeType)) : (new JavaMethodRef("Store" + opcodeDescr, voidType, opcodeType)); if (opcodeDescr == "") { spanMethod.Parameters.Add(new JavaFieldRef("", JavaType.ClassType)); } code.NewInstruction(0xB6 /* invokevirtual */, SpanType, spanMethod); if (isLoad) { code.StackMap.PushStack(CilType.From(opcodeType)); } return(true); } return(false); }
public static bool Address(CilType fromType, CilType intoType, JavaCode code) { if (intoType.Equals(SpanType) && (!fromType.Equals(SpanType))) { // allow assignment of null to clear the pointer if (fromType.Equals(JavaStackMap.Null)) { return(true); } // allow assignment of native int (presumably zero) bool callAssign = false; bool pushNullType = true; JavaType argType = fromType; JavaType retType = SpanType; if ((!fromType.IsReference) && fromType.PrimitiveType == TypeCode.UInt64) { callAssign = true; } else if (intoType.GenericParameters != null) { // allow assignment when the types match callAssign = intoType.GenericParameters[0].Equals(fromType) || fromType.JavaName == intoType.GenericParameters[0].JavaName; // for arbitrary value types, call a Assign(ValueType) if (fromType.IsValueClass) { argType = retType = CilType.SystemValueType; GenericUtil.LoadMaybeGeneric(fromType, code); pushNullType = false; } } if (callAssign) { if (pushNullType) { code.NewInstruction(0x01 /* aconst_null */, null, null); code.StackMap.PushStack(CilType.SystemTypeType); } code.NewInstruction(0xB8 /* invokestatic */, SpanType, new JavaMethodRef("Assign" + CilMain.EXCLAMATION, retType, argType, CilType.SystemTypeType)); code.NewInstruction(0xC0 /* checkcast */, SpanType, null); code.StackMap.PopStack(CilMain.Where); // null type return(true); } throw new Exception($"bad assignment of '{fromType.JavaName}' into pointer of '{intoType.GenericParameters[0].JavaName}'"); } return(false); }
public static CilType CastMaybeGeneric(CilType castType, bool valueOnly, JavaCode code) { if (!castType.IsGenericParameter) { return(castType); } if (!valueOnly) { GenericUtil.ValueLoad(code); } var genericMark = CilMain.GenericStack.Mark(); var(resolvedType, resolvedIndex) = CilMain.GenericStack.Resolve(castType.JavaName); if (resolvedIndex == 0) { if (valueOnly) { // this flag is set when called from LoadFieldAddress. we can cast // the generic field to the actual type only if it is a value type if (resolvedType.IsValueClass) { castType = resolvedType; code.NewInstruction(0xC0 /* checkcast */, castType.AsWritableClass, null); } else if (castType.IsByReference) { var boxedType = new BoxedType(resolvedType, false); code.NewInstruction(0xC0 /* checkcast */, boxedType, null); castType = boxedType; } } else { // this flag is clear whe called from LoadFieldValue and // PushMethodReturnType. we can cast to any known actual types. var arrayRank = castType.GetMethodGenericParameter()?.ArrayRank ?? 0; castType = (arrayRank == 0) ? resolvedType : resolvedType.AdjustRank(arrayRank); if (!castType.IsReference) { var boxedType = new BoxedType(castType, false); code.NewInstruction(0xC0 /* checkcast */, boxedType, null); boxedType.GetValue(code); } else { code.NewInstruction(0xC0 /* checkcast */, castType.AsWritableClass, null); } } } CilMain.GenericStack.Release(genericMark); return(castType); }
public static bool CheckCast(CilType castType, bool @throw, JavaCode code) { if (object.ReferenceEquals(castType, GenericArrayType) || (castType.IsArray && (castType.IsInterface || castType.IsGenericParameter || castType.ClassName == JavaType.ObjectType.ClassName || castType.ClassName == CilType.SystemValueType.ClassName))) { // if casting to Object[], ValueType[], to an array of interface type, // or to an array of a generic parameter, we can't rely on a simple // 'checkcast' or 'instanceof', because the jvm will permit the cast // of a value type array to the aforementioned reference types. // // instead, we generate a call to system.Array.CheckCast in baselib, // except if we are generating code for the system.Array class itself. if (code.Method.Class.Name.StartsWith("system.Array")) { return(false); } // note the caller of this method already popped the stack once. // which we have to undo that, before we push anything else. code.StackMap.PushStack(JavaType.ObjectType); // array var method = new JavaMethodRef("CheckCast", JavaType.ObjectType); method.Parameters.Add(new JavaFieldRef("", JavaType.ObjectType)); if (object.ReferenceEquals(castType, GenericArrayType) || castType.IsGenericParameter) { method.Parameters.Add(new JavaFieldRef("", CilType.SystemTypeType)); GenericUtil.LoadMaybeGeneric(castType, code); // CilType.SystemTypeType pushed to the stack } else { method.Parameters.Add(new JavaFieldRef("", JavaType.ClassType)); code.NewInstruction(0x12 /* ldc */, castType.AdjustRank(-1), null); code.StackMap.PushStack(JavaType.ClassType); } method.Parameters.Add(new JavaFieldRef("", JavaType.BooleanType)); code.NewInstruction(0x12 /* ldc */, null, (int)(@throw ? 1 : 0)); code.StackMap.PushStack(JavaType.IntegerType); // boolean code.NewInstruction(0xB8 /* invokestatic */, SystemArrayType, method); code.StackMap.PopStack(CilMain.Where); // boolean code.StackMap.PopStack(CilMain.Where); // class/type code.StackMap.PopStack(CilMain.Where); // array return(true); } return(false); }
public JavaType GetInnerObject(JavaCode code) { var innerType = new JavaType(0, 0, OldClassName); code.NewInstruction(0xB6 /* invokevirtual */, this, new JavaMethodRef("get", JavaType.ObjectType)); code.NewInstruction(0xC0 /* checkcast */, innerType, null); return(UnboxedType.IsEnum ? SystemEnumType : innerType); }
static void LoadGenericInstance_3_N(CilType loadType, int genericCount, List <JavaFieldRef> parameters, JavaCode code) { if (genericCount <= 8) { // handling for the less common case of a generic instace with // less than eight arguments. we don't check if the provided // type arguments are concrete or generic, and call a GetType() // override for the appropriate number of parameters. // note that the first class argument to GetType was alredy // inserted by our caller, LoadMaybeGeneric(). for (int i = 0; i < genericCount; i++) { LoadMaybeGeneric(loadType.GenericParameters[i], code); // next parameter always has type system.Type parameters.Add(new JavaFieldRef("", CilType.SystemTypeType)); } } else { // generic handling for the less common case of a generic instace // with more than eight arguments. we don't check if the provided // type arguments are concrete or generic. we build an array of // system.Type references, and call GetType(class, system.Type[]). // note that the first class argument to GetType was alredy // inserted by our caller, LoadMaybeGeneric(). var arrayOfType = CilType.SystemTypeType.AdjustRank(1); parameters.Add(new JavaFieldRef("", arrayOfType)); code.NewInstruction(0x12 /* ldc */, null, genericCount); code.StackMap.PushStack(JavaType.IntegerType); code.NewInstruction(0xBD /* anewarray */, CilType.SystemTypeType, null); code.StackMap.PopStack(CilMain.Where); code.StackMap.PushStack(arrayOfType); for (int i = 0; i < genericCount; i++) { code.NewInstruction(0x59 /* dup */, null, null); code.StackMap.PushStack(arrayOfType); code.NewInstruction(0x12 /* ldc */, null, i); code.StackMap.PushStack(JavaType.IntegerType); LoadMaybeGeneric(loadType.GenericParameters[i], code); code.NewInstruction(0x53 /* aastore */, null, null); code.StackMap.PopStack(CilMain.Where); code.StackMap.PopStack(CilMain.Where); code.StackMap.PopStack(CilMain.Where); } } }
public static void LoadMaybeGeneric(CilType loadType, JavaCode code) { if (loadType.IsGenericParameter) { LoadGeneric(loadType.JavaName, code); } else { // all GetType variants take a first parameter of type java.lang.Class List <JavaFieldRef> parameters = new List <JavaFieldRef>(); parameters.Add(new JavaFieldRef("", JavaType.ClassType)); int arrayRank = loadType.ArrayRank; if (arrayRank == 0 || (!loadType.IsGenericParameter)) { code.NewInstruction(0x12 /* ldc */, loadType.AsWritableClass, null); } else { // for a generic type T[], we want to load just the element T, // and then (see below) call MakeArrayType on the result var loadTypeElem = loadType.AdjustRank(-arrayRank); code.NewInstruction(0x12 /* ldc */, loadTypeElem.AsWritableClass, null); } code.StackMap.PushStack(JavaType.ClassType); if (loadType.HasGenericParameters) { LoadGenericInstance(loadType, parameters, code); } code.NewInstruction(0xB8 /* invokestatic */, CilType.SystemRuntimeTypeType, new JavaMethodRef("GetType", CilType.SystemTypeType, parameters)); for (int i = 0; i < parameters.Count; i++) { code.StackMap.PopStack(CilMain.Where); } code.StackMap.PushStack(CilType.SystemTypeType); if (arrayRank != 0 && loadType.IsGenericParameter) { code.NewInstruction(0x12 /* ldc */, null, (int)arrayRank); code.StackMap.PushStack(JavaType.IntegerType); code.NewInstruction(0xB6 /* invokevirtual */, CilType.SystemTypeType, new JavaMethodRef("MakeArrayType", CilType.SystemTypeType, JavaType.IntegerType)); code.StackMap.PopStack(CilMain.Where); } } }
static int ConvertToInteger(JavaCode code, TypeCode oldType, TypeCode newType) { if (oldType == TypeCode.Double) { if (newType == TypeCode.Int32 || oldType == TypeCode.UInt32) { return(0x8E); // d2i } code.NewInstruction(0x8E /* d2i */, null, null); } if (oldType == TypeCode.Single) { if (newType == TypeCode.Int32 || oldType == TypeCode.UInt32) { return(0x8B); // f2i } code.NewInstruction(0x8B /* f2i */, null, null); } if (oldType == TypeCode.Int64 || oldType == TypeCode.UInt64) { if (newType == TypeCode.Int32 || oldType == TypeCode.UInt32) { return(0x88); // l2i } code.NewInstruction(0x88 /* l2i */, null, null); } if (newType == TypeCode.SByte) { return(0x91); // i2b } if (newType == TypeCode.Byte) { code.StackMap.PushStack(JavaType.IntegerType); code.NewInstruction(0x12 /* ldc */, null, (int)0xFF); code.StackMap.PushStack(JavaType.IntegerType); code.StackMap.PopStack(CilMain.Where); code.StackMap.PopStack(CilMain.Where); return(0x7E); // iand } if (newType == TypeCode.Int16) { return(0x93); // i2s } if (newType == TypeCode.UInt16) { return(0x92); // i2c } return(0x00); // nop }
// // generate code to initialize the generic type field // public static void InitializeTypeField(CilType declType, JavaCode code) { code.NewInstruction(0x19 /* aload */, null, (int)0); code.StackMap.PushStack(declType); LoadMaybeGeneric(declType, code); code.NewInstruction(0xC0 /* checkcast */, CilType.SystemRuntimeTypeType, null); code.NewInstruction(0xB5 /* putfield */, declType, ConcreteTypeField); code.StackMap.PopStack(CilMain.Where); code.StackMap.PopStack(CilMain.Where); }
public static CilType LoadStaticData(CilType fldClass, JavaCode code) { LoadMaybeGeneric(fldClass, code); code.StackMap.PopStack(CilMain.Where); code.NewInstruction(0xB8 /* invokestatic */, CilType.SystemRuntimeTypeType, new JavaMethodRef("GetStatic", JavaType.ObjectType, CilType.SystemTypeType)); var returnType = PushStaticDataType(fldClass, code); code.NewInstruction(0xC0 /* checkcast */, returnType, null); return(returnType); }
static void UnsignedDivide(JavaCode code, TypeCode typeCode, bool remainder) { TypeCode unsignedTypeCode; if (typeCode == TypeCode.Int32) { unsignedTypeCode = TypeCode.UInt32; } else if (typeCode == TypeCode.Int64) { unsignedTypeCode = TypeCode.UInt64; } else { throw new InvalidProgramException(); } var signedType = CilType.From(new JavaType(typeCode, 0, null)); code.StackMap.PushStack(signedType); code.NewInstruction(0xB8 /* invokestatic */, CilType.From(new JavaType(unsignedTypeCode, 0, null)).AsWritableClass, new JavaMethodRef("Unsigned" + (remainder ? "Remainder" : "Division"), signedType, signedType, signedType)); }
static void OverflowArithmetic(JavaCode code, TypeCode typeCode, Code cilOp) { bool unsigned = (cilOp == Code.Add_Ovf_Un || cilOp == Code.Sub_Ovf_Un || cilOp == Code.Mul_Ovf_Un); TypeCode callTypeCode; if (typeCode == TypeCode.Int32) { callTypeCode = unsigned ? TypeCode.UInt32 : typeCode; } else if (typeCode == TypeCode.Int64) { callTypeCode = unsigned ? TypeCode.UInt64 : typeCode; } else { throw new InvalidProgramException(); } var signedType = CilType.From(new JavaType(typeCode, 0, null)); code.StackMap.PushStack(signedType); string verb = (cilOp == Code.Add_Ovf || cilOp == Code.Add_Ovf_Un) ? "Add" : (cilOp == Code.Sub_Ovf || cilOp == Code.Sub_Ovf_Un) ? "Subtract" : (cilOp == Code.Mul_Ovf || cilOp == Code.Mul_Ovf_Un) ? "Multiply" : throw new InvalidProgramException(); code.NewInstruction(0xB8 /* invokestatic */, CilType.From(new JavaType(callTypeCode, 0, null)).AsWritableClass, new JavaMethodRef("Overflow" + verb, signedType, signedType, signedType)); }
public static void Conversion(JavaCode code, Code cilOp) { var oldType = (CilType)code.StackMap.PopStack(CilMain.Where); var(newType, overflow, unsigned) = ConvertOpCodeToTypeCode(cilOp); int op; if (oldType.IsReference) { ConvertReference(code, oldType, newType); return; } if (newType == TypeCode.Single || newType == TypeCode.Double) { op = ConvertToFloat(code, oldType.PrimitiveType, newType, unsigned); } else if (newType == TypeCode.Int64 || newType == TypeCode.UInt64) { op = ConvertToLong(code, oldType.PrimitiveType, newType, overflow); } else { op = ConvertToInteger(code, oldType.PrimitiveType, newType, overflow); } if (op != -1) { code.NewInstruction((byte)op, null, null); } code.StackMap.PushStack(CilType.From(new JavaType(newType, 0, null))); }
public static void Switch(JavaCode code, Mono.Cecil.Cil.Instruction cilInst) { if (cilInst.Operand is Mono.Cecil.Cil.Instruction[] targets) { if ((targets.Length > Int32.MaxValue - 1) || cilInst.Next == null || (!code.StackMap.PopStack(CilMain.Where).IsIntLike)) { throw new InvalidProgramException(); } ushort offset = (ushort)cilInst.Next.Offset; code.StackMap.SaveFrame(offset, true, CilMain.Where); int n = targets.Length; var instdata = new int[3 + n]; instdata[0] = offset; instdata[2] = n - 1; for (int i = 0; i < n; i++) { offset = (ushort)targets[i].Offset; code.StackMap.SaveFrame(offset, true, CilMain.Where); instdata[i + 3] = offset; } code.NewInstruction(0xAA /* tableswitch */, null, instdata); } }
public override void SetValueOV(JavaCode code, bool isVolatile = false) { var innerOrEnum = GetInnerObject(code); code.NewInstruction(0xB6 /* invokevirtual */, innerOrEnum, new JavaMethodRef("Set", JavaType.VoidType, UnboxedTypeInMethod)); }
public static void ValueCopy(CilType valueType, JavaCode code, bool swap = false) { // if 'from' value is pushed before 'into' object, call with swap == false // if 'into' object is pushed before 'from' value, call with swap == true if (valueType.IsGenericParameter) { if (swap) { code.NewInstruction(0x5F /* swap */, null, null); } else { // if storing a primitive value into a generic type, // and the generic type can be resolved to a primitive type, // then use a boxed-set method call var stackArray = code.StackMap.StackArray(); int stackArrayLen = stackArray.Length; if (stackArrayLen > 0 && (!stackArray[stackArrayLen - 1].IsReference)) { var genericMark = CilMain.GenericStack.Mark(); var(primitiveType, _) = CilMain.GenericStack.Resolve(valueType.JavaName); CilMain.GenericStack.Release(genericMark); if (!primitiveType.IsReference) { var boxedType = new BoxedType(primitiveType, false); code.NewInstruction(0xC0 /* checkcast */, boxedType, null); boxedType.SetValueVO(code); return; } } } code.NewInstruction(0xB8 /* invokestatic */, SystemGenericType, new JavaMethod("Copy", JavaType.VoidType, JavaType.ObjectType, JavaType.ObjectType)); } else { if (swap) { code.NewInstruction(0x5F /* swap */, null, null); } CilMethod.ValueMethod(CilMethod.ValueCopyTo, code); } }
public virtual void SetValueVO(JavaCode code, bool isVolatile = false) { var thisOrEnum = ThisOrEnum; code.NewInstruction(0xB8 /* invokestatic */, thisOrEnum, new JavaMethodRef(VolatileName("Set", isVolatile), JavaType.VoidType, UnboxedTypeInMethod, thisOrEnum)); }
static void Finish(JavaCode code, CodeLocals locals, Mono.Cecil.Cil.Instruction cilInst, byte op) { var inst = (Mono.Cecil.Cil.Instruction)cilInst.Operand; bool isNop; if (op == 0x00 || op == 0x57 || op == 0x58) // nop, pop, pop2 { isNop = true; } else { isNop = false; int diff = cilInst.Offset - inst.Offset; if (diff < -0x2000 || diff > 0x2000) { // branch instructions use 16-bits for the signed offset. // for farther branches, we have to negate the condition, // and insert a 32-bit 'goto_w' instruction. if (cilInst.Next != null) { op = NegateCondition(op); var nextOffset = (ushort)cilInst.Next.Offset; code.NewInstruction(op, null, nextOffset); code.StackMap.SaveFrame(nextOffset, true, CilMain.Where); } op = 0xC8; } } code.NewInstruction(op, null, (ushort)inst.Offset); if (!isNop) // no stack frame for 'nop' or 'pop' { var resetLocals = code.StackMap.SaveFrame((ushort)inst.Offset, true, CilMain.Where); if (resetLocals != null) { ResetLocalsOutOfScope(code.StackMap, locals, resetLocals, cilInst, inst); } } }
static void LoadGeneric(CilType loadType, int loadIndex, JavaCode code) { if (loadIndex < 0) { if (code.Method.Class != null && (code.Method.Class .Flags & JavaAccessFlags.ACC_INTERFACE) != 0) { // a method compiled as part of an interface does not // have access to the generic-type member field throw CilMain.Where.Exception( "unsupported generic argument reference in interface method"); } // generic type is accessible through the generic-type member field code.NewInstruction(0x19 /* aload */, null, (int)0); code.NewInstruction(0xB4 /* getfield */, loadType, ConcreteTypeField); code.StackMap.PushStack(ConcreteTypeField.Type); code.NewInstruction(0x12 /* ldc */, null, -loadIndex - 1); code.StackMap.PushStack(JavaType.IntegerType); // call system.RuntimeType.Argument(RuntimeType runtimeType, int typeArgumentIndex) code.NewInstruction(0xB8 /* invokestatic */, CilType.SystemRuntimeTypeType, new JavaMethodRef("Argument", CilType.SystemTypeType, CilType.SystemRuntimeTypeType, JavaType.IntegerType)); code.StackMap.PopStack(CilMain.Where); // integer code.StackMap.PopStack(CilMain.Where); // generic type field code.StackMap.PushStack(CilType.SystemTypeType); // type result } else if (loadIndex > 0) { // generic type is accessible through a parameter code.NewInstruction(0x19 /* aload */, null, (int)(loadIndex - 1)); code.StackMap.PushStack(CilType.SystemTypeType); } else { // generic type is known to be a constant LoadMaybeGeneric(loadType, code); } }
public static bool CompareGtLt(JavaType stackTop, JavaType stackTop2, JavaCode code) { if (stackTop.Equals(SpanType) && stackTop2.Equals(SpanType)) { code.NewInstruction(0x01 /* aconst_null */, null, null); code.StackMap.PushStack(CilType.SystemTypeType); code.NewInstruction(0xB8 /* invokestatic */, SpanType, new JavaMethodRef("CompareTo" + CilMain.EXCLAMATION, JavaType.IntegerType, SpanType, SpanType, CilType.SystemTypeType)); code.StackMap.PopStack(CilMain.Where); // null type return(true); } return(false); }
public virtual void BoxValue(JavaCode code) { if (UnboxedType.IsEnum) { code.NewInstruction(0x12 /* ldc */, this, null); code.StackMap.PushStack(JavaType.ClassType); code.NewInstruction(0xB8 /* invokestatic */, SystemEnumType, new JavaMethodRef("Box", JavaType.ObjectType, UnboxedTypeInMethod, JavaType.ClassType)); code.NewInstruction(0xC0 /* checkcast */, this, null); code.StackMap.PopStack(CilMain.Where); } else { code.NewInstruction(0xB8 /* invokestatic */, this, new JavaMethodRef("Box", this, UnboxedTypeInMethod)); } }
public virtual void GetValue(JavaCode code, bool isVolatile = false) { code.NewInstruction(0xB6 /* invokevirtual */, ThisOrEnum, new JavaMethodRef(VolatileName("Get", isVolatile), UnboxedTypeInMethod)); if (UnboxedTypeInMethod.Category == 2) { CilMain.MakeRoomForCategory2ValueOnStack(code); } }
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 }
public static bool AddOffset(JavaType offsetType, JavaType spanType, JavaCode code) { if (spanType.Equals(SpanType)) { code.StackMap.PushStack(spanType); if (offsetType.Equals(JavaType.IntegerType)) { code.NewInstruction(0x85 /* i2l */, null, null); offsetType = JavaType.LongType; } code.StackMap.PushStack(offsetType); bool loadedType = false; if (spanType is CilType spanType2) { if ((!spanType2.HasGenericParameters) && spanType2.GenericParameters != null && spanType2.GenericParameters[0] is CilType spanPointerType && (!spanPointerType.IsGenericParameter)) { GenericUtil.LoadMaybeGeneric(spanPointerType, code); loadedType = true; } } if (!loadedType) { code.NewInstruction(0x01 /* aconst_null */, null, null); code.StackMap.PushStack(CilType.SystemTypeType); } code.NewInstruction(0xB6 /* invokevirtual */, SpanType, new JavaMethodRef("Add", SpanType, offsetType, CilType.SystemTypeType)); code.StackMap.PopStack(CilMain.Where); // span type code.StackMap.PopStack(CilMain.Where); // offset return(true); } return(false); }