1 /* 2 * Copyright (c) 2008, 2013, 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 26 package java.lang.invoke; 27 28 import java.util.Arrays; 29 import sun.invoke.empty.Empty; 30 import static java.lang.invoke.MethodHandleStatics.*; 31 import static java.lang.invoke.MethodHandleNatives.Constants.*; 32 import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP; 33 import static java.lang.invoke.LambdaForm.*; 34 35 /** 36 * Construction and caching of often-used invokers. 37 * @author jrose 38 */ 39 class Invokers { 40 // exact type (sans leading taget MH) for the outgoing call 41 private final MethodType targetType; 42 43 // FIXME: Get rid of the invokers that are not useful. 44 45 // exact invoker for the outgoing call 46 private /*lazy*/ MethodHandle exactInvoker; 47 private /*lazy*/ MethodHandle basicInvoker; // invokeBasic (unchecked exact) 48 49 // erased (partially untyped but with primitives) invoker for the outgoing call 50 // FIXME: get rid of 51 private /*lazy*/ MethodHandle erasedInvoker; 52 // FIXME: get rid of 53 /*lazy*/ MethodHandle erasedInvokerWithDrops; // for InvokeGeneric 54 55 // general invoker for the outgoing call 56 private /*lazy*/ MethodHandle generalInvoker; 57 58 // general invoker for the outgoing call, uses varargs 59 private /*lazy*/ MethodHandle varargsInvoker; 60 61 // general invoker for the outgoing call; accepts a trailing Object[] 62 private final /*lazy*/ MethodHandle[] spreadInvokers; 63 64 // invoker for an unbound callsite 65 private /*lazy*/ MethodHandle uninitializedCallSite; 66 67 /** Compute and cache information common to all collecting adapters 68 * that implement members of the erasure-family of the given erased type. 69 */ 70 /*non-public*/ Invokers(MethodType targetType) { 71 this.targetType = targetType; 72 this.spreadInvokers = new MethodHandle[targetType.parameterCount()+1]; 73 } 74 75 /*non-public*/ MethodHandle exactInvoker() { 76 MethodHandle invoker = exactInvoker; 77 if (invoker != null) return invoker; 78 invoker = makeExactOrGeneralInvoker(true); 79 exactInvoker = invoker; 80 return invoker; 81 } 82 83 /*non-public*/ MethodHandle generalInvoker() { 84 MethodHandle invoker = generalInvoker; 85 if (invoker != null) return invoker; 86 invoker = makeExactOrGeneralInvoker(false); 87 generalInvoker = invoker; 88 return invoker; 89 } 90 91 private MethodHandle makeExactOrGeneralInvoker(boolean isExact) { 92 MethodType mtype = targetType; 93 MethodType invokerType = mtype.invokerType(); 94 int which = (isExact ? MethodTypeForm.LF_EX_INVOKER : MethodTypeForm.LF_GEN_INVOKER); 95 LambdaForm lform = invokeHandleForm(mtype, false, which); 96 MethodHandle invoker = BoundMethodHandle.bindSingle(invokerType, lform, mtype); 97 String whichName = (isExact ? "invokeExact" : "invoke"); 98 invoker = invoker.withInternalMemberName(MemberName.makeMethodHandleInvoke(whichName, mtype)); 99 assert(checkInvoker(invoker)); 100 maybeCompileToBytecode(invoker); 101 return invoker; 102 } 103 104 /** If the target type seems to be common enough, eagerly compile the invoker to bytecodes. */ 105 private void maybeCompileToBytecode(MethodHandle invoker) { 106 final int EAGER_COMPILE_ARITY_LIMIT = 10; 107 if (targetType == targetType.erase() && 108 targetType.parameterCount() < EAGER_COMPILE_ARITY_LIMIT) { 109 invoker.form.compileToBytecode(); 110 } 111 } 112 113 /*non-public*/ MethodHandle basicInvoker() { 114 MethodHandle invoker = basicInvoker; 115 if (invoker != null) return invoker; 116 MethodType basicType = targetType.basicType(); 117 if (basicType != targetType) { 118 // double cache; not used significantly 119 return basicInvoker = basicType.invokers().basicInvoker(); 120 } 121 MemberName method = invokeBasicMethod(basicType); 122 invoker = DirectMethodHandle.make(method); 123 assert(checkInvoker(invoker)); 124 basicInvoker = invoker; 125 return invoker; 126 } 127 128 // This next one is called from LambdaForm.NamedFunction.<init>. 129 /*non-public*/ static MemberName invokeBasicMethod(MethodType basicType) { 130 assert(basicType == basicType.basicType()); 131 try { 132 //Lookup.findVirtual(MethodHandle.class, name, type); 133 return IMPL_LOOKUP.resolveOrFail(REF_invokeVirtual, MethodHandle.class, "invokeBasic", basicType); 134 } catch (ReflectiveOperationException ex) { 135 throw newInternalError("JVM cannot find invoker for "+basicType, ex); 136 } 137 } 138 139 private boolean checkInvoker(MethodHandle invoker) { 140 assert(targetType.invokerType().equals(invoker.type())) 141 : java.util.Arrays.asList(targetType, targetType.invokerType(), invoker); 142 assert(invoker.internalMemberName() == null || 143 invoker.internalMemberName().getMethodType().equals(targetType)); 144 assert(!invoker.isVarargsCollector()); 145 return true; 146 } 147 148 // FIXME: get rid of 149 /*non-public*/ MethodHandle erasedInvoker() { 150 MethodHandle xinvoker = exactInvoker(); 151 MethodHandle invoker = erasedInvoker; 152 if (invoker != null) return invoker; 153 MethodType erasedType = targetType.erase(); 154 invoker = xinvoker.asType(erasedType.invokerType()); 155 erasedInvoker = invoker; 156 return invoker; 157 } 158 159 /*non-public*/ MethodHandle spreadInvoker(int leadingArgCount) { 160 MethodHandle vaInvoker = spreadInvokers[leadingArgCount]; 161 if (vaInvoker != null) return vaInvoker; 162 int spreadArgCount = targetType.parameterCount() - leadingArgCount; 163 MethodType spreadInvokerType = targetType 164 .replaceParameterTypes(leadingArgCount, targetType.parameterCount(), Object[].class); 165 if (targetType.parameterSlotCount() <= MethodType.MAX_MH_INVOKER_ARITY) { 166 // Factor sinvoker.invoke(mh, a) into ginvoker.asSpreader().invoke(mh, a) 167 // where ginvoker.invoke(mh, a*) => mh.invoke(a*). 168 MethodHandle genInvoker = generalInvoker(); 169 vaInvoker = genInvoker.asSpreader(Object[].class, spreadArgCount); 170 } else { 171 // Cannot build a general invoker here of type ginvoker.invoke(mh, a*[254]). 172 // Instead, factor sinvoker.invoke(mh, a) into ainvoker.invoke(filter(mh), a) 173 // where filter(mh) == mh.asSpreader(Object[], spreadArgCount) 174 MethodHandle arrayInvoker = MethodHandles.exactInvoker(spreadInvokerType); 175 MethodHandle makeSpreader; 176 try { 177 makeSpreader = IMPL_LOOKUP 178 .findVirtual(MethodHandle.class, "asSpreader", 179 MethodType.methodType(MethodHandle.class, Class.class, int.class)); 180 } catch (ReflectiveOperationException ex) { 181 throw newInternalError(ex); 182 } 183 makeSpreader = MethodHandles.insertArguments(makeSpreader, 1, Object[].class, spreadArgCount); 184 vaInvoker = MethodHandles.filterArgument(arrayInvoker, 0, makeSpreader); 185 } 186 assert(vaInvoker.type().equals(spreadInvokerType.invokerType())); 187 maybeCompileToBytecode(vaInvoker); 188 spreadInvokers[leadingArgCount] = vaInvoker; 189 return vaInvoker; 190 } 191 192 /*non-public*/ MethodHandle varargsInvoker() { 193 MethodHandle vaInvoker = varargsInvoker; 194 if (vaInvoker != null) return vaInvoker; 195 vaInvoker = spreadInvoker(0).asType(MethodType.genericMethodType(0, true).invokerType()); 196 varargsInvoker = vaInvoker; 197 return vaInvoker; 198 } 199 200 private static MethodHandle THROW_UCS = null; 201 202 /*non-public*/ MethodHandle uninitializedCallSite() { 203 MethodHandle invoker = uninitializedCallSite; 204 if (invoker != null) return invoker; 205 if (targetType.parameterCount() > 0) { 206 MethodType type0 = targetType.dropParameterTypes(0, targetType.parameterCount()); 207 Invokers invokers0 = type0.invokers(); 208 invoker = MethodHandles.dropArguments(invokers0.uninitializedCallSite(), 209 0, targetType.parameterList()); 210 assert(invoker.type().equals(targetType)); 211 uninitializedCallSite = invoker; 212 return invoker; 213 } 214 invoker = THROW_UCS; 215 if (invoker == null) { 216 try { 217 THROW_UCS = invoker = IMPL_LOOKUP 218 .findStatic(CallSite.class, "uninitializedCallSite", 219 MethodType.methodType(Empty.class)); 220 } catch (ReflectiveOperationException ex) { 221 throw newInternalError(ex); 222 } 223 } 224 invoker = MethodHandles.explicitCastArguments(invoker, MethodType.methodType(targetType.returnType())); 225 invoker = invoker.dropArguments(targetType, 0, targetType.parameterCount()); 226 assert(invoker.type().equals(targetType)); 227 uninitializedCallSite = invoker; 228 return invoker; 229 } 230 231 public String toString() { 232 return "Invokers"+targetType; 233 } 234 235 static MemberName methodHandleInvokeLinkerMethod(String name, 236 MethodType mtype, 237 Object[] appendixResult) { 238 int which; 239 switch (name) { 240 case "invokeExact": which = MethodTypeForm.LF_EX_LINKER; break; 241 case "invoke": which = MethodTypeForm.LF_GEN_LINKER; break; 242 default: throw new InternalError("not invoker: "+name); 243 } 244 LambdaForm lform; 245 if (mtype.parameterSlotCount() <= MethodType.MAX_MH_ARITY - MH_LINKER_ARG_APPENDED) { 246 lform = invokeHandleForm(mtype, false, which); 247 appendixResult[0] = mtype; 248 } else { 249 lform = invokeHandleForm(mtype, true, which); 250 } 251 return lform.vmentry; 252 } 253 254 // argument count to account for trailing "appendix value" (typically the mtype) 255 private static final int MH_LINKER_ARG_APPENDED = 1; 256 257 /** Returns an adapter for invokeExact or generic invoke, as a MH or constant pool linker. 258 * If !customized, caller is responsible for supplying, during adapter execution, 259 * a copy of the exact mtype. This is because the adapter might be generalized to 260 * a basic type. 261 * @param mtype the caller's method type (either basic or full-custom) 262 * @param customized whether to use a trailing appendix argument (to carry the mtype) 263 * @param which bit-encoded 0x01 whether it is a CP adapter ("linker") or MHs.invoker value ("invoker"); 264 * 0x02 whether it is for invokeExact or generic invoke 265 */ 266 private static LambdaForm invokeHandleForm(MethodType mtype, boolean customized, int which) { 267 boolean isCached; 268 if (!customized) { 269 mtype = mtype.basicType(); // normalize Z to I, String to Object, etc. 270 isCached = true; 271 } else { 272 isCached = false; // maybe cache if mtype == mtype.basicType() 273 } 274 boolean isLinker, isGeneric; 275 String debugName; 276 switch (which) { 277 case MethodTypeForm.LF_EX_LINKER: isLinker = true; isGeneric = false; debugName = "invokeExact_MT"; break; 278 case MethodTypeForm.LF_EX_INVOKER: isLinker = false; isGeneric = false; debugName = "exactInvoker"; break; 279 case MethodTypeForm.LF_GEN_LINKER: isLinker = true; isGeneric = true; debugName = "invoke_MT"; break; 280 case MethodTypeForm.LF_GEN_INVOKER: isLinker = false; isGeneric = true; debugName = "invoker"; break; 281 default: throw new InternalError(); 282 } 283 LambdaForm lform; 284 if (isCached) { 285 lform = mtype.form().cachedLambdaForm(which); 286 if (lform != null) return lform; 287 } 288 // exactInvokerForm (Object,Object)Object 289 // link with java.lang.invoke.MethodHandle.invokeBasic(MethodHandle,Object,Object)Object/invokeSpecial 290 final int THIS_MH = 0; 291 final int CALL_MH = THIS_MH + (isLinker ? 0 : 1); 292 final int ARG_BASE = CALL_MH + 1; 293 final int OUTARG_LIMIT = ARG_BASE + mtype.parameterCount(); 294 final int INARG_LIMIT = OUTARG_LIMIT + (isLinker && !customized ? 1 : 0); 295 int nameCursor = OUTARG_LIMIT; 296 final int MTYPE_ARG = customized ? -1 : nameCursor++; // might be last in-argument 297 final int CHECK_TYPE = nameCursor++; 298 final int LINKER_CALL = nameCursor++; 299 MethodType invokerFormType = mtype.invokerType(); 300 if (isLinker) { 301 if (!customized) 302 invokerFormType = invokerFormType.appendParameterTypes(MemberName.class); 303 } else { 304 invokerFormType = invokerFormType.invokerType(); 305 } 306 Name[] names = arguments(nameCursor - INARG_LIMIT, invokerFormType); 307 assert(names.length == nameCursor) 308 : Arrays.asList(mtype, customized, which, nameCursor, names.length); 309 if (MTYPE_ARG >= INARG_LIMIT) { 310 assert(names[MTYPE_ARG] == null); 311 NamedFunction getter = BoundMethodHandle.getSpeciesData("L").getterFunction(0); 312 names[MTYPE_ARG] = new Name(getter, names[THIS_MH]); 313 // else if isLinker, then MTYPE is passed in from the caller (e.g., the JVM) 314 } 315 316 // Make the final call. If isGeneric, then prepend the result of type checking. 317 MethodType outCallType = mtype.basicType(); 318 Object[] outArgs = Arrays.copyOfRange(names, CALL_MH, OUTARG_LIMIT, Object[].class); 319 Object mtypeArg = (customized ? mtype : names[MTYPE_ARG]); 320 if (!isGeneric) { 321 names[CHECK_TYPE] = new Name(NF_checkExactType, names[CALL_MH], mtypeArg); 322 // mh.invokeExact(a*):R => checkExactType(mh, TYPEOF(a*:R)); mh.invokeBasic(a*) 323 } else { 324 names[CHECK_TYPE] = new Name(NF_checkGenericType, names[CALL_MH], mtypeArg); 325 // mh.invokeGeneric(a*):R => checkGenericType(mh, TYPEOF(a*:R)).invokeBasic(a*) 326 outArgs[0] = names[CHECK_TYPE]; 327 } 328 names[LINKER_CALL] = new Name(outCallType, outArgs); 329 lform = new LambdaForm(debugName, INARG_LIMIT, names); 330 if (isLinker) 331 lform.compileToBytecode(); // JVM needs a real methodOop 332 if (isCached) 333 lform = mtype.form().setCachedLambdaForm(which, lform); 334 return lform; 335 } 336 337 /*non-public*/ static 338 WrongMethodTypeException newWrongMethodTypeException(MethodType actual, MethodType expected) { 339 // FIXME: merge with JVM logic for throwing WMTE 340 return new WrongMethodTypeException("expected "+expected+" but found "+actual); 341 } 342 343 /** Static definition of MethodHandle.invokeExact checking code. */ 344 /*non-public*/ static 345 @ForceInline 346 void checkExactType(Object mhObj, Object expectedObj) { 347 MethodHandle mh = (MethodHandle) mhObj; 348 MethodType expected = (MethodType) expectedObj; 349 MethodType actual = mh.type(); 350 if (actual != expected) 351 throw newWrongMethodTypeException(expected, actual); 352 } 353 354 /** Static definition of MethodHandle.invokeGeneric checking code. 355 * Directly returns the type-adjusted MH to invoke, as follows: 356 * {@code (R)MH.invoke(a*) => MH.asType(TYPEOF(a*:R)).invokeBasic(a*)} 357 */ 358 /*non-public*/ static 359 @ForceInline 360 Object checkGenericType(Object mhObj, Object expectedObj) { 361 MethodHandle mh = (MethodHandle) mhObj; 362 MethodType expected = (MethodType) expectedObj; 363 if (mh.type() == expected) return mh; 364 MethodHandle atc = mh.asTypeCache; 365 if (atc != null && atc.type() == expected) return atc; 366 return mh.asType(expected); 367 /* Maybe add more paths here. Possible optimizations: 368 * for (R)MH.invoke(a*), 369 * let MT0 = TYPEOF(a*:R), MT1 = MH.type 370 * 371 * if MT0==MT1 or MT1 can be safely called by MT0 372 * => MH.invokeBasic(a*) 373 * if MT1 can be safely called by MT0[R := Object] 374 * => MH.invokeBasic(a*) & checkcast(R) 375 * if MT1 can be safely called by MT0[* := Object] 376 * => checkcast(A)* & MH.invokeBasic(a*) & checkcast(R) 377 * if a big adapter BA can be pulled out of (MT0,MT1) 378 * => BA.invokeBasic(MT0,MH,a*) 379 * if a local adapter LA can cached on static CS0 = new GICS(MT0) 380 * => CS0.LA.invokeBasic(MH,a*) 381 * else 382 * => MH.asType(MT0).invokeBasic(A*) 383 */ 384 } 385 386 static MemberName linkToCallSiteMethod(MethodType mtype) { 387 LambdaForm lform = callSiteForm(mtype, false); 388 return lform.vmentry; 389 } 390 391 static MemberName linkToTargetMethod(MethodType mtype) { 392 LambdaForm lform = callSiteForm(mtype, true); 393 return lform.vmentry; 394 } 395 396 // skipCallSite is true if we are optimizing a ConstantCallSite 397 private static LambdaForm callSiteForm(MethodType mtype, boolean skipCallSite) { 398 mtype = mtype.basicType(); // normalize Z to I, String to Object, etc. 399 final int which = (skipCallSite ? MethodTypeForm.LF_MH_LINKER : MethodTypeForm.LF_CS_LINKER); 400 LambdaForm lform = mtype.form().cachedLambdaForm(which); 401 if (lform != null) return lform; 402 // exactInvokerForm (Object,Object)Object 403 // link with java.lang.invoke.MethodHandle.invokeBasic(MethodHandle,Object,Object)Object/invokeSpecial 404 final int ARG_BASE = 0; 405 final int OUTARG_LIMIT = ARG_BASE + mtype.parameterCount(); 406 final int INARG_LIMIT = OUTARG_LIMIT + 1; 407 int nameCursor = OUTARG_LIMIT; 408 final int APPENDIX_ARG = nameCursor++; // the last in-argument 409 final int CSITE_ARG = skipCallSite ? -1 : APPENDIX_ARG; 410 final int CALL_MH = skipCallSite ? APPENDIX_ARG : nameCursor++; // result of getTarget 411 final int LINKER_CALL = nameCursor++; 412 MethodType invokerFormType = mtype.appendParameterTypes(skipCallSite ? MethodHandle.class : CallSite.class); 413 Name[] names = arguments(nameCursor - INARG_LIMIT, invokerFormType); 414 assert(names.length == nameCursor); 415 assert(names[APPENDIX_ARG] != null); 416 if (!skipCallSite) 417 names[CALL_MH] = new Name(NF_getCallSiteTarget, names[CSITE_ARG]); 418 // (site.)invokedynamic(a*):R => mh = site.getTarget(); mh.invokeBasic(a*) 419 final int PREPEND_MH = 0, PREPEND_COUNT = 1; 420 Object[] outArgs = Arrays.copyOfRange(names, ARG_BASE, OUTARG_LIMIT + PREPEND_COUNT, Object[].class); 421 // prepend MH argument: 422 System.arraycopy(outArgs, 0, outArgs, PREPEND_COUNT, outArgs.length - PREPEND_COUNT); 423 outArgs[PREPEND_MH] = names[CALL_MH]; 424 names[LINKER_CALL] = new Name(mtype, outArgs); 425 lform = new LambdaForm((skipCallSite ? "linkToTargetMethod" : "linkToCallSite"), INARG_LIMIT, names); 426 lform.compileToBytecode(); // JVM needs a real methodOop 427 lform = mtype.form().setCachedLambdaForm(which, lform); 428 return lform; 429 } 430 431 /** Static definition of MethodHandle.invokeGeneric checking code. */ 432 /*non-public*/ static 433 @ForceInline 434 Object getCallSiteTarget(Object site) { 435 return ((CallSite)site).getTarget(); 436 } 437 438 // Local constant functions: 439 private static final NamedFunction NF_checkExactType; 440 private static final NamedFunction NF_checkGenericType; 441 private static final NamedFunction NF_asType; 442 private static final NamedFunction NF_getCallSiteTarget; 443 static { 444 try { 445 NF_checkExactType = new NamedFunction(Invokers.class 446 .getDeclaredMethod("checkExactType", Object.class, Object.class)); 447 NF_checkGenericType = new NamedFunction(Invokers.class 448 .getDeclaredMethod("checkGenericType", Object.class, Object.class)); 449 NF_asType = new NamedFunction(MethodHandle.class 450 .getDeclaredMethod("asType", MethodType.class)); 451 NF_getCallSiteTarget = new NamedFunction(Invokers.class 452 .getDeclaredMethod("getCallSiteTarget", Object.class)); 453 NF_checkExactType.resolve(); 454 NF_checkGenericType.resolve(); 455 NF_getCallSiteTarget.resolve(); 456 // bound 457 } catch (ReflectiveOperationException ex) { 458 throw newInternalError(ex); 459 } 460 } 461 462 }