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 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 invoke(MethodHandle bootstrapMethod, Lookup caller, String name, Object type)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 invoke(MethodHandle bootstrapMethod, Lookup caller, String name, Object type, Object arg0)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 invoke(MethodHandle bootstrapMethod, Lookup caller, String name, Object type, Object arg0, Object arg1)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 invoke(MethodHandle bootstrapMethod, Lookup caller, String name, Object type, Object arg0, Object arg1, Object arg2)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 invoke(MethodHandle bootstrapMethod, Lookup caller, String name, Object type, Object arg0, Object arg1, Object arg2, Object arg3)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 invoke(MethodHandle bootstrapMethod, Lookup caller, String name, Object type, Object arg0, Object arg1, Object arg2, Object arg3, Object arg4)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 invoke(MethodHandle bootstrapMethod, Lookup caller, String name, Object type, Object arg0, Object arg1, Object arg2, Object arg3, Object arg4, Object arg5)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 invokeWithManyArguments(MethodHandle bootstrapMethod, Lookup caller, String name, Object type, Object[] argv)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 */ isStringConcatFactoryBSM(MethodType bsmType)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 */ isLambdaMetafactoryCondyBSM(MethodType bsmType)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 */ isLambdaMetafactoryIndyBSM(MethodType bsmType)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 */ isLambdaMetafactoryAltMetafactoryBSM(MethodType bsmType)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 */ maybeReBox(Object x)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 maybeReBoxElements(Object[] xa)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 VM_BSCI(MethodHandle bsm, String name, T type, Lookup lookup, int[] indexInfo)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 fillCache(int i)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 copyConstants(int start, int end, Object[] buf, int pos)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; maybePrefetchIntoCache(int i, boolean bulk)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 prefetchIntoCache(int i, int pfLimit)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: pushToBootstrapMethod(MethodHandle pullModeBSM, MethodHandles.Lookup lookup, String name, Object type, Object... arguments)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: pullFromBootstrapMethod(MethodHandle pushModeBSM, MethodHandles.Lookup lookup, BootstrapCallInfo<?> bsci)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 */ pushMePullYou(MethodHandle bsm, boolean goToPushMode)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 } 575