Hi, I am wondering if people can help shed some light on the MHS.Lookup.unreflect implementation for the MethodHandle.invoke/invokeExact.
It's clear that one should not be able to operate reflectively on polysig methods and when doing do a USO is throw (as specified), but the implementation seems a little odd. A call to the following succeeds: Method m = MethodHandle.class.getMethod("invokeExact", Object[].class); MethodHandle rmh = MethodHandles.lookup().unreflect(m); The type of "rmh" is "(MethodHandle,Object[])Object", thus any "rmh.invokeExact" that does not match that type will fail with a WrongMethodTypeException. A call to the following: Object o = rmh.invokeExact((MethodHandle) null, new Object[]{}); Will result in a: java.lang.UnsupportedOperationException: cannot reflectively invoke MethodHandle However, the stack trace corresponds to the stack where the call to "unreflect" was performed and not where the invocation occurs. The implementation caches the MethodHandle instances for invokeExact/invoke methods: static MethodHandle throwException(MethodType type) { assert(Throwable.class.isAssignableFrom(type.parameterType(0))); int arity = type.parameterCount(); if (arity > 1) { MethodHandle mh = throwException(type.dropParameterTypes(1, arity)); mh = MethodHandles.dropArguments(mh, 1, type.parameterList().subList(1, arity)); return mh; } return makePairwiseConvert(Lazy.NF_throwException.resolvedHandle(), type, false, true); } static <T extends Throwable> Empty throwException(T t) throws T { throw t; } static MethodHandle[] FAKE_METHOD_HANDLE_INVOKE = new MethodHandle[2]; static MethodHandle fakeMethodHandleInvoke(MemberName method) { int idx; assert(method.isMethodHandleInvoke()); switch (method.getName()) { case "invoke": idx = 0; break; case "invokeExact": idx = 1; break; default: throw new InternalError(method.getName()); } MethodHandle mh = FAKE_METHOD_HANDLE_INVOKE[idx]; if (mh != null) return mh; MethodType type = MethodType.methodType(Object.class, UnsupportedOperationException.class, MethodHandle.class, Object[].class); mh = throwException(type); mh = mh.bindTo(new UnsupportedOperationException("cannot reflectively invoke MethodHandle")); if (!method.getInvocationType().equals(mh.type())) throw new InternalError(method.toString()); mh = mh.withInternalMemberName(method, false); mh = mh.asVarargsCollector(Object[].class); assert(method.isVarargs()); FAKE_METHOD_HANDLE_INVOKE[idx] = mh; return mh; } Further it does "mh.withInternalMemberName(method, false)", that i cannot explain. Why do we need to re-associate the MH throwing the USO with the member name corresponding to the MH.invokeExact/invoke method? Would it not be simpler if the implementation was something like: public static MethodHandle unsupportedOperation(MethodType type, String message) throws Exception { MethodHandle mh = MethodHandles.lookup().findStatic( X.class, "throwUOE", MethodType.methodType(void.class, String.class)); return MethodHandles.dropArguments(mh, 1, type.parameterList()) .bindTo(message) .asType(type) .asVarargsCollector(Object[].class); } public static void throwUOE(String s) { throw new UnsupportedOperationException(s); } For such edge cases perhaps caching is not required. ? The motivation behind the above is i need to provide similar behaviour for VarHandle polysig methods. Thanks, Paul.
signature.asc
Description: Message signed with OpenPGP using GPGMail
_______________________________________________ mlvm-dev mailing list mlvm-dev@openjdk.java.net http://mail.openjdk.java.net/mailman/listinfo/mlvm-dev