Invokers.java revision 14370:ee18c1df243b
1/* 2 * Copyright (c) 2008, 2016, 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 26package java.lang.invoke; 27 28import jdk.internal.vm.annotation.DontInline; 29import jdk.internal.vm.annotation.ForceInline; 30import jdk.internal.vm.annotation.Stable; 31 32import java.lang.reflect.Array; 33import java.util.Arrays; 34 35import static java.lang.invoke.MethodHandleStatics.*; 36import static java.lang.invoke.MethodHandleNatives.Constants.*; 37import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP; 38import static java.lang.invoke.LambdaForm.*; 39 40/** 41 * Construction and caching of often-used invokers. 42 * @author jrose 43 */ 44class Invokers { 45 // exact type (sans leading target MH) for the outgoing call 46 private final MethodType targetType; 47 48 // Cached adapter information: 49 private final @Stable MethodHandle[] invokers = new MethodHandle[INV_LIMIT]; 50 // Indexes into invokers: 51 static final int 52 INV_EXACT = 0, // MethodHandles.exactInvoker 53 INV_GENERIC = 1, // MethodHandles.invoker (generic invocation) 54 INV_BASIC = 2, // MethodHandles.basicInvoker 55 INV_LIMIT = 3; 56 57 /** Compute and cache information common to all collecting adapters 58 * that implement members of the erasure-family of the given erased type. 59 */ 60 /*non-public*/ Invokers(MethodType targetType) { 61 this.targetType = targetType; 62 } 63 64 /*non-public*/ MethodHandle exactInvoker() { 65 MethodHandle invoker = cachedInvoker(INV_EXACT); 66 if (invoker != null) return invoker; 67 invoker = makeExactOrGeneralInvoker(true); 68 return setCachedInvoker(INV_EXACT, invoker); 69 } 70 71 /*non-public*/ MethodHandle genericInvoker() { 72 MethodHandle invoker = cachedInvoker(INV_GENERIC); 73 if (invoker != null) return invoker; 74 invoker = makeExactOrGeneralInvoker(false); 75 return setCachedInvoker(INV_GENERIC, invoker); 76 } 77 78 /*non-public*/ MethodHandle basicInvoker() { 79 MethodHandle invoker = cachedInvoker(INV_BASIC); 80 if (invoker != null) return invoker; 81 MethodType basicType = targetType.basicType(); 82 if (basicType != targetType) { 83 // double cache; not used significantly 84 return setCachedInvoker(INV_BASIC, basicType.invokers().basicInvoker()); 85 } 86 invoker = basicType.form().cachedMethodHandle(MethodTypeForm.MH_BASIC_INV); 87 if (invoker == null) { 88 MemberName method = invokeBasicMethod(basicType); 89 invoker = DirectMethodHandle.make(method); 90 assert(checkInvoker(invoker)); 91 invoker = basicType.form().setCachedMethodHandle(MethodTypeForm.MH_BASIC_INV, invoker); 92 } 93 return setCachedInvoker(INV_BASIC, invoker); 94 } 95 96 /*non-public*/ MethodHandle varHandleMethodInvoker(VarHandle.AccessMode ak) { 97 // TODO cache invoker 98 return makeVarHandleMethodInvoker(ak); 99 } 100 101 /*non-public*/ MethodHandle varHandleMethodExactInvoker(VarHandle.AccessMode ak) { 102 // TODO cache invoker 103 return makeVarHandleMethodExactInvoker(ak); 104 } 105 106 private MethodHandle cachedInvoker(int idx) { 107 return invokers[idx]; 108 } 109 110 private synchronized MethodHandle setCachedInvoker(int idx, final MethodHandle invoker) { 111 // Simulate a CAS, to avoid racy duplication of results. 112 MethodHandle prev = invokers[idx]; 113 if (prev != null) return prev; 114 return invokers[idx] = invoker; 115 } 116 117 private MethodHandle makeExactOrGeneralInvoker(boolean isExact) { 118 MethodType mtype = targetType; 119 MethodType invokerType = mtype.invokerType(); 120 int which = (isExact ? MethodTypeForm.LF_EX_INVOKER : MethodTypeForm.LF_GEN_INVOKER); 121 LambdaForm lform = invokeHandleForm(mtype, false, which); 122 MethodHandle invoker = BoundMethodHandle.bindSingle(invokerType, lform, mtype); 123 String whichName = (isExact ? "invokeExact" : "invoke"); 124 invoker = invoker.withInternalMemberName(MemberName.makeMethodHandleInvoke(whichName, mtype), false); 125 assert(checkInvoker(invoker)); 126 maybeCompileToBytecode(invoker); 127 return invoker; 128 } 129 130 private MethodHandle makeVarHandleMethodInvoker(VarHandle.AccessMode ak) { 131 MethodType mtype = targetType; 132 MethodType invokerType = mtype.insertParameterTypes(0, VarHandle.class); 133 134 LambdaForm lform = varHandleMethodGenericInvokerHandleForm(ak.methodName(), mtype); 135 VarHandle.AccessDescriptor ad = new VarHandle.AccessDescriptor(mtype, ak.at.ordinal(), ak.ordinal()); 136 MethodHandle invoker = BoundMethodHandle.bindSingle(invokerType, lform, ad); 137 138 invoker = invoker.withInternalMemberName(MemberName.makeVarHandleMethodInvoke(ak.methodName(), mtype), false); 139 assert(checkVarHandleInvoker(invoker)); 140 141 maybeCompileToBytecode(invoker); 142 return invoker; 143 } 144 145 private MethodHandle makeVarHandleMethodExactInvoker(VarHandle.AccessMode ak) { 146 MethodType mtype = targetType; 147 MethodType invokerType = mtype.insertParameterTypes(0, VarHandle.class); 148 149 LambdaForm lform = varHandleMethodExactInvokerHandleForm(ak.methodName(), mtype); 150 VarHandle.AccessDescriptor ad = new VarHandle.AccessDescriptor(mtype, ak.at.ordinal(), ak.ordinal()); 151 MethodHandle invoker = BoundMethodHandle.bindSingle(invokerType, lform, ad); 152 153 invoker = invoker.withInternalMemberName(MemberName.makeVarHandleMethodInvoke(ak.methodName(), mtype), false); 154 assert(checkVarHandleInvoker(invoker)); 155 156 maybeCompileToBytecode(invoker); 157 return invoker; 158 } 159 160 /** If the target type seems to be common enough, eagerly compile the invoker to bytecodes. */ 161 private void maybeCompileToBytecode(MethodHandle invoker) { 162 final int EAGER_COMPILE_ARITY_LIMIT = 10; 163 if (targetType == targetType.erase() && 164 targetType.parameterCount() < EAGER_COMPILE_ARITY_LIMIT) { 165 invoker.form.compileToBytecode(); 166 } 167 } 168 169 // This next one is called from LambdaForm.NamedFunction.<init>. 170 /*non-public*/ static MemberName invokeBasicMethod(MethodType basicType) { 171 assert(basicType == basicType.basicType()); 172 try { 173 //Lookup.findVirtual(MethodHandle.class, name, type); 174 return IMPL_LOOKUP.resolveOrFail(REF_invokeVirtual, MethodHandle.class, "invokeBasic", basicType); 175 } catch (ReflectiveOperationException ex) { 176 throw newInternalError("JVM cannot find invoker for "+basicType, ex); 177 } 178 } 179 180 private boolean checkInvoker(MethodHandle invoker) { 181 assert(targetType.invokerType().equals(invoker.type())) 182 : java.util.Arrays.asList(targetType, targetType.invokerType(), invoker); 183 assert(invoker.internalMemberName() == null || 184 invoker.internalMemberName().getMethodType().equals(targetType)); 185 assert(!invoker.isVarargsCollector()); 186 return true; 187 } 188 189 private boolean checkVarHandleInvoker(MethodHandle invoker) { 190 MethodType invokerType = targetType.insertParameterTypes(0, VarHandle.class); 191 assert(invokerType.equals(invoker.type())) 192 : java.util.Arrays.asList(targetType, invokerType, invoker); 193 assert(invoker.internalMemberName() == null || 194 invoker.internalMemberName().getMethodType().equals(targetType)); 195 assert(!invoker.isVarargsCollector()); 196 return true; 197 } 198 199 /** 200 * Find or create an invoker which passes unchanged a given number of arguments 201 * and spreads the rest from a trailing array argument. 202 * The invoker target type is the post-spread type {@code (TYPEOF(uarg*), TYPEOF(sarg*))=>RT}. 203 * All the {@code sarg}s must have a common type {@code C}. (If there are none, {@code Object} is assumed.} 204 * @param leadingArgCount the number of unchanged (non-spread) arguments 205 * @return {@code invoker.invokeExact(mh, uarg*, C[]{sarg*}) := (RT)mh.invoke(uarg*, sarg*)} 206 */ 207 /*non-public*/ MethodHandle spreadInvoker(int leadingArgCount) { 208 int spreadArgCount = targetType.parameterCount() - leadingArgCount; 209 MethodType postSpreadType = targetType; 210 Class<?> argArrayType = impliedRestargType(postSpreadType, leadingArgCount); 211 if (postSpreadType.parameterSlotCount() <= MethodType.MAX_MH_INVOKER_ARITY) { 212 return genericInvoker().asSpreader(argArrayType, spreadArgCount); 213 } 214 // Cannot build a generic invoker here of type ginvoker.invoke(mh, a*[254]). 215 // Instead, factor sinvoker.invoke(mh, a) into ainvoker.invoke(filter(mh), a) 216 // where filter(mh) == mh.asSpreader(Object[], spreadArgCount) 217 MethodType preSpreadType = postSpreadType 218 .replaceParameterTypes(leadingArgCount, postSpreadType.parameterCount(), argArrayType); 219 MethodHandle arrayInvoker = MethodHandles.invoker(preSpreadType); 220 MethodHandle makeSpreader = MethodHandles.insertArguments(Lazy.MH_asSpreader, 1, argArrayType, spreadArgCount); 221 return MethodHandles.filterArgument(arrayInvoker, 0, makeSpreader); 222 } 223 224 private static Class<?> impliedRestargType(MethodType restargType, int fromPos) { 225 if (restargType.isGeneric()) return Object[].class; // can be nothing else 226 int maxPos = restargType.parameterCount(); 227 if (fromPos >= maxPos) return Object[].class; // reasonable default 228 Class<?> argType = restargType.parameterType(fromPos); 229 for (int i = fromPos+1; i < maxPos; i++) { 230 if (argType != restargType.parameterType(i)) 231 throw newIllegalArgumentException("need homogeneous rest arguments", restargType); 232 } 233 if (argType == Object.class) return Object[].class; 234 return Array.newInstance(argType, 0).getClass(); 235 } 236 237 public String toString() { 238 return "Invokers"+targetType; 239 } 240 241 static MemberName methodHandleInvokeLinkerMethod(String name, 242 MethodType mtype, 243 Object[] appendixResult) { 244 int which; 245 switch (name) { 246 case "invokeExact": which = MethodTypeForm.LF_EX_LINKER; break; 247 case "invoke": which = MethodTypeForm.LF_GEN_LINKER; break; 248 default: throw new InternalError("not invoker: "+name); 249 } 250 LambdaForm lform; 251 if (mtype.parameterSlotCount() <= MethodType.MAX_MH_ARITY - MH_LINKER_ARG_APPENDED) { 252 lform = invokeHandleForm(mtype, false, which); 253 appendixResult[0] = mtype; 254 } else { 255 lform = invokeHandleForm(mtype, true, which); 256 } 257 return lform.vmentry; 258 } 259 260 // argument count to account for trailing "appendix value" (typically the mtype) 261 private static final int MH_LINKER_ARG_APPENDED = 1; 262 263 /** Returns an adapter for invokeExact or generic invoke, as a MH or constant pool linker. 264 * If !customized, caller is responsible for supplying, during adapter execution, 265 * a copy of the exact mtype. This is because the adapter might be generalized to 266 * a basic type. 267 * @param mtype the caller's method type (either basic or full-custom) 268 * @param customized whether to use a trailing appendix argument (to carry the mtype) 269 * @param which bit-encoded 0x01 whether it is a CP adapter ("linker") or MHs.invoker value ("invoker"); 270 * 0x02 whether it is for invokeExact or generic invoke 271 */ 272 private static LambdaForm invokeHandleForm(MethodType mtype, boolean customized, int which) { 273 boolean isCached; 274 if (!customized) { 275 mtype = mtype.basicType(); // normalize Z to I, String to Object, etc. 276 isCached = true; 277 } else { 278 isCached = false; // maybe cache if mtype == mtype.basicType() 279 } 280 boolean isLinker, isGeneric; 281 String debugName; 282 switch (which) { 283 case MethodTypeForm.LF_EX_LINKER: isLinker = true; isGeneric = false; debugName = "invokeExact_MT"; break; 284 case MethodTypeForm.LF_EX_INVOKER: isLinker = false; isGeneric = false; debugName = "exactInvoker"; break; 285 case MethodTypeForm.LF_GEN_LINKER: isLinker = true; isGeneric = true; debugName = "invoke_MT"; break; 286 case MethodTypeForm.LF_GEN_INVOKER: isLinker = false; isGeneric = true; debugName = "invoker"; break; 287 default: throw new InternalError(); 288 } 289 LambdaForm lform; 290 if (isCached) { 291 lform = mtype.form().cachedLambdaForm(which); 292 if (lform != null) return lform; 293 } 294 // exactInvokerForm (Object,Object)Object 295 // link with java.lang.invoke.MethodHandle.invokeBasic(MethodHandle,Object,Object)Object/invokeSpecial 296 final int THIS_MH = 0; 297 final int CALL_MH = THIS_MH + (isLinker ? 0 : 1); 298 final int ARG_BASE = CALL_MH + 1; 299 final int OUTARG_LIMIT = ARG_BASE + mtype.parameterCount(); 300 final int INARG_LIMIT = OUTARG_LIMIT + (isLinker && !customized ? 1 : 0); 301 int nameCursor = OUTARG_LIMIT; 302 final int MTYPE_ARG = customized ? -1 : nameCursor++; // might be last in-argument 303 final int CHECK_TYPE = nameCursor++; 304 final int CHECK_CUSTOM = (CUSTOMIZE_THRESHOLD >= 0) ? nameCursor++ : -1; 305 final int LINKER_CALL = nameCursor++; 306 MethodType invokerFormType = mtype.invokerType(); 307 if (isLinker) { 308 if (!customized) 309 invokerFormType = invokerFormType.appendParameterTypes(MemberName.class); 310 } else { 311 invokerFormType = invokerFormType.invokerType(); 312 } 313 Name[] names = arguments(nameCursor - INARG_LIMIT, invokerFormType); 314 assert(names.length == nameCursor) 315 : Arrays.asList(mtype, customized, which, nameCursor, names.length); 316 if (MTYPE_ARG >= INARG_LIMIT) { 317 assert(names[MTYPE_ARG] == null); 318 BoundMethodHandle.SpeciesData speciesData = BoundMethodHandle.speciesData_L(); 319 names[THIS_MH] = names[THIS_MH].withConstraint(speciesData); 320 NamedFunction getter = speciesData.getterFunction(0); 321 names[MTYPE_ARG] = new Name(getter, names[THIS_MH]); 322 // else if isLinker, then MTYPE is passed in from the caller (e.g., the JVM) 323 } 324 325 // Make the final call. If isGeneric, then prepend the result of type checking. 326 MethodType outCallType = mtype.basicType(); 327 Object[] outArgs = Arrays.copyOfRange(names, CALL_MH, OUTARG_LIMIT, Object[].class); 328 Object mtypeArg = (customized ? mtype : names[MTYPE_ARG]); 329 if (!isGeneric) { 330 names[CHECK_TYPE] = new Name(NF_checkExactType, names[CALL_MH], mtypeArg); 331 // mh.invokeExact(a*):R => checkExactType(mh, TYPEOF(a*:R)); mh.invokeBasic(a*) 332 } else { 333 names[CHECK_TYPE] = new Name(NF_checkGenericType, names[CALL_MH], mtypeArg); 334 // mh.invokeGeneric(a*):R => checkGenericType(mh, TYPEOF(a*:R)).invokeBasic(a*) 335 outArgs[0] = names[CHECK_TYPE]; 336 } 337 if (CHECK_CUSTOM != -1) { 338 names[CHECK_CUSTOM] = new Name(NF_checkCustomized, outArgs[0]); 339 } 340 names[LINKER_CALL] = new Name(outCallType, outArgs); 341 lform = new LambdaForm(debugName, INARG_LIMIT, names); 342 if (isLinker) 343 lform.compileToBytecode(); // JVM needs a real methodOop 344 if (isCached) 345 lform = mtype.form().setCachedLambdaForm(which, lform); 346 return lform; 347 } 348 349 350 static MemberName varHandleInvokeLinkerMethod(String name, 351 MethodType mtype) { 352 LambdaForm lform; 353 if (mtype.parameterSlotCount() <= MethodType.MAX_MH_ARITY - MH_LINKER_ARG_APPENDED) { 354 lform = varHandleMethodGenericLinkerHandleForm(name, mtype); 355 } else { 356 // TODO 357 throw newInternalError("Unsupported parameter slot count " + mtype.parameterSlotCount()); 358 } 359 return lform.vmentry; 360 } 361 362 private static LambdaForm varHandleMethodGenericLinkerHandleForm(String name, MethodType mtype) { 363 // TODO Cache form? 364 365 final int THIS_VH = 0; 366 final int ARG_BASE = THIS_VH + 1; 367 final int ARG_LIMIT = ARG_BASE + mtype.parameterCount(); 368 int nameCursor = ARG_LIMIT; 369 final int VAD_ARG = nameCursor++; 370 final int CHECK_TYPE = nameCursor++; 371 final int CHECK_CUSTOM = (CUSTOMIZE_THRESHOLD >= 0) ? nameCursor++ : -1; 372 final int LINKER_CALL = nameCursor++; 373 374 Name[] names = new Name[LINKER_CALL + 1]; 375 names[THIS_VH] = argument(THIS_VH, BasicType.basicType(Object.class)); 376 for (int i = 0; i < mtype.parameterCount(); i++) { 377 names[ARG_BASE + i] = argument(ARG_BASE + i, BasicType.basicType(mtype.parameterType(i))); 378 } 379 names[VAD_ARG] = new Name(ARG_LIMIT, BasicType.basicType(Object.class)); 380 381 names[CHECK_TYPE] = new Name(NF_checkVarHandleGenericType, names[THIS_VH], names[VAD_ARG]); 382 383 Object[] outArgs = new Object[ARG_LIMIT + 1]; 384 outArgs[0] = names[CHECK_TYPE]; 385 for (int i = 0; i < ARG_LIMIT; i++) { 386 outArgs[i + 1] = names[i]; 387 } 388 389 if (CHECK_CUSTOM != -1) { 390 names[CHECK_CUSTOM] = new Name(NF_checkCustomized, outArgs[0]); 391 } 392 393 MethodType outCallType = mtype.insertParameterTypes(0, VarHandle.class) 394 .basicType(); 395 names[LINKER_CALL] = new Name(outCallType, outArgs); 396 LambdaForm lform = new LambdaForm(name + ":VarHandle_invoke_MT_" + shortenSignature(basicTypeSignature(mtype)), 397 ARG_LIMIT + 1, names); 398 399 lform.compileToBytecode(); 400 return lform; 401 } 402 403 private static LambdaForm varHandleMethodExactInvokerHandleForm(String name, MethodType mtype) { 404 // TODO Cache form? 405 406 final int THIS_MH = 0; 407 final int CALL_VH = THIS_MH + 1; 408 final int ARG_BASE = CALL_VH + 1; 409 final int ARG_LIMIT = ARG_BASE + mtype.parameterCount(); 410 int nameCursor = ARG_LIMIT; 411 final int VAD_ARG = nameCursor++; 412 final int CHECK_TYPE = nameCursor++; 413 final int GET_MEMBER = nameCursor++; 414 final int LINKER_CALL = nameCursor++; 415 416 MethodType invokerFormType = mtype.insertParameterTypes(0, VarHandle.class) 417 .basicType() 418 .appendParameterTypes(MemberName.class); 419 420 MemberName linker = new MemberName(MethodHandle.class, "linkToStatic", invokerFormType, REF_invokeStatic); 421 try { 422 linker = MemberName.getFactory().resolveOrFail(REF_invokeStatic, linker, null, NoSuchMethodException.class); 423 } catch (ReflectiveOperationException ex) { 424 throw newInternalError(ex); 425 } 426 427 Name[] names = new Name[LINKER_CALL + 1]; 428 names[THIS_MH] = argument(THIS_MH, BasicType.basicType(Object.class)); 429 names[CALL_VH] = argument(CALL_VH, BasicType.basicType(Object.class)); 430 for (int i = 0; i < mtype.parameterCount(); i++) { 431 names[ARG_BASE + i] = argument(ARG_BASE + i, BasicType.basicType(mtype.parameterType(i))); 432 } 433 434 BoundMethodHandle.SpeciesData speciesData = BoundMethodHandle.speciesData_L(); 435 names[THIS_MH] = names[THIS_MH].withConstraint(speciesData); 436 437 NamedFunction getter = speciesData.getterFunction(0); 438 names[VAD_ARG] = new Name(getter, names[THIS_MH]); 439 440 Object[] outArgs = Arrays.copyOfRange(names, CALL_VH, ARG_LIMIT + 1, Object[].class); 441 442 names[CHECK_TYPE] = new Name(NF_checkVarHandleExactType, names[CALL_VH], names[VAD_ARG]); 443 444 names[GET_MEMBER] = new Name(NF_getVarHandleMemberName, names[CALL_VH], names[VAD_ARG]); 445 outArgs[outArgs.length - 1] = names[GET_MEMBER]; 446 447 names[LINKER_CALL] = new Name(linker, outArgs); 448 LambdaForm lform = new LambdaForm(name + ":VarHandle_exactInvoker" + shortenSignature(basicTypeSignature(mtype)), 449 ARG_LIMIT, names); 450 451 lform.compileToBytecode(); 452 return lform; 453 } 454 455 private static LambdaForm varHandleMethodGenericInvokerHandleForm(String name, MethodType mtype) { 456 // TODO Cache form? 457 458 final int THIS_MH = 0; 459 final int CALL_VH = THIS_MH + 1; 460 final int ARG_BASE = CALL_VH + 1; 461 final int ARG_LIMIT = ARG_BASE + mtype.parameterCount(); 462 int nameCursor = ARG_LIMIT; 463 final int VAD_ARG = nameCursor++; 464 final int CHECK_TYPE = nameCursor++; 465 final int LINKER_CALL = nameCursor++; 466 467 Name[] names = new Name[LINKER_CALL + 1]; 468 names[THIS_MH] = argument(THIS_MH, BasicType.basicType(Object.class)); 469 names[CALL_VH] = argument(CALL_VH, BasicType.basicType(Object.class)); 470 for (int i = 0; i < mtype.parameterCount(); i++) { 471 names[ARG_BASE + i] = argument(ARG_BASE + i, BasicType.basicType(mtype.parameterType(i))); 472 } 473 474 BoundMethodHandle.SpeciesData speciesData = BoundMethodHandle.speciesData_L(); 475 names[THIS_MH] = names[THIS_MH].withConstraint(speciesData); 476 477 NamedFunction getter = speciesData.getterFunction(0); 478 names[VAD_ARG] = new Name(getter, names[THIS_MH]); 479 480 names[CHECK_TYPE] = new Name(NF_checkVarHandleGenericType, names[CALL_VH], names[VAD_ARG]); 481 482 Object[] outArgs = new Object[ARG_LIMIT]; 483 outArgs[0] = names[CHECK_TYPE]; 484 for (int i = 1; i < ARG_LIMIT; i++) { 485 outArgs[i] = names[i]; 486 } 487 488 MethodType outCallType = mtype.insertParameterTypes(0, VarHandle.class) 489 .basicType(); 490 names[LINKER_CALL] = new Name(outCallType, outArgs); 491 LambdaForm lform = new LambdaForm(name + ":VarHandle_invoker" + shortenSignature(basicTypeSignature(mtype)), 492 ARG_LIMIT, names); 493 494 lform.prepare(); 495 return lform; 496 } 497 498 /*non-public*/ static 499 @ForceInline 500 MethodHandle checkVarHandleGenericType(VarHandle handle, VarHandle.AccessDescriptor ad) { 501 // Test for exact match on invoker types 502 // TODO match with erased types and add cast of return value to lambda form 503 MethodHandle mh = handle.getMethodHandle(ad.mode); 504 if (mh.type() == ad.symbolicMethodTypeInvoker) { 505 return mh; 506 } 507 else { 508 return mh.asType(ad.symbolicMethodTypeInvoker); 509 } 510 } 511 512 /*non-public*/ static 513 @ForceInline 514 void checkVarHandleExactType(VarHandle handle, VarHandle.AccessDescriptor ad) { 515 MethodType erasedTarget = handle.vform.methodType_table[ad.type]; 516 MethodType erasedSymbolic = ad.symbolicMethodTypeErased; 517 if (erasedTarget != erasedSymbolic) 518 throw newWrongMethodTypeException(erasedTarget, erasedSymbolic); 519 } 520 521 /*non-public*/ static 522 @ForceInline 523 MemberName getVarHandleMemberName(VarHandle handle, VarHandle.AccessDescriptor ad) { 524 MemberName mn = handle.vform.memberName_table[ad.mode]; 525 if (mn == null) { 526 throw handle.unsupported(); 527 } 528 return mn; 529 } 530 531 /*non-public*/ static 532 WrongMethodTypeException newWrongMethodTypeException(MethodType actual, MethodType expected) { 533 // FIXME: merge with JVM logic for throwing WMTE 534 return new WrongMethodTypeException("expected "+expected+" but found "+actual); 535 } 536 537 /** Static definition of MethodHandle.invokeExact checking code. */ 538 /*non-public*/ static 539 @ForceInline 540 void checkExactType(MethodHandle mh, MethodType expected) { 541 MethodType actual = mh.type(); 542 if (actual != expected) 543 throw newWrongMethodTypeException(expected, actual); 544 } 545 546 /** Static definition of MethodHandle.invokeGeneric checking code. 547 * Directly returns the type-adjusted MH to invoke, as follows: 548 * {@code (R)MH.invoke(a*) => MH.asType(TYPEOF(a*:R)).invokeBasic(a*)} 549 */ 550 /*non-public*/ static 551 @ForceInline 552 MethodHandle checkGenericType(MethodHandle mh, MethodType expected) { 553 return mh.asType(expected); 554 /* Maybe add more paths here. Possible optimizations: 555 * for (R)MH.invoke(a*), 556 * let MT0 = TYPEOF(a*:R), MT1 = MH.type 557 * 558 * if MT0==MT1 or MT1 can be safely called by MT0 559 * => MH.invokeBasic(a*) 560 * if MT1 can be safely called by MT0[R := Object] 561 * => MH.invokeBasic(a*) & checkcast(R) 562 * if MT1 can be safely called by MT0[* := Object] 563 * => checkcast(A)* & MH.invokeBasic(a*) & checkcast(R) 564 * if a big adapter BA can be pulled out of (MT0,MT1) 565 * => BA.invokeBasic(MT0,MH,a*) 566 * if a local adapter LA can cached on static CS0 = new GICS(MT0) 567 * => CS0.LA.invokeBasic(MH,a*) 568 * else 569 * => MH.asType(MT0).invokeBasic(A*) 570 */ 571 } 572 573 static MemberName linkToCallSiteMethod(MethodType mtype) { 574 LambdaForm lform = callSiteForm(mtype, false); 575 return lform.vmentry; 576 } 577 578 static MemberName linkToTargetMethod(MethodType mtype) { 579 LambdaForm lform = callSiteForm(mtype, true); 580 return lform.vmentry; 581 } 582 583 // skipCallSite is true if we are optimizing a ConstantCallSite 584 private static LambdaForm callSiteForm(MethodType mtype, boolean skipCallSite) { 585 mtype = mtype.basicType(); // normalize Z to I, String to Object, etc. 586 final int which = (skipCallSite ? MethodTypeForm.LF_MH_LINKER : MethodTypeForm.LF_CS_LINKER); 587 LambdaForm lform = mtype.form().cachedLambdaForm(which); 588 if (lform != null) return lform; 589 // exactInvokerForm (Object,Object)Object 590 // link with java.lang.invoke.MethodHandle.invokeBasic(MethodHandle,Object,Object)Object/invokeSpecial 591 final int ARG_BASE = 0; 592 final int OUTARG_LIMIT = ARG_BASE + mtype.parameterCount(); 593 final int INARG_LIMIT = OUTARG_LIMIT + 1; 594 int nameCursor = OUTARG_LIMIT; 595 final int APPENDIX_ARG = nameCursor++; // the last in-argument 596 final int CSITE_ARG = skipCallSite ? -1 : APPENDIX_ARG; 597 final int CALL_MH = skipCallSite ? APPENDIX_ARG : nameCursor++; // result of getTarget 598 final int LINKER_CALL = nameCursor++; 599 MethodType invokerFormType = mtype.appendParameterTypes(skipCallSite ? MethodHandle.class : CallSite.class); 600 Name[] names = arguments(nameCursor - INARG_LIMIT, invokerFormType); 601 assert(names.length == nameCursor); 602 assert(names[APPENDIX_ARG] != null); 603 if (!skipCallSite) 604 names[CALL_MH] = new Name(NF_getCallSiteTarget, names[CSITE_ARG]); 605 // (site.)invokedynamic(a*):R => mh = site.getTarget(); mh.invokeBasic(a*) 606 final int PREPEND_MH = 0, PREPEND_COUNT = 1; 607 Object[] outArgs = Arrays.copyOfRange(names, ARG_BASE, OUTARG_LIMIT + PREPEND_COUNT, Object[].class); 608 // prepend MH argument: 609 System.arraycopy(outArgs, 0, outArgs, PREPEND_COUNT, outArgs.length - PREPEND_COUNT); 610 outArgs[PREPEND_MH] = names[CALL_MH]; 611 names[LINKER_CALL] = new Name(mtype, outArgs); 612 lform = new LambdaForm((skipCallSite ? "linkToTargetMethod" : "linkToCallSite"), INARG_LIMIT, names); 613 lform.compileToBytecode(); // JVM needs a real methodOop 614 lform = mtype.form().setCachedLambdaForm(which, lform); 615 return lform; 616 } 617 618 /** Static definition of MethodHandle.invokeGeneric checking code. */ 619 /*non-public*/ static 620 @ForceInline 621 MethodHandle getCallSiteTarget(CallSite site) { 622 return site.getTarget(); 623 } 624 625 /*non-public*/ static 626 @ForceInline 627 void checkCustomized(MethodHandle mh) { 628 if (MethodHandleImpl.isCompileConstant(mh)) return; 629 if (mh.form.customized == null) { 630 maybeCustomize(mh); 631 } 632 } 633 634 /*non-public*/ static 635 @DontInline 636 void maybeCustomize(MethodHandle mh) { 637 byte count = mh.customizationCount; 638 if (count >= CUSTOMIZE_THRESHOLD) { 639 mh.customize(); 640 } else { 641 mh.customizationCount = (byte)(count+1); 642 } 643 } 644 645 // Local constant functions: 646 private static final NamedFunction 647 NF_checkExactType, 648 NF_checkGenericType, 649 NF_getCallSiteTarget, 650 NF_checkCustomized, 651 NF_checkVarHandleGenericType, 652 NF_checkVarHandleExactType, 653 NF_getVarHandleMemberName; 654 static { 655 try { 656 NamedFunction nfs[] = { 657 NF_checkExactType = new NamedFunction(Invokers.class 658 .getDeclaredMethod("checkExactType", MethodHandle.class, MethodType.class)), 659 NF_checkGenericType = new NamedFunction(Invokers.class 660 .getDeclaredMethod("checkGenericType", MethodHandle.class, MethodType.class)), 661 NF_getCallSiteTarget = new NamedFunction(Invokers.class 662 .getDeclaredMethod("getCallSiteTarget", CallSite.class)), 663 NF_checkCustomized = new NamedFunction(Invokers.class 664 .getDeclaredMethod("checkCustomized", MethodHandle.class)), 665 NF_checkVarHandleGenericType = new NamedFunction(Invokers.class 666 .getDeclaredMethod("checkVarHandleGenericType", VarHandle.class, VarHandle.AccessDescriptor.class)), 667 NF_checkVarHandleExactType = new NamedFunction(Invokers.class 668 .getDeclaredMethod("checkVarHandleExactType", VarHandle.class, VarHandle.AccessDescriptor.class)), 669 NF_getVarHandleMemberName = new NamedFunction(Invokers.class 670 .getDeclaredMethod("getVarHandleMemberName", VarHandle.class, VarHandle.AccessDescriptor.class)) 671 }; 672 // Each nf must be statically invocable or we get tied up in our bootstraps. 673 assert(InvokerBytecodeGenerator.isStaticallyInvocable(nfs)); 674 } catch (ReflectiveOperationException ex) { 675 throw newInternalError(ex); 676 } 677 } 678 679 private static class Lazy { 680 private static final MethodHandle MH_asSpreader; 681 682 static { 683 try { 684 MH_asSpreader = IMPL_LOOKUP.findVirtual(MethodHandle.class, "asSpreader", 685 MethodType.methodType(MethodHandle.class, Class.class, int.class)); 686 } catch (ReflectiveOperationException ex) { 687 throw newInternalError(ex); 688 } 689 } 690 } 691} 692