1 /* 2 * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved. 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * This code is free software; you can redistribute it and/or modify it 6 * under the terms of the GNU General Public License version 2 only, as 7 * published by the Free Software Foundation. Oracle designates this 8 * particular file as subject to the "Classpath" exception as provided 9 * by Oracle in the LICENSE file that accompanied this code. 10 * 11 * This code is distributed in the hope that it will be useful, but WITHOUT 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 14 * version 2 for more details (a copy is included in the LICENSE file that 15 * accompanied this code). 16 * 17 * You should have received a copy of the GNU General Public License version 18 * 2 along with this work; if not, write to the Free Software Foundation, 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 20 * 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 22 * or visit www.oracle.com if you need additional information or have any 23 * questions. 24 */ 25 package java.lang.invoke; 26 27 import jdk.internal.reflect.ConstantPool; 28 import jdk.internal.vm.annotation.Stable; 29 30 import java.lang.constant.Constable; 31 import java.lang.constant.ConstantDesc; 32 import java.lang.constant.DynamicConstantDesc; 33 import java.lang.reflect.Array; 34 import java.util.Arrays; 35 import java.util.List; 36 import java.util.Objects; 37 38 import java.lang.invoke.AbstractBootstrapCallInfo.*; 39 40 import static java.lang.invoke.AbstractBootstrapCallInfo.maybeShareArguments; 41 import static java.lang.invoke.MethodHandleNatives.Constants.*; 42 import static java.lang.invoke.MethodHandleStatics.TRACE_METHOD_LINKAGE; 43 import static java.lang.invoke.MethodHandles.Lookup; 44 import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP; 45 import static java.util.Objects.requireNonNull; 46 47 final class BootstrapMethodInvoker { 48 /** 49 * Factored code for invoking a bootstrap method for invokedynamic 50 * or a dynamic constant. 51 * @param lookup the capability to access the caller class's constants 52 * @param bsci the BootstrapCallInfo provided by the JVM 53 * @param <T> the kind of the type argument, {@code Class} or {@code MethodType} 54 * @return the expected value, either a CallSite or a constant value 55 */ 56 static <T extends TypeDescriptor & Constable<T>> 57 Object invoke(Lookup lookup, 58 BootstrapCallInfo<T> bsci) { 59 Objects.requireNonNull(lookup); 60 MethodHandle bsm = bsci.bootstrapMethod(); 61 MethodType bsmType = bsm.type(); 62 boolean bsmIsVarargs = bsm.isVarargsCollector(); 63 Object result; 64 65 try { 66 // By using maybeShareArguments, we avoid extra copy steps 67 // on the argument list between a BSM created for the JVM 68 // (by MethodHandleNatives) and the invocation logic of 69 // invokeCommon. 70 if (isPullModeBSM(bsm)) { 71 // Pull-mode API is (Lookup, BootstrapCallInfo) -> Object 72 result = bsm.invoke(lookup, bsci); 73 } else if (isExpressionBSM(bsm)) { 74 if (bsci.invocationName().equals("invoke")) 75 // short circuit in common case 76 result = invokeCommon(bsm, 77 null, null, null, 78 maybeShareArguments(bsci), 79 bsci.argumentList()); 80 else 81 result = ConstantBootstraps.linkExpression(lookup, bsci); 82 } else { 83 // Push-mode BSM, needs to get (lookup, name, type, arg...). 84 result = invokeCommon(bsm, lookup, 85 bsci.invocationName(), bsci.invocationType(), 86 maybeShareArguments(bsci), bsci.argumentList()); 87 } 88 return BootstrapCallInfo.convertResult(bsci.invocationType(), bsmType.returnType(), result); 89 } 90 catch (Error e) { 91 // Pass through an Error, including BootstrapMethodError, any other 92 // form of linkage error, such as IllegalAccessError if the bootstrap 93 // method is inaccessible, or say ThreadDeath/OutOfMemoryError 94 // See the "Linking Exceptions" section for the invokedynamic 95 // instruction in JVMS 6.5. 96 throw e; 97 } 98 catch (Throwable ex) { 99 // Wrap anything else in BootstrapMethodError 100 throw new BootstrapMethodError("bootstrap method initialization exception", ex); 101 } 102 } 103 104 /** A BSM runs in pull mode if and only if its sole arguments 105 * are {@code (Lookup, BootstrapCallInfo)}. 106 * Since the trailing argument is not an array type, it cannot be of variable arity. 107 * The return type of the BSM is unconstrained, but it will often be {@code Object}. 108 */ 109 public static boolean isPullModeBSM(MethodHandle bsm) { 110 MethodType mtype = bsm.type(); 111 return mtype.parameterCount() == 2 112 && mtype.parameterType(0) == Lookup.class 113 && mtype.parameterType(1) == BootstrapCallInfo.class; 114 } 115 116 /** Most BSM calls take a standard set of metadata arguments, 117 * one of {@code (Lookup, String, Class)}, {@code (Lookup, String, MethodType)}, 118 * or {@code (Lookup, BootstrapCallInfo)}. 119 * But if the lead argument is <em>not</em> {@code Lookup} <em>and</em> 120 * the invocation type being linked is a field type ({@code Class}), 121 * then only the static arguments will be passed. 122 * Such a BSM is called an <em>expression mode BSM</em>. 123 * The standard bootstrap method {@link ConstantBootstraps#linkExpression} 124 * is consulted to correctly invoke such an expression bootstrap method. 125 * Often, it is just applied directly to the static arguments. 126 */ 127 static boolean isExpressionBSM(MethodHandle bsm) { 128 MethodType mtype = bsm.type(); 129 return (mtype.parameterCount() == 0 130 || mtype.parameterType(0) != Lookup.class); 131 } 132 133 /** Given a poorly typed BSM, wrap it in a BSM whose 134 * type starts with Lookup. This will prevent it from 135 * being accidentally treated as an expression-mode BSM. 136 * We only do this, of course, if we know that the BSM 137 * is not supposed to have expression mode. This is the 138 * case when the BSM links an invokedynamic instruction. 139 */ 140 static MethodHandle forceLookupParameter(MethodHandle bsm) { 141 if (TRACE_METHOD_LINKAGE) 142 System.out.println("[TRACE_METHOD_LINKAGE] forceLookupParameter "+bsm); 143 MethodHandle mh = MH_forceLookupParameter; 144 if (mh == null) { 145 try { 146 mh = IMPL_LOOKUP.findStatic(BootstrapMethodInvoker.class, "forceLookupParameter", 147 MethodType.methodType(Object.class, MethodHandle.class, 148 Lookup.class, Object[].class)); 149 } catch (ReflectiveOperationException ex) { 150 throw new InternalError(ex); 151 } 152 MH_forceLookupParameter = mh; 153 } 154 return mh.bindTo(bsm).withVarargs(true); 155 } 156 private static @Stable MethodHandle MH_forceLookupParameter; 157 private static Object forceLookupParameter(MethodHandle bsm, 158 Lookup lookup, 159 Object... otherArgs) throws Throwable { 160 // There are often faster ways to get this done, but this formulation 161 // covers all the corner cases. Poorly typed BSMs are rare, anyway. 162 Object[] args = new Object[1 + otherArgs.length]; 163 args[0] = lookup; System.arraycopy(otherArgs, 0, args, 1, otherArgs.length); 164 return bsm.invokeWithArguments(args); 165 } 166 167 /// Signatures which have bespoke invocation paths: 168 169 // Lambda metafactory, standard. 170 private static final MethodType LMF_INDY_MT = MethodType.methodType(CallSite.class, 171 Lookup.class, String.class, MethodType.class, MethodType.class, MethodHandle.class, MethodType.class); 172 173 // Lambda metafactory, alternate. 174 private static final MethodType LMF_ALT_MT = MethodType.methodType(CallSite.class, 175 Lookup.class, String.class, MethodType.class, Object[].class); 176 177 // Lambda metafactory, condy. 178 private static final MethodType LMF_CONDY_MT = MethodType.methodType(Object.class, 179 Lookup.class, String.class, Class.class, MethodType.class, MethodHandle.class, MethodType.class); 180 181 // String concat metafactory. 182 private static final MethodType SCF_MT = MethodType.methodType(CallSite.class, 183 Lookup.class, String.class, MethodType.class, String.class, Object[].class); 184 185 /** The JVM produces java.lang.Integer values to box 186 * CONSTANT_Integer boxes but does not intern them. 187 * Let's intern them. This is slightly wrong for 188 * a {@code CONSTANT_Dynamic} which produces an 189 * un-interned integer (e.g., {@code new Integer(0)}). 190 */ 191 static Object maybeReBox(Object x) { 192 if (x instanceof Integer) { 193 int xi = (int) x; 194 if (xi == (byte) xi) 195 x = xi; // must rebox; see JLS 5.1.7 196 } 197 return x; 198 } 199 200 static void maybeReBoxElements(Object[] xa) { 201 for (int i = 0; i < xa.length; i++) { 202 xa[i] = maybeReBox(xa[i]); 203 } 204 } 205 206 static Object invokeCommon(MethodHandle handle, 207 Lookup lookup, 208 String name, 209 TypeDescriptor type, 210 Object[] argv, 211 List<Object> args) 212 throws Throwable { 213 // Efficiently invoke a method (probably a BSM) on a particular 214 // set of bootstrap arguments, perhaps including the usual 215 // metadata values of (lookup, name, type). 216 // To avoid copying, source the arguments from whatever 217 // the caller has on hand: A Java array, a List, or both. 218 // 219 // Support fast arity-specific invocation paths for both 220 // method types and field types (Class and MethodType), and 221 // no-metadata calls also. To get to these paths as often 222 // as possible, executet some varargs processing directly. 223 // 224 // For further optimization we special-case various known BSMs, 225 // including LambdaMetafactory::metafactory and 226 // StringConcatFactory::makeConcatWithConstants. 227 // (Actually, we special-case their *types*, which amounts 228 // to the same thing.) 229 // 230 // By providing static type information or even invoking 231 // exactly, we avoid emitting code to perform runtime 232 // checking. 233 // 234 // Because we usually don't examine the BSM return type, 235 // we can't use the MH.invokeExact mode as much as we would 236 // like, but at least the MH.invoke path has a reasonably 237 // small type mismatch. 238 239 if (TRACE_METHOD_LINKAGE) { 240 System.out.println("invoking " + handle + " on " + (argv == null ? args : Arrays.asList(argv))); 241 } 242 int argc = argv != null ? argv.length : args.size(); 243 244 boolean isFieldType = (type instanceof Class); 245 boolean isMethodType = (type instanceof MethodType); 246 247 boolean passMetadata = (lookup != null); 248 final int MAX_ARITY = 7, FT = MAX_ARITY+1, MT = FT*2, NMD = 0; 249 final int METADATA_ARG_COUNT = 3; // (lookup, name, type) 250 final int metaArgc = passMetadata ? METADATA_ARG_COUNT : 0; 251 if (passMetadata) { 252 requireNonNull(name); 253 requireNonNull(type); 254 } 255 256 MethodType handleType = handle.type(); 257 boolean handleVarargs = handle.isVarargsCollector(); 258 259 if (!passMetadata) { 260 // Must not lead with a Lookup formal parameter type. 261 // Lookup leading types are reserved for metadata-using BSMs. 262 assert(handleType.parameterCount() == 0 || 263 handleType.parameterType(0) != Lookup.class); 264 assert(name == null); 265 assert(type == null); 266 } else if (isFieldType) { 267 // With condy, we require an explicit leading type of Lookup, 268 // if metadata is to be passed. 269 assert(handleType.parameterCount() == 0 || 270 handleType.parameterType(0) == Lookup.class); 271 // Also, the caller should not try to handle a BSCI call here. 272 assert(handleType.parameterCount() != 2 || 273 handleType.parameterType(1) != BootstrapCallInfo.class); 274 // Otherwise, we are doing an old-style indy bootstrap, 275 // which tolerates Object in the metadata positions. 276 } 277 278 // Some varargs methods can be handled quickly here, 279 // rather than going through more dynamic invocation paths. 280 // Do the varargs spreading if: the BSM is varargs, the BSM 281 // directly accepts at least the metadata arguments (if applicable), 282 // the given static arguments fill in the BSM's inital set 283 // of arguments, and the BSM's trailing argument is a 284 // reference array. In that case, split the static argument 285 // list into head and tail arrays, and link the latter onto the 286 // end of the former. 287 if (handleVarargs) { 288 int headArgc = (handleType.parameterCount() - 1) - metaArgc; 289 Class<?> tailType = handleType.lastParameterType(); 290 Class<?> tailElementType = tailType.getComponentType(); 291 if (headArgc >= 0 && 292 headArgc <= argc && 293 Object[].class.isAssignableFrom(tailType) && 294 tailElementType != null) { 295 // Make a shortened argument list for a fixed-arity call. 296 Object[] headArgv = new Object[headArgc + 1]; 297 if (argv != null) { 298 System.arraycopy(argv, 0, headArgv, 0, headArgc); 299 } else { 300 List<Object> headArgs = args.subList(0, headArgc); 301 headArgv = headArgs.toArray(headArgv); 302 } 303 // Collect the trailing arguments into an array of the 304 // required type. Also, make sure they fit into the array. 305 int tailArgc = argc - headArgc; 306 Object[] tailArgv = (tailElementType == Object.class) 307 ? new Object[tailArgc] 308 : (Object[]) Array.newInstance(tailElementType, tailArgc); 309 try { 310 if (argv != null) { 311 System.arraycopy(argv, headArgc, tailArgv, 0, tailArgc); 312 } else { 313 List<Object> tailArgs = args.subList(headArgc, argc); 314 tailArgv = tailArgs.toArray(tailArgv); 315 } 316 } catch (ArrayStoreException ex) { 317 // Oops, one of the actuals doesn't fit in the varargs formal. 318 // For example, f(String...) is passed ("foo", 42, "bar"). 319 tailArgv = null; // bail out 320 } 321 if (tailArgv != null) { 322 // Link the head to the tail: 323 headArgv[headArgc] = tailArgv; 324 // Now swap in a new MH and arglist: 325 handle = handle.asFixedArity(); 326 assert(handleType == handle.type()); // still true 327 handleVarargs = false; 328 argv = headArgv; 329 args = null; 330 argc = headArgc + 1; 331 } 332 } 333 } 334 335 // Now try to make an inline call: 336 if (argc <= MAX_ARITY && argv == null) 337 argv = args.toArray(); 338 339 assert(argv == null || argc == argv.length); 340 assert(args == null || argc == args.size()); 341 342 // If we don't provide static type information for the type, 343 // we'll generate runtime checks. The cases marked FT and MT 344 // avoid that problem. 345 346 switch (argc > MAX_ARITY ? -1 : 347 argc + (isFieldType ? FT : isMethodType ? MT : NMD)) { 348 // Fixed-arity cases for a Class (field) type: 349 case 0+FT: 350 return handle.invoke(lookup, name, (Class<?>)type); 351 case 1+FT: 352 return handle.invoke(lookup, name, (Class<?>)type, 353 argv[0]); 354 case 2+FT: 355 return handle.invoke(lookup, name, (Class<?>)type, 356 argv[0], argv[1]); 357 case 3+FT: 358 if (handleType == LMF_CONDY_MT && !handleVarargs) { 359 return handle.invokeExact(lookup, name, (Class<?>)type, 360 (MethodType)argv[0], 361 (MethodHandle)argv[1], 362 (MethodType)argv[2]); 363 } 364 return handle.invoke(lookup, name, (Class<?>)type, 365 argv[0], argv[1], argv[2]); 366 case 4+FT: 367 return handle.invoke(lookup, name, (Class<?>)type, 368 argv[0], argv[1], argv[2], argv[3]); 369 case 5+FT: 370 return handle.invoke(lookup, name, (Class<?>)type, 371 argv[0], argv[1], argv[2], argv[3], 372 argv[4]); 373 case 6+FT: 374 return handle.invoke(lookup, name, (Class<?>)type, 375 argv[0], argv[1], argv[2], argv[3], 376 argv[4], argv[5]); 377 case MAX_ARITY+FT: 378 return handle.invoke(lookup, name, (Class<?>)type, 379 argv[0], argv[1], argv[2], argv[3], 380 argv[4], argv[5], argv[6]); 381 382 // Same cases, but for a MethodType argument: 383 case 0+MT: 384 return handle.invoke(lookup, name, (MethodType)type); 385 case 1+MT: 386 if (handleType == LMF_ALT_MT && !handleVarargs) { 387 return (CallSite) 388 handle.invokeExact(lookup, name, (MethodType)type, 389 (Object[])argv[0]); 390 } 391 return handle.invoke(lookup, name, (MethodType)type, 392 argv[0]); 393 case 2+MT: 394 if (handleType == SCF_MT && !handleVarargs) { 395 return (CallSite) 396 handle.invokeExact(lookup, name, (MethodType)type, 397 (String)argv[0], 398 (Object[])argv[1]); 399 } 400 return handle.invoke(lookup, name, (MethodType)type, 401 argv[0], argv[1]); 402 case 3+MT: 403 if (handleType == LMF_INDY_MT && !handleVarargs) { 404 return (CallSite) 405 handle.invokeExact(lookup, name, (MethodType)type, 406 (MethodType)argv[0], 407 (MethodHandle)argv[1], 408 (MethodType)argv[2]); 409 } 410 return handle.invoke(lookup, name, (MethodType)type, 411 argv[0], argv[1], argv[2]); 412 case 4+MT: 413 return handle.invoke(lookup, name, (MethodType)type, 414 argv[0], argv[1], argv[2], argv[3]); 415 case 5+MT: 416 return handle.invoke(lookup, name, (MethodType)type, 417 argv[0], argv[1], argv[2], argv[3], 418 argv[4]); 419 case 6+MT: 420 return handle.invoke(lookup, name, (MethodType)type, 421 argv[0], argv[1], argv[2], argv[3], 422 argv[4], argv[5]); 423 case MAX_ARITY+MT: 424 return handle.invoke(lookup, name, (MethodType)type, 425 argv[0], argv[1], argv[2], argv[3], 426 argv[4], argv[5], argv[6]); 427 428 // Same cases again, but without metadata: 429 case 0+NMD: 430 return handle.invoke(); 431 case 1+NMD: 432 return handle.invoke(argv[0]); 433 case 2+NMD: 434 return handle.invoke(argv[0], argv[1]); 435 case 3+NMD: 436 return handle.invoke(argv[0], argv[1], argv[2]); 437 case 4+NMD: 438 return handle.invoke(argv[0], argv[1], argv[2], argv[3]); 439 case 5+NMD: 440 return handle.invoke(argv[0], argv[1], argv[2], argv[3], 441 argv[4]); 442 case 6+NMD: 443 return handle.invoke(argv[0], argv[1], argv[2], argv[3], 444 argv[4], argv[5]); 445 case MAX_ARITY+NMD: 446 return handle.invoke(argv[0], argv[1], argv[2], argv[3], 447 argv[4], argv[5], argv[6]); 448 } 449 450 // We have to stop at some point and use invokeWithArguments instead. 451 // Note that invokeWithArguments handles jumbo argument lists. 452 453 if (passMetadata) { 454 Object[] allArgv = new Object[metaArgc + argc]; 455 int pos = 0; 456 allArgv[pos++] = lookup; 457 allArgv[pos++] = name; 458 allArgv[pos++] = type; 459 assert(pos == metaArgc); 460 if (argv != null) { 461 System.arraycopy(argv, 0, allArgv, pos, argc); 462 pos += argc; 463 } else { 464 for (Object arg : args) { 465 allArgv[pos++] = arg; 466 } 467 } 468 assert(pos == allArgv.length); 469 return handle.invokeWithArguments(allArgv); 470 } else if (argv != null) { 471 // It's simple if there are no metadata arguments to prepend. 472 return handle.invokeWithArguments(argv); 473 } else { 474 return handle.invokeWithArguments(args); 475 } 476 } 477 478 /** Canonical VM-aware implementation of BootstrapCallInfo. 479 * Knows how to dig into the JVM for lazily resolved (pull-mode) constants. 480 */ 481 static final class VM_BSCI<T extends TypeDescriptor & Constable<T>> extends WithCache<T> { 482 private final int bssIndex; 483 private final int indyIndex; 484 private final ConstantPool pool; 485 private int[] argIndexes; // lazy 486 487 public VM_BSCI(ConstantPool pool, int bssIndex, int indyIndex, 488 MethodHandle bsm, String name, TypeView<T> type, Object[] arguments) { 489 super(bsm, name, type, arguments); 490 this.pool = pool; 491 this.bssIndex = bssIndex; 492 this.indyIndex = indyIndex; 493 } 494 495 /** Special VM-specific hook to resolve static arguments. */ 496 @Override Object resolveConstant(int i) { 497 Object[] buf = { null }; 498 copyVMArguments(i, i+1, buf, 0, BAR_FORCE, null); 499 Object res = buf[0]; 500 int next = i + 1; 501 if (next < cache.length && cache[next] == null) 502 maybePrefetchIntoCache(cache, next, false); // try to prefetch 503 return res; 504 } 505 506 /** Special VM-specific hook to find symbolic references. */ 507 @Override ConstantDesc<?> findSymbol(int i) { 508 Object[] buf = { null }; 509 copyVMArguments(i, i+1, buf, 0, BAR_SYMREF, null); 510 ConstantDesc<?> res = (ConstantDesc<?>) buf[0]; 511 //int next = i + 1; 512 //if (next < symCache.length && symCache[next] == null) 513 // maybePrefetchIntoCache(symCache, next, false); // try to prefetch 514 return res; 515 } 516 517 private Class<?> caller() { return pool.getHolder(); } 518 519 /*non-public contract with ArgList*/ 520 void copyVMArguments(int start, int end, 521 Object[] buf, int pos, 522 byte resolving, Object ifNotPresent) { 523 if (buf.getClass() != Object[].class) throw new InternalError(); 524 int i = start, bufi = pos; 525 if (resolving == BAR_SYMREF) { 526 while (i < end) { 527 Object x = symCache[i]; 528 if (x == null) break; 529 buf[bufi++] = x; 530 i++; 531 } 532 if (i >= end) return; 533 // pull in all of the symbols into symCache 534 int[] temp = new int[end - i]; 535 int tempi = 0; 536 pool.copyOutBootstrapArgumentsAt(bssIndex, 537 start, end, temp, 0, 538 BAR_SYMREF, null, null, false); 539 for (; i < end; i++) { 540 ConstantDesc<?> x = symCache[i]; 541 int symIndex = temp[tempi++]; 542 if (x == null) { 543 x = makeConstantFromPool(symIndex); 544 symCache[i] = x; 545 } 546 buf[bufi++] = x; 547 } 548 return; 549 } 550 assert(resolving == BAR_IFPRESENT || resolving == BAR_FORCE); 551 for (; i < end; i++) { 552 Object x = cache[i]; 553 if (x == null) break; 554 buf[bufi++] = unwrapNull(x); 555 } 556 // give up at first null and grab the rest in one big block 557 if (i >= end) return; 558 if (TRACE_METHOD_LINKAGE) { 559 System.out.println("resolving more BSM arguments: " + 560 Arrays.asList(caller().getSimpleName(), bssIndex, indyIndex, i, end)); 561 } 562 pool.copyOutBootstrapArgumentsAt(bssIndex, 563 i, end, cache, i, 564 resolving, null, wrapNull(null), true); 565 for (; i < end; i++) { 566 Object x = cache[i]; 567 Object x2 = maybeReBox(x); 568 if (x2 != x) cache[i] = x = x2; 569 buf[bufi++] = (x == null) ? ifNotPresent : unwrapNull(x); 570 } 571 if (end < cache.length && cache[end] == null) 572 maybePrefetchIntoCache(cache, end, true); // try to prefetch 573 } 574 575 private ConstantDesc<?> makeConstantFromPool(int symIndex) { 576 return pool.getConstantDescAt(symIndex); 577 } 578 579 private static final int MIN_PF = 4; 580 private void maybePrefetchIntoCache(Object[] cache, int i, boolean bulk) { 581 int len = cache.length; 582 assert(0 <= i && i <= len); 583 int pfLimit = i; 584 if (bulk) pfLimit += i; // exponential prefetch expansion 585 // try to prefetch at least MIN_PF elements 586 if (pfLimit < i + MIN_PF) pfLimit = i + MIN_PF; 587 if (pfLimit > len || pfLimit < 0) pfLimit = len; 588 // stop prefetching where cache is more full than empty 589 int empty = 0, nonEmpty = 0, lastEmpty = i; 590 for (int j = i; j < pfLimit; j++) { 591 if (cache[j] == null) { 592 empty++; 593 lastEmpty = j; 594 } else { 595 nonEmpty++; 596 if (nonEmpty > empty) { 597 pfLimit = lastEmpty + 1; 598 break; 599 } 600 if (pfLimit < len) pfLimit++; 601 } 602 } 603 if (bulk && empty < MIN_PF && pfLimit < len) 604 return; // not worth the effort 605 prefetchIntoCache(cache, i, pfLimit); 606 } 607 608 private void prefetchIntoCache(Object[] cache, int i, int pfLimit) { 609 if (pfLimit <= i) return; // corner case 610 if (TRACE_METHOD_LINKAGE) { 611 System.out.println("prefetching BSM arguments: " + 612 Arrays.asList(caller().getSimpleName(), bssIndex, indyIndex, i, pfLimit)); 613 } 614 pool.copyOutBootstrapArgumentsAt(bssIndex, 615 i, pfLimit, cache, i, 616 BAR_IFPRESENT, null, wrapNull(null), true); 617 } 618 619 void setArgIndexes(int[] argIndexes) { 620 assert(this.argIndexes == null); 621 this.argIndexes = argIndexes; 622 } 623 } 624 625 /** Canonical DynamicConstantDesc implementation of BootstrapCallInfo. 626 */ 627 static final class DCD_BSCI extends WithCache<Class<?>> { 628 private Lookup lookup; 629 private DynamicConstantDesc<?> desc; 630 private final List<ConstantDesc<?>> args; 631 632 public DCD_BSCI(Lookup lookup, DynamicConstantDesc<?> desc) throws ReflectiveOperationException { 633 super(desc.bootstrapMethod().resolveConstantDesc(lookup), 634 desc.constantName(), 635 new TypeView<Class<?>>(desc.constantType(), lookup), 636 desc.bootstrapArgs()); 637 this.lookup = lookup; 638 this.desc = desc; 639 this.args = desc.bootstrapArgsList(); 640 } 641 642 @Override Object resolveConstant(int i) throws BootstrapMethodError { 643 try { 644 return argumentDesc(i).resolveConstantDesc(lookup); 645 } catch (ReflectiveOperationException ex) { 646 throw new BootstrapMethodError(ex); 647 } 648 } 649 650 @Override 651 ConstantDesc<?> findSymbol(int i) { 652 return args.get(i); 653 } 654 } 655 656 /** 657 * Create a BootstrapCallInfo whose symbolic content is derived from the given 658 * descriptor. When it resolves constants, it will use the given Lookup object. 659 * @param desc the dynamic constant descriptor 660 * @param lookup a lookup object which is capable of resolving the dynamic constant 661 * @return a BootstrapCallInfo which carries the given 662 * @throws ReflectiveOperationException if the bootstrap method fails to resolve 663 */ 664 static BootstrapCallInfo<Class<?>> ofConstantDesc(DynamicConstantDesc<?> desc, Lookup lookup) 665 throws ReflectiveOperationException { 666 return new BootstrapMethodInvoker.DCD_BSCI(lookup, desc); 667 } 668 669 /** 670 * Resolve a dynamic constant, by creating a temporary BootstrapCallInfo for it 671 * and immediately invoking its resolution behavior. Any cached resolution state 672 * will be lost after the temporary BootstrapCallInfo is discarded. 673 * @param desc the dynamic constant descriptor 674 * @param lookup a lookup object which is capable of resolving the dynamic constant 675 * @return the result of resolving the descriptor in the lookup class 676 * @throws ReflectiveOperationException 677 */ 678 static Object resolveDynamicConstant(DynamicConstantDesc<?> desc, Lookup lookup) 679 throws ReflectiveOperationException { 680 try { 681 return invoke(lookup, ofConstantDesc(desc, lookup)); 682 } catch (LinkageError ex) { 683 var roe = ex.getCause(); 684 if (roe instanceof ReflectiveOperationException) 685 throw (ReflectiveOperationException) roe; 686 throw ex; 687 } 688 } 689 }