示例#1
0
文件: remapper.cs 项目: moayyaed/ikvm
 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);
    }