src/java.base/share/classes/java/lang/invoke/BootstrapMethodInvoker.java
changeset 48895 7a1916641c0c
parent 48826 c4d9d1b08e2e
child 48921 576e024f10b6
equal deleted inserted replaced
48894:99b94636fcd3 48895:7a1916641c0c
    65         // match the VM with the BSM
    65         // match the VM with the BSM
    66         if (vmIsPushing) {
    66         if (vmIsPushing) {
    67             // VM is pushing arguments at us
    67             // VM is pushing arguments at us
    68             pullModeBSM = null;
    68             pullModeBSM = null;
    69             if (pullMode) {
    69             if (pullMode) {
    70                 bootstrapMethod = Adapters.pushMePullYou(bootstrapMethod, true);
    70                 bootstrapMethod = pushMePullYou(bootstrapMethod, true);
    71             }
    71             }
    72         } else {
    72         } else {
    73             // VM wants us to pull args from it
    73             // VM wants us to pull args from it
    74             pullModeBSM = pullMode ? bootstrapMethod :
    74             pullModeBSM = pullMode ? bootstrapMethod :
    75                     Adapters.pushMePullYou(bootstrapMethod, false);
    75                     pushMePullYou(bootstrapMethod, false);
    76             bootstrapMethod = null;
    76             bootstrapMethod = null;
    77         }
    77         }
    78         try {
    78         try {
    79             info = maybeReBox(info);
    79             info = maybeReBox(info);
    80             if (info == null) {
    80             if (info == null) {
   235                 i++;
   235                 i++;
   236             }
   236             }
   237             // give up at first null and grab the rest in one big block
   237             // give up at first null and grab the rest in one big block
   238             if (i >= end)  return i;
   238             if (i >= end)  return i;
   239             Object[] temp = new Object[end - i];
   239             Object[] temp = new Object[end - i];
   240             if (TRACE_METHOD_LINKAGE)
   240             if (TRACE_METHOD_LINKAGE) {
   241                 System.out.println("resolving more BSM arguments: "+
   241                 System.out.println("resolving more BSM arguments: " +
   242                         Arrays.asList(caller.getSimpleName(), Arrays.toString(indexInfo), i, end));
   242                         Arrays.asList(caller.getSimpleName(), Arrays.toString(indexInfo), i, end));
       
   243             }
   243             copyOutBootstrapArguments(caller, indexInfo,
   244             copyOutBootstrapArguments(caller, indexInfo,
   244                                       i, end, temp, 0,
   245                                       i, end, temp, 0,
   245                                       true, null);
   246                                       true, null);
   246             for (Object x : temp) {
   247             for (Object x : temp) {
   247                 x = maybeReBox(x);
   248                 x = maybeReBox(x);
   283         }
   284         }
   284 
   285 
   285         private void prefetchIntoCache(int i, int pfLimit) {
   286         private void prefetchIntoCache(int i, int pfLimit) {
   286             if (pfLimit <= i)  return;  // corner case
   287             if (pfLimit <= i)  return;  // corner case
   287             Object[] temp = new Object[pfLimit - i];
   288             Object[] temp = new Object[pfLimit - i];
   288             if (TRACE_METHOD_LINKAGE)
   289             if (TRACE_METHOD_LINKAGE) {
   289                 System.out.println("prefetching BSM arguments: "+
   290                 System.out.println("prefetching BSM arguments: " +
   290                         Arrays.asList(caller.getSimpleName(), Arrays.toString(indexInfo), i, pfLimit));
   291                         Arrays.asList(caller.getSimpleName(), Arrays.toString(indexInfo), i, pfLimit));
       
   292             }
   291             copyOutBootstrapArguments(caller, indexInfo,
   293             copyOutBootstrapArguments(caller, indexInfo,
   292                                       i, pfLimit, temp, 0,
   294                                       i, pfLimit, temp, 0,
   293                                       false, NOT_PRESENT);
   295                                       false, NOT_PRESENT);
   294             for (Object x : temp) {
   296             for (Object x : temp) {
   295                 if (x != NOT_PRESENT && cache[i] == null) {
   297                 if (x != NOT_PRESENT && cache[i] == null) {
   299             }
   301             }
   300         }
   302         }
   301     }
   303     }
   302 
   304 
   303     /*non-public*/ static final
   305     /*non-public*/ static final
   304     class Adapters {
   306     class PushAdapter {
   305         // skeleton for push-mode BSM which wraps a pull-mode BSM:
   307         // skeleton for push-mode BSM which wraps a pull-mode BSM:
   306         static Object pushToBootstrapMethod(MethodHandle pullModeBSM,
   308         static Object pushToBootstrapMethod(MethodHandle pullModeBSM,
   307                                             MethodHandles.Lookup lookup, String name, Object type,
   309                                             MethodHandles.Lookup lookup, String name, Object type,
   308                                             Object... arguments) throws Throwable {
   310                                             Object... arguments) throws Throwable {
   309             ConstantGroup cons = makeConstantGroup(Arrays.asList(arguments));
   311             ConstantGroup cons = makeConstantGroup(Arrays.asList(arguments));
   311             if (TRACE_METHOD_LINKAGE)
   313             if (TRACE_METHOD_LINKAGE)
   312                 System.out.println("pull-mode BSM gets pushed arguments from fake BSCI");
   314                 System.out.println("pull-mode BSM gets pushed arguments from fake BSCI");
   313             return pullModeBSM.invoke(lookup, bsci);
   315             return pullModeBSM.invoke(lookup, bsci);
   314         }
   316         }
   315 
   317 
   316         // skeleton for pull-mode BSM which wraps a push-mode BSM:
       
   317         static Object pullFromBootstrapMethod(MethodHandle pushModeBSM,
       
   318                                               MethodHandles.Lookup lookup, BootstrapCallInfo<?> bsci)
       
   319                 throws Throwable {
       
   320             int argc = bsci.size();
       
   321             Object arguments[] = new Object[3 + argc];
       
   322             arguments[0] = lookup;
       
   323             arguments[1] = bsci.invocationName();
       
   324             arguments[2] = bsci.invocationType();
       
   325             bsci.copyConstants(0, argc, arguments, 3);
       
   326             if (TRACE_METHOD_LINKAGE)
       
   327                 System.out.println("pulled arguments from VM for push-mode BSM");
       
   328             return pushModeBSM.invokeWithArguments(arguments);
       
   329         }
       
   330         static final MethodHandle MH_pushToBootstrapMethod;
   318         static final MethodHandle MH_pushToBootstrapMethod;
   331         static final MethodHandle MH_pullFromBootstrapMethod;
       
   332         static {
   319         static {
   333             final Class<?> THIS_CLASS = Adapters.class;
   320             final Class<?> THIS_CLASS = PushAdapter.class;
   334             try {
   321             try {
   335                 MH_pushToBootstrapMethod = IMPL_LOOKUP
   322                 MH_pushToBootstrapMethod = IMPL_LOOKUP
   336                     .findStatic(THIS_CLASS, "pushToBootstrapMethod",
   323                     .findStatic(THIS_CLASS, "pushToBootstrapMethod",
   337                                 MethodType.methodType(Object.class, MethodHandle.class,
   324                                 MethodType.methodType(Object.class, MethodHandle.class,
   338                                         Lookup.class, String.class, Object.class, Object[].class));
   325                                         Lookup.class, String.class, Object.class, Object[].class));
       
   326             } catch (Throwable ex) {
       
   327                 throw new InternalError(ex);
       
   328             }
       
   329         }
       
   330     }
       
   331 
       
   332     /*non-public*/ static final
       
   333     class PullAdapter {
       
   334         // skeleton for pull-mode BSM which wraps a push-mode BSM:
       
   335         static Object pullFromBootstrapMethod(MethodHandle pushModeBSM,
       
   336                                               MethodHandles.Lookup lookup,
       
   337                                               BootstrapCallInfo<?> bsci)
       
   338                 throws Throwable {
       
   339             int argc = bsci.size();
       
   340             switch (argc) {
       
   341                 case 0:
       
   342                     return pushModeBSM.invoke(lookup, bsci.invocationName(), bsci.invocationType());
       
   343                 case 1:
       
   344                     return pushModeBSM.invoke(lookup, bsci.invocationName(), bsci.invocationType(),
       
   345                             bsci.get(0));
       
   346                 case 2:
       
   347                     return pushModeBSM.invoke(lookup, bsci.invocationName(), bsci.invocationType(),
       
   348                             bsci.get(0), bsci.get(1));
       
   349                 case 3:
       
   350                     return pushModeBSM.invoke(lookup, bsci.invocationName(), bsci.invocationType(),
       
   351                             bsci.get(0), bsci.get(1), bsci.get(2));
       
   352                 case 4:
       
   353                     return pushModeBSM.invoke(lookup, bsci.invocationName(), bsci.invocationType(),
       
   354                             bsci.get(0), bsci.get(1), bsci.get(2), bsci.get(3));
       
   355                 case 5:
       
   356                     return pushModeBSM.invoke(lookup, bsci.invocationName(), bsci.invocationType(),
       
   357                             bsci.get(0), bsci.get(1), bsci.get(2), bsci.get(3), bsci.get(4));
       
   358                 case 6:
       
   359                     return pushModeBSM.invoke(lookup, bsci.invocationName(), bsci.invocationType(),
       
   360                             bsci.get(0), bsci.get(1), bsci.get(2), bsci.get(3), bsci.get(4), bsci.get(5));
       
   361                 default:
       
   362                     final int NON_SPREAD_ARG_COUNT = 3;  // (lookup, name, type)
       
   363                     final int MAX_SAFE_SIZE = MethodType.MAX_MH_ARITY / 2 - NON_SPREAD_ARG_COUNT;
       
   364                     if (argc >= MAX_SAFE_SIZE) {
       
   365                         // to be on the safe side, use invokeWithArguments which handles jumbo lists
       
   366                         Object[] newargv = new Object[NON_SPREAD_ARG_COUNT + argc];
       
   367                         newargv[0] = lookup;
       
   368                         newargv[1] = bsci.invocationName();
       
   369                         newargv[2] = bsci.invocationType();
       
   370                         bsci.copyConstants(0, argc, newargv, NON_SPREAD_ARG_COUNT);
       
   371                         return pushModeBSM.invokeWithArguments(newargv);
       
   372                     }
       
   373                     MethodType invocationType = MethodType.genericMethodType(NON_SPREAD_ARG_COUNT + argc);
       
   374                     MethodHandle typedBSM = pushModeBSM.asType(invocationType);
       
   375                     MethodHandle spreader = invocationType.invokers().spreadInvoker(NON_SPREAD_ARG_COUNT);
       
   376                     Object[] argv = new Object[argc];
       
   377                     bsci.copyConstants(0, argc, argv, 0);
       
   378                     return spreader.invokeExact(typedBSM, (Object) lookup, (Object) bsci.invocationName(), bsci.invocationType(), argv);
       
   379                 }
       
   380         }
       
   381 
       
   382         static final MethodHandle MH_pullFromBootstrapMethod;
       
   383 
       
   384         static {
       
   385             final Class<?> THIS_CLASS = PullAdapter.class;
       
   386             try {
   339                 MH_pullFromBootstrapMethod = IMPL_LOOKUP
   387                 MH_pullFromBootstrapMethod = IMPL_LOOKUP
   340                     .findStatic(THIS_CLASS, "pullFromBootstrapMethod",
   388                     .findStatic(THIS_CLASS, "pullFromBootstrapMethod",
   341                                 MethodType.methodType(Object.class, MethodHandle.class,
   389                                 MethodType.methodType(Object.class, MethodHandle.class,
   342                                         Lookup.class, BootstrapCallInfo.class));
   390                                         Lookup.class, BootstrapCallInfo.class));
   343             } catch (Throwable ex) {
   391             } catch (Throwable ex) {
   344                 throw new InternalError(ex);
   392                 throw new InternalError(ex);
   345             }
   393             }
   346         }
   394         }
   347 
   395     }
   348         /** Given a push-mode BSM (taking one argument) convert it to a
   396 
   349          *  pull-mode BSM (taking N pre-resolved arguments).
   397     /** Given a push-mode BSM (taking one argument) convert it to a
   350          *  This method is used when, in fact, the JVM is passing up
   398      *  pull-mode BSM (taking N pre-resolved arguments).
   351          *  pre-resolved arguments, but the BSM is expecting lazy stuff.
   399      *  This method is used when, in fact, the JVM is passing up
   352          *  Or, when goToPushMode is true, do the reverse transform.
   400      *  pre-resolved arguments, but the BSM is expecting lazy stuff.
   353          *  (The two transforms are exactly inverse.)
   401      *  Or, when goToPushMode is true, do the reverse transform.
   354          */
   402      *  (The two transforms are exactly inverse.)
   355         static MethodHandle pushMePullYou(MethodHandle bsm, boolean goToPushMode) {
   403      */
   356             if (TRACE_METHOD_LINKAGE)
   404     static MethodHandle pushMePullYou(MethodHandle bsm, boolean goToPushMode) {
   357                 System.out.println("converting BSM to "+(goToPushMode ? "push mode" : "pull mode"));
   405         if (TRACE_METHOD_LINKAGE) {
   358             assert(isPullModeBSM(bsm) == goToPushMode);  //there must be a change
   406             System.out.println("converting BSM of type " + bsm.type() + " to "
   359             if (goToPushMode) {
   407                     + (goToPushMode ? "push mode" : "pull mode"));
   360                 return Adapters.MH_pushToBootstrapMethod.bindTo(bsm).withVarargs(true);
   408         }
   361             } else {
   409         assert(isPullModeBSM(bsm) == goToPushMode); // there must be a change
   362                 return Adapters.MH_pullFromBootstrapMethod.bindTo(bsm).withVarargs(false);
   410         if (goToPushMode) {
   363             }
   411             return PushAdapter.MH_pushToBootstrapMethod.bindTo(bsm).withVarargs(true);
       
   412         } else {
       
   413             return PullAdapter.MH_pullFromBootstrapMethod.bindTo(bsm).withVarargs(false);
   364         }
   414         }
   365     }
   415     }
   366 }
   416 }