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); } }
public static void Straight(JavaCode code, Code cilOp, CodeLocals locals, Mono.Cecil.Cil.Instruction cilInst) { // // a straight branch maps to the corresponding compare logic // (beq = ceq, bgt = cgt, blt = clt), plus logic for brtrue. // byte op; ushort nextInstOffset = 0; if (cilOp == Code.Br || cilOp == Code.Br_S) { if (cilInst.Operand is Mono.Cecil.Cil.Instruction inst) { if (inst == cilInst.Next) { op = 0x00; // nop } else { op = 0xA7; // goto if (cilInst.Next != null) { nextInstOffset = (ushort)cilInst.Next.Offset; } } } else { throw new InvalidProgramException(); } } else { var stackTop = code.StackMap.PopStack(CilMain.Where); op = Common(code, cilOp, cilInst, stackTop); } Finish(code, locals, cilInst, op); if (nextInstOffset != 0) { if (!code.StackMap.LoadFrame(nextInstOffset, true, null)) { if (op == 0xA7 /* goto */) { locals.TrackUnconditionalBranch(cilInst); } } } }
public CodeExceptions(MethodBody body, JavaCode _code, CodeLocals locals) { tryClauses = new List <TryClause>(); catchClauses = new Dictionary <int, CatchClause>(); code = _code; stackMap = code.StackMap; this.locals = locals; if (body.HasExceptionHandlers) { if (!InitExceptionClauses(body)) { throw CilMain.Where.Exception("error in exception handlers data"); } } }
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); } } }
void Process(int numCastableInterfaces) { code = newMethod.Code = new JavaCode(newMethod); var oldLabel = code.SetLabel(0xFFFF); locals = new CodeLocals(method, defMethod, code); arrays = new CodeArrays(code, locals); exceptions = new CodeExceptions(defMethodBody, code, locals); InsertMethodInitCode(numCastableInterfaces); code.SetLabel(oldLabel); stackMap = code.StackMap; stackMap.SaveFrame(0, false, CilMain.Where); ProcessInstructions(); (code.MaxLocals, code.MaxStack) = locals.GetMaxLocalsAndStack(); locals.TrackUnconditionalBranch(null); }
public CodeArrays(JavaCode _code, CodeLocals _locals) { locals = _locals; code = _code; stackMap = code.StackMap; }
public static void Opposite(JavaCode code, Code cilOp, CodeLocals locals, Mono.Cecil.Cil.Instruction cilInst) { // // an opposite branch works by generating logic/opcode for // the opposite test (e.g. clt for bge), and an opposite // branch opcode (e.g. for bge, branch if clt returns zero) // var stackTop = code.StackMap.PopStack(CilMain.Where); bool isFloat = (stackTop.PrimitiveType == TypeCode.Single || stackTop.PrimitiveType == TypeCode.Double); if (cilOp == Code.Brfalse || cilOp == Code.Brfalse_S) { cilOp = Code.Brtrue; } else if (cilOp == Code.Bne_Un || cilOp == Code.Bne_Un_S) { cilOp = Code.Beq; } else if (cilOp == Code.Ble || cilOp == Code.Ble_S) { // for integer, this is the opposite of BGT // for float, this is the opposite of BGT.UN cilOp = isFloat ? Code.Bgt_Un : Code.Bgt; } else if (cilOp == Code.Ble_Un || cilOp == Code.Ble_Un_S) { // for integer, this is the opposite of BGT.UN // for float, this is the opposite of BGT cilOp = isFloat ? Code.Bgt : Code.Bgt_Un; } else if (cilOp == Code.Bge || cilOp == Code.Bge_S) { // for integer, this is the opposite of BLT // for float, this is the opposite of BLT.UN cilOp = isFloat ? Code.Blt_Un : Code.Blt; } else if (cilOp == Code.Bge_Un || cilOp == Code.Bge_Un_S) { // for integer, this is the opposite of BLT.UN // for float, this is the opposite of BLT cilOp = isFloat ? Code.Blt : Code.Blt_Un; } else { throw new InvalidProgramException(); } // // change the branch test to the opposite result // byte op = Common(code, cilOp, cilInst, stackTop); op = NegateCondition(op); Finish(code, locals, cilInst, op); }