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.security.AccessController; 29 import java.security.PrivilegedAction; 30 import java.util.Arrays; 31 import java.util.HashMap; 32 import sun.invoke.empty.Empty; 33 import sun.invoke.util.ValueConversions; 34 import sun.invoke.util.VerifyType; 35 import sun.invoke.util.Wrapper; 36 import sun.reflect.CallerSensitive; 37 import sun.reflect.Reflection; 38 import static java.lang.invoke.LambdaForm.*; 39 import static java.lang.invoke.MethodHandleStatics.*; 40 import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP; 41 42 /** 43 * Trusted implementation code for MethodHandle. 44 * @author jrose 45 */ 46 /*non-public*/ abstract class MethodHandleImpl { 47 /// Factory methods to create method handles: 48 49 static void initStatics() { 50 // Trigger selected static initializations. 51 MemberName.Factory.INSTANCE.getClass(); 52 } 53 54 static MethodHandle makeArrayElementAccessor(Class<?> arrayClass, boolean isSetter) { 55 if (arrayClass == Object[].class) 56 return (isSetter ? ArrayAccessor.OBJECT_ARRAY_SETTER : ArrayAccessor.OBJECT_ARRAY_GETTER); 57 if (!arrayClass.isArray()) 58 throw newIllegalArgumentException("not an array: "+arrayClass); 59 MethodHandle[] cache = ArrayAccessor.TYPED_ACCESSORS.get(arrayClass); 60 int cacheIndex = (isSetter ? ArrayAccessor.SETTER_INDEX : ArrayAccessor.GETTER_INDEX); 61 MethodHandle mh = cache[cacheIndex]; 62 if (mh != null) return mh; 63 mh = ArrayAccessor.getAccessor(arrayClass, isSetter); 64 MethodType correctType = ArrayAccessor.correctType(arrayClass, isSetter); 65 if (mh.type() != correctType) { 66 assert(mh.type().parameterType(0) == Object[].class); 67 assert((isSetter ? mh.type().parameterType(2) : mh.type().returnType()) == Object.class); 68 assert(isSetter || correctType.parameterType(0).getComponentType() == correctType.returnType()); 69 // safe to view non-strictly, because element type follows from array type 70 mh = mh.viewAsType(correctType); 71 } 72 // Atomically update accessor cache. 73 synchronized(cache) { 74 if (cache[cacheIndex] == null) { 75 cache[cacheIndex] = mh; 76 } else { 77 // Throw away newly constructed accessor and use cached version. 78 mh = cache[cacheIndex]; 79 } 80 } 81 return mh; 82 } 83 84 static final class ArrayAccessor { 85 /// Support for array element access 86 static final int GETTER_INDEX = 0, SETTER_INDEX = 1, INDEX_LIMIT = 2; 87 static final ClassValue<MethodHandle[]> TYPED_ACCESSORS 88 = new ClassValue<MethodHandle[]>() { 89 @Override 90 protected MethodHandle[] computeValue(Class<?> type) { 91 return new MethodHandle[INDEX_LIMIT]; 92 } 93 }; 94 static final MethodHandle OBJECT_ARRAY_GETTER, OBJECT_ARRAY_SETTER; 95 static { 96 MethodHandle[] cache = TYPED_ACCESSORS.get(Object[].class); 97 cache[GETTER_INDEX] = OBJECT_ARRAY_GETTER = getAccessor(Object[].class, false); 98 cache[SETTER_INDEX] = OBJECT_ARRAY_SETTER = getAccessor(Object[].class, true); 99 100 assert(InvokerBytecodeGenerator.isStaticallyInvocable(ArrayAccessor.OBJECT_ARRAY_GETTER.internalMemberName())); 101 assert(InvokerBytecodeGenerator.isStaticallyInvocable(ArrayAccessor.OBJECT_ARRAY_SETTER.internalMemberName())); 102 } 103 104 static int getElementI(int[] a, int i) { return a[i]; } 105 static long getElementJ(long[] a, int i) { return a[i]; } 106 static float getElementF(float[] a, int i) { return a[i]; } 107 static double getElementD(double[] a, int i) { return a[i]; } 108 static boolean getElementZ(boolean[] a, int i) { return a[i]; } 109 static byte getElementB(byte[] a, int i) { return a[i]; } 110 static short getElementS(short[] a, int i) { return a[i]; } 111 static char getElementC(char[] a, int i) { return a[i]; } 112 static Object getElementL(Object[] a, int i) { return a[i]; } 113 114 static void setElementI(int[] a, int i, int x) { a[i] = x; } 115 static void setElementJ(long[] a, int i, long x) { a[i] = x; } 116 static void setElementF(float[] a, int i, float x) { a[i] = x; } 117 static void setElementD(double[] a, int i, double x) { a[i] = x; } 118 static void setElementZ(boolean[] a, int i, boolean x) { a[i] = x; } 119 static void setElementB(byte[] a, int i, byte x) { a[i] = x; } 120 static void setElementS(short[] a, int i, short x) { a[i] = x; } 121 static void setElementC(char[] a, int i, char x) { a[i] = x; } 122 static void setElementL(Object[] a, int i, Object x) { a[i] = x; } 123 124 static String name(Class<?> arrayClass, boolean isSetter) { 125 Class<?> elemClass = arrayClass.getComponentType(); 126 if (elemClass == null) throw newIllegalArgumentException("not an array", arrayClass); 127 return (!isSetter ? "getElement" : "setElement") + Wrapper.basicTypeChar(elemClass); 128 } 129 static MethodType type(Class<?> arrayClass, boolean isSetter) { 130 Class<?> elemClass = arrayClass.getComponentType(); 131 Class<?> arrayArgClass = arrayClass; 132 if (!elemClass.isPrimitive()) { 133 arrayArgClass = Object[].class; 134 elemClass = Object.class; 135 } 136 return !isSetter ? 137 MethodType.methodType(elemClass, arrayArgClass, int.class) : 138 MethodType.methodType(void.class, arrayArgClass, int.class, elemClass); 139 } 140 static MethodType correctType(Class<?> arrayClass, boolean isSetter) { 141 Class<?> elemClass = arrayClass.getComponentType(); 142 return !isSetter ? 143 MethodType.methodType(elemClass, arrayClass, int.class) : 144 MethodType.methodType(void.class, arrayClass, int.class, elemClass); 145 } 146 static MethodHandle getAccessor(Class<?> arrayClass, boolean isSetter) { 147 String name = name(arrayClass, isSetter); 148 MethodType type = type(arrayClass, isSetter); 149 try { 150 return IMPL_LOOKUP.findStatic(ArrayAccessor.class, name, type); 151 } catch (ReflectiveOperationException ex) { 152 throw uncaughtException(ex); 153 } 154 } 155 } 156 157 /** 158 * Create a JVM-level adapter method handle to conform the given method 159 * handle to the similar newType, using only pairwise argument conversions. 160 * For each argument, convert incoming argument to the exact type needed. 161 * The argument conversions allowed are casting, boxing and unboxing, 162 * integral widening or narrowing, and floating point widening or narrowing. 163 * @param srcType required call type 164 * @param target original method handle 165 * @param level which strength of conversion is allowed 166 * @return an adapter to the original handle with the desired new type, 167 * or the original target if the types are already identical 168 * or null if the adaptation cannot be made 169 */ 170 static MethodHandle makePairwiseConvert(MethodHandle target, MethodType srcType, int level) { 171 assert(level >= 0 && level <= 2); 172 MethodType dstType = target.type(); 173 assert(dstType.parameterCount() == target.type().parameterCount()); 174 if (srcType == dstType) 175 return target; 176 177 // Calculate extra arguments (temporaries) required in the names array. 178 // FIXME: Use an ArrayList<Name>. Some arguments require more than one conversion step. 179 final int INARG_COUNT = srcType.parameterCount(); 180 int conversions = 0; 181 boolean[] needConv = new boolean[1+INARG_COUNT]; 182 for (int i = 0; i <= INARG_COUNT; i++) { 183 Class<?> src = (i == INARG_COUNT) ? dstType.returnType() : srcType.parameterType(i); 184 Class<?> dst = (i == INARG_COUNT) ? srcType.returnType() : dstType.parameterType(i); 185 if (!VerifyType.isNullConversion(src, dst, false) || 186 level <= 1 && dst.isInterface() && !dst.isAssignableFrom(src)) { 187 needConv[i] = true; 188 conversions++; 189 } 190 } 191 boolean retConv = needConv[INARG_COUNT]; 192 if (retConv && srcType.returnType() == void.class) { 193 retConv = false; 194 conversions--; 195 } 196 197 final int IN_MH = 0; 198 final int INARG_BASE = 1; 199 final int INARG_LIMIT = INARG_BASE + INARG_COUNT; 200 final int NAME_LIMIT = INARG_LIMIT + conversions + 1; 201 final int RETURN_CONV = (!retConv ? -1 : NAME_LIMIT - 1); 202 final int OUT_CALL = (!retConv ? NAME_LIMIT : RETURN_CONV) - 1; 203 final int RESULT = (srcType.returnType() == void.class ? -1 : NAME_LIMIT - 1); 204 205 // Now build a LambdaForm. 206 MethodType lambdaType = srcType.basicType().invokerType(); 207 Name[] names = arguments(NAME_LIMIT - INARG_LIMIT, lambdaType); 208 209 // Collect the arguments to the outgoing call, maybe with conversions: 210 final int OUTARG_BASE = 0; // target MH is Name.function, name Name.arguments[0] 211 Object[] outArgs = new Object[OUTARG_BASE + INARG_COUNT]; 212 213 int nameCursor = INARG_LIMIT; 214 for (int i = 0; i < INARG_COUNT; i++) { 215 Class<?> src = srcType.parameterType(i); 216 Class<?> dst = dstType.parameterType(i); 217 218 if (!needConv[i]) { 219 // do nothing: difference is trivial 220 outArgs[OUTARG_BASE + i] = names[INARG_BASE + i]; 221 continue; 222 } 223 224 // Tricky case analysis follows. 225 MethodHandle fn = null; 226 if (src.isPrimitive()) { 227 if (dst.isPrimitive()) { 228 fn = ValueConversions.convertPrimitive(src, dst); 229 } else { 230 Wrapper w = Wrapper.forPrimitiveType(src); 231 MethodHandle boxMethod = ValueConversions.box(w); 232 if (dst == w.wrapperType()) 233 fn = boxMethod; 234 else 235 fn = boxMethod.asType(MethodType.methodType(dst, src)); 236 } 237 } else { 238 if (dst.isPrimitive()) { 239 // Caller has boxed a primitive. Unbox it for the target. 240 Wrapper w = Wrapper.forPrimitiveType(dst); 241 if (level == 0 || VerifyType.isNullConversion(src, w.wrapperType(), false)) { 242 fn = ValueConversions.unbox(dst); 243 } else if (src == Object.class || !Wrapper.isWrapperType(src)) { 244 // Examples: Object->int, Number->int, Comparable->int; Byte->int, Character->int 245 // must include additional conversions 246 // src must be examined at runtime, to detect Byte, Character, etc. 247 MethodHandle unboxMethod = (level == 1 248 ? ValueConversions.unbox(dst) 249 : ValueConversions.unboxCast(dst)); 250 fn = unboxMethod; 251 } else { 252 // Example: Byte->int 253 // Do this by reformulating the problem to Byte->byte. 254 Class<?> srcPrim = Wrapper.forWrapperType(src).primitiveType(); 255 MethodHandle unbox = ValueConversions.unbox(srcPrim); 256 // Compose the two conversions. FIXME: should make two Names for this job 257 fn = unbox.asType(MethodType.methodType(dst, src)); 258 } 259 } else { 260 // Simple reference conversion. 261 // Note: Do not check for a class hierarchy relation 262 // between src and dst. In all cases a 'null' argument 263 // will pass the cast conversion. 264 fn = ValueConversions.cast(dst, Lazy.MH_castReference); 265 } 266 } 267 Name conv = new Name(fn, names[INARG_BASE + i]); 268 assert(names[nameCursor] == null); 269 names[nameCursor++] = conv; 270 assert(outArgs[OUTARG_BASE + i] == null); 271 outArgs[OUTARG_BASE + i] = conv; 272 } 273 274 // Build argument array for the call. 275 assert(nameCursor == OUT_CALL); 276 names[OUT_CALL] = new Name(target, outArgs); 277 278 if (RETURN_CONV < 0) { 279 assert(OUT_CALL == names.length-1); 280 } else { 281 Class<?> needReturn = srcType.returnType(); 282 Class<?> haveReturn = dstType.returnType(); 283 MethodHandle fn; 284 Object[] arg = { names[OUT_CALL] }; 285 if (haveReturn == void.class) { 286 // synthesize a zero value for the given void 287 Object zero = Wrapper.forBasicType(needReturn).zero(); 288 fn = MethodHandles.constant(needReturn, zero); 289 arg = new Object[0]; // don't pass names[OUT_CALL] to conversion 290 } else { 291 MethodHandle identity = MethodHandles.identity(needReturn); 292 MethodType needConversion = identity.type().changeParameterType(0, haveReturn); 293 fn = makePairwiseConvert(identity, needConversion, level); 294 } 295 assert(names[RETURN_CONV] == null); 296 names[RETURN_CONV] = new Name(fn, arg); 297 assert(RETURN_CONV == names.length-1); 298 } 299 300 LambdaForm form = new LambdaForm("convert", lambdaType.parameterCount(), names, RESULT); 301 return SimpleMethodHandle.make(srcType, form); 302 } 303 304 /** 305 * Identity function, with reference cast. 306 * @param t an arbitrary reference type 307 * @param x an arbitrary reference value 308 * @return the same value x 309 */ 310 @ForceInline 311 @SuppressWarnings("unchecked") 312 static <T,U> T castReference(Class<? extends T> t, U x) { 313 // inlined Class.cast because we can't ForceInline it 314 if (x != null && !t.isInstance(x)) 315 throw newClassCastException(t, x); 316 return (T) x; 317 } 318 319 private static ClassCastException newClassCastException(Class<?> t, Object obj) { 320 return new ClassCastException("Cannot cast " + obj.getClass().getName() + " to " + t.getName()); 321 } 322 323 static MethodHandle makeReferenceIdentity(Class<?> refType) { 324 MethodType lambdaType = MethodType.genericMethodType(1).invokerType(); 325 Name[] names = arguments(1, lambdaType); 326 names[names.length - 1] = new Name(ValueConversions.identity(), names[1]); 327 LambdaForm form = new LambdaForm("identity", lambdaType.parameterCount(), names); 328 return SimpleMethodHandle.make(MethodType.methodType(refType, refType), form); 329 } 330 331 static MethodHandle makeVarargsCollector(MethodHandle target, Class<?> arrayType) { 332 MethodType type = target.type(); 333 int last = type.parameterCount() - 1; 334 if (type.parameterType(last) != arrayType) 335 target = target.asType(type.changeParameterType(last, arrayType)); 336 target = target.asFixedArity(); // make sure this attribute is turned off 337 return new AsVarargsCollector(target, target.type(), arrayType); 338 } 339 340 static class AsVarargsCollector extends MethodHandle { 341 private final MethodHandle target; 342 private final Class<?> arrayType; 343 private /*@Stable*/ MethodHandle asCollectorCache; 344 345 AsVarargsCollector(MethodHandle target, MethodType type, Class<?> arrayType) { 346 super(type, reinvokerForm(target)); 347 this.target = target; 348 this.arrayType = arrayType; 349 this.asCollectorCache = target.asCollector(arrayType, 0); 350 } 351 352 @Override MethodHandle reinvokerTarget() { return target; } 353 354 @Override 355 public boolean isVarargsCollector() { 356 return true; 357 } 358 359 @Override 360 public MethodHandle asFixedArity() { 361 return target; 362 } 363 364 @Override 365 public MethodHandle asTypeUncached(MethodType newType) { 366 MethodType type = this.type(); 367 int collectArg = type.parameterCount() - 1; 368 int newArity = newType.parameterCount(); 369 if (newArity == collectArg+1 && 370 type.parameterType(collectArg).isAssignableFrom(newType.parameterType(collectArg))) { 371 // if arity and trailing parameter are compatible, do normal thing 372 return asTypeCache = asFixedArity().asType(newType); 373 } 374 // check cache 375 MethodHandle acc = asCollectorCache; 376 if (acc != null && acc.type().parameterCount() == newArity) 377 return asTypeCache = acc.asType(newType); 378 // build and cache a collector 379 int arrayLength = newArity - collectArg; 380 MethodHandle collector; 381 try { 382 collector = asFixedArity().asCollector(arrayType, arrayLength); 383 assert(collector.type().parameterCount() == newArity) : "newArity="+newArity+" but collector="+collector; 384 } catch (IllegalArgumentException ex) { 385 throw new WrongMethodTypeException("cannot build collector", ex); 386 } 387 asCollectorCache = collector; 388 return asTypeCache = collector.asType(newType); 389 } 390 391 @Override 392 MethodHandle setVarargs(MemberName member) { 393 if (member.isVarargs()) return this; 394 return asFixedArity(); 395 } 396 397 @Override 398 MethodHandle viewAsType(MethodType newType) { 399 if (newType.lastParameterType() != type().lastParameterType()) 400 throw new InternalError(); 401 MethodHandle newTarget = asFixedArity().viewAsType(newType); 402 // put back the varargs bit: 403 return new AsVarargsCollector(newTarget, newType, arrayType); 404 } 405 406 @Override 407 MemberName internalMemberName() { 408 return asFixedArity().internalMemberName(); 409 } 410 @Override 411 Class<?> internalCallerClass() { 412 return asFixedArity().internalCallerClass(); 413 } 414 415 /*non-public*/ 416 @Override 417 boolean isInvokeSpecial() { 418 return asFixedArity().isInvokeSpecial(); 419 } 420 421 422 @Override 423 MethodHandle bindArgument(int pos, BasicType basicType, Object value) { 424 return asFixedArity().bindArgument(pos, basicType, value); 425 } 426 427 @Override 428 MethodHandle bindReceiver(Object receiver) { 429 return asFixedArity().bindReceiver(receiver); 430 } 431 432 @Override 433 MethodHandle dropArguments(MethodType srcType, int pos, int drops) { 434 return asFixedArity().dropArguments(srcType, pos, drops); 435 } 436 437 @Override 438 MethodHandle permuteArguments(MethodType newType, int[] reorder) { 439 return asFixedArity().permuteArguments(newType, reorder); 440 } 441 } 442 443 /** Factory method: Spread selected argument. */ 444 static MethodHandle makeSpreadArguments(MethodHandle target, 445 Class<?> spreadArgType, int spreadArgPos, int spreadArgCount) { 446 MethodType targetType = target.type(); 447 448 for (int i = 0; i < spreadArgCount; i++) { 449 Class<?> arg = VerifyType.spreadArgElementType(spreadArgType, i); 450 if (arg == null) arg = Object.class; 451 targetType = targetType.changeParameterType(spreadArgPos + i, arg); 452 } 453 target = target.asType(targetType); 454 455 MethodType srcType = targetType 456 .replaceParameterTypes(spreadArgPos, spreadArgPos + spreadArgCount, spreadArgType); 457 // Now build a LambdaForm. 458 MethodType lambdaType = srcType.invokerType(); 459 Name[] names = arguments(spreadArgCount + 2, lambdaType); 460 int nameCursor = lambdaType.parameterCount(); 461 int[] indexes = new int[targetType.parameterCount()]; 462 463 for (int i = 0, argIndex = 1; i < targetType.parameterCount() + 1; i++, argIndex++) { 464 Class<?> src = lambdaType.parameterType(i); 465 if (i == spreadArgPos) { 466 // Spread the array. 467 MethodHandle aload = MethodHandles.arrayElementGetter(spreadArgType); 468 Name array = names[argIndex]; 469 names[nameCursor++] = new Name(Lazy.NF_checkSpreadArgument, array, spreadArgCount); 470 for (int j = 0; j < spreadArgCount; i++, j++) { 471 indexes[i] = nameCursor; 472 names[nameCursor++] = new Name(aload, array, j); 473 } 474 } else if (i < indexes.length) { 475 indexes[i] = argIndex; 476 } 477 } 478 assert(nameCursor == names.length-1); // leave room for the final call 479 480 // Build argument array for the call. 481 Name[] targetArgs = new Name[targetType.parameterCount()]; 482 for (int i = 0; i < targetType.parameterCount(); i++) { 483 int idx = indexes[i]; 484 targetArgs[i] = names[idx]; 485 } 486 names[names.length - 1] = new Name(target, (Object[]) targetArgs); 487 488 LambdaForm form = new LambdaForm("spread", lambdaType.parameterCount(), names); 489 return SimpleMethodHandle.make(srcType, form); 490 } 491 492 static void checkSpreadArgument(Object av, int n) { 493 if (av == null) { 494 if (n == 0) return; 495 } else if (av instanceof Object[]) { 496 int len = ((Object[])av).length; 497 if (len == n) return; 498 } else { 499 int len = java.lang.reflect.Array.getLength(av); 500 if (len == n) return; 501 } 502 // fall through to error: 503 throw newIllegalArgumentException("array is not of length "+n); 504 } 505 506 /** 507 * Pre-initialized NamedFunctions for bootstrapping purposes. 508 * Factored in an inner class to delay initialization until first usage. 509 */ 510 private static class Lazy { 511 private static final Class<?> MHI = MethodHandleImpl.class; 512 513 static final NamedFunction NF_checkSpreadArgument; 514 static final NamedFunction NF_guardWithCatch; 515 static final NamedFunction NF_selectAlternative; 516 static final NamedFunction NF_throwException; 517 518 static final MethodHandle MH_castReference; 519 520 static { 521 try { 522 NF_checkSpreadArgument = new NamedFunction(MHI.getDeclaredMethod("checkSpreadArgument", Object.class, int.class)); 523 NF_guardWithCatch = new NamedFunction(MHI.getDeclaredMethod("guardWithCatch", MethodHandle.class, Class.class, 524 MethodHandle.class, Object[].class)); 525 NF_selectAlternative = new NamedFunction(MHI.getDeclaredMethod("selectAlternative", boolean.class, MethodHandle.class, 526 MethodHandle.class)); 527 NF_throwException = new NamedFunction(MHI.getDeclaredMethod("throwException", Throwable.class)); 528 529 NF_checkSpreadArgument.resolve(); 530 NF_guardWithCatch.resolve(); 531 NF_selectAlternative.resolve(); 532 NF_throwException.resolve(); 533 534 MethodType mt = MethodType.methodType(Object.class, Class.class, Object.class); 535 MH_castReference = IMPL_LOOKUP.findStatic(MHI, "castReference", mt); 536 } catch (ReflectiveOperationException ex) { 537 throw newInternalError(ex); 538 } 539 } 540 } 541 542 /** Factory method: Collect or filter selected argument(s). */ 543 static MethodHandle makeCollectArguments(MethodHandle target, 544 MethodHandle collector, int collectArgPos, boolean retainOriginalArgs) { 545 MethodType targetType = target.type(); // (a..., c, [b...])=>r 546 MethodType collectorType = collector.type(); // (b...)=>c 547 int collectArgCount = collectorType.parameterCount(); 548 Class<?> collectValType = collectorType.returnType(); 549 int collectValCount = (collectValType == void.class ? 0 : 1); 550 MethodType srcType = targetType // (a..., [b...])=>r 551 .dropParameterTypes(collectArgPos, collectArgPos+collectValCount); 552 if (!retainOriginalArgs) { // (a..., b...)=>r 553 srcType = srcType.insertParameterTypes(collectArgPos, collectorType.parameterList()); 554 } 555 // in arglist: [0: ...keep1 | cpos: collect... | cpos+cacount: keep2... ] 556 // out arglist: [0: ...keep1 | cpos: collectVal? | cpos+cvcount: keep2... ] 557 // out(retain): [0: ...keep1 | cpos: cV? coll... | cpos+cvc+cac: keep2... ] 558 559 // Now build a LambdaForm. 560 MethodType lambdaType = srcType.invokerType(); 561 Name[] names = arguments(2, lambdaType); 562 final int collectNamePos = names.length - 2; 563 final int targetNamePos = names.length - 1; 564 565 Name[] collectorArgs = Arrays.copyOfRange(names, 1 + collectArgPos, 1 + collectArgPos + collectArgCount); 566 names[collectNamePos] = new Name(collector, (Object[]) collectorArgs); 567 568 // Build argument array for the target. 569 // Incoming LF args to copy are: [ (mh) headArgs collectArgs tailArgs ]. 570 // Output argument array is [ headArgs (collectVal)? (collectArgs)? tailArgs ]. 571 Name[] targetArgs = new Name[targetType.parameterCount()]; 572 int inputArgPos = 1; // incoming LF args to copy to target 573 int targetArgPos = 0; // fill pointer for targetArgs 574 int chunk = collectArgPos; // |headArgs| 575 System.arraycopy(names, inputArgPos, targetArgs, targetArgPos, chunk); 576 inputArgPos += chunk; 577 targetArgPos += chunk; 578 if (collectValType != void.class) { 579 targetArgs[targetArgPos++] = names[collectNamePos]; 580 } 581 chunk = collectArgCount; 582 if (retainOriginalArgs) { 583 System.arraycopy(names, inputArgPos, targetArgs, targetArgPos, chunk); 584 targetArgPos += chunk; // optionally pass on the collected chunk 585 } 586 inputArgPos += chunk; 587 chunk = targetArgs.length - targetArgPos; // all the rest 588 System.arraycopy(names, inputArgPos, targetArgs, targetArgPos, chunk); 589 assert(inputArgPos + chunk == collectNamePos); // use of rest of input args also 590 names[targetNamePos] = new Name(target, (Object[]) targetArgs); 591 592 LambdaForm form = new LambdaForm("collect", lambdaType.parameterCount(), names); 593 return SimpleMethodHandle.make(srcType, form); 594 } 595 596 @LambdaForm.Hidden 597 static 598 MethodHandle selectAlternative(boolean testResult, MethodHandle target, MethodHandle fallback) { 599 return testResult ? target : fallback; 600 } 601 602 static 603 MethodHandle makeGuardWithTest(MethodHandle test, 604 MethodHandle target, 605 MethodHandle fallback) { 606 MethodType basicType = target.type().basicType(); 607 MethodHandle invokeBasic = MethodHandles.basicInvoker(basicType); 608 int arity = basicType.parameterCount(); 609 int extraNames = 3; 610 MethodType lambdaType = basicType.invokerType(); 611 Name[] names = arguments(extraNames, lambdaType); 612 613 Object[] testArgs = Arrays.copyOfRange(names, 1, 1 + arity, Object[].class); 614 Object[] targetArgs = Arrays.copyOfRange(names, 0, 1 + arity, Object[].class); 615 616 // call test 617 names[arity + 1] = new Name(test, testArgs); 618 619 // call selectAlternative 620 Object[] selectArgs = { names[arity + 1], target, fallback }; 621 names[arity + 2] = new Name(Lazy.NF_selectAlternative, selectArgs); 622 targetArgs[0] = names[arity + 2]; 623 624 // call target or fallback 625 names[arity + 3] = new Name(new NamedFunction(invokeBasic), targetArgs); 626 627 LambdaForm form = new LambdaForm("guard", lambdaType.parameterCount(), names); 628 return SimpleMethodHandle.make(target.type(), form); 629 } 630 631 /** 632 * The LambaForm shape for catchException combinator is the following: 633 * <blockquote><pre>{@code 634 * guardWithCatch=Lambda(a0:L,a1:L,a2:L)=>{ 635 * t3:L=BoundMethodHandle$Species_LLLLL.argL0(a0:L); 636 * t4:L=BoundMethodHandle$Species_LLLLL.argL1(a0:L); 637 * t5:L=BoundMethodHandle$Species_LLLLL.argL2(a0:L); 638 * t6:L=BoundMethodHandle$Species_LLLLL.argL3(a0:L); 639 * t7:L=BoundMethodHandle$Species_LLLLL.argL4(a0:L); 640 * t8:L=MethodHandle.invokeBasic(t6:L,a1:L,a2:L); 641 * t9:L=MethodHandleImpl.guardWithCatch(t3:L,t4:L,t5:L,t8:L); 642 * t10:I=MethodHandle.invokeBasic(t7:L,t9:L);t10:I} 643 * }</pre></blockquote> 644 * 645 * argL0 and argL2 are target and catcher method handles. argL1 is exception class. 646 * argL3 and argL4 are auxiliary method handles: argL3 boxes arguments and wraps them into Object[] 647 * (ValueConversions.array()) and argL4 unboxes result if necessary (ValueConversions.unbox()). 648 * 649 * Having t8 and t10 passed outside and not hardcoded into a lambda form allows to share lambda forms 650 * among catchException combinators with the same basic type. 651 */ 652 private static LambdaForm makeGuardWithCatchForm(MethodType basicType) { 653 MethodType lambdaType = basicType.invokerType(); 654 655 LambdaForm lform = basicType.form().cachedLambdaForm(MethodTypeForm.LF_GWC); 656 if (lform != null) { 657 return lform; 658 } 659 final int THIS_MH = 0; // the BMH_LLLLL 660 final int ARG_BASE = 1; // start of incoming arguments 661 final int ARG_LIMIT = ARG_BASE + basicType.parameterCount(); 662 663 int nameCursor = ARG_LIMIT; 664 final int GET_TARGET = nameCursor++; 665 final int GET_CLASS = nameCursor++; 666 final int GET_CATCHER = nameCursor++; 667 final int GET_COLLECT_ARGS = nameCursor++; 668 final int GET_UNBOX_RESULT = nameCursor++; 669 final int BOXED_ARGS = nameCursor++; 670 final int TRY_CATCH = nameCursor++; 671 final int UNBOX_RESULT = nameCursor++; 672 673 Name[] names = arguments(nameCursor - ARG_LIMIT, lambdaType); 674 675 BoundMethodHandle.SpeciesData data = BoundMethodHandle.speciesData_LLLLL(); 676 names[GET_TARGET] = new Name(data.getterFunction(0), names[THIS_MH]); 677 names[GET_CLASS] = new Name(data.getterFunction(1), names[THIS_MH]); 678 names[GET_CATCHER] = new Name(data.getterFunction(2), names[THIS_MH]); 679 names[GET_COLLECT_ARGS] = new Name(data.getterFunction(3), names[THIS_MH]); 680 names[GET_UNBOX_RESULT] = new Name(data.getterFunction(4), names[THIS_MH]); 681 682 // FIXME: rework argument boxing/result unboxing logic for LF interpretation 683 684 // t_{i}:L=MethodHandle.invokeBasic(collectArgs:L,a1:L,...); 685 MethodType collectArgsType = basicType.changeReturnType(Object.class); 686 MethodHandle invokeBasic = MethodHandles.basicInvoker(collectArgsType); 687 Object[] args = new Object[invokeBasic.type().parameterCount()]; 688 args[0] = names[GET_COLLECT_ARGS]; 689 System.arraycopy(names, ARG_BASE, args, 1, ARG_LIMIT-ARG_BASE); 690 names[BOXED_ARGS] = new Name(new NamedFunction(invokeBasic), args); 691 692 // t_{i+1}:L=MethodHandleImpl.guardWithCatch(target:L,exType:L,catcher:L,t_{i}:L); 693 Object[] gwcArgs = new Object[] {names[GET_TARGET], names[GET_CLASS], names[GET_CATCHER], names[BOXED_ARGS]}; 694 names[TRY_CATCH] = new Name(Lazy.NF_guardWithCatch, gwcArgs); 695 696 // t_{i+2}:I=MethodHandle.invokeBasic(unbox:L,t_{i+1}:L); 697 MethodHandle invokeBasicUnbox = MethodHandles.basicInvoker(MethodType.methodType(basicType.rtype(), Object.class)); 698 Object[] unboxArgs = new Object[] {names[GET_UNBOX_RESULT], names[TRY_CATCH]}; 699 names[UNBOX_RESULT] = new Name(new NamedFunction(invokeBasicUnbox), unboxArgs); 700 701 lform = new LambdaForm("guardWithCatch", lambdaType.parameterCount(), names); 702 703 return basicType.form().setCachedLambdaForm(MethodTypeForm.LF_GWC, lform); 704 } 705 706 static 707 MethodHandle makeGuardWithCatch(MethodHandle target, 708 Class<? extends Throwable> exType, 709 MethodHandle catcher) { 710 MethodType type = target.type(); 711 LambdaForm form = makeGuardWithCatchForm(type.basicType()); 712 713 // Prepare auxiliary method handles used during LambdaForm interpreation. 714 // Box arguments and wrap them into Object[]: ValueConversions.array(). 715 MethodType varargsType = type.changeReturnType(Object[].class); 716 MethodHandle collectArgs = ValueConversions.varargsArray(type.parameterCount()) 717 .asType(varargsType); 718 // Result unboxing: ValueConversions.unbox() OR ValueConversions.identity() OR ValueConversions.ignore(). 719 MethodHandle unboxResult; 720 if (type.returnType().isPrimitive()) { 721 unboxResult = ValueConversions.unbox(type.returnType()); 722 } else { 723 unboxResult = ValueConversions.identity(); 724 } 725 726 BoundMethodHandle.SpeciesData data = BoundMethodHandle.speciesData_LLLLL(); 727 BoundMethodHandle mh; 728 try { 729 mh = (BoundMethodHandle) 730 data.constructor[0].invokeBasic(type, form, (Object) target, (Object) exType, (Object) catcher, 731 (Object) collectArgs, (Object) unboxResult); 732 } catch (Throwable ex) { 733 throw uncaughtException(ex); 734 } 735 assert(mh.type() == type); 736 return mh; 737 } 738 739 /** 740 * Intrinsified during LambdaForm compilation 741 * (see {@link InvokerBytecodeGenerator#emitGuardWithCatch emitGuardWithCatch}). 742 */ 743 @LambdaForm.Hidden 744 static Object guardWithCatch(MethodHandle target, Class<? extends Throwable> exType, MethodHandle catcher, 745 Object... av) throws Throwable { 746 // Use asFixedArity() to avoid unnecessary boxing of last argument for VarargsCollector case. 747 try { 748 return target.asFixedArity().invokeWithArguments(av); 749 } catch (Throwable t) { 750 if (!exType.isInstance(t)) throw t; 751 return catcher.asFixedArity().invokeWithArguments(prepend(t, av)); 752 } 753 } 754 755 /** Prepend an element {@code elem} to an {@code array}. */ 756 @LambdaForm.Hidden 757 private static Object[] prepend(Object elem, Object[] array) { 758 Object[] newArray = new Object[array.length+1]; 759 newArray[0] = elem; 760 System.arraycopy(array, 0, newArray, 1, array.length); 761 return newArray; 762 } 763 764 static 765 MethodHandle throwException(MethodType type) { 766 assert(Throwable.class.isAssignableFrom(type.parameterType(0))); 767 int arity = type.parameterCount(); 768 if (arity > 1) { 769 return throwException(type.dropParameterTypes(1, arity)).dropArguments(type, 1, arity-1); 770 } 771 return makePairwiseConvert(Lazy.NF_throwException.resolvedHandle(), type, 2); 772 } 773 774 static <T extends Throwable> Empty throwException(T t) throws T { throw t; } 775 776 static MethodHandle[] FAKE_METHOD_HANDLE_INVOKE = new MethodHandle[2]; 777 static MethodHandle fakeMethodHandleInvoke(MemberName method) { 778 int idx; 779 assert(method.isMethodHandleInvoke()); 780 switch (method.getName()) { 781 case "invoke": idx = 0; break; 782 case "invokeExact": idx = 1; break; 783 default: throw new InternalError(method.getName()); 784 } 785 MethodHandle mh = FAKE_METHOD_HANDLE_INVOKE[idx]; 786 if (mh != null) return mh; 787 MethodType type = MethodType.methodType(Object.class, UnsupportedOperationException.class, 788 MethodHandle.class, Object[].class); 789 mh = throwException(type); 790 mh = mh.bindTo(new UnsupportedOperationException("cannot reflectively invoke MethodHandle")); 791 if (!method.getInvocationType().equals(mh.type())) 792 throw new InternalError(method.toString()); 793 mh = mh.withInternalMemberName(method); 794 mh = mh.asVarargsCollector(Object[].class); 795 assert(method.isVarargs()); 796 FAKE_METHOD_HANDLE_INVOKE[idx] = mh; 797 return mh; 798 } 799 800 /** 801 * Create an alias for the method handle which, when called, 802 * appears to be called from the same class loader and protection domain 803 * as hostClass. 804 * This is an expensive no-op unless the method which is called 805 * is sensitive to its caller. A small number of system methods 806 * are in this category, including Class.forName and Method.invoke. 807 */ 808 static 809 MethodHandle bindCaller(MethodHandle mh, Class<?> hostClass) { 810 return BindCaller.bindCaller(mh, hostClass); 811 } 812 813 // Put the whole mess into its own nested class. 814 // That way we can lazily load the code and set up the constants. 815 private static class BindCaller { 816 static 817 MethodHandle bindCaller(MethodHandle mh, Class<?> hostClass) { 818 // Do not use this function to inject calls into system classes. 819 if (hostClass == null 820 || (hostClass.isArray() || 821 hostClass.isPrimitive() || 822 hostClass.getName().startsWith("java.") || 823 hostClass.getName().startsWith("sun."))) { 824 throw new InternalError(); // does not happen, and should not anyway 825 } 826 // For simplicity, convert mh to a varargs-like method. 827 MethodHandle vamh = prepareForInvoker(mh); 828 // Cache the result of makeInjectedInvoker once per argument class. 829 MethodHandle bccInvoker = CV_makeInjectedInvoker.get(hostClass); 830 return restoreToType(bccInvoker.bindTo(vamh), mh.type(), mh.internalMemberName(), hostClass); 831 } 832 833 private static MethodHandle makeInjectedInvoker(Class<?> hostClass) { 834 Class<?> bcc = UNSAFE.defineAnonymousClass(hostClass, T_BYTES, null); 835 if (hostClass.getClassLoader() != bcc.getClassLoader()) 836 throw new InternalError(hostClass.getName()+" (CL)"); 837 try { 838 if (hostClass.getProtectionDomain() != bcc.getProtectionDomain()) 839 throw new InternalError(hostClass.getName()+" (PD)"); 840 } catch (SecurityException ex) { 841 // Self-check was blocked by security manager. This is OK. 842 // In fact the whole try body could be turned into an assertion. 843 } 844 try { 845 MethodHandle init = IMPL_LOOKUP.findStatic(bcc, "init", MethodType.methodType(void.class)); 846 init.invokeExact(); // force initialization of the class 847 } catch (Throwable ex) { 848 throw uncaughtException(ex); 849 } 850 MethodHandle bccInvoker; 851 try { 852 MethodType invokerMT = MethodType.methodType(Object.class, MethodHandle.class, Object[].class); 853 bccInvoker = IMPL_LOOKUP.findStatic(bcc, "invoke_V", invokerMT); 854 } catch (ReflectiveOperationException ex) { 855 throw uncaughtException(ex); 856 } 857 // Test the invoker, to ensure that it really injects into the right place. 858 try { 859 MethodHandle vamh = prepareForInvoker(MH_checkCallerClass); 860 Object ok = bccInvoker.invokeExact(vamh, new Object[]{hostClass, bcc}); 861 } catch (Throwable ex) { 862 throw new InternalError(ex); 863 } 864 return bccInvoker; 865 } 866 private static ClassValue<MethodHandle> CV_makeInjectedInvoker = new ClassValue<MethodHandle>() { 867 @Override protected MethodHandle computeValue(Class<?> hostClass) { 868 return makeInjectedInvoker(hostClass); 869 } 870 }; 871 872 // Adapt mh so that it can be called directly from an injected invoker: 873 private static MethodHandle prepareForInvoker(MethodHandle mh) { 874 mh = mh.asFixedArity(); 875 MethodType mt = mh.type(); 876 int arity = mt.parameterCount(); 877 MethodHandle vamh = mh.asType(mt.generic()); 878 vamh.internalForm().compileToBytecode(); // eliminate LFI stack frames 879 vamh = vamh.asSpreader(Object[].class, arity); 880 vamh.internalForm().compileToBytecode(); // eliminate LFI stack frames 881 return vamh; 882 } 883 884 // Undo the adapter effect of prepareForInvoker: 885 private static MethodHandle restoreToType(MethodHandle vamh, MethodType type, 886 MemberName member, 887 Class<?> hostClass) { 888 MethodHandle mh = vamh.asCollector(Object[].class, type.parameterCount()); 889 mh = mh.asType(type); 890 mh = new WrappedMember(mh, type, member, hostClass); 891 return mh; 892 } 893 894 private static final MethodHandle MH_checkCallerClass; 895 static { 896 final Class<?> THIS_CLASS = BindCaller.class; 897 assert(checkCallerClass(THIS_CLASS, THIS_CLASS)); 898 try { 899 MH_checkCallerClass = IMPL_LOOKUP 900 .findStatic(THIS_CLASS, "checkCallerClass", 901 MethodType.methodType(boolean.class, Class.class, Class.class)); 902 assert((boolean) MH_checkCallerClass.invokeExact(THIS_CLASS, THIS_CLASS)); 903 } catch (Throwable ex) { 904 throw new InternalError(ex); 905 } 906 } 907 908 @CallerSensitive 909 private static boolean checkCallerClass(Class<?> expected, Class<?> expected2) { 910 // This method is called via MH_checkCallerClass and so it's 911 // correct to ask for the immediate caller here. 912 Class<?> actual = Reflection.getCallerClass(); 913 if (actual != expected && actual != expected2) 914 throw new InternalError("found "+actual.getName()+", expected "+expected.getName() 915 +(expected == expected2 ? "" : ", or else "+expected2.getName())); 916 return true; 917 } 918 919 private static final byte[] T_BYTES; 920 static { 921 final Object[] values = {null}; 922 AccessController.doPrivileged(new PrivilegedAction<Void>() { 923 public Void run() { 924 try { 925 Class<T> tClass = T.class; 926 String tName = tClass.getName(); 927 String tResource = tName.substring(tName.lastIndexOf('.')+1)+".class"; 928 java.net.URLConnection uconn = tClass.getResource(tResource).openConnection(); 929 int len = uconn.getContentLength(); 930 byte[] bytes = new byte[len]; 931 try (java.io.InputStream str = uconn.getInputStream()) { 932 int nr = str.read(bytes); 933 if (nr != len) throw new java.io.IOException(tResource); 934 } 935 values[0] = bytes; 936 } catch (java.io.IOException ex) { 937 throw new InternalError(ex); 938 } 939 return null; 940 } 941 }); 942 T_BYTES = (byte[]) values[0]; 943 } 944 945 // The following class is used as a template for Unsafe.defineAnonymousClass: 946 private static class T { 947 static void init() { } // side effect: initializes this class 948 static Object invoke_V(MethodHandle vamh, Object[] args) throws Throwable { 949 return vamh.invokeExact(args); 950 } 951 } 952 } 953 954 955 /** This subclass allows a wrapped method handle to be re-associated with an arbitrary member name. */ 956 static class WrappedMember extends MethodHandle { 957 private final MethodHandle target; 958 private final MemberName member; 959 private final Class<?> callerClass; 960 961 private WrappedMember(MethodHandle target, MethodType type, MemberName member, Class<?> callerClass) { 962 super(type, reinvokerForm(target)); 963 this.target = target; 964 this.member = member; 965 this.callerClass = callerClass; 966 } 967 968 @Override 969 MethodHandle reinvokerTarget() { 970 return target; 971 } 972 @Override 973 public MethodHandle asTypeUncached(MethodType newType) { 974 // This MH is an alias for target, except for the MemberName 975 // Drop the MemberName if there is any conversion. 976 return asTypeCache = target.asType(newType); 977 } 978 @Override 979 MemberName internalMemberName() { 980 return member; 981 } 982 @Override 983 Class<?> internalCallerClass() { 984 return callerClass; 985 } 986 @Override 987 boolean isInvokeSpecial() { 988 return target.isInvokeSpecial(); 989 } 990 @Override 991 MethodHandle viewAsType(MethodType newType) { 992 return new WrappedMember(target, newType, member, callerClass); 993 } 994 } 995 996 static MethodHandle makeWrappedMember(MethodHandle target, MemberName member) { 997 if (member.equals(target.internalMemberName())) 998 return target; 999 return new WrappedMember(target, target.type(), member, null); 1000 } 1001 1002 }