internal override void Generate(CodeGenContext context, CodeEmitter ilgen) { ilgen.BeginExceptionBlock(); @try.Generate(context, ilgen); if (@catch != null) { Type type; if (@catch.type != null) { type = StaticCompiler.GetTypeForMapXml(context.ClassLoader, @catch.type); } else { type = context.ClassLoader.LoadClassByDottedName(@catch.Class).TypeAsExceptionType; } ilgen.BeginCatchBlock(type); @catch.Generate(context, ilgen); } if (@finally != null) { ilgen.BeginFinallyBlock(); @finally.Generate(context, ilgen); } ilgen.EndExceptionBlock(); }
/** * Emit bytecode for the guardWithCatch idiom. * * The pattern looks like (Cf. MethodHandleImpl.makeGuardWithCatch): * <blockquote><pre>{@code * guardWithCatch=Lambda(a0:L,a1:L,a2:L,a3:L,a4:L,a5:L,a6:L,a7:L)=>{ * t8:L=MethodHandle.invokeBasic(a4:L,a6:L,a7:L); * t9:L=MethodHandleImpl.guardWithCatch(a1:L,a2:L,a3:L,t8:L); * t10:I=MethodHandle.invokeBasic(a5:L,t9:L);t10:I} * }</pre></blockquote> * * It is compiled into bytecode equivalent of the following code: * <blockquote><pre>{@code * try { * return a1.invokeBasic(a6, a7); * } catch (Throwable e) { * if (!a2.isInstance(e)) throw e; * return a3.invokeBasic(ex, a6, a7); * }}</pre></blockquote> */ private Name emitGuardWithCatch(int pos) { Name args = lambdaForm.names[pos]; Name invoker = lambdaForm.names[pos + 1]; Name result = lambdaForm.names[pos + 2]; CodeEmitterLabel L_handler = ilgen.DefineLabel(); CodeEmitterLabel L_done = ilgen.DefineLabel(); Class returnType = result.function._resolvedHandle().type().returnType(); MethodType type = args.function._resolvedHandle().type() .dropParameterTypes(0, 1) .changeReturnType(returnType); // Normal case ilgen.BeginExceptionBlock(); // load target emitPushArgument(invoker, 0); emitPushArguments(args, 1); // skip 1st argument: method handle EmitInvokeBasic(type.basicType()); CodeEmitterLocal returnValue = null; if (returnType != java.lang.Void.TYPE) { returnValue = ilgen.DeclareLocal(TypeWrapper.FromClass(returnType).TypeAsLocalOrStackType); ilgen.Emit(OpCodes.Stloc, returnValue); } ilgen.EmitLeave(L_done); // Exceptional case ilgen.BeginCatchBlock(typeof(Exception)); // [IKVM] map the exception and store it in a local and exit the handler ilgen.EmitLdc_I4(0); ilgen.Emit(OpCodes.Call, ByteCodeHelperMethods.mapException.MakeGenericMethod(typeof(Exception))); CodeEmitterLocal exception = ilgen.DeclareLocal(typeof(Exception)); ilgen.Emit(OpCodes.Stloc, exception); ilgen.EmitLeave(L_handler); ilgen.EndExceptionBlock(); // Check exception's type ilgen.MarkLabel(L_handler); // load exception class emitPushArgument(invoker, 1); ilgen.Emit(OpCodes.Ldloc, exception); CoreClasses.java.lang.Class.Wrapper.GetMethodWrapper("isInstance", "(Ljava.lang.Object;)Z", false).EmitCall(ilgen); CodeEmitterLabel L_rethrow = ilgen.DefineLabel(); ilgen.EmitBrfalse(L_rethrow); // Invoke catcher // load catcher emitPushArgument(invoker, 2); ilgen.Emit(OpCodes.Ldloc, exception); emitPushArguments(args, 1); // skip 1st argument: method handle MethodType catcherType = type.insertParameterTypes(0, CoreClasses.java.lang.Throwable.Wrapper.ClassObject); EmitInvokeBasic(catcherType.basicType()); if (returnValue != null) { ilgen.Emit(OpCodes.Stloc, returnValue); } ilgen.EmitBr(L_done); ilgen.MarkLabel(L_rethrow); ilgen.Emit(OpCodes.Ldloc, exception); ilgen.Emit(OpCodes.Call, Compiler.unmapExceptionMethod); ilgen.Emit(OpCodes.Throw); ilgen.MarkLabel(L_done); if (returnValue != null) { ilgen.Emit(OpCodes.Ldloc, returnValue); } return(result); }