internal static void LoadFrameOrClearStack(JavaStackMap stackMap, Mono.Cecil.Cil.Instruction inst) { // following any instruction that breaks the normal flow of execution, // we need to load an stack frame already recorded for some following // instruction, if any (e.g. as part of a conditional branch sequence). // if there isn't such a frame, just clear and reset the stack frame. for (;;) { inst = inst.Next; if (inst == null) { break; } if (stackMap.LoadFrame((ushort)inst.Offset, true, null)) { return; } var flowControl = inst.OpCode.FlowControl; if (flowControl == Mono.Cecil.Cil.FlowControl.Branch || flowControl == Mono.Cecil.Cil.FlowControl.Break || flowControl == Mono.Cecil.Cil.FlowControl.Cond_Branch || flowControl == Mono.Cecil.Cil.FlowControl.Return || flowControl == Mono.Cecil.Cil.FlowControl.Throw) { break; } } stackMap.ClearStack(); }
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); }