/** * Emit an invoke for the given name. */ void emitInvoke(Name name) { //assert(!isLinkerMethodInvoke(name)); // should use the static path for these if (true) { // push receiver MethodHandle target = name.function._resolvedHandle(); //assert(target != null) : name.exprString(); //mv.visitLdcInsn(constantPlaceholder(target)); EmitConstant(target); emitReferenceCast(CoreClasses.java.lang.invoke.MethodHandle.Wrapper.ClassObject, target); } else { // load receiver //emitAloadInsn(0); //emitReferenceCast(MethodHandle.class, null); //mv.visitFieldInsn(Opcodes.GETFIELD, MH, "form", LF_SIG); //mv.visitFieldInsn(Opcodes.GETFIELD, LF, "names", LFN_SIG); // TODO more to come } // push arguments emitPushArguments(name); // invocation MethodType type = name.function.methodType(); //mv.visitMethodInsn(Opcodes.INVOKEVIRTUAL, MH, "invokeBasic", type.basicType().toMethodDescriptorString(), false); EmitInvokeBasic(type.basicType()); }
internal static Type GetMemberWrapperDelegateType(MethodType type) { #if FIRST_PASS return(null); #else return(GetDelegateTypeForInvokeExact(type.basicType())); #endif }
private NativeInvokerBytecodeGenerator(LambdaForm lambdaForm, MethodType invokerType) { if (invokerType != invokerType.basicType()) { throw new BailoutException(Bailout.NotBasicType, invokerType); } this.lambdaForm = lambdaForm; this.invokerType = invokerType; this.delegateType = MethodHandleUtil.GetMemberWrapperDelegateType(invokerType); MethodInfo mi = MethodHandleUtil.GetDelegateInvokeMethod(delegateType); Type[] paramTypes = MethodHandleUtil.GetParameterTypes(typeof(object[]), mi); // HACK the code we generate is not verifiable (known issue: locals aren't typed correctly), so we stick the DynamicMethod into mscorlib (a security critical assembly) this.dm = new DynamicMethod(lambdaForm.debugName, mi.ReturnType, paramTypes, typeof(object).Module, true); this.ilgen = CodeEmitter.Create(this.dm); if (invokerType.parameterCount() > MethodHandleUtil.MaxArity) { this.packedArgType = paramTypes[paramTypes.Length - 1]; this.packedArgPos = paramTypes.Length - 1; } else { this.packedArgPos = Int32.MaxValue; } locals = new CodeEmitterLocal[lambdaForm.names.Length]; for (int i = lambdaForm._arity(); i < lambdaForm.names.Length; i++) { Name name = lambdaForm.names[i]; if (name.index() != i) { throw new BailoutException(Bailout.PreconditionViolated, "name.index() != i"); } switch (name.typeChar()) { case 'L': locals[i] = ilgen.DeclareLocal(Types.Object); break; case 'I': locals[i] = ilgen.DeclareLocal(Types.Int32); break; case 'J': locals[i] = ilgen.DeclareLocal(Types.Int64); break; case 'F': locals[i] = ilgen.DeclareLocal(Types.Single); break; case 'D': locals[i] = ilgen.DeclareLocal(Types.Double); break; case 'V': break; default: throw new BailoutException(Bailout.PreconditionViolated, "Unsupported typeChar(): " + name.typeChar()); } } }
/** * 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); }