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 sun.invoke.util.Wrapper; 28 29 import java.lang.invoke.AbstractConstantGroup.BSCIWithCache; 30 import java.util.Arrays; 31 32 import static java.lang.invoke.BootstrapCallInfo.makeBootstrapCallInfo; 33 import static java.lang.invoke.ConstantGroup.makeConstantGroup; 34 import static java.lang.invoke.MethodHandleNatives.*; 35 import static java.lang.invoke.MethodHandleStatics.TRACE_METHOD_LINKAGE; 36 import static java.lang.invoke.MethodHandles.Lookup; 37 import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP; 38 39 final class BootstrapMethodInvoker { 40 41 /** 42 * Factored code for invoking a bootstrap method for invokedynamic 43 * or a dynamic constant. 44 * @param resultType the expected return type (either CallSite or a constant type) 45 * @param bootstrapMethod the BSM to call 46 * @param name the method name or constant name 47 * @param type the method type or constant type 48 * @param info information passed up from the JVM, to derive static arguments 49 * @param callerClass the class containing the resolved method call or constant load 50 * @param <T> the expected return type 51 * @return the expected value, either a CallSite or a constant value 52 */ 53 static <T> T invoke(Class<T> resultType, 54 MethodHandle bootstrapMethod, 55 // Callee information: 56 String name, Object type, 57 // Extra arguments for BSM, if any: 58 Object info, 59 // Caller information: 60 Class<?> callerClass) { 61 MethodHandles.Lookup caller = IMPL_LOOKUP.in(callerClass); 62 Object result; 63 boolean pullMode = isPullModeBSM(bootstrapMethod); // default value is false 64 boolean vmIsPushing = !staticArgumentsPulled(info); // default value is true 65 MethodHandle pullModeBSM; 66 // match the VM with the BSM 67 if (vmIsPushing) { 68 // VM is pushing arguments at us 69 pullModeBSM = null; 70 if (pullMode) { 71 bootstrapMethod = pushMePullYou(bootstrapMethod, true); 72 } 73 } else { 74 // VM wants us to pull args from it 75 pullModeBSM = pullMode ? bootstrapMethod : 76 pushMePullYou(bootstrapMethod, false); 77 bootstrapMethod = null; 78 } 79 try { 80 // As an optimization we special case various known BSMs, 81 // such as LambdaMetafactory::metafactory and 82 // StringConcatFactory::makeConcatWithConstants. 83 // 84 // By providing static type information or even invoking 85 // exactly, we avoid emitting code to perform runtime 86 // checking. 87 info = maybeReBox(info); 88 if (info == null) { 89 // VM is allowed to pass up a null meaning no BSM args 90 result = invoke(bootstrapMethod, caller, name, type); 91 } 92 else if (!info.getClass().isArray()) { 93 // VM is allowed to pass up a single BSM arg directly 94 95 // Call to StringConcatFactory::makeConcatWithConstants 96 // with empty constant arguments? 97 if (isStringConcatFactoryBSM(bootstrapMethod.type())) { 98 result = (CallSite)bootstrapMethod 99 .invokeExact(caller, name, (MethodType)type, 100 (String)info, new Object[0]); 101 } else { 102 result = invoke(bootstrapMethod, caller, name, type, info); 103 } 104 } 105 else if (info.getClass() == int[].class) { 106 // VM is allowed to pass up a pair {argc, index} 107 // referring to 'argc' BSM args at some place 'index' 108 // in the guts of the VM (associated with callerClass). 109 // The format of this index pair is private to the 110 // handshake between the VM and this class only. 111 // This supports "pulling" of arguments. 112 // The VM is allowed to do this for any reason. 113 // The code in this method makes up for any mismatches. 114 BootstrapCallInfo<Object> bsci 115 = new VM_BSCI<>(bootstrapMethod, name, type, caller, (int[])info); 116 // Pull-mode API is (Lookup, BootstrapCallInfo) -> Object 117 result = pullModeBSM.invoke(caller, bsci); 118 } 119 else { 120 // VM is allowed to pass up a full array of resolved BSM args 121 Object[] argv = (Object[]) info; 122 maybeReBoxElements(argv); 123 124 MethodType bsmType = bootstrapMethod.type(); 125 if (isLambdaMetafactoryIndyBSM(bsmType) && argv.length == 3) { 126 result = (CallSite)bootstrapMethod 127 .invokeExact(caller, name, (MethodType)type, (MethodType)argv[0], 128 (MethodHandle)argv[1], (MethodType)argv[2]); 129 } else if (isLambdaMetafactoryCondyBSM(bsmType) && argv.length == 3) { 130 result = bootstrapMethod 131 .invokeExact(caller, name, (Class<?>)type, (MethodType)argv[0], 132 (MethodHandle)argv[1], (MethodType)argv[2]); 133 } else if (isStringConcatFactoryBSM(bsmType) && argv.length >= 1) { 134 String recipe = (String)argv[0]; 135 Object[] shiftedArgs = Arrays.copyOfRange(argv, 1, argv.length); 136 result = (CallSite)bootstrapMethod.invokeExact(caller, name, (MethodType)type, recipe, shiftedArgs); 137 } else if (isLambdaMetafactoryAltMetafactoryBSM(bsmType)) { 138 result = (CallSite)bootstrapMethod.invokeExact(caller, name, (MethodType)type, argv); 139 } else { 140 switch (argv.length) { 141 case 0: 142 result = invoke(bootstrapMethod, caller, name, type); 143 break; 144 case 1: 145 result = invoke(bootstrapMethod, caller, name, type, 146 argv[0]); 147 break; 148 case 2: 149 result = invoke(bootstrapMethod, caller, name, type, 150 argv[0], argv[1]); 151 break; 152 case 3: 153 result = invoke(bootstrapMethod, caller, name, type, 154 argv[0], argv[1], argv[2]); 155 break; 156 case 4: 157 result = invoke(bootstrapMethod, caller, name, type, 158 argv[0], argv[1], argv[2], argv[3]); 159 break; 160 case 5: 161 result = invoke(bootstrapMethod, caller, name, type, 162 argv[0], argv[1], argv[2], argv[3], argv[4]); 163 break; 164 case 6: 165 result = invoke(bootstrapMethod, caller, name, type, 166 argv[0], argv[1], argv[2], argv[3], argv[4], argv[5]); 167 break; 168 default: 169 result = invokeWithManyArguments(bootstrapMethod, caller, name, type, argv); 170 } 171 } 172 } 173 if (resultType.isPrimitive()) { 174 // Non-reference conversions are more than just plain casts. 175 // By pushing the value through a funnel of the form (T x)->x, 176 // the boxed result can be widened as needed. See MH::asType. 177 MethodHandle funnel = MethodHandles.identity(resultType); 178 result = funnel.invoke(result); 179 // Now it is the wrapper type for resultType. 180 resultType = Wrapper.asWrapperType(resultType); 181 } 182 return resultType.cast(result); 183 } 184 catch (Error e) { 185 // Pass through an Error, including BootstrapMethodError, any other 186 // form of linkage error, such as IllegalAccessError if the bootstrap 187 // method is inaccessible, or say ThreadDeath/OutOfMemoryError 188 // See the "Linking Exceptions" section for the invokedynamic 189 // instruction in JVMS 6.5. 190 throw e; 191 } 192 catch (Throwable ex) { 193 // Wrap anything else in BootstrapMethodError 194 throw new BootstrapMethodError("bootstrap method initialization exception", ex); 195 } 196 } 197 198 // If we don't provide static type information for type, we'll generate runtime 199 // checks. Let's try not to... 200 201 private static Object invoke(MethodHandle bootstrapMethod, Lookup caller, 202 String name, Object type) throws Throwable { 203 if (type instanceof Class) { 204 return bootstrapMethod.invoke(caller, name, (Class<?>)type); 205 } else { 206 return bootstrapMethod.invoke(caller, name, (MethodType)type); 207 } 208 } 209 210 private static Object invoke(MethodHandle bootstrapMethod, Lookup caller, 211 String name, Object type, Object arg0) throws Throwable { 212 if (type instanceof Class) { 213 return bootstrapMethod.invoke(caller, name, (Class<?>)type, arg0); 214 } else { 215 return bootstrapMethod.invoke(caller, name, (MethodType)type, arg0); 216 } 217 } 218 219 private static Object invoke(MethodHandle bootstrapMethod, Lookup caller, String name, 220 Object type, Object arg0, Object arg1) throws Throwable { 221 if (type instanceof Class) { 222 return bootstrapMethod.invoke(caller, name, (Class<?>)type, arg0, arg1); 223 } else { 224 return bootstrapMethod.invoke(caller, name, (MethodType)type, arg0, arg1); 225 } 226 } 227 228 private static Object invoke(MethodHandle bootstrapMethod, Lookup caller, String name, 229 Object type, Object arg0, Object arg1, 230 Object arg2) throws Throwable { 231 if (type instanceof Class) { 232 return bootstrapMethod.invoke(caller, name, (Class<?>)type, arg0, arg1, arg2); 233 } else { 234 return bootstrapMethod.invoke(caller, name, (MethodType)type, arg0, arg1, arg2); 235 } 236 } 237 238 private static Object invoke(MethodHandle bootstrapMethod, Lookup caller, String name, 239 Object type, Object arg0, Object arg1, 240 Object arg2, Object arg3) throws Throwable { 241 if (type instanceof Class) { 242 return bootstrapMethod.invoke(caller, name, (Class<?>)type, arg0, arg1, arg2, arg3); 243 } else { 244 return bootstrapMethod.invoke(caller, name, (MethodType)type, arg0, arg1, arg2, arg3); 245 } 246 } 247 248 private static Object invoke(MethodHandle bootstrapMethod, Lookup caller, 249 String name, Object type, Object arg0, Object arg1, 250 Object arg2, Object arg3, Object arg4) throws Throwable { 251 if (type instanceof Class) { 252 return bootstrapMethod.invoke(caller, name, (Class<?>)type, arg0, arg1, arg2, arg3, arg4); 253 } else { 254 return bootstrapMethod.invoke(caller, name, (MethodType)type, arg0, arg1, arg2, arg3, arg4); 255 } 256 } 257 258 private static Object invoke(MethodHandle bootstrapMethod, Lookup caller, 259 String name, Object type, Object arg0, Object arg1, 260 Object arg2, Object arg3, Object arg4, Object arg5) throws Throwable { 261 if (type instanceof Class) { 262 return bootstrapMethod.invoke(caller, name, (Class<?>)type, arg0, arg1, arg2, arg3, arg4, arg5); 263 } else { 264 return bootstrapMethod.invoke(caller, name, (MethodType)type, arg0, arg1, arg2, arg3, arg4, arg5); 265 } 266 } 267 268 private static Object invokeWithManyArguments(MethodHandle bootstrapMethod, Lookup caller, 269 String name, Object type, Object[] argv) throws Throwable { 270 final int NON_SPREAD_ARG_COUNT = 3; // (caller, name, type) 271 final int MAX_SAFE_SIZE = MethodType.MAX_MH_ARITY / 2 - NON_SPREAD_ARG_COUNT; 272 if (argv.length >= MAX_SAFE_SIZE) { 273 // to be on the safe side, use invokeWithArguments which handles jumbo lists 274 Object[] newargv = new Object[NON_SPREAD_ARG_COUNT + argv.length]; 275 newargv[0] = caller; 276 newargv[1] = name; 277 newargv[2] = type; 278 System.arraycopy(argv, 0, newargv, NON_SPREAD_ARG_COUNT, argv.length); 279 return bootstrapMethod.invokeWithArguments(newargv); 280 } else { 281 MethodType invocationType = MethodType.genericMethodType(NON_SPREAD_ARG_COUNT + argv.length); 282 MethodHandle typedBSM = bootstrapMethod.asType(invocationType); 283 MethodHandle spreader = invocationType.invokers().spreadInvoker(NON_SPREAD_ARG_COUNT); 284 return spreader.invokeExact(typedBSM, (Object) caller, (Object) name, type, argv); 285 } 286 } 287 288 private static final MethodType LMF_INDY_MT = MethodType.methodType(CallSite.class, 289 Lookup.class, String.class, MethodType.class, MethodType.class, MethodHandle.class, MethodType.class); 290 291 private static final MethodType LMF_ALT_MT = MethodType.methodType(CallSite.class, 292 Lookup.class, String.class, MethodType.class, Object[].class); 293 294 private static final MethodType LMF_CONDY_MT = MethodType.methodType(Object.class, 295 Lookup.class, String.class, Class.class, MethodType.class, MethodHandle.class, MethodType.class); 296 297 private static final MethodType SCF_MT = MethodType.methodType(CallSite.class, 298 Lookup.class, String.class, MethodType.class, String.class, Object[].class); 299 300 /** 301 * @return true iff the BSM method type exactly matches 302 * {@see java.lang.invoke.StringConcatFactory#makeConcatWithConstants(MethodHandles.Lookup, 303 * String,MethodType,String,Object...))} 304 */ 305 private static boolean isStringConcatFactoryBSM(MethodType bsmType) { 306 return bsmType == SCF_MT; 307 } 308 309 /** 310 * @return true iff the BSM method type exactly matches 311 * {@see java.lang.invoke.LambdaMetafactory#metafactory( 312 * MethodHandles.Lookup,String,Class,MethodType,MethodHandle,MethodType)} 313 */ 314 private static boolean isLambdaMetafactoryCondyBSM(MethodType bsmType) { 315 return bsmType == LMF_CONDY_MT; 316 } 317 318 /** 319 * @return true iff the BSM method type exactly matches 320 * {@see java.lang.invoke.LambdaMetafactory#metafactory( 321 * MethodHandles.Lookup,String,MethodType,MethodType,MethodHandle,MethodType)} 322 */ 323 private static boolean isLambdaMetafactoryIndyBSM(MethodType bsmType) { 324 return bsmType == LMF_INDY_MT; 325 } 326 327 /** 328 * @return true iff the BSM method type exactly matches 329 * {@see java.lang.invoke.LambdaMetafactory#altMetafactory( 330 * MethodHandles.Lookup,String,MethodType,Object[])} 331 */ 332 private static boolean isLambdaMetafactoryAltMetafactoryBSM(MethodType bsmType) { 333 return bsmType == LMF_ALT_MT; 334 } 335 336 /** The JVM produces java.lang.Integer values to box 337 * CONSTANT_Integer boxes but does not intern them. 338 * Let's intern them. This is slightly wrong for 339 * a {@code CONSTANT_Dynamic} which produces an 340 * un-interned integer (e.g., {@code new Integer(0)}). 341 */ 342 private static Object maybeReBox(Object x) { 343 if (x instanceof Integer) { 344 int xi = (int) x; 345 if (xi == (byte) xi) 346 x = xi; // must rebox; see JLS 5.1.7 347 } 348 return x; 349 } 350 351 private static void maybeReBoxElements(Object[] xa) { 352 for (int i = 0; i < xa.length; i++) { 353 xa[i] = maybeReBox(xa[i]); 354 } 355 } 356 357 /** Canonical VM-aware implementation of BootstrapCallInfo. 358 * Knows how to dig into the JVM for lazily resolved (pull-mode) constants. 359 */ 360 private static final class VM_BSCI<T> extends BSCIWithCache<T> { 361 private final int[] indexInfo; 362 private final Class<?> caller; // for index resolution only 363 364 VM_BSCI(MethodHandle bsm, String name, T type, 365 Lookup lookup, int[] indexInfo) { 366 super(bsm, name, type, indexInfo[0]); 367 if (!lookup.hasPrivateAccess()) //D.I.D. 368 throw new AssertionError("bad Lookup object"); 369 this.caller = lookup.lookupClass(); 370 this.indexInfo = indexInfo; 371 // scoop up all the easy stuff right away: 372 prefetchIntoCache(0, size()); 373 } 374 375 @Override Object fillCache(int i) { 376 Object[] buf = { null }; 377 copyConstants(i, i+1, buf, 0); 378 Object res = wrapNull(buf[0]); 379 cache[i] = res; 380 int next = i + 1; 381 if (next < cache.length && cache[next] == null) 382 maybePrefetchIntoCache(next, false); // try to prefetch 383 return res; 384 } 385 386 @Override public int copyConstants(int start, int end, 387 Object[] buf, int pos) { 388 int i = start, bufi = pos; 389 while (i < end) { 390 Object x = cache[i]; 391 if (x == null) break; 392 buf[bufi++] = unwrapNull(x); 393 i++; 394 } 395 // give up at first null and grab the rest in one big block 396 if (i >= end) return i; 397 Object[] temp = new Object[end - i]; 398 if (TRACE_METHOD_LINKAGE) { 399 System.out.println("resolving more BSM arguments: " + 400 Arrays.asList(caller.getSimpleName(), Arrays.toString(indexInfo), i, end)); 401 } 402 copyOutBootstrapArguments(caller, indexInfo, 403 i, end, temp, 0, 404 true, null); 405 for (Object x : temp) { 406 x = maybeReBox(x); 407 buf[bufi++] = x; 408 cache[i++] = wrapNull(x); 409 } 410 if (end < cache.length && cache[end] == null) 411 maybePrefetchIntoCache(end, true); // try to prefetch 412 return i; 413 } 414 415 private static final int MIN_PF = 4; 416 private void maybePrefetchIntoCache(int i, boolean bulk) { 417 int len = cache.length; 418 assert(0 <= i && i <= len); 419 int pfLimit = i; 420 if (bulk) pfLimit += i; // exponential prefetch expansion 421 // try to prefetch at least MIN_PF elements 422 if (pfLimit < i + MIN_PF) pfLimit = i + MIN_PF; 423 if (pfLimit > len || pfLimit < 0) pfLimit = len; 424 // stop prefetching where cache is more full than empty 425 int empty = 0, nonEmpty = 0, lastEmpty = i; 426 for (int j = i; j < pfLimit; j++) { 427 if (cache[j] == null) { 428 empty++; 429 lastEmpty = j; 430 } else { 431 nonEmpty++; 432 if (nonEmpty > empty) { 433 pfLimit = lastEmpty + 1; 434 break; 435 } 436 if (pfLimit < len) pfLimit++; 437 } 438 } 439 if (bulk && empty < MIN_PF && pfLimit < len) 440 return; // not worth the effort 441 prefetchIntoCache(i, pfLimit); 442 } 443 444 private void prefetchIntoCache(int i, int pfLimit) { 445 if (pfLimit <= i) return; // corner case 446 Object[] temp = new Object[pfLimit - i]; 447 if (TRACE_METHOD_LINKAGE) { 448 System.out.println("prefetching BSM arguments: " + 449 Arrays.asList(caller.getSimpleName(), Arrays.toString(indexInfo), i, pfLimit)); 450 } 451 copyOutBootstrapArguments(caller, indexInfo, 452 i, pfLimit, temp, 0, 453 false, NOT_PRESENT); 454 for (Object x : temp) { 455 if (x != NOT_PRESENT && cache[i] == null) { 456 cache[i] = wrapNull(maybeReBox(x)); 457 } 458 i++; 459 } 460 } 461 } 462 463 /*non-public*/ static final 464 class PushAdapter { 465 // skeleton for push-mode BSM which wraps a pull-mode BSM: 466 static Object pushToBootstrapMethod(MethodHandle pullModeBSM, 467 MethodHandles.Lookup lookup, String name, Object type, 468 Object... arguments) throws Throwable { 469 ConstantGroup cons = makeConstantGroup(Arrays.asList(arguments)); 470 BootstrapCallInfo<?> bsci = makeBootstrapCallInfo(pullModeBSM, name, type, cons); 471 if (TRACE_METHOD_LINKAGE) 472 System.out.println("pull-mode BSM gets pushed arguments from fake BSCI"); 473 return pullModeBSM.invoke(lookup, bsci); 474 } 475 476 static final MethodHandle MH_pushToBootstrapMethod; 477 static { 478 final Class<?> THIS_CLASS = PushAdapter.class; 479 try { 480 MH_pushToBootstrapMethod = IMPL_LOOKUP 481 .findStatic(THIS_CLASS, "pushToBootstrapMethod", 482 MethodType.methodType(Object.class, MethodHandle.class, 483 Lookup.class, String.class, Object.class, Object[].class)); 484 } catch (Throwable ex) { 485 throw new InternalError(ex); 486 } 487 } 488 } 489 490 /*non-public*/ static final 491 class PullAdapter { 492 // skeleton for pull-mode BSM which wraps a push-mode BSM: 493 static Object pullFromBootstrapMethod(MethodHandle pushModeBSM, 494 MethodHandles.Lookup lookup, 495 BootstrapCallInfo<?> bsci) 496 throws Throwable { 497 int argc = bsci.size(); 498 switch (argc) { 499 case 0: 500 return pushModeBSM.invoke(lookup, bsci.invocationName(), bsci.invocationType()); 501 case 1: 502 return pushModeBSM.invoke(lookup, bsci.invocationName(), bsci.invocationType(), 503 bsci.get(0)); 504 case 2: 505 return pushModeBSM.invoke(lookup, bsci.invocationName(), bsci.invocationType(), 506 bsci.get(0), bsci.get(1)); 507 case 3: 508 return pushModeBSM.invoke(lookup, bsci.invocationName(), bsci.invocationType(), 509 bsci.get(0), bsci.get(1), bsci.get(2)); 510 case 4: 511 return pushModeBSM.invoke(lookup, bsci.invocationName(), bsci.invocationType(), 512 bsci.get(0), bsci.get(1), bsci.get(2), bsci.get(3)); 513 case 5: 514 return pushModeBSM.invoke(lookup, bsci.invocationName(), bsci.invocationType(), 515 bsci.get(0), bsci.get(1), bsci.get(2), bsci.get(3), bsci.get(4)); 516 case 6: 517 return pushModeBSM.invoke(lookup, bsci.invocationName(), bsci.invocationType(), 518 bsci.get(0), bsci.get(1), bsci.get(2), bsci.get(3), bsci.get(4), bsci.get(5)); 519 default: 520 final int NON_SPREAD_ARG_COUNT = 3; // (lookup, name, type) 521 final int MAX_SAFE_SIZE = MethodType.MAX_MH_ARITY / 2 - NON_SPREAD_ARG_COUNT; 522 if (argc >= MAX_SAFE_SIZE) { 523 // to be on the safe side, use invokeWithArguments which handles jumbo lists 524 Object[] newargv = new Object[NON_SPREAD_ARG_COUNT + argc]; 525 newargv[0] = lookup; 526 newargv[1] = bsci.invocationName(); 527 newargv[2] = bsci.invocationType(); 528 bsci.copyConstants(0, argc, newargv, NON_SPREAD_ARG_COUNT); 529 return pushModeBSM.invokeWithArguments(newargv); 530 } 531 MethodType invocationType = MethodType.genericMethodType(NON_SPREAD_ARG_COUNT + argc); 532 MethodHandle typedBSM = pushModeBSM.asType(invocationType); 533 MethodHandle spreader = invocationType.invokers().spreadInvoker(NON_SPREAD_ARG_COUNT); 534 Object[] argv = new Object[argc]; 535 bsci.copyConstants(0, argc, argv, 0); 536 return spreader.invokeExact(typedBSM, (Object) lookup, (Object) bsci.invocationName(), bsci.invocationType(), argv); 537 } 538 } 539 540 static final MethodHandle MH_pullFromBootstrapMethod; 541 542 static { 543 final Class<?> THIS_CLASS = PullAdapter.class; 544 try { 545 MH_pullFromBootstrapMethod = IMPL_LOOKUP 546 .findStatic(THIS_CLASS, "pullFromBootstrapMethod", 547 MethodType.methodType(Object.class, MethodHandle.class, 548 Lookup.class, BootstrapCallInfo.class)); 549 } catch (Throwable ex) { 550 throw new InternalError(ex); 551 } 552 } 553 } 554 555 /** Given a push-mode BSM (taking one argument) convert it to a 556 * pull-mode BSM (taking N pre-resolved arguments). 557 * This method is used when, in fact, the JVM is passing up 558 * pre-resolved arguments, but the BSM is expecting lazy stuff. 559 * Or, when goToPushMode is true, do the reverse transform. 560 * (The two transforms are exactly inverse.) 561 */ 562 static MethodHandle pushMePullYou(MethodHandle bsm, boolean goToPushMode) { 563 if (TRACE_METHOD_LINKAGE) { 564 System.out.println("converting BSM of type " + bsm.type() + " to " 565 + (goToPushMode ? "push mode" : "pull mode")); 566 } 567 assert(isPullModeBSM(bsm) == goToPushMode); // there must be a change 568 if (goToPushMode) { 569 return PushAdapter.MH_pushToBootstrapMethod.bindTo(bsm).withVarargs(true); 570 } else { 571 return PullAdapter.MH_pullFromBootstrapMethod.bindTo(bsm).withVarargs(false); 572 } 573 } 574 }