--- old/src/java.base/share/classes/java/lang/invoke/MethodHandleNatives.java 2018-09-28 11:54:29.000000000 -0700 +++ new/src/java.base/share/classes/java/lang/invoke/MethodHandleNatives.java 2018-09-28 11:54:28.000000000 -0700 @@ -26,13 +26,20 @@ package java.lang.invoke; import jdk.internal.ref.CleanerFactory; +import jdk.internal.reflect.ConstantPool; import sun.invoke.util.Wrapper; +import java.lang.constant.ClassDesc; +import java.lang.constant.MethodTypeDesc; +import java.lang.invoke.AbstractBootstrapCallInfo.TypeView; +import java.lang.invoke.BootstrapMethodInvoker.VM_BSCI; import java.lang.invoke.MethodHandles.Lookup; import java.lang.reflect.Field; +import java.util.Arrays; import static java.lang.invoke.MethodHandleNatives.Constants.*; import static java.lang.invoke.MethodHandleStatics.TRACE_METHOD_LINKAGE; +import static java.lang.invoke.MethodHandleStatics.TRACE_RESOLVE; import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP; /** @@ -66,12 +73,6 @@ static native void setCallSiteTargetNormal(CallSite site, MethodHandle target); static native void setCallSiteTargetVolatile(CallSite site, MethodHandle target); - static native void copyOutBootstrapArguments(Class caller, int[] indexInfo, - int start, int end, - Object[] buf, int pos, - boolean resolve, - Object ifNotAvailable); - /** Represents a context to track nmethod dependencies on CallSite instance target. */ static class CallSiteContext implements Runnable { //@Injected JVM_nmethodBucket* vmdependencies; @@ -136,6 +137,11 @@ REF_newInvokeSpecial = 8, REF_invokeInterface = 9, REF_LIMIT = 10; + + /** + * Flag values which affect the copying of bootstrap static arguments. + */ + static final byte BAR_IFPRESENT = 0, BAR_FORCE = 1, BAR_SYMREF = 2; } static boolean refKindIsValid(int refKind) { @@ -199,6 +205,10 @@ private static native int getNamedCon(int which, Object[] name); static boolean verifyConstants() { + // This code requires ADVERTISE_CON_VALUES to be turned on + // in methodHandles.cpp, which is usually only true in debug builds. + // If that is not the case, then getNamedCon returns nothing and + // the loop body never runs. Object[] box = { null }; for (int i = 0; ; i++) { box[0] = null; @@ -208,12 +218,11 @@ try { Field con = Constants.class.getDeclaredField(name); int jval = con.getInt(null); + if (TRACE_RESOLVE) { + System.out.println("[CON_RESOLVE] " + name + " = " + vmval); + } if (jval == vmval) continue; String err = (name+": JVM has "+vmval+" while Java has "+jval); - if (name.equals("CONV_OP_LIMIT")) { - System.err.println("warning: "+err); - continue; - } throw new InternalError(err); } catch (NoSuchFieldException | IllegalAccessException ex) { String err = (name+": JVM has "+vmval+" which Java does not define"); @@ -225,148 +234,140 @@ return true; } static { - assert(verifyConstants()); + if (TRACE_RESOLVE) { + boolean ok = verifyConstants(); + assert(ok); + } else { + assert(verifyConstants()); + } } // Up-calls from the JVM. // These must NOT be public. /** - * The JVM is linking an invokedynamic instruction. Create a reified call site for it. - */ - static MemberName linkCallSite(Object callerObj, - int indexInCP, - Object bootstrapMethodObj, - Object nameObj, Object typeObj, - Object staticArguments, - Object[] appendixResult) { - MethodHandle bootstrapMethod = (MethodHandle)bootstrapMethodObj; - Class caller = (Class)callerObj; - String name = nameObj.toString().intern(); - MethodType type = (MethodType)typeObj; - if (!TRACE_METHOD_LINKAGE) - return linkCallSiteImpl(caller, bootstrapMethod, name, type, - staticArguments, appendixResult); - return linkCallSiteTracing(caller, bootstrapMethod, name, type, - staticArguments, appendixResult); - } - static MemberName linkCallSiteImpl(Class caller, - MethodHandle bootstrapMethod, - String name, MethodType type, - Object staticArguments, - Object[] appendixResult) { - CallSite callSite = CallSite.makeSite(bootstrapMethod, - name, - type, - staticArguments, - caller); - if (callSite instanceof ConstantCallSite) { - appendixResult[0] = callSite.dynamicInvoker(); - return Invokers.linkToTargetMethod(type); + * All bootstrap method invocations funnel through this single method. + * A large subset of the values of the JVM's BootstrapInfo structure is + * made available here, basically everything that can be easily computed + * without a detectable side effect or exception. The callee is + * invited to call back the JVM for more information. + */ + static Object bootstrapMethodHelper(ConstantPool pool, + int bssIndex, + int indyIndex, + int argc, + MethodHandle bsm, + String name, + Object type, // Class or MethodType or String + int[] argIndexes, + Object[] argValues, + Object request, + Object[] appendixResult) { + assert((appendixResult != null) == (indyIndex != 0)); + assert(request == (indyIndex == 0 ? null : CallSite.class)); + // Special case: If the bsm does not begin with Lookup, *and* + // it is a CallSite request (i.e., legacy from Java 7), then + // forcibly convert the leading type to Lookup. + if (request == CallSite.class && BootstrapMethodInvoker.isExpressionBSM(bsm)) { + bsm = BootstrapMethodInvoker.forceLookupParameter(bsm); + assert(!BootstrapMethodInvoker.isExpressionBSM(bsm)); // properly wrapped + } + // Make a full-power lookup into the CP (a privileged operation). + Lookup lookup = IMPL_LOOKUP.in(pool.getHolder()); + // Process the type: { field, method } x { resolved, string } + TypeView> ftype = null; + TypeView mtype = null; + if (type instanceof MethodType) { + mtype = new TypeView<>((MethodType)type); + } else if (type instanceof Class) { + ftype = new TypeView<>((Class)type); } else { - appendixResult[0] = callSite; - return Invokers.linkToCallSiteMethod(type); - } - } - // Tracing logic: - static MemberName linkCallSiteTracing(Class caller, - MethodHandle bootstrapMethod, - String name, MethodType type, - Object staticArguments, - Object[] appendixResult) { - Object bsmReference = bootstrapMethod.internalMemberName(); - if (bsmReference == null) bsmReference = bootstrapMethod; - String staticArglist = staticArglistForTrace(staticArguments); - System.out.println("linkCallSite "+caller.getName()+" "+ - bsmReference+" "+ - name+type+"/"+staticArglist); - try { - MemberName res = linkCallSiteImpl(caller, bootstrapMethod, name, type, - staticArguments, appendixResult); - System.out.println("linkCallSite => "+res+" + "+appendixResult[0]); - return res; - } catch (Throwable ex) { - ex.printStackTrace(); // print now in case exception is swallowed - System.out.println("linkCallSite => throw "+ex); - throw ex; + // JVM was not able to resolve the type. Keep the ball rolling. + String desc = (String) type; + if (desc.startsWith("(")) + mtype = new TypeView<>(MethodTypeDesc.ofDescriptor(desc), lookup); + else + ftype = new TypeView<>(ClassDesc.ofDescriptor(desc), lookup); + } + // If VM is pushing up argument values, use them. Otherwise make a fresh buffer. + if (argValues == null) { + argValues = new Object[argc]; + } else { + assert(argValues.length == argc); + // The JVM resolves CONSTANT_Integer CP items without calling Integer.valueOf. + BootstrapMethodInvoker.maybeReBoxElements(argValues); + } + // Make a BSCI wrapper for all of this state. + VM_BSCI bsci; + // (The following if/then/else is required to make the generic types match up.) + if (ftype != null) + bsci = new VM_BSCI<>(pool, bssIndex, indyIndex, bsm, name, ftype, argValues); + else + bsci = new VM_BSCI<>(pool, bssIndex, indyIndex, bsm, name, mtype, argValues); + // If VM is passing up argument indexes, accept that also. + if (argIndexes != null) bsci.setArgIndexes(argIndexes); + // Finish the job by invoking the fresh BSCI under the Lookup: + if (!TRACE_METHOD_LINKAGE) { + Object res = BootstrapMethodInvoker.invoke(lookup, bsci); + if (appendixResult == null) { + return res; + } + return encodeBindingViaAppendix(bsci, res, appendixResult); } - } - - // this implements the upcall from the JVM, MethodHandleNatives.linkDynamicConstant: - static Object linkDynamicConstant(Object callerObj, - int indexInCP, - Object bootstrapMethodObj, - Object nameObj, Object typeObj, - Object staticArguments) { - MethodHandle bootstrapMethod = (MethodHandle)bootstrapMethodObj; - Class caller = (Class)callerObj; - String name = nameObj.toString().intern(); - Class type = (Class)typeObj; - if (!TRACE_METHOD_LINKAGE) - return linkDynamicConstantImpl(caller, bootstrapMethod, name, type, staticArguments); - return linkDynamicConstantTracing(caller, bootstrapMethod, name, type, staticArguments); - } - - static Object linkDynamicConstantImpl(Class caller, - MethodHandle bootstrapMethod, - String name, Class type, - Object staticArguments) { - return ConstantBootstraps.makeConstant(bootstrapMethod, name, type, staticArguments, caller); - } - - private static String staticArglistForTrace(Object staticArguments) { - if (staticArguments instanceof Object[]) - return "BSA="+java.util.Arrays.asList((Object[]) staticArguments); - if (staticArguments instanceof int[]) - return "BSA@"+java.util.Arrays.toString((int[]) staticArguments); - if (staticArguments == null) - return "BSA0=null"; - return "BSA1="+staticArguments; - } - // Tracing logic: - static Object linkDynamicConstantTracing(Class caller, - MethodHandle bootstrapMethod, - String name, Class type, - Object staticArguments) { - Object bsmReference = bootstrapMethod.internalMemberName(); - if (bsmReference == null) bsmReference = bootstrapMethod; - String staticArglist = staticArglistForTrace(staticArguments); - System.out.println("linkDynamicConstant "+caller.getName()+" "+ - bsmReference+" "+ - name+type+"/"+staticArglist); + // Tracing logic follows: + String linkWhat = "[TRACE_METHOD_LINKAGE] link" + + ((request == null) ? "DynamicConstant" + : request instanceof Class ? ((Class)request).getSimpleName() + : request); + System.out.println(linkWhat+" "+bsci.toString()); try { - Object res = linkDynamicConstantImpl(caller, bootstrapMethod, name, type, staticArguments); - System.out.println("linkDynamicConstantImpl => "+res); - return res; + Object res = BootstrapMethodInvoker.invoke(lookup, bsci); + if (appendixResult == null) { + System.out.println(linkWhat+" => "+res); return res; + } + MemberName mem = encodeBindingViaAppendix(bsci, res, appendixResult); + System.out.println(linkWhat+" => "+res+" => "+mem+" + "+appendixResult[0]); + return mem; } catch (Throwable ex) { ex.printStackTrace(); // print now in case exception is swallowed - System.out.println("linkDynamicConstant => throw "+ex); + System.out.println(linkWhat+" => throw "+ex); throw ex; } } - /** The JVM is requesting pull-mode bootstrap when it provides - * a tuple of the form int[]{ argc, vmindex }. - * The BSM is expected to call back to the JVM using the caller - * class and vmindex to resolve the static arguments. - */ - static boolean staticArgumentsPulled(Object staticArguments) { - return staticArguments instanceof int[]; - } - - /** A BSM runs in pull-mode if and only if its sole arguments - * are (Lookup, BootstrapCallInfo), or can be converted pairwise - * to those types, and it is not of variable arity. - * Excluding error cases, we can just test that the arity is a constant 2. - * - * NOTE: This method currently returns false, since pulling is not currently - * exposed to a BSM. When pull mode is supported the method block will be - * replaced with currently commented out code. - */ - static boolean isPullModeBSM(MethodHandle bsm) { - return false; -// return bsm.type().parameterCount() == 2 && !bsm.isVarargsCollector(); + // Follow-up step to bootstrapMethodHelper, when an appendix was provided. + // The basic result was a specific behavior; factor it (for the VM's sake) + // into a generic chunk of argument shuffling plus a datum. + static MemberName encodeBindingViaAppendix(BootstrapCallInfo bsci, Object binding, Object[] appendixResult) { + MethodType type = (MethodType) bsci.invocationType(); + MemberName result; + MethodType resultType; + Object appendix; + if (binding instanceof ConstantCallSite) { + ConstantCallSite ccs = (ConstantCallSite) binding; + result = Invokers.linkToTargetMethod(type); + appendix = ccs.getTarget(); + resultType = ((MethodHandle) appendix).type(); + } else if (binding instanceof CallSite) { + result = Invokers.linkToCallSiteMethod(type); + appendix = binding; + resultType = ((CallSite) appendix).type(); + } else if (binding instanceof MethodHandle) { + result = Invokers.linkToTargetMethod(type); + appendix = binding; + resultType = ((MethodHandle) appendix).type(); + } else { + throw new InternalError("should not get here: "+binding+":"+binding.getClass().getName()); + } + // Double-check the function type also. + if (!resultType.equals(type)) { + throw new InternalError("should not get here: "+binding+type); + } + // After type checking, give the JVM the two bits it needs + // to implement the call site: A behavior method, and a cookie. + appendixResult[0] = appendix; + return result; } /** @@ -473,6 +474,7 @@ } 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;