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