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); } }
void CastToClass(object data) { var srcType = (CilType)code.StackMap.PopStack(CilMain.Where); if (!(srcType.IsReference && data is TypeReference)) { throw new InvalidProgramException(); } byte op; var dstType = (CilType)CilType.From((TypeReference)data); if (GenericUtil.ShouldCallGenericCast(srcType, dstType)) { code.StackMap.PushStack(srcType); // casting to a generic type is done via GenericType.TestCast GenericUtil.CastToGenericType((TypeReference)data, 1, code); code.StackMap.PopStack(CilMain.Where); // srcType op = 0xC0; // checkcast } else { // cast to a non-generic type if (dstType.Equals(srcType) || dstType.Equals(JavaType.ObjectType)) { op = 0x00; // nop } else if (dstType.IsReference) { CodeArrays.CheckCast(dstType, true, code); if (srcType.ArrayRank != 0 && srcType.ArrayRank == dstType.ArrayRank && srcType.PrimitiveType != 0 && dstType.PrimitiveType != 0 && srcType.AdjustRank(-srcType.ArrayRank).NewArrayType == dstType.AdjustRank(-dstType.ArrayRank).NewArrayType) { // casting to same java array type, e.g. byte[] to sbyte[] op = 0x00; // nop } else if (dstType.IsGenericParameter) { op = 0x00; // nop } else { op = 0xC0; // checkcast } } else { throw new InvalidProgramException(); } } code.NewInstruction(op, dstType, null); code.StackMap.PushStack(dstType); }
void CastToClass(object data) { var srcType = (CilType)code.StackMap.PopStack(CilMain.Where); if (!(srcType.IsReference && data is TypeReference)) { throw new InvalidProgramException(); } byte op; var dstType = (CilType)CilType.From((TypeReference)data); if (GenericUtil.ShouldCallGenericCast(srcType, dstType)) { code.StackMap.PushStack(srcType); // casting to a generic type is done via GenericType.TestCast GenericUtil.CastToGenericType((TypeReference)data, 1, code); code.StackMap.PopStack(CilMain.Where); // srcType op = 0xC0; // checkcast } else { // cast to a non-generic type if (dstType.Equals(srcType) || dstType.Equals(JavaType.ObjectType)) { op = 0x00; // nop } else if (dstType.IsReference) { CodeArrays.CheckCast(dstType, true, code); op = 0xC0; // checkcast } else { throw new InvalidProgramException(); } } code.NewInstruction(op, dstType, null); code.StackMap.PushStack(dstType); }
void ExceptionClauseSetup(ushort instOffset, CatchClause catchClause) { // if this is the first exception for the try block: // // the offset is recorded in the exception attribute, so we need // to generate a stack frame for it, which matches the stack frame // on entry to the try block, with a pushed java.lang.Throwable. var tryClause = catchClause.tryClause; if (catchClause == tryClause.catchClauses[0]) { stackMap.LoadFrame((ushort)tryClause.tryStart, false, CilMain.Where); stackMap.PushStack(ThrowableType); stackMap.SaveFrame((ushort)instOffset, true, CilMain.Where); if (!catchClause.finallyClause) { code.NewInstruction(0xB8 /* invokestatic */, CilType.SystemUtilType, new JavaMethodRef("TranslateException", ThrowableType, ThrowableType)); } } // if this is a finally clause, we have nothing further to do. // but if this is a filter clause, do some additional set up. if (catchClause.finallyClause) { if (catchClause.hasNestedTry) { // see also: ScanCatchClauseForNestedTry SaveExceptionObject(tryClause, false); } if (catchClause.faultClause) { // the 'fault' clause should start with a check whether // an exception was thrown, which is very similar to what // 'endfinally' does at the end of a normal 'finally' block, // so we can reuse the same code. Translate_Endfinally(instOffset, true); } return; } // // if this is a filter clause, we just need to initialize loals // if (catchClause.filterCondStart != 0) { // should the filter test pass, we need push the exception // object. we don't know which local the filter test uses // to store the exception, so we make our own copy. this // will be loaded by the 'endfilter' instruction, see there. SaveExceptionObject(tryClause); return; } // // for a non-filter catch clause that catches any kind of // exception, we don't need to test the exception type at all // if (catchClause.catchType.Equals(ThrowableType)) { if (catchClause.includesRethrow) { SaveExceptionObject(tryClause); } } // // otherwise, we do need to test the exception type, and // possibly branch to a secondary catch clause in the chain. // if (catchClause.catchFromType == null) { // exception type is plain type. we will use follow up // instructions 'ifeq == zero' and 'ifne != zero', // see ExceptionClauseCommon if (catchClause.catchType.Equals(ThrowableType)) { code.NewInstruction(0x04 /* iconst_1 */, null, null); stackMap.PushStack(JavaType.IntegerType); } else { code.NewInstruction(0x59 /* dup */, null, null); stackMap.PushStack(ThrowableType); code.NewInstruction(0xC1 /* instanceof */, catchClause.catchType, null); } } else { // exception type is a generic type. we will use follow up // instructions 'ifnull' and 'ifnonnnull'. // see also below in ExceptionClauseCommon code.NewInstruction(0x59 /* dup */, null, null); stackMap.PushStack(ThrowableType); GenericUtil.CastToGenericType(catchClause.catchFromType, 0, code); } stackMap.PopStack(CilMain.Where); ExceptionClauseCommon(catchClause); }