- * The nominal method at such a call site is an instance of - * a signature-polymorphic method (see @PolymorphicSignature). - * Such method instances are user-visible entities which are - * "split" from the generic placeholder method in {@code MethodHandle}. - * (Note that the placeholder method is not identical with any of - * its instances. If invoked reflectively, is guaranteed to throw an - * {@code UnsupportedOperationException}.) - * If the signature-polymorphic method instance is ever reified, - * it appears as a "copy" of the original placeholder - * (a native final member of {@code MethodHandle}) except - * that its type descriptor has shape required by the instance, - * and the method instance is not varargs. - * The method instance is also marked synthetic, since the - * method (by definition) does not appear in Java source code. - *
- * The JVM is allowed to reify this method as instance metadata. - * For example, {@code invokeBasic} is always reified. - * But the JVM may instead call {@code linkMethod}. - * If the result is an * ordered pair of a {@code (method, appendix)}, - * the method gets all the arguments (0..N inclusive) - * plus the appendix (N+1), and uses the appendix to complete the call. - * In this way, one reusable method (called a "linker method") - * can perform the function of any number of polymorphic instance - * methods. - *
- * Linker methods are allowed to be weakly typed, with any or - * all references rewritten to {@code Object} and any primitives - * (except {@code long}/{@code float}/{@code double}) - * rewritten to {@code int}. - * A linker method is trusted to return a strongly typed result, - * according to the specific method type descriptor of the - * signature-polymorphic instance it is emulating. - * This can involve (as necessary) a dynamic check using - * data extracted from the appendix argument. - *
- * The JVM does not inspect the appendix, other than to pass - * it verbatim to the linker method at every call. - * This means that the JDK runtime has wide latitude - * for choosing the shape of each linker method and its - * corresponding appendix. - * Linker methods should be generated from {@code LambdaForm}s - * so that they do not become visible on stack traces. - *
- * The {@code linkMethod} call is free to omit the appendix - * (returning null) and instead emulate the required function - * completely in the linker method. - * As a corner case, if N==255, no appendix is possible. - * In this case, the method returned must be custom-generated to - * to perform any needed type checking. - *
- * If the JVM does not reify a method at a call site, but instead - * calls {@code linkMethod}, the corresponding call represented - * in the bytecodes may mention a valid method which is not - * representable with a {@code MemberName}. - * Therefore, use cases for {@code linkMethod} tend to correspond to - * special cases in reflective code such as {@code findVirtual} - * or {@code revealDirect}. - */ - static MemberName linkMethod(Class> callerClass, int refKind, - Class> defc, String name, Object type, - Object[] appendixResult) { - if (!TRACE_METHOD_LINKAGE) - return linkMethodImpl(callerClass, refKind, defc, name, type, appendixResult); - return linkMethodTracing(callerClass, refKind, defc, name, type, appendixResult); - } - static MemberName linkMethodImpl(Class> callerClass, int refKind, - Class> defc, String name, Object type, - Object[] appendixResult) { - try { - if (defc == MethodHandle.class && refKind == REF_invokeVirtual) { - return Invokers.methodHandleInvokeLinkerMethod(name, fixMethodType(callerClass, type), appendixResult); - } - } catch (Throwable ex) { - if (ex instanceof LinkageError) - throw (LinkageError) ex; - else - throw new LinkageError(ex.getMessage(), ex); - } - throw new LinkageError("no such method "+defc.getName()+"."+name+type); - } - private static MethodType fixMethodType(Class> callerClass, Object type) { - if (type instanceof MethodType) - return (MethodType) type; - else - return MethodType.fromMethodDescriptorString((String)type, callerClass.getClassLoader()); - } - // Tracing logic: - static MemberName linkMethodTracing(Class> callerClass, int refKind, - Class> defc, String name, Object type, - Object[] appendixResult) { - System.out.println("linkMethod "+defc.getName()+"."+ - name+type+"/"+Integer.toHexString(refKind)); - try { - MemberName res = linkMethodImpl(callerClass, refKind, defc, name, type, appendixResult); - System.out.println("linkMethod => "+res+" + "+appendixResult[0]); - return res; - } catch (Throwable ex) { - System.out.println("linkMethod => throw "+ex); - throw ex; - } - } - - - /** - * The JVM is resolving a CONSTANT_MethodHandle CP entry. And it wants our help. - * It will make an up-call to this method. (Do not change the name or signature.) - * The type argument is a Class for field requests and a MethodType for non-fields. - *
- * Recent versions of the JVM may also pass a resolved MemberName for the type. - * In that case, the name is ignored and may be null. - */ - static MethodHandle linkMethodHandleConstant(Class> callerClass, int refKind, - Class> defc, String name, Object type) { - try { - Lookup lookup = IMPL_LOOKUP.in(callerClass); - assert(refKindIsValid(refKind)); - return lookup.linkMethodHandleConstant((byte) refKind, defc, name, type); - } catch (IllegalAccessException ex) { - Throwable cause = ex.getCause(); - if (cause instanceof AbstractMethodError) { - throw (AbstractMethodError) cause; - } else { - Error err = new IllegalAccessError(ex.getMessage()); - throw initCauseFrom(err, ex); - } - } catch (NoSuchMethodException ex) { - Error err = new NoSuchMethodError(ex.getMessage()); - throw initCauseFrom(err, ex); - } catch (NoSuchFieldException ex) { - Error err = new NoSuchFieldError(ex.getMessage()); - throw initCauseFrom(err, ex); - } catch (ReflectiveOperationException ex) { - Error err = new IncompatibleClassChangeError(); - throw initCauseFrom(err, ex); - } - } - - /** - * Use best possible cause for err.initCause(), substituting the - * cause for err itself if the cause has the same (or better) type. - */ - static private Error initCauseFrom(Error err, Exception ex) { - Throwable th = ex.getCause(); - if (err.getClass().isInstance(th)) - return (Error) th; - err.initCause(th == null ? ex : th); - return err; - } - - /** - * Is this method a caller-sensitive method? - * I.e., does it call Reflection.getCallerClass or a similer method - * to ask about the identity of its caller? - */ - static boolean isCallerSensitive(MemberName mem) { - if (!mem.isInvocable()) return false; // fields are not caller sensitive - - return mem.isCallerSensitive() || canBeCalledVirtual(mem); - } - - static boolean canBeCalledVirtual(MemberName mem) { - assert(mem.isInvocable()); - Class> defc = mem.getDeclaringClass(); - switch (mem.getName()) { - case "checkMemberAccess": - return true; //canBeCalledVirtual(mem, java.lang.SecurityManager.class); - case "getContextClassLoader": - return canBeCalledVirtual(mem, java.lang.Thread.class); - } - return false; - } - - static boolean canBeCalledVirtual(MemberName symbolicRef, Class> definingClass) { - Class> symbolicRefClass = symbolicRef.getDeclaringClass(); - if (symbolicRefClass == definingClass) return true; - if (symbolicRef.isStatic() || symbolicRef.isPrivate()) return false; - return (definingClass.isAssignableFrom(symbolicRefClass) || // Msym overrides Mdef - symbolicRefClass.isInterface()); // Mdef implements Msym - } -}