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