< prev index next >

src/java.base/share/classes/java/lang/invoke/BootstrapMethodInvoker.java

Print this page
rev 48895 : 8195850: Improve startup of code to pull arguments from BootstrapMethodInvoker
Reviewed-by: psandoz, jrose


  50      * @return the expected value, either a CallSite or a constant value
  51      */
  52     static <T> T invoke(Class<T> resultType,
  53                         MethodHandle bootstrapMethod,
  54                         // Callee information:
  55                         String name, Object type,
  56                         // Extra arguments for BSM, if any:
  57                         Object info,
  58                         // Caller information:
  59                         Class<?> callerClass) {
  60         MethodHandles.Lookup caller = IMPL_LOOKUP.in(callerClass);
  61         Object result;
  62         boolean pullMode = isPullModeBSM(bootstrapMethod);  // default value is false
  63         boolean vmIsPushing = !staticArgumentsPulled(info); // default value is true
  64         MethodHandle pullModeBSM;
  65         // match the VM with the BSM
  66         if (vmIsPushing) {
  67             // VM is pushing arguments at us
  68             pullModeBSM = null;
  69             if (pullMode) {
  70                 bootstrapMethod = Adapters.pushMePullYou(bootstrapMethod, true);
  71             }
  72         } else {
  73             // VM wants us to pull args from it
  74             pullModeBSM = pullMode ? bootstrapMethod :
  75                     Adapters.pushMePullYou(bootstrapMethod, false);
  76             bootstrapMethod = null;
  77         }
  78         try {
  79             info = maybeReBox(info);
  80             if (info == null) {
  81                 // VM is allowed to pass up a null meaning no BSM args
  82                 result = bootstrapMethod.invoke(caller, name, type);
  83             }
  84             else if (!info.getClass().isArray()) {
  85                 // VM is allowed to pass up a single BSM arg directly
  86                 result = bootstrapMethod.invoke(caller, name, type, info);
  87             }
  88             else if (info.getClass() == int[].class) {
  89                 // VM is allowed to pass up a pair {argc, index}
  90                 // referring to 'argc' BSM args at some place 'index'
  91                 // in the guts of the VM (associated with callerClass).
  92                 // The format of this index pair is private to the
  93                 // handshake between the VM and this class only.
  94                 // This supports "pulling" of arguments.
  95                 // The VM is allowed to do this for any reason.


 220             Object res = wrapNull(buf[0]);
 221             cache[i] = res;
 222             int next = i + 1;
 223             if (next < cache.length && cache[next] == null)
 224                 maybePrefetchIntoCache(next, false);  // try to prefetch
 225             return res;
 226         }
 227 
 228         @Override public int copyConstants(int start, int end,
 229                                            Object[] buf, int pos) {
 230             int i = start, bufi = pos;
 231             while (i < end) {
 232                 Object x = cache[i];
 233                 if (x == null)  break;
 234                 buf[bufi++] = unwrapNull(x);
 235                 i++;
 236             }
 237             // give up at first null and grab the rest in one big block
 238             if (i >= end)  return i;
 239             Object[] temp = new Object[end - i];
 240             if (TRACE_METHOD_LINKAGE)
 241                 System.out.println("resolving more BSM arguments: "+
 242                         Arrays.asList(caller.getSimpleName(), Arrays.toString(indexInfo), i, end));

 243             copyOutBootstrapArguments(caller, indexInfo,
 244                                       i, end, temp, 0,
 245                                       true, null);
 246             for (Object x : temp) {
 247                 x = maybeReBox(x);
 248                 buf[bufi++] = x;
 249                 cache[i++] = wrapNull(x);
 250             }
 251             if (end < cache.length && cache[end] == null)
 252                 maybePrefetchIntoCache(end, true);  // try to prefetch
 253             return i;
 254         }
 255 
 256         private static final int MIN_PF = 4;
 257         private void maybePrefetchIntoCache(int i, boolean bulk) {
 258             int len = cache.length;
 259             assert(0 <= i && i <= len);
 260             int pfLimit = i;
 261             if (bulk)  pfLimit += i;  // exponential prefetch expansion
 262             // try to prefetch at least MIN_PF elements


 268                 if (cache[j] == null) {
 269                     empty++;
 270                     lastEmpty = j;
 271                 } else {
 272                     nonEmpty++;
 273                     if (nonEmpty > empty) {
 274                         pfLimit = lastEmpty + 1;
 275                         break;
 276                     }
 277                     if (pfLimit < len)  pfLimit++;
 278                 }
 279             }
 280             if (bulk && empty < MIN_PF && pfLimit < len)
 281                 return;  // not worth the effort
 282             prefetchIntoCache(i, pfLimit);
 283         }
 284 
 285         private void prefetchIntoCache(int i, int pfLimit) {
 286             if (pfLimit <= i)  return;  // corner case
 287             Object[] temp = new Object[pfLimit - i];
 288             if (TRACE_METHOD_LINKAGE)
 289                 System.out.println("prefetching BSM arguments: "+
 290                         Arrays.asList(caller.getSimpleName(), Arrays.toString(indexInfo), i, pfLimit));

 291             copyOutBootstrapArguments(caller, indexInfo,
 292                                       i, pfLimit, temp, 0,
 293                                       false, NOT_PRESENT);
 294             for (Object x : temp) {
 295                 if (x != NOT_PRESENT && cache[i] == null) {
 296                     cache[i] = wrapNull(maybeReBox(x));
 297                 }
 298                 i++;
 299             }
 300         }
 301     }
 302 
 303     /*non-public*/ static final
 304     class Adapters {
 305         // skeleton for push-mode BSM which wraps a pull-mode BSM:
 306         static Object pushToBootstrapMethod(MethodHandle pullModeBSM,
 307                                             MethodHandles.Lookup lookup, String name, Object type,
 308                                             Object... arguments) throws Throwable {
 309             ConstantGroup cons = makeConstantGroup(Arrays.asList(arguments));
 310             BootstrapCallInfo<?> bsci = makeBootstrapCallInfo(pullModeBSM, name, type, cons);
 311             if (TRACE_METHOD_LINKAGE)
 312                 System.out.println("pull-mode BSM gets pushed arguments from fake BSCI");
 313             return pullModeBSM.invoke(lookup, bsci);
 314         }
 315 
















 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;








 331         static final MethodHandle MH_pullFromBootstrapMethod;

 332         static {
 333             final Class<?> THIS_CLASS = Adapters.class;
 334             try {
 335                 MH_pushToBootstrapMethod = IMPL_LOOKUP
 336                     .findStatic(THIS_CLASS, "pushToBootstrapMethod",
 337                                 MethodType.methodType(Object.class, MethodHandle.class,
 338                                         Lookup.class, String.class, Object.class, Object[].class));
 339                 MH_pullFromBootstrapMethod = IMPL_LOOKUP
 340                     .findStatic(THIS_CLASS, "pullFromBootstrapMethod",
 341                                 MethodType.methodType(Object.class, MethodHandle.class,
 342                                         Lookup.class, BootstrapCallInfo.class));
 343             } catch (Throwable ex) {
 344                 throw new InternalError(ex);
 345             }
 346         }

 347 
 348         /** Given a push-mode BSM (taking one argument) convert it to a
 349          *  pull-mode BSM (taking N pre-resolved arguments).
 350          *  This method is used when, in fact, the JVM is passing up
 351          *  pre-resolved arguments, but the BSM is expecting lazy stuff.
 352          *  Or, when goToPushMode is true, do the reverse transform.
 353          *  (The two transforms are exactly inverse.)
 354          */
 355         static MethodHandle pushMePullYou(MethodHandle bsm, boolean goToPushMode) {
 356             if (TRACE_METHOD_LINKAGE)
 357                 System.out.println("converting BSM to "+(goToPushMode ? "push mode" : "pull mode"));
 358             assert(isPullModeBSM(bsm) == goToPushMode);  //there must be a change


 359             if (goToPushMode) {
 360                 return Adapters.MH_pushToBootstrapMethod.bindTo(bsm).withVarargs(true);
 361             } else {
 362                 return Adapters.MH_pullFromBootstrapMethod.bindTo(bsm).withVarargs(false);
 363             }
 364         }
 365     }
 366 }


  50      * @return the expected value, either a CallSite or a constant value
  51      */
  52     static <T> T invoke(Class<T> resultType,
  53                         MethodHandle bootstrapMethod,
  54                         // Callee information:
  55                         String name, Object type,
  56                         // Extra arguments for BSM, if any:
  57                         Object info,
  58                         // Caller information:
  59                         Class<?> callerClass) {
  60         MethodHandles.Lookup caller = IMPL_LOOKUP.in(callerClass);
  61         Object result;
  62         boolean pullMode = isPullModeBSM(bootstrapMethod);  // default value is false
  63         boolean vmIsPushing = !staticArgumentsPulled(info); // default value is true
  64         MethodHandle pullModeBSM;
  65         // match the VM with the BSM
  66         if (vmIsPushing) {
  67             // VM is pushing arguments at us
  68             pullModeBSM = null;
  69             if (pullMode) {
  70                 bootstrapMethod = pushMePullYou(bootstrapMethod, true);
  71             }
  72         } else {
  73             // VM wants us to pull args from it
  74             pullModeBSM = pullMode ? bootstrapMethod :
  75                     pushMePullYou(bootstrapMethod, false);
  76             bootstrapMethod = null;
  77         }
  78         try {
  79             info = maybeReBox(info);
  80             if (info == null) {
  81                 // VM is allowed to pass up a null meaning no BSM args
  82                 result = bootstrapMethod.invoke(caller, name, type);
  83             }
  84             else if (!info.getClass().isArray()) {
  85                 // VM is allowed to pass up a single BSM arg directly
  86                 result = bootstrapMethod.invoke(caller, name, type, info);
  87             }
  88             else if (info.getClass() == int[].class) {
  89                 // VM is allowed to pass up a pair {argc, index}
  90                 // referring to 'argc' BSM args at some place 'index'
  91                 // in the guts of the VM (associated with callerClass).
  92                 // The format of this index pair is private to the
  93                 // handshake between the VM and this class only.
  94                 // This supports "pulling" of arguments.
  95                 // The VM is allowed to do this for any reason.


 220             Object res = wrapNull(buf[0]);
 221             cache[i] = res;
 222             int next = i + 1;
 223             if (next < cache.length && cache[next] == null)
 224                 maybePrefetchIntoCache(next, false);  // try to prefetch
 225             return res;
 226         }
 227 
 228         @Override public int copyConstants(int start, int end,
 229                                            Object[] buf, int pos) {
 230             int i = start, bufi = pos;
 231             while (i < end) {
 232                 Object x = cache[i];
 233                 if (x == null)  break;
 234                 buf[bufi++] = unwrapNull(x);
 235                 i++;
 236             }
 237             // give up at first null and grab the rest in one big block
 238             if (i >= end)  return i;
 239             Object[] temp = new Object[end - i];
 240             if (TRACE_METHOD_LINKAGE) {
 241                 System.out.println("resolving more BSM arguments: " +
 242                         Arrays.asList(caller.getSimpleName(), Arrays.toString(indexInfo), i, end));
 243             }
 244             copyOutBootstrapArguments(caller, indexInfo,
 245                                       i, end, temp, 0,
 246                                       true, null);
 247             for (Object x : temp) {
 248                 x = maybeReBox(x);
 249                 buf[bufi++] = x;
 250                 cache[i++] = wrapNull(x);
 251             }
 252             if (end < cache.length && cache[end] == null)
 253                 maybePrefetchIntoCache(end, true);  // try to prefetch
 254             return i;
 255         }
 256 
 257         private static final int MIN_PF = 4;
 258         private void maybePrefetchIntoCache(int i, boolean bulk) {
 259             int len = cache.length;
 260             assert(0 <= i && i <= len);
 261             int pfLimit = i;
 262             if (bulk)  pfLimit += i;  // exponential prefetch expansion
 263             // try to prefetch at least MIN_PF elements


 269                 if (cache[j] == null) {
 270                     empty++;
 271                     lastEmpty = j;
 272                 } else {
 273                     nonEmpty++;
 274                     if (nonEmpty > empty) {
 275                         pfLimit = lastEmpty + 1;
 276                         break;
 277                     }
 278                     if (pfLimit < len)  pfLimit++;
 279                 }
 280             }
 281             if (bulk && empty < MIN_PF && pfLimit < len)
 282                 return;  // not worth the effort
 283             prefetchIntoCache(i, pfLimit);
 284         }
 285 
 286         private void prefetchIntoCache(int i, int pfLimit) {
 287             if (pfLimit <= i)  return;  // corner case
 288             Object[] temp = new Object[pfLimit - i];
 289             if (TRACE_METHOD_LINKAGE) {
 290                 System.out.println("prefetching BSM arguments: " +
 291                         Arrays.asList(caller.getSimpleName(), Arrays.toString(indexInfo), i, pfLimit));
 292             }
 293             copyOutBootstrapArguments(caller, indexInfo,
 294                                       i, pfLimit, temp, 0,
 295                                       false, NOT_PRESENT);
 296             for (Object x : temp) {
 297                 if (x != NOT_PRESENT && cache[i] == null) {
 298                     cache[i] = wrapNull(maybeReBox(x));
 299                 }
 300                 i++;
 301             }
 302         }
 303     }
 304 
 305     /*non-public*/ static final
 306     class PushAdapter {
 307         // skeleton for push-mode BSM which wraps a pull-mode BSM:
 308         static Object pushToBootstrapMethod(MethodHandle pullModeBSM,
 309                                             MethodHandles.Lookup lookup, String name, Object type,
 310                                             Object... arguments) throws Throwable {
 311             ConstantGroup cons = makeConstantGroup(Arrays.asList(arguments));
 312             BootstrapCallInfo<?> bsci = makeBootstrapCallInfo(pullModeBSM, name, type, cons);
 313             if (TRACE_METHOD_LINKAGE)
 314                 System.out.println("pull-mode BSM gets pushed arguments from fake BSCI");
 315             return pullModeBSM.invoke(lookup, bsci);
 316         }
 317 
 318         static final MethodHandle MH_pushToBootstrapMethod;
 319         static {
 320             final Class<?> THIS_CLASS = PushAdapter.class;
 321             try {
 322                 MH_pushToBootstrapMethod = IMPL_LOOKUP
 323                     .findStatic(THIS_CLASS, "pushToBootstrapMethod",
 324                                 MethodType.methodType(Object.class, MethodHandle.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 {




 387                 MH_pullFromBootstrapMethod = IMPL_LOOKUP
 388                     .findStatic(THIS_CLASS, "pullFromBootstrapMethod",
 389                                 MethodType.methodType(Object.class, MethodHandle.class,
 390                                         Lookup.class, BootstrapCallInfo.class));
 391             } catch (Throwable ex) {
 392                 throw new InternalError(ex);
 393             }
 394         }
 395     }
 396 
 397     /** Given a push-mode BSM (taking one argument) convert it to a
 398      *  pull-mode BSM (taking N pre-resolved arguments).
 399      *  This method is used when, in fact, the JVM is passing up
 400      *  pre-resolved arguments, but the BSM is expecting lazy stuff.
 401      *  Or, when goToPushMode is true, do the reverse transform.
 402      *  (The two transforms are exactly inverse.)
 403      */
 404     static MethodHandle pushMePullYou(MethodHandle bsm, boolean goToPushMode) {
 405         if (TRACE_METHOD_LINKAGE) {
 406             System.out.println("converting BSM of type " + bsm.type() + " to "
 407                     + (goToPushMode ? "push mode" : "pull mode"));
 408         }
 409         assert(isPullModeBSM(bsm) == goToPushMode); // there must be a change
 410         if (goToPushMode) {
 411             return PushAdapter.MH_pushToBootstrapMethod.bindTo(bsm).withVarargs(true);
 412         } else {
 413             return PullAdapter.MH_pullFromBootstrapMethod.bindTo(bsm).withVarargs(false);

 414         }
 415     }
 416 }
< prev index next >