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.ArrayList; 31 import java.util.Arrays; 32 import java.util.Collections; 33 34 import sun.invoke.empty.Empty; 35 import sun.invoke.util.ValueConversions; 36 import sun.invoke.util.VerifyType; 37 import sun.invoke.util.Wrapper; 38 import sun.reflect.CallerSensitive; 39 import sun.reflect.Reflection; 40 import static java.lang.invoke.LambdaForm.*; 41 import static java.lang.invoke.MethodHandleStatics.*; 42 import static java.lang.invoke.MethodHandles.Lookup.IMPL_LOOKUP; 43 44 /** 45 * Trusted implementation code for MethodHandle. 46 * @author jrose 47 */ 48 /*non-public*/ abstract class MethodHandleImpl { 49 // Do not adjust this except for special platforms: 50 private static final int MAX_ARITY; 51 static { 52 final Object[] values = { 255 }; 53 AccessController.doPrivileged(new PrivilegedAction<Void>() { 54 @Override 55 public Void run() { 56 values[0] = Integer.getInteger(MethodHandleImpl.class.getName()+".MAX_ARITY", 255); 57 return null; 58 } 59 }); 60 MAX_ARITY = (Integer) values[0]; 61 } 62 63 /// Factory methods to create method handles: 64 65 static void initStatics() { 66 // Trigger selected static initializations. 67 MemberName.Factory.INSTANCE.getClass(); 68 } 69 70 static MethodHandle makeArrayElementAccessor(Class<?> arrayClass, boolean isSetter) { 71 if (arrayClass == Object[].class) 72 return (isSetter ? ArrayAccessor.OBJECT_ARRAY_SETTER : ArrayAccessor.OBJECT_ARRAY_GETTER); 73 if (!arrayClass.isArray()) 74 throw newIllegalArgumentException("not an array: "+arrayClass); 75 MethodHandle[] cache = ArrayAccessor.TYPED_ACCESSORS.get(arrayClass); 76 int cacheIndex = (isSetter ? ArrayAccessor.SETTER_INDEX : ArrayAccessor.GETTER_INDEX); 77 MethodHandle mh = cache[cacheIndex]; 78 if (mh != null) return mh; 79 mh = ArrayAccessor.getAccessor(arrayClass, isSetter); 80 MethodType correctType = ArrayAccessor.correctType(arrayClass, isSetter); 81 if (mh.type() != correctType) { 82 assert(mh.type().parameterType(0) == Object[].class); 83 assert((isSetter ? mh.type().parameterType(2) : mh.type().returnType()) == Object.class); 84 assert(isSetter || correctType.parameterType(0).getComponentType() == correctType.returnType()); 85 // safe to view non-strictly, because element type follows from array type 86 mh = mh.viewAsType(correctType, false); 87 } 88 mh = makeIntrinsic(mh, (isSetter ? Intrinsic.ARRAY_STORE : Intrinsic.ARRAY_LOAD)); 89 // Atomically update accessor cache. 90 synchronized(cache) { 91 if (cache[cacheIndex] == null) { 92 cache[cacheIndex] = mh; 93 } else { 94 // Throw away newly constructed accessor and use cached version. 95 mh = cache[cacheIndex]; 96 } 97 } 98 return mh; 99 } 100 101 static final class ArrayAccessor { 102 /// Support for array element access 103 static final int GETTER_INDEX = 0, SETTER_INDEX = 1, INDEX_LIMIT = 2; 104 static final ClassValue<MethodHandle[]> TYPED_ACCESSORS 105 = new ClassValue<MethodHandle[]>() { 106 @Override 107 protected MethodHandle[] computeValue(Class<?> type) { 108 return new MethodHandle[INDEX_LIMIT]; 109 } 110 }; 111 static final MethodHandle OBJECT_ARRAY_GETTER, OBJECT_ARRAY_SETTER; 112 static { 113 MethodHandle[] cache = TYPED_ACCESSORS.get(Object[].class); 114 cache[GETTER_INDEX] = OBJECT_ARRAY_GETTER = makeIntrinsic(getAccessor(Object[].class, false), Intrinsic.ARRAY_LOAD); 115 cache[SETTER_INDEX] = OBJECT_ARRAY_SETTER = makeIntrinsic(getAccessor(Object[].class, true), Intrinsic.ARRAY_STORE); 116 117 assert(InvokerBytecodeGenerator.isStaticallyInvocable(ArrayAccessor.OBJECT_ARRAY_GETTER.internalMemberName())); 118 assert(InvokerBytecodeGenerator.isStaticallyInvocable(ArrayAccessor.OBJECT_ARRAY_SETTER.internalMemberName())); 119 } 120 121 static int getElementI(int[] a, int i) { return a[i]; } 122 static long getElementJ(long[] a, int i) { return a[i]; } 123 static float getElementF(float[] a, int i) { return a[i]; } 124 static double getElementD(double[] a, int i) { return a[i]; } 125 static boolean getElementZ(boolean[] a, int i) { return a[i]; } 126 static byte getElementB(byte[] a, int i) { return a[i]; } 127 static short getElementS(short[] a, int i) { return a[i]; } 128 static char getElementC(char[] a, int i) { return a[i]; } 129 static Object getElementL(Object[] a, int i) { return a[i]; } 130 131 static void setElementI(int[] a, int i, int x) { a[i] = x; } 132 static void setElementJ(long[] a, int i, long x) { a[i] = x; } 133 static void setElementF(float[] a, int i, float x) { a[i] = x; } 134 static void setElementD(double[] a, int i, double x) { a[i] = x; } 135 static void setElementZ(boolean[] a, int i, boolean x) { a[i] = x; } 136 static void setElementB(byte[] a, int i, byte x) { a[i] = x; } 137 static void setElementS(short[] a, int i, short x) { a[i] = x; } 138 static void setElementC(char[] a, int i, char x) { a[i] = x; } 139 static void setElementL(Object[] a, int i, Object x) { a[i] = x; } 140 141 static String name(Class<?> arrayClass, boolean isSetter) { 142 Class<?> elemClass = arrayClass.getComponentType(); 143 if (elemClass == null) throw newIllegalArgumentException("not an array", arrayClass); 144 return (!isSetter ? "getElement" : "setElement") + Wrapper.basicTypeChar(elemClass); 145 } 146 static MethodType type(Class<?> arrayClass, boolean isSetter) { 147 Class<?> elemClass = arrayClass.getComponentType(); 148 Class<?> arrayArgClass = arrayClass; 149 if (!elemClass.isPrimitive()) { 150 arrayArgClass = Object[].class; 151 elemClass = Object.class; 152 } 153 return !isSetter ? 154 MethodType.methodType(elemClass, arrayArgClass, int.class) : 155 MethodType.methodType(void.class, arrayArgClass, int.class, elemClass); 156 } 157 static MethodType correctType(Class<?> arrayClass, boolean isSetter) { 158 Class<?> elemClass = arrayClass.getComponentType(); 159 return !isSetter ? 160 MethodType.methodType(elemClass, arrayClass, int.class) : 161 MethodType.methodType(void.class, arrayClass, int.class, elemClass); 162 } 163 static MethodHandle getAccessor(Class<?> arrayClass, boolean isSetter) { 164 String name = name(arrayClass, isSetter); 165 MethodType type = type(arrayClass, isSetter); 166 try { 167 return IMPL_LOOKUP.findStatic(ArrayAccessor.class, name, type); 168 } catch (ReflectiveOperationException ex) { 169 throw uncaughtException(ex); 170 } 171 } 172 } 173 174 /** 175 * Create a JVM-level adapter method handle to conform the given method 176 * handle to the similar newType, using only pairwise argument conversions. 177 * For each argument, convert incoming argument to the exact type needed. 178 * The argument conversions allowed are casting, boxing and unboxing, 179 * integral widening or narrowing, and floating point widening or narrowing. 180 * @param srcType required call type 181 * @param target original method handle 182 * @param strict if true, only asType conversions are allowed; if false, explicitCastArguments conversions allowed 183 * @param monobox if true, unboxing conversions are assumed to be exactly typed (Integer to int only, not long or double) 184 * @return an adapter to the original handle with the desired new type, 185 * or the original target if the types are already identical 186 * or null if the adaptation cannot be made 187 */ 188 static MethodHandle makePairwiseConvert(MethodHandle target, MethodType srcType, 189 boolean strict, boolean monobox) { 190 MethodType dstType = target.type(); 191 if (srcType == dstType) 192 return target; 193 if (USE_LAMBDA_FORM_EDITOR) { 194 return makePairwiseConvertByEditor(target, srcType, strict, monobox); 195 } else { 196 return makePairwiseConvertIndirect(target, srcType, strict, monobox); 197 } 198 } 199 200 private static int countNonNull(Object[] array) { 201 int count = 0; 202 for (Object x : array) { 203 if (x != null) ++count; 204 } 205 return count; 206 } 207 208 static MethodHandle makePairwiseConvertByEditor(MethodHandle target, MethodType srcType, 209 boolean strict, boolean monobox) { 210 Object[] convSpecs = computeValueConversions(srcType, target.type(), strict, monobox); 211 int convCount = countNonNull(convSpecs); 212 if (convCount == 0) 213 return target.viewAsType(srcType, strict); 214 MethodType basicSrcType = srcType.basicType(); 215 MethodType midType = target.type().basicType(); 216 BoundMethodHandle mh = target.rebind(); 217 // FIXME: Reduce number of bindings when there is more than one Class conversion. 218 // FIXME: Reduce number of bindings when there are repeated conversions. 219 for (int i = 0; i < convSpecs.length-1; i++) { 220 Object convSpec = convSpecs[i]; 221 if (convSpec == null) continue; 222 MethodHandle fn; 223 if (convSpec instanceof Class) { 224 fn = Lazy.MH_castReference.bindTo(convSpec); 225 } else { 226 fn = (MethodHandle) convSpec; 227 } 228 Class<?> newType = basicSrcType.parameterType(i); 229 if (--convCount == 0) 230 midType = srcType; 231 else 232 midType = midType.changeParameterType(i, newType); 233 LambdaForm form2 = mh.editor().filterArgumentForm(1+i, BasicType.basicType(newType)); 234 mh = mh.copyWithExtendL(midType, form2, fn); 235 mh = mh.rebind(); 236 } 237 Object convSpec = convSpecs[convSpecs.length-1]; 238 if (convSpec != null) { 239 MethodHandle fn; 240 if (convSpec instanceof Class) { 241 if (convSpec == void.class) 242 fn = null; 243 else 244 fn = Lazy.MH_castReference.bindTo(convSpec); 245 } else { 246 fn = (MethodHandle) convSpec; 247 } 248 Class<?> newType = basicSrcType.returnType(); 249 assert(--convCount == 0); 250 midType = srcType; 251 if (fn != null) { 252 mh = mh.rebind(); // rebind if too complex 253 LambdaForm form2 = mh.editor().filterReturnForm(BasicType.basicType(newType), false); 254 mh = mh.copyWithExtendL(midType, form2, fn); 255 } else { 256 LambdaForm form2 = mh.editor().filterReturnForm(BasicType.basicType(newType), true); 257 mh = mh.copyWith(midType, form2); 258 } 259 } 260 assert(convCount == 0); 261 assert(mh.type().equals(srcType)); 262 return mh; 263 } 264 265 static MethodHandle makePairwiseConvertIndirect(MethodHandle target, MethodType srcType, 266 boolean strict, boolean monobox) { 267 assert(target.type().parameterCount() == srcType.parameterCount()); 268 // Calculate extra arguments (temporaries) required in the names array. 269 Object[] convSpecs = computeValueConversions(srcType, target.type(), strict, monobox); 270 final int INARG_COUNT = srcType.parameterCount(); 271 int convCount = countNonNull(convSpecs); 272 boolean retConv = (convSpecs[INARG_COUNT] != null); 273 boolean retVoid = srcType.returnType() == void.class; 274 if (retConv && retVoid) { 275 convCount -= 1; 276 retConv = false; 277 } 278 279 final int IN_MH = 0; 280 final int INARG_BASE = 1; 281 final int INARG_LIMIT = INARG_BASE + INARG_COUNT; 282 final int NAME_LIMIT = INARG_LIMIT + convCount + 1; 283 final int RETURN_CONV = (!retConv ? -1 : NAME_LIMIT - 1); 284 final int OUT_CALL = (!retConv ? NAME_LIMIT : RETURN_CONV) - 1; 285 final int RESULT = (retVoid ? -1 : NAME_LIMIT - 1); 286 287 // Now build a LambdaForm. 288 MethodType lambdaType = srcType.basicType().invokerType(); 289 Name[] names = arguments(NAME_LIMIT - INARG_LIMIT, lambdaType); 290 291 // Collect the arguments to the outgoing call, maybe with conversions: 292 final int OUTARG_BASE = 0; // target MH is Name.function, name Name.arguments[0] 293 Object[] outArgs = new Object[OUTARG_BASE + INARG_COUNT]; 294 295 int nameCursor = INARG_LIMIT; 296 for (int i = 0; i < INARG_COUNT; i++) { 297 Object convSpec = convSpecs[i]; 298 if (convSpec == null) { 299 // do nothing: difference is trivial 300 outArgs[OUTARG_BASE + i] = names[INARG_BASE + i]; 301 continue; 302 } 303 304 Name conv; 305 if (convSpec instanceof Class) { 306 Class<?> convClass = (Class<?>) convSpec; 307 conv = new Name(Lazy.MH_castReference, convClass, names[INARG_BASE + i]); 308 } else { 309 MethodHandle fn = (MethodHandle) convSpec; 310 conv = new Name(fn, names[INARG_BASE + i]); 311 } 312 assert(names[nameCursor] == null); 313 names[nameCursor++] = conv; 314 assert(outArgs[OUTARG_BASE + i] == null); 315 outArgs[OUTARG_BASE + i] = conv; 316 } 317 318 // Build argument array for the call. 319 assert(nameCursor == OUT_CALL); 320 names[OUT_CALL] = new Name(target, outArgs); 321 322 Object convSpec = convSpecs[INARG_COUNT]; 323 if (!retConv) { 324 assert(OUT_CALL == names.length-1); 325 } else { 326 Name conv; 327 if (convSpec == void.class) { 328 conv = new Name(LambdaForm.constantZero(BasicType.basicType(srcType.returnType()))); 329 } else if (convSpec instanceof Class) { 330 Class<?> convClass = (Class<?>) convSpec; 331 conv = new Name(Lazy.MH_castReference, convClass, names[OUT_CALL]); 332 } else { 333 MethodHandle fn = (MethodHandle) convSpec; 334 if (fn.type().parameterCount() == 0) 335 conv = new Name(fn); // don't pass retval to void conversion 336 else 337 conv = new Name(fn, names[OUT_CALL]); 338 } 339 assert(names[RETURN_CONV] == null); 340 names[RETURN_CONV] = conv; 341 assert(RETURN_CONV == names.length-1); 342 } 343 344 LambdaForm form = new LambdaForm("convert", lambdaType.parameterCount(), names, RESULT); 345 return SimpleMethodHandle.make(srcType, form); 346 } 347 348 /** 349 * Identity function, with reference cast. 350 * @param t an arbitrary reference type 351 * @param x an arbitrary reference value 352 * @return the same value x 353 */ 354 @ForceInline 355 @SuppressWarnings("unchecked") 356 static <T,U> T castReference(Class<? extends T> t, U x) { 357 // inlined Class.cast because we can't ForceInline it 358 if (x != null && !t.isInstance(x)) 359 throw newClassCastException(t, x); 360 return (T) x; 361 } 362 363 private static ClassCastException newClassCastException(Class<?> t, Object obj) { 364 return new ClassCastException("Cannot cast " + obj.getClass().getName() + " to " + t.getName()); 365 } 366 367 static Object[] computeValueConversions(MethodType srcType, MethodType dstType, 368 boolean strict, boolean monobox) { 369 final int INARG_COUNT = srcType.parameterCount(); 370 Object[] convSpecs = new Object[INARG_COUNT+1]; 371 for (int i = 0; i <= INARG_COUNT; i++) { 372 boolean isRet = (i == INARG_COUNT); 373 Class<?> src = isRet ? dstType.returnType() : srcType.parameterType(i); 374 Class<?> dst = isRet ? srcType.returnType() : dstType.parameterType(i); 375 if (!VerifyType.isNullConversion(src, dst, /*keepInterfaces=*/ strict)) { 376 convSpecs[i] = valueConversion(src, dst, strict, monobox); 377 } 378 } 379 return convSpecs; 380 } 381 static MethodHandle makePairwiseConvert(MethodHandle target, MethodType srcType, 382 boolean strict) { 383 return makePairwiseConvert(target, srcType, strict, /*monobox=*/ false); 384 } 385 386 /** 387 * Find a conversion function from the given source to the given destination. 388 * This conversion function will be used as a LF NamedFunction. 389 * Return a Class object if a simple cast is needed. 390 * Return void.class if void is involved. 391 */ 392 static Object valueConversion(Class<?> src, Class<?> dst, boolean strict, boolean monobox) { 393 assert(!VerifyType.isNullConversion(src, dst, /*keepInterfaces=*/ strict)); // caller responsibility 394 if (dst == void.class) 395 return dst; 396 MethodHandle fn; 397 if (src.isPrimitive()) { 398 if (src == void.class) { 399 return void.class; // caller must recognize this specially 400 } else if (dst.isPrimitive()) { 401 // Examples: int->byte, byte->int, boolean->int (!strict) 402 fn = ValueConversions.convertPrimitive(src, dst); 403 } else { 404 // Examples: int->Integer, boolean->Object, float->Number 405 Wrapper wsrc = Wrapper.forPrimitiveType(src); 406 fn = ValueConversions.boxExact(wsrc); 407 assert(fn.type().parameterType(0) == wsrc.primitiveType()); 408 assert(fn.type().returnType() == wsrc.wrapperType()); 409 if (!VerifyType.isNullConversion(wsrc.wrapperType(), dst, strict)) { 410 // Corner case, such as int->Long, which will probably fail. 411 MethodType mt = MethodType.methodType(dst, src); 412 if (strict) 413 fn = fn.asType(mt); 414 else 415 fn = MethodHandleImpl.makePairwiseConvert(fn, mt, /*strict=*/ false); 416 } 417 } 418 } else if (dst.isPrimitive()) { 419 Wrapper wdst = Wrapper.forPrimitiveType(dst); 420 if (monobox || src == wdst.wrapperType()) { 421 // Use a strongly-typed unboxer, if possible. 422 fn = ValueConversions.unboxExact(wdst, strict); 423 } else { 424 // Examples: Object->int, Number->int, Comparable->int, Byte->int 425 // must include additional conversions 426 // src must be examined at runtime, to detect Byte, Character, etc. 427 fn = (strict 428 ? ValueConversions.unboxWiden(wdst) 429 : ValueConversions.unboxCast(wdst)); 430 } 431 } else { 432 // Simple reference conversion. 433 // Note: Do not check for a class hierarchy relation 434 // between src and dst. In all cases a 'null' argument 435 // will pass the cast conversion. 436 return dst; 437 } 438 assert(fn.type().parameterCount() <= 1) : "pc"+Arrays.asList(src.getSimpleName(), dst.getSimpleName(), fn); 439 return fn; 440 } 441 442 static MethodHandle makeVarargsCollector(MethodHandle target, Class<?> arrayType) { 443 MethodType type = target.type(); 444 int last = type.parameterCount() - 1; 445 if (type.parameterType(last) != arrayType) 446 target = target.asType(type.changeParameterType(last, arrayType)); 447 target = target.asFixedArity(); // make sure this attribute is turned off 448 return new AsVarargsCollector(target, arrayType); 449 } 450 451 private static final class AsVarargsCollector extends DelegatingMethodHandle { 452 private final MethodHandle target; 453 private final Class<?> arrayType; 454 private @Stable MethodHandle asCollectorCache; 455 456 AsVarargsCollector(MethodHandle target, Class<?> arrayType) { 457 this(target.type(), target, arrayType); 458 } 459 AsVarargsCollector(MethodType type, MethodHandle target, Class<?> arrayType) { 460 super(type, target); 461 this.target = target; 462 this.arrayType = arrayType; 463 this.asCollectorCache = target.asCollector(arrayType, 0); 464 } 465 466 @Override 467 public boolean isVarargsCollector() { 468 return true; 469 } 470 471 @Override 472 protected MethodHandle getTarget() { 473 return target; 474 } 475 476 @Override 477 public MethodHandle asFixedArity() { 478 return target; 479 } 480 481 @Override 482 MethodHandle setVarargs(MemberName member) { 483 if (member.isVarargs()) return this; 484 return asFixedArity(); 485 } 486 487 @Override 488 public MethodHandle asTypeUncached(MethodType newType) { 489 MethodType type = this.type(); 490 int collectArg = type.parameterCount() - 1; 491 int newArity = newType.parameterCount(); 492 if (newArity == collectArg+1 && 493 type.parameterType(collectArg).isAssignableFrom(newType.parameterType(collectArg))) { 494 // if arity and trailing parameter are compatible, do normal thing 495 return asTypeCache = asFixedArity().asType(newType); 496 } 497 // check cache 498 MethodHandle acc = asCollectorCache; 499 if (acc != null && acc.type().parameterCount() == newArity) 500 return asTypeCache = acc.asType(newType); 501 // build and cache a collector 502 int arrayLength = newArity - collectArg; 503 MethodHandle collector; 504 try { 505 collector = asFixedArity().asCollector(arrayType, arrayLength); 506 assert(collector.type().parameterCount() == newArity) : "newArity="+newArity+" but collector="+collector; 507 } catch (IllegalArgumentException ex) { 508 throw new WrongMethodTypeException("cannot build collector", ex); 509 } 510 asCollectorCache = collector; 511 return asTypeCache = collector.asType(newType); 512 } 513 514 @Override 515 boolean viewAsTypeChecks(MethodType newType, boolean strict) { 516 super.viewAsTypeChecks(newType, true); 517 if (strict) return true; 518 // extra assertion for non-strict checks: 519 assert (type().lastParameterType().getComponentType() 520 .isAssignableFrom( 521 newType.lastParameterType().getComponentType())) 522 : Arrays.asList(this, newType); 523 return true; 524 } 525 } 526 527 /** Factory method: Spread selected argument. */ 528 static MethodHandle makeSpreadArguments(MethodHandle target, 529 Class<?> spreadArgType, int spreadArgPos, int spreadArgCount) { 530 MethodType targetType = target.type(); 531 532 for (int i = 0; i < spreadArgCount; i++) { 533 Class<?> arg = VerifyType.spreadArgElementType(spreadArgType, i); 534 if (arg == null) arg = Object.class; 535 targetType = targetType.changeParameterType(spreadArgPos + i, arg); 536 } 537 target = target.asType(targetType); 538 539 MethodType srcType = targetType 540 .replaceParameterTypes(spreadArgPos, spreadArgPos + spreadArgCount, spreadArgType); 541 // Now build a LambdaForm. 542 MethodType lambdaType = srcType.invokerType(); 543 Name[] names = arguments(spreadArgCount + 2, lambdaType); 544 int nameCursor = lambdaType.parameterCount(); 545 int[] indexes = new int[targetType.parameterCount()]; 546 547 for (int i = 0, argIndex = 1; i < targetType.parameterCount() + 1; i++, argIndex++) { 548 Class<?> src = lambdaType.parameterType(i); 549 if (i == spreadArgPos) { 550 // Spread the array. 551 MethodHandle aload = MethodHandles.arrayElementGetter(spreadArgType); 552 Name array = names[argIndex]; 553 names[nameCursor++] = new Name(Lazy.NF_checkSpreadArgument, array, spreadArgCount); 554 for (int j = 0; j < spreadArgCount; i++, j++) { 555 indexes[i] = nameCursor; 556 names[nameCursor++] = new Name(aload, array, j); 557 } 558 } else if (i < indexes.length) { 559 indexes[i] = argIndex; 560 } 561 } 562 assert(nameCursor == names.length-1); // leave room for the final call 563 564 // Build argument array for the call. 565 Name[] targetArgs = new Name[targetType.parameterCount()]; 566 for (int i = 0; i < targetType.parameterCount(); i++) { 567 int idx = indexes[i]; 568 targetArgs[i] = names[idx]; 569 } 570 names[names.length - 1] = new Name(target, (Object[]) targetArgs); 571 572 LambdaForm form = new LambdaForm("spread", lambdaType.parameterCount(), names); 573 return SimpleMethodHandle.make(srcType, form); 574 } 575 576 static void checkSpreadArgument(Object av, int n) { 577 if (av == null) { 578 if (n == 0) return; 579 } else if (av instanceof Object[]) { 580 int len = ((Object[])av).length; 581 if (len == n) return; 582 } else { 583 int len = java.lang.reflect.Array.getLength(av); 584 if (len == n) return; 585 } 586 // fall through to error: 587 throw newIllegalArgumentException("array is not of length "+n); 588 } 589 590 /** 591 * Pre-initialized NamedFunctions for bootstrapping purposes. 592 * Factored in an inner class to delay initialization until first usage. 593 */ 594 static class Lazy { 595 private static final Class<?> MHI = MethodHandleImpl.class; 596 597 static final NamedFunction NF_checkSpreadArgument; 598 static final NamedFunction NF_guardWithCatch; 599 static final NamedFunction NF_throwException; 600 601 static final MethodHandle MH_castReference; 602 static final MethodHandle MH_selectAlternative; 603 static final MethodHandle MH_copyAsPrimitiveArray; 604 static final MethodHandle MH_fillNewTypedArray; 605 static final MethodHandle MH_fillNewArray; 606 static final MethodHandle MH_arrayIdentity; 607 608 static { 609 try { 610 NF_checkSpreadArgument = new NamedFunction(MHI.getDeclaredMethod("checkSpreadArgument", Object.class, int.class)); 611 NF_guardWithCatch = new NamedFunction(MHI.getDeclaredMethod("guardWithCatch", MethodHandle.class, Class.class, 612 MethodHandle.class, Object[].class)); 613 NF_throwException = new NamedFunction(MHI.getDeclaredMethod("throwException", Throwable.class)); 614 615 NF_checkSpreadArgument.resolve(); 616 NF_guardWithCatch.resolve(); 617 NF_throwException.resolve(); 618 619 MH_castReference = IMPL_LOOKUP.findStatic(MHI, "castReference", 620 MethodType.methodType(Object.class, Class.class, Object.class)); 621 MH_copyAsPrimitiveArray = IMPL_LOOKUP.findStatic(MHI, "copyAsPrimitiveArray", 622 MethodType.methodType(Object.class, Wrapper.class, Object[].class)); 623 MH_arrayIdentity = IMPL_LOOKUP.findStatic(MHI, "identity", 624 MethodType.methodType(Object[].class, Object[].class)); 625 MH_fillNewArray = IMPL_LOOKUP.findStatic(MHI, "fillNewArray", 626 MethodType.methodType(Object[].class, Integer.class, Object[].class)); 627 MH_fillNewTypedArray = IMPL_LOOKUP.findStatic(MHI, "fillNewTypedArray", 628 MethodType.methodType(Object[].class, Object[].class, Integer.class, Object[].class)); 629 630 MH_selectAlternative = makeIntrinsic( 631 IMPL_LOOKUP.findStatic(MHI, "selectAlternative", 632 MethodType.methodType(MethodHandle.class, boolean.class, MethodHandle.class, MethodHandle.class)), 633 Intrinsic.SELECT_ALTERNATIVE); 634 } catch (ReflectiveOperationException ex) { 635 throw newInternalError(ex); 636 } 637 } 638 } 639 640 /** Factory method: Collect or filter selected argument(s). */ 641 static MethodHandle makeCollectArguments(MethodHandle target, 642 MethodHandle collector, int collectArgPos, boolean retainOriginalArgs) { 643 MethodType targetType = target.type(); // (a..., c, [b...])=>r 644 MethodType collectorType = collector.type(); // (b...)=>c 645 int collectArgCount = collectorType.parameterCount(); 646 Class<?> collectValType = collectorType.returnType(); 647 int collectValCount = (collectValType == void.class ? 0 : 1); 648 MethodType srcType = targetType // (a..., [b...])=>r 649 .dropParameterTypes(collectArgPos, collectArgPos+collectValCount); 650 if (!retainOriginalArgs) { // (a..., b...)=>r 651 srcType = srcType.insertParameterTypes(collectArgPos, collectorType.parameterList()); 652 } 653 // in arglist: [0: ...keep1 | cpos: collect... | cpos+cacount: keep2... ] 654 // out arglist: [0: ...keep1 | cpos: collectVal? | cpos+cvcount: keep2... ] 655 // out(retain): [0: ...keep1 | cpos: cV? coll... | cpos+cvc+cac: keep2... ] 656 657 // Now build a LambdaForm. 658 MethodType lambdaType = srcType.invokerType(); 659 Name[] names = arguments(2, lambdaType); 660 final int collectNamePos = names.length - 2; 661 final int targetNamePos = names.length - 1; 662 663 Name[] collectorArgs = Arrays.copyOfRange(names, 1 + collectArgPos, 1 + collectArgPos + collectArgCount); 664 names[collectNamePos] = new Name(collector, (Object[]) collectorArgs); 665 666 // Build argument array for the target. 667 // Incoming LF args to copy are: [ (mh) headArgs collectArgs tailArgs ]. 668 // Output argument array is [ headArgs (collectVal)? (collectArgs)? tailArgs ]. 669 Name[] targetArgs = new Name[targetType.parameterCount()]; 670 int inputArgPos = 1; // incoming LF args to copy to target 671 int targetArgPos = 0; // fill pointer for targetArgs 672 int chunk = collectArgPos; // |headArgs| 673 System.arraycopy(names, inputArgPos, targetArgs, targetArgPos, chunk); 674 inputArgPos += chunk; 675 targetArgPos += chunk; 676 if (collectValType != void.class) { 677 targetArgs[targetArgPos++] = names[collectNamePos]; 678 } 679 chunk = collectArgCount; 680 if (retainOriginalArgs) { 681 System.arraycopy(names, inputArgPos, targetArgs, targetArgPos, chunk); 682 targetArgPos += chunk; // optionally pass on the collected chunk 683 } 684 inputArgPos += chunk; 685 chunk = targetArgs.length - targetArgPos; // all the rest 686 System.arraycopy(names, inputArgPos, targetArgs, targetArgPos, chunk); 687 assert(inputArgPos + chunk == collectNamePos); // use of rest of input args also 688 names[targetNamePos] = new Name(target, (Object[]) targetArgs); 689 690 LambdaForm form = new LambdaForm("collect", lambdaType.parameterCount(), names); 691 return SimpleMethodHandle.make(srcType, form); 692 } 693 694 @LambdaForm.Hidden 695 static 696 MethodHandle selectAlternative(boolean testResult, MethodHandle target, MethodHandle fallback) { 697 return testResult ? target : fallback; 698 } 699 700 static 701 MethodHandle makeGuardWithTest(MethodHandle test, 702 MethodHandle target, 703 MethodHandle fallback) { 704 MethodType type = target.type(); 705 assert(test.type().equals(type.changeReturnType(boolean.class)) && fallback.type().equals(type)); 706 MethodType basicType = type.basicType(); 707 LambdaForm form = makeGuardWithTestForm(basicType); 708 BoundMethodHandle.SpeciesData data = BoundMethodHandle.speciesData_LLL(); 709 BoundMethodHandle mh; 710 try { 711 mh = (BoundMethodHandle) 712 data.constructor().invokeBasic(type, form, 713 (Object) test, (Object) target, (Object) fallback); 714 } catch (Throwable ex) { 715 throw uncaughtException(ex); 716 } 717 assert(mh.type() == type); 718 return mh; 719 } 720 721 static 722 LambdaForm makeGuardWithTestForm(MethodType basicType) { 723 LambdaForm lform = basicType.form().cachedLambdaForm(MethodTypeForm.LF_GWT); 724 if (lform != null) return lform; 725 final int THIS_MH = 0; // the BMH_LLL 726 final int ARG_BASE = 1; // start of incoming arguments 727 final int ARG_LIMIT = ARG_BASE + basicType.parameterCount(); 728 int nameCursor = ARG_LIMIT; 729 final int GET_TEST = nameCursor++; 730 final int GET_TARGET = nameCursor++; 731 final int GET_FALLBACK = nameCursor++; 732 final int CALL_TEST = nameCursor++; 733 final int SELECT_ALT = nameCursor++; 734 final int CALL_TARGET = nameCursor++; 735 assert(CALL_TARGET == SELECT_ALT+1); // must be true to trigger IBG.emitSelectAlternative 736 737 MethodType lambdaType = basicType.invokerType(); 738 Name[] names = arguments(nameCursor - ARG_LIMIT, lambdaType); 739 740 BoundMethodHandle.SpeciesData data = BoundMethodHandle.speciesData_LLL(); 741 names[THIS_MH] = names[THIS_MH].withConstraint(data); 742 names[GET_TEST] = new Name(data.getterFunction(0), names[THIS_MH]); 743 names[GET_TARGET] = new Name(data.getterFunction(1), names[THIS_MH]); 744 names[GET_FALLBACK] = new Name(data.getterFunction(2), names[THIS_MH]); 745 746 Object[] invokeArgs = Arrays.copyOfRange(names, 0, ARG_LIMIT, Object[].class); 747 748 // call test 749 MethodType testType = basicType.changeReturnType(boolean.class).basicType(); 750 invokeArgs[0] = names[GET_TEST]; 751 names[CALL_TEST] = new Name(testType, invokeArgs); 752 753 // call selectAlternative 754 names[SELECT_ALT] = new Name(Lazy.MH_selectAlternative, names[CALL_TEST], 755 names[GET_TARGET], names[GET_FALLBACK]); 756 757 // call target or fallback 758 invokeArgs[0] = names[SELECT_ALT]; 759 names[CALL_TARGET] = new Name(basicType, invokeArgs); 760 761 lform = new LambdaForm("guard", lambdaType.parameterCount(), names); 762 763 return basicType.form().setCachedLambdaForm(MethodTypeForm.LF_GWT, lform); 764 } 765 766 /** 767 * The LambdaForm shape for catchException combinator is the following: 768 * <blockquote><pre>{@code 769 * guardWithCatch=Lambda(a0:L,a1:L,a2:L)=>{ 770 * t3:L=BoundMethodHandle$Species_LLLLL.argL0(a0:L); 771 * t4:L=BoundMethodHandle$Species_LLLLL.argL1(a0:L); 772 * t5:L=BoundMethodHandle$Species_LLLLL.argL2(a0:L); 773 * t6:L=BoundMethodHandle$Species_LLLLL.argL3(a0:L); 774 * t7:L=BoundMethodHandle$Species_LLLLL.argL4(a0:L); 775 * t8:L=MethodHandle.invokeBasic(t6:L,a1:L,a2:L); 776 * t9:L=MethodHandleImpl.guardWithCatch(t3:L,t4:L,t5:L,t8:L); 777 * t10:I=MethodHandle.invokeBasic(t7:L,t9:L);t10:I} 778 * }</pre></blockquote> 779 * 780 * argL0 and argL2 are target and catcher method handles. argL1 is exception class. 781 * argL3 and argL4 are auxiliary method handles: argL3 boxes arguments and wraps them into Object[] 782 * (ValueConversions.array()) and argL4 unboxes result if necessary (ValueConversions.unbox()). 783 * 784 * Having t8 and t10 passed outside and not hardcoded into a lambda form allows to share lambda forms 785 * among catchException combinators with the same basic type. 786 */ 787 private static LambdaForm makeGuardWithCatchForm(MethodType basicType) { 788 MethodType lambdaType = basicType.invokerType(); 789 790 LambdaForm lform = basicType.form().cachedLambdaForm(MethodTypeForm.LF_GWC); 791 if (lform != null) { 792 return lform; 793 } 794 final int THIS_MH = 0; // the BMH_LLLLL 795 final int ARG_BASE = 1; // start of incoming arguments 796 final int ARG_LIMIT = ARG_BASE + basicType.parameterCount(); 797 798 int nameCursor = ARG_LIMIT; 799 final int GET_TARGET = nameCursor++; 800 final int GET_CLASS = nameCursor++; 801 final int GET_CATCHER = nameCursor++; 802 final int GET_COLLECT_ARGS = nameCursor++; 803 final int GET_UNBOX_RESULT = nameCursor++; 804 final int BOXED_ARGS = nameCursor++; 805 final int TRY_CATCH = nameCursor++; 806 final int UNBOX_RESULT = nameCursor++; 807 808 Name[] names = arguments(nameCursor - ARG_LIMIT, lambdaType); 809 810 BoundMethodHandle.SpeciesData data = BoundMethodHandle.speciesData_LLLLL(); 811 names[THIS_MH] = names[THIS_MH].withConstraint(data); 812 names[GET_TARGET] = new Name(data.getterFunction(0), names[THIS_MH]); 813 names[GET_CLASS] = new Name(data.getterFunction(1), names[THIS_MH]); 814 names[GET_CATCHER] = new Name(data.getterFunction(2), names[THIS_MH]); 815 names[GET_COLLECT_ARGS] = new Name(data.getterFunction(3), names[THIS_MH]); 816 names[GET_UNBOX_RESULT] = new Name(data.getterFunction(4), names[THIS_MH]); 817 818 // FIXME: rework argument boxing/result unboxing logic for LF interpretation 819 820 // t_{i}:L=MethodHandle.invokeBasic(collectArgs:L,a1:L,...); 821 MethodType collectArgsType = basicType.changeReturnType(Object.class); 822 MethodHandle invokeBasic = MethodHandles.basicInvoker(collectArgsType); 823 Object[] args = new Object[invokeBasic.type().parameterCount()]; 824 args[0] = names[GET_COLLECT_ARGS]; 825 System.arraycopy(names, ARG_BASE, args, 1, ARG_LIMIT-ARG_BASE); 826 names[BOXED_ARGS] = new Name(makeIntrinsic(invokeBasic, Intrinsic.GUARD_WITH_CATCH), args); 827 828 // t_{i+1}:L=MethodHandleImpl.guardWithCatch(target:L,exType:L,catcher:L,t_{i}:L); 829 Object[] gwcArgs = new Object[] {names[GET_TARGET], names[GET_CLASS], names[GET_CATCHER], names[BOXED_ARGS]}; 830 names[TRY_CATCH] = new Name(Lazy.NF_guardWithCatch, gwcArgs); 831 832 // t_{i+2}:I=MethodHandle.invokeBasic(unbox:L,t_{i+1}:L); 833 MethodHandle invokeBasicUnbox = MethodHandles.basicInvoker(MethodType.methodType(basicType.rtype(), Object.class)); 834 Object[] unboxArgs = new Object[] {names[GET_UNBOX_RESULT], names[TRY_CATCH]}; 835 names[UNBOX_RESULT] = new Name(invokeBasicUnbox, unboxArgs); 836 837 lform = new LambdaForm("guardWithCatch", lambdaType.parameterCount(), names); 838 839 return basicType.form().setCachedLambdaForm(MethodTypeForm.LF_GWC, lform); 840 } 841 842 static 843 MethodHandle makeGuardWithCatch(MethodHandle target, 844 Class<? extends Throwable> exType, 845 MethodHandle catcher) { 846 MethodType type = target.type(); 847 LambdaForm form = makeGuardWithCatchForm(type.basicType()); 848 849 // Prepare auxiliary method handles used during LambdaForm interpretation. 850 // Box arguments and wrap them into Object[]: ValueConversions.array(). 851 MethodType varargsType = type.changeReturnType(Object[].class); 852 MethodHandle collectArgs = varargsArray(type.parameterCount()).asType(varargsType); 853 // Result unboxing: ValueConversions.unbox() OR ValueConversions.identity() OR ValueConversions.ignore(). 854 MethodHandle unboxResult; 855 Class<?> rtype = type.returnType(); 856 if (rtype.isPrimitive()) { 857 if (rtype == void.class) { 858 unboxResult = ValueConversions.ignore(); 859 } else { 860 Wrapper w = Wrapper.forPrimitiveType(type.returnType()); 861 unboxResult = ValueConversions.unboxExact(w); 862 } 863 } else { 864 unboxResult = MethodHandles.identity(Object.class); 865 } 866 867 BoundMethodHandle.SpeciesData data = BoundMethodHandle.speciesData_LLLLL(); 868 BoundMethodHandle mh; 869 try { 870 mh = (BoundMethodHandle) 871 data.constructor().invokeBasic(type, form, (Object) target, (Object) exType, (Object) catcher, 872 (Object) collectArgs, (Object) unboxResult); 873 } catch (Throwable ex) { 874 throw uncaughtException(ex); 875 } 876 assert(mh.type() == type); 877 return mh; 878 } 879 880 /** 881 * Intrinsified during LambdaForm compilation 882 * (see {@link InvokerBytecodeGenerator#emitGuardWithCatch emitGuardWithCatch}). 883 */ 884 @LambdaForm.Hidden 885 static Object guardWithCatch(MethodHandle target, Class<? extends Throwable> exType, MethodHandle catcher, 886 Object... av) throws Throwable { 887 // Use asFixedArity() to avoid unnecessary boxing of last argument for VarargsCollector case. 888 try { 889 return target.asFixedArity().invokeWithArguments(av); 890 } catch (Throwable t) { 891 if (!exType.isInstance(t)) throw t; 892 return catcher.asFixedArity().invokeWithArguments(prepend(t, av)); 893 } 894 } 895 896 /** Prepend an element {@code elem} to an {@code array}. */ 897 @LambdaForm.Hidden 898 private static Object[] prepend(Object elem, Object[] array) { 899 Object[] newArray = new Object[array.length+1]; 900 newArray[0] = elem; 901 System.arraycopy(array, 0, newArray, 1, array.length); 902 return newArray; 903 } 904 905 static 906 MethodHandle throwException(MethodType type) { 907 assert(Throwable.class.isAssignableFrom(type.parameterType(0))); 908 int arity = type.parameterCount(); 909 if (arity > 1) { 910 MethodHandle mh = throwException(type.dropParameterTypes(1, arity)); 911 mh = MethodHandles.dropArguments(mh, 1, type.parameterList().subList(1, arity)); 912 return mh; 913 } 914 return makePairwiseConvert(Lazy.NF_throwException.resolvedHandle(), type, false, true); 915 } 916 917 static <T extends Throwable> Empty throwException(T t) throws T { throw t; } 918 919 static MethodHandle[] FAKE_METHOD_HANDLE_INVOKE = new MethodHandle[2]; 920 static MethodHandle fakeMethodHandleInvoke(MemberName method) { 921 int idx; 922 assert(method.isMethodHandleInvoke()); 923 switch (method.getName()) { 924 case "invoke": idx = 0; break; 925 case "invokeExact": idx = 1; break; 926 default: throw new InternalError(method.getName()); 927 } 928 MethodHandle mh = FAKE_METHOD_HANDLE_INVOKE[idx]; 929 if (mh != null) return mh; 930 MethodType type = MethodType.methodType(Object.class, UnsupportedOperationException.class, 931 MethodHandle.class, Object[].class); 932 mh = throwException(type); 933 mh = mh.bindTo(new UnsupportedOperationException("cannot reflectively invoke MethodHandle")); 934 if (!method.getInvocationType().equals(mh.type())) 935 throw new InternalError(method.toString()); 936 mh = mh.withInternalMemberName(method, false); 937 mh = mh.asVarargsCollector(Object[].class); 938 assert(method.isVarargs()); 939 FAKE_METHOD_HANDLE_INVOKE[idx] = mh; 940 return mh; 941 } 942 943 /** 944 * Create an alias for the method handle which, when called, 945 * appears to be called from the same class loader and protection domain 946 * as hostClass. 947 * This is an expensive no-op unless the method which is called 948 * is sensitive to its caller. A small number of system methods 949 * are in this category, including Class.forName and Method.invoke. 950 */ 951 static 952 MethodHandle bindCaller(MethodHandle mh, Class<?> hostClass) { 953 return BindCaller.bindCaller(mh, hostClass); 954 } 955 956 // Put the whole mess into its own nested class. 957 // That way we can lazily load the code and set up the constants. 958 private static class BindCaller { 959 static 960 MethodHandle bindCaller(MethodHandle mh, Class<?> hostClass) { 961 // Do not use this function to inject calls into system classes. 962 if (hostClass == null 963 || (hostClass.isArray() || 964 hostClass.isPrimitive() || 965 hostClass.getName().startsWith("java.") || 966 hostClass.getName().startsWith("sun."))) { 967 throw new InternalError(); // does not happen, and should not anyway 968 } 969 // For simplicity, convert mh to a varargs-like method. 970 MethodHandle vamh = prepareForInvoker(mh); 971 // Cache the result of makeInjectedInvoker once per argument class. 972 MethodHandle bccInvoker = CV_makeInjectedInvoker.get(hostClass); 973 return restoreToType(bccInvoker.bindTo(vamh), mh, hostClass); 974 } 975 976 private static MethodHandle makeInjectedInvoker(Class<?> hostClass) { 977 Class<?> bcc = UNSAFE.defineAnonymousClass(hostClass, T_BYTES, null); 978 if (hostClass.getClassLoader() != bcc.getClassLoader()) 979 throw new InternalError(hostClass.getName()+" (CL)"); 980 try { 981 if (hostClass.getProtectionDomain() != bcc.getProtectionDomain()) 982 throw new InternalError(hostClass.getName()+" (PD)"); 983 } catch (SecurityException ex) { 984 // Self-check was blocked by security manager. This is OK. 985 // In fact the whole try body could be turned into an assertion. 986 } 987 try { 988 MethodHandle init = IMPL_LOOKUP.findStatic(bcc, "init", MethodType.methodType(void.class)); 989 init.invokeExact(); // force initialization of the class 990 } catch (Throwable ex) { 991 throw uncaughtException(ex); 992 } 993 MethodHandle bccInvoker; 994 try { 995 MethodType invokerMT = MethodType.methodType(Object.class, MethodHandle.class, Object[].class); 996 bccInvoker = IMPL_LOOKUP.findStatic(bcc, "invoke_V", invokerMT); 997 } catch (ReflectiveOperationException ex) { 998 throw uncaughtException(ex); 999 } 1000 // Test the invoker, to ensure that it really injects into the right place. 1001 try { 1002 MethodHandle vamh = prepareForInvoker(MH_checkCallerClass); 1003 Object ok = bccInvoker.invokeExact(vamh, new Object[]{hostClass, bcc}); 1004 } catch (Throwable ex) { 1005 throw new InternalError(ex); 1006 } 1007 return bccInvoker; 1008 } 1009 private static ClassValue<MethodHandle> CV_makeInjectedInvoker = new ClassValue<MethodHandle>() { 1010 @Override protected MethodHandle computeValue(Class<?> hostClass) { 1011 return makeInjectedInvoker(hostClass); 1012 } 1013 }; 1014 1015 // Adapt mh so that it can be called directly from an injected invoker: 1016 private static MethodHandle prepareForInvoker(MethodHandle mh) { 1017 mh = mh.asFixedArity(); 1018 MethodType mt = mh.type(); 1019 int arity = mt.parameterCount(); 1020 MethodHandle vamh = mh.asType(mt.generic()); 1021 vamh.internalForm().compileToBytecode(); // eliminate LFI stack frames 1022 vamh = vamh.asSpreader(Object[].class, arity); 1023 vamh.internalForm().compileToBytecode(); // eliminate LFI stack frames 1024 return vamh; 1025 } 1026 1027 // Undo the adapter effect of prepareForInvoker: 1028 private static MethodHandle restoreToType(MethodHandle vamh, 1029 MethodHandle original, 1030 Class<?> hostClass) { 1031 MethodType type = original.type(); 1032 MethodHandle mh = vamh.asCollector(Object[].class, type.parameterCount()); 1033 MemberName member = original.internalMemberName(); 1034 mh = mh.asType(type); 1035 mh = new WrappedMember(mh, type, member, original.isInvokeSpecial(), hostClass); 1036 return mh; 1037 } 1038 1039 private static final MethodHandle MH_checkCallerClass; 1040 static { 1041 final Class<?> THIS_CLASS = BindCaller.class; 1042 assert(checkCallerClass(THIS_CLASS, THIS_CLASS)); 1043 try { 1044 MH_checkCallerClass = IMPL_LOOKUP 1045 .findStatic(THIS_CLASS, "checkCallerClass", 1046 MethodType.methodType(boolean.class, Class.class, Class.class)); 1047 assert((boolean) MH_checkCallerClass.invokeExact(THIS_CLASS, THIS_CLASS)); 1048 } catch (Throwable ex) { 1049 throw new InternalError(ex); 1050 } 1051 } 1052 1053 @CallerSensitive 1054 private static boolean checkCallerClass(Class<?> expected, Class<?> expected2) { 1055 // This method is called via MH_checkCallerClass and so it's 1056 // correct to ask for the immediate caller here. 1057 Class<?> actual = Reflection.getCallerClass(); 1058 if (actual != expected && actual != expected2) 1059 throw new InternalError("found "+actual.getName()+", expected "+expected.getName() 1060 +(expected == expected2 ? "" : ", or else "+expected2.getName())); 1061 return true; 1062 } 1063 1064 private static final byte[] T_BYTES; 1065 static { 1066 final Object[] values = {null}; 1067 AccessController.doPrivileged(new PrivilegedAction<Void>() { 1068 public Void run() { 1069 try { 1070 Class<T> tClass = T.class; 1071 String tName = tClass.getName(); 1072 String tResource = tName.substring(tName.lastIndexOf('.')+1)+".class"; 1073 java.net.URLConnection uconn = tClass.getResource(tResource).openConnection(); 1074 int len = uconn.getContentLength(); 1075 byte[] bytes = new byte[len]; 1076 try (java.io.InputStream str = uconn.getInputStream()) { 1077 int nr = str.read(bytes); 1078 if (nr != len) throw new java.io.IOException(tResource); 1079 } 1080 values[0] = bytes; 1081 } catch (java.io.IOException ex) { 1082 throw new InternalError(ex); 1083 } 1084 return null; 1085 } 1086 }); 1087 T_BYTES = (byte[]) values[0]; 1088 } 1089 1090 // The following class is used as a template for Unsafe.defineAnonymousClass: 1091 private static class T { 1092 static void init() { } // side effect: initializes this class 1093 static Object invoke_V(MethodHandle vamh, Object[] args) throws Throwable { 1094 return vamh.invokeExact(args); 1095 } 1096 } 1097 } 1098 1099 1100 /** This subclass allows a wrapped method handle to be re-associated with an arbitrary member name. */ 1101 private static final class WrappedMember extends DelegatingMethodHandle { 1102 private final MethodHandle target; 1103 private final MemberName member; 1104 private final Class<?> callerClass; 1105 private final boolean isInvokeSpecial; 1106 1107 private WrappedMember(MethodHandle target, MethodType type, 1108 MemberName member, boolean isInvokeSpecial, 1109 Class<?> callerClass) { 1110 super(type, target); 1111 this.target = target; 1112 this.member = member; 1113 this.callerClass = callerClass; 1114 this.isInvokeSpecial = isInvokeSpecial; 1115 } 1116 1117 @Override 1118 MemberName internalMemberName() { 1119 return member; 1120 } 1121 @Override 1122 Class<?> internalCallerClass() { 1123 return callerClass; 1124 } 1125 @Override 1126 boolean isInvokeSpecial() { 1127 return isInvokeSpecial; 1128 } 1129 @Override 1130 protected MethodHandle getTarget() { 1131 return target; 1132 } 1133 @Override 1134 public MethodHandle asTypeUncached(MethodType newType) { 1135 // This MH is an alias for target, except for the MemberName 1136 // Drop the MemberName if there is any conversion. 1137 return asTypeCache = target.asType(newType); 1138 } 1139 } 1140 1141 static MethodHandle makeWrappedMember(MethodHandle target, MemberName member, boolean isInvokeSpecial) { 1142 if (member.equals(target.internalMemberName()) && isInvokeSpecial == target.isInvokeSpecial()) 1143 return target; 1144 return new WrappedMember(target, target.type(), member, isInvokeSpecial, null); 1145 } 1146 1147 /** Intrinsic IDs */ 1148 /*non-public*/ 1149 enum Intrinsic { 1150 SELECT_ALTERNATIVE, 1151 GUARD_WITH_CATCH, 1152 NEW_ARRAY, 1153 ARRAY_LOAD, 1154 ARRAY_STORE, 1155 IDENTITY, 1156 ZERO, 1157 NONE // no intrinsic associated 1158 } 1159 1160 /** Mark arbitrary method handle as intrinsic. 1161 * InvokerBytecodeGenerator uses this info to produce more efficient bytecode shape. */ 1162 private static final class IntrinsicMethodHandle extends DelegatingMethodHandle { 1163 private final MethodHandle target; 1164 private final Intrinsic intrinsicName; 1165 1166 IntrinsicMethodHandle(MethodHandle target, Intrinsic intrinsicName) { 1167 super(target.type(), target); 1168 this.target = target; 1169 this.intrinsicName = intrinsicName; 1170 } 1171 1172 @Override 1173 protected MethodHandle getTarget() { 1174 return target; 1175 } 1176 1177 @Override 1178 Intrinsic intrinsicName() { 1179 return intrinsicName; 1180 } 1181 1182 @Override 1183 public MethodHandle asTypeUncached(MethodType newType) { 1184 // This MH is an alias for target, except for the intrinsic name 1185 // Drop the name if there is any conversion. 1186 return asTypeCache = target.asType(newType); 1187 } 1188 1189 @Override 1190 String internalProperties() { 1191 return super.internalProperties() + 1192 "\n& Intrinsic="+intrinsicName; 1193 } 1194 1195 @Override 1196 public MethodHandle asCollector(Class<?> arrayType, int arrayLength) { 1197 if (intrinsicName == Intrinsic.IDENTITY) { 1198 MethodType resultType = type().asCollectorType(arrayType, arrayLength); 1199 MethodHandle newArray = MethodHandleImpl.varargsArray(arrayType, arrayLength); 1200 return newArray.asType(resultType); 1201 } 1202 return super.asCollector(arrayType, arrayLength); 1203 } 1204 } 1205 1206 static MethodHandle makeIntrinsic(MethodHandle target, Intrinsic intrinsicName) { 1207 if (intrinsicName == target.intrinsicName()) 1208 return target; 1209 return new IntrinsicMethodHandle(target, intrinsicName); 1210 } 1211 1212 static MethodHandle makeIntrinsic(MethodType type, LambdaForm form, Intrinsic intrinsicName) { 1213 return new IntrinsicMethodHandle(SimpleMethodHandle.make(type, form), intrinsicName); 1214 } 1215 1216 /// Collection of multiple arguments. 1217 1218 private static MethodHandle findCollector(String name, int nargs, Class<?> rtype, Class<?>... ptypes) { 1219 MethodType type = MethodType.genericMethodType(nargs) 1220 .changeReturnType(rtype) 1221 .insertParameterTypes(0, ptypes); 1222 try { 1223 return IMPL_LOOKUP.findStatic(MethodHandleImpl.class, name, type); 1224 } catch (ReflectiveOperationException ex) { 1225 return null; 1226 } 1227 } 1228 1229 private static final Object[] NO_ARGS_ARRAY = {}; 1230 private static Object[] makeArray(Object... args) { return args; } 1231 private static Object[] array() { return NO_ARGS_ARRAY; } 1232 private static Object[] array(Object a0) 1233 { return makeArray(a0); } 1234 private static Object[] array(Object a0, Object a1) 1235 { return makeArray(a0, a1); } 1236 private static Object[] array(Object a0, Object a1, Object a2) 1237 { return makeArray(a0, a1, a2); } 1238 private static Object[] array(Object a0, Object a1, Object a2, Object a3) 1239 { return makeArray(a0, a1, a2, a3); } 1240 private static Object[] array(Object a0, Object a1, Object a2, Object a3, 1241 Object a4) 1242 { return makeArray(a0, a1, a2, a3, a4); } 1243 private static Object[] array(Object a0, Object a1, Object a2, Object a3, 1244 Object a4, Object a5) 1245 { return makeArray(a0, a1, a2, a3, a4, a5); } 1246 private static Object[] array(Object a0, Object a1, Object a2, Object a3, 1247 Object a4, Object a5, Object a6) 1248 { return makeArray(a0, a1, a2, a3, a4, a5, a6); } 1249 private static Object[] array(Object a0, Object a1, Object a2, Object a3, 1250 Object a4, Object a5, Object a6, Object a7) 1251 { return makeArray(a0, a1, a2, a3, a4, a5, a6, a7); } 1252 private static Object[] array(Object a0, Object a1, Object a2, Object a3, 1253 Object a4, Object a5, Object a6, Object a7, 1254 Object a8) 1255 { return makeArray(a0, a1, a2, a3, a4, a5, a6, a7, a8); } 1256 private static Object[] array(Object a0, Object a1, Object a2, Object a3, 1257 Object a4, Object a5, Object a6, Object a7, 1258 Object a8, Object a9) 1259 { return makeArray(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9); } 1260 private static MethodHandle[] makeArrays() { 1261 ArrayList<MethodHandle> mhs = new ArrayList<>(); 1262 for (;;) { 1263 MethodHandle mh = findCollector("array", mhs.size(), Object[].class); 1264 if (mh == null) break; 1265 mh = makeIntrinsic(mh, Intrinsic.NEW_ARRAY); 1266 mhs.add(mh); 1267 } 1268 assert(mhs.size() == 11); // current number of methods 1269 return mhs.toArray(new MethodHandle[MAX_ARITY+1]); 1270 } 1271 private static final MethodHandle[] ARRAYS = makeArrays(); 1272 1273 // filling versions of the above: 1274 // using Integer len instead of int len and no varargs to avoid bootstrapping problems 1275 private static Object[] fillNewArray(Integer len, Object[] /*not ...*/ args) { 1276 Object[] a = new Object[len]; 1277 fillWithArguments(a, 0, args); 1278 return a; 1279 } 1280 private static Object[] fillNewTypedArray(Object[] example, Integer len, Object[] /*not ...*/ args) { 1281 Object[] a = Arrays.copyOf(example, len); 1282 assert(a.getClass() != Object[].class); 1283 fillWithArguments(a, 0, args); 1284 return a; 1285 } 1286 private static void fillWithArguments(Object[] a, int pos, Object... args) { 1287 System.arraycopy(args, 0, a, pos, args.length); 1288 } 1289 // using Integer pos instead of int pos to avoid bootstrapping problems 1290 private static Object[] fillArray(Integer pos, Object[] a, Object a0) 1291 { fillWithArguments(a, pos, a0); return a; } 1292 private static Object[] fillArray(Integer pos, Object[] a, Object a0, Object a1) 1293 { fillWithArguments(a, pos, a0, a1); return a; } 1294 private static Object[] fillArray(Integer pos, Object[] a, Object a0, Object a1, Object a2) 1295 { fillWithArguments(a, pos, a0, a1, a2); return a; } 1296 private static Object[] fillArray(Integer pos, Object[] a, Object a0, Object a1, Object a2, Object a3) 1297 { fillWithArguments(a, pos, a0, a1, a2, a3); return a; } 1298 private static Object[] fillArray(Integer pos, Object[] a, Object a0, Object a1, Object a2, Object a3, 1299 Object a4) 1300 { fillWithArguments(a, pos, a0, a1, a2, a3, a4); return a; } 1301 private static Object[] fillArray(Integer pos, Object[] a, Object a0, Object a1, Object a2, Object a3, 1302 Object a4, Object a5) 1303 { fillWithArguments(a, pos, a0, a1, a2, a3, a4, a5); return a; } 1304 private static Object[] fillArray(Integer pos, Object[] a, Object a0, Object a1, Object a2, Object a3, 1305 Object a4, Object a5, Object a6) 1306 { fillWithArguments(a, pos, a0, a1, a2, a3, a4, a5, a6); return a; } 1307 private static Object[] fillArray(Integer pos, Object[] a, Object a0, Object a1, Object a2, Object a3, 1308 Object a4, Object a5, Object a6, Object a7) 1309 { fillWithArguments(a, pos, a0, a1, a2, a3, a4, a5, a6, a7); return a; } 1310 private static Object[] fillArray(Integer pos, Object[] a, Object a0, Object a1, Object a2, Object a3, 1311 Object a4, Object a5, Object a6, Object a7, 1312 Object a8) 1313 { fillWithArguments(a, pos, a0, a1, a2, a3, a4, a5, a6, a7, a8); return a; } 1314 private static Object[] fillArray(Integer pos, Object[] a, Object a0, Object a1, Object a2, Object a3, 1315 Object a4, Object a5, Object a6, Object a7, 1316 Object a8, Object a9) 1317 { fillWithArguments(a, pos, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9); return a; } 1318 private static MethodHandle[] makeFillArrays() { 1319 ArrayList<MethodHandle> mhs = new ArrayList<>(); 1320 mhs.add(null); // there is no empty fill; at least a0 is required 1321 for (;;) { 1322 MethodHandle mh = findCollector("fillArray", mhs.size(), Object[].class, Integer.class, Object[].class); 1323 if (mh == null) break; 1324 mhs.add(mh); 1325 } 1326 assert(mhs.size() == 11); // current number of methods 1327 return mhs.toArray(new MethodHandle[0]); 1328 } 1329 private static final MethodHandle[] FILL_ARRAYS = makeFillArrays(); 1330 1331 private static Object copyAsPrimitiveArray(Wrapper w, Object... boxes) { 1332 Object a = w.makeArray(boxes.length); 1333 w.copyArrayUnboxing(boxes, 0, a, 0, boxes.length); 1334 return a; 1335 } 1336 1337 /** Return a method handle that takes the indicated number of Object 1338 * arguments and returns an Object array of them, as if for varargs. 1339 */ 1340 static MethodHandle varargsArray(int nargs) { 1341 MethodHandle mh = ARRAYS[nargs]; 1342 if (mh != null) return mh; 1343 mh = findCollector("array", nargs, Object[].class); 1344 if (mh != null) mh = makeIntrinsic(mh, Intrinsic.NEW_ARRAY); 1345 if (mh != null) return ARRAYS[nargs] = mh; 1346 mh = buildVarargsArray(Lazy.MH_fillNewArray, Lazy.MH_arrayIdentity, nargs); 1347 assert(assertCorrectArity(mh, nargs)); 1348 mh = makeIntrinsic(mh, Intrinsic.NEW_ARRAY); 1349 return ARRAYS[nargs] = mh; 1350 } 1351 1352 private static boolean assertCorrectArity(MethodHandle mh, int arity) { 1353 assert(mh.type().parameterCount() == arity) : "arity != "+arity+": "+mh; 1354 return true; 1355 } 1356 1357 // Array identity function (used as Lazy.MH_arrayIdentity). 1358 static <T> T[] identity(T[] x) { 1359 return x; 1360 } 1361 1362 private static MethodHandle buildVarargsArray(MethodHandle newArray, MethodHandle finisher, int nargs) { 1363 // Build up the result mh as a sequence of fills like this: 1364 // finisher(fill(fill(newArrayWA(23,x1..x10),10,x11..x20),20,x21..x23)) 1365 // The various fill(_,10*I,___*[J]) are reusable. 1366 int leftLen = Math.min(nargs, LEFT_ARGS); // absorb some arguments immediately 1367 int rightLen = nargs - leftLen; 1368 MethodHandle leftCollector = newArray.bindTo(nargs); 1369 leftCollector = leftCollector.asCollector(Object[].class, leftLen); 1370 MethodHandle mh = finisher; 1371 if (rightLen > 0) { 1372 MethodHandle rightFiller = fillToRight(LEFT_ARGS + rightLen); 1373 if (mh == Lazy.MH_arrayIdentity) 1374 mh = rightFiller; 1375 else 1376 mh = MethodHandles.collectArguments(mh, 0, rightFiller); 1377 } 1378 if (mh == Lazy.MH_arrayIdentity) 1379 mh = leftCollector; 1380 else 1381 mh = MethodHandles.collectArguments(mh, 0, leftCollector); 1382 return mh; 1383 } 1384 1385 private static final int LEFT_ARGS = (FILL_ARRAYS.length - 1); 1386 private static final MethodHandle[] FILL_ARRAY_TO_RIGHT = new MethodHandle[MAX_ARITY+1]; 1387 /** fill_array_to_right(N).invoke(a, argL..arg[N-1]) 1388 * fills a[L]..a[N-1] with corresponding arguments, 1389 * and then returns a. The value L is a global constant (LEFT_ARGS). 1390 */ 1391 private static MethodHandle fillToRight(int nargs) { 1392 MethodHandle filler = FILL_ARRAY_TO_RIGHT[nargs]; 1393 if (filler != null) return filler; 1394 filler = buildFiller(nargs); 1395 assert(assertCorrectArity(filler, nargs - LEFT_ARGS + 1)); 1396 return FILL_ARRAY_TO_RIGHT[nargs] = filler; 1397 } 1398 private static MethodHandle buildFiller(int nargs) { 1399 if (nargs <= LEFT_ARGS) 1400 return Lazy.MH_arrayIdentity; // no args to fill; return the array unchanged 1401 // we need room for both mh and a in mh.invoke(a, arg*[nargs]) 1402 final int CHUNK = LEFT_ARGS; 1403 int rightLen = nargs % CHUNK; 1404 int midLen = nargs - rightLen; 1405 if (rightLen == 0) { 1406 midLen = nargs - (rightLen = CHUNK); 1407 if (FILL_ARRAY_TO_RIGHT[midLen] == null) { 1408 // build some precursors from left to right 1409 for (int j = LEFT_ARGS % CHUNK; j < midLen; j += CHUNK) 1410 if (j > LEFT_ARGS) fillToRight(j); 1411 } 1412 } 1413 if (midLen < LEFT_ARGS) rightLen = nargs - (midLen = LEFT_ARGS); 1414 assert(rightLen > 0); 1415 MethodHandle midFill = fillToRight(midLen); // recursive fill 1416 MethodHandle rightFill = FILL_ARRAYS[rightLen].bindTo(midLen); // [midLen..nargs-1] 1417 assert(midFill.type().parameterCount() == 1 + midLen - LEFT_ARGS); 1418 assert(rightFill.type().parameterCount() == 1 + rightLen); 1419 1420 // Combine the two fills: 1421 // right(mid(a, x10..x19), x20..x23) 1422 // The final product will look like this: 1423 // right(mid(newArrayLeft(24, x0..x9), x10..x19), x20..x23) 1424 if (midLen == LEFT_ARGS) 1425 return rightFill; 1426 else 1427 return MethodHandles.collectArguments(rightFill, 0, midFill); 1428 } 1429 1430 // Type-polymorphic version of varargs maker. 1431 private static final ClassValue<MethodHandle[]> TYPED_COLLECTORS 1432 = new ClassValue<MethodHandle[]>() { 1433 @Override 1434 protected MethodHandle[] computeValue(Class<?> type) { 1435 return new MethodHandle[256]; 1436 } 1437 }; 1438 1439 static final int MAX_JVM_ARITY = 255; // limit imposed by the JVM 1440 1441 /** Return a method handle that takes the indicated number of 1442 * typed arguments and returns an array of them. 1443 * The type argument is the array type. 1444 */ 1445 static MethodHandle varargsArray(Class<?> arrayType, int nargs) { 1446 Class<?> elemType = arrayType.getComponentType(); 1447 if (elemType == null) throw new IllegalArgumentException("not an array: "+arrayType); 1448 // FIXME: Need more special casing and caching here. 1449 if (nargs >= MAX_JVM_ARITY/2 - 1) { 1450 int slots = nargs; 1451 final int MAX_ARRAY_SLOTS = MAX_JVM_ARITY - 1; // 1 for receiver MH 1452 if (slots <= MAX_ARRAY_SLOTS && elemType.isPrimitive()) 1453 slots *= Wrapper.forPrimitiveType(elemType).stackSlots(); 1454 if (slots > MAX_ARRAY_SLOTS) 1455 throw new IllegalArgumentException("too many arguments: "+arrayType.getSimpleName()+", length "+nargs); 1456 } 1457 if (elemType == Object.class) 1458 return varargsArray(nargs); 1459 // other cases: primitive arrays, subtypes of Object[] 1460 MethodHandle cache[] = TYPED_COLLECTORS.get(elemType); 1461 MethodHandle mh = nargs < cache.length ? cache[nargs] : null; 1462 if (mh != null) return mh; 1463 if (nargs == 0) { 1464 Object example = java.lang.reflect.Array.newInstance(arrayType.getComponentType(), 0); 1465 mh = MethodHandles.constant(arrayType, example); 1466 } else if (elemType.isPrimitive()) { 1467 MethodHandle builder = Lazy.MH_fillNewArray; 1468 MethodHandle producer = buildArrayProducer(arrayType); 1469 mh = buildVarargsArray(builder, producer, nargs); 1470 } else { 1471 Class<? extends Object[]> objArrayType = arrayType.asSubclass(Object[].class); 1472 Object[] example = Arrays.copyOf(NO_ARGS_ARRAY, 0, objArrayType); 1473 MethodHandle builder = Lazy.MH_fillNewTypedArray.bindTo(example); 1474 MethodHandle producer = Lazy.MH_arrayIdentity; // must be weakly typed 1475 mh = buildVarargsArray(builder, producer, nargs); 1476 } 1477 mh = mh.asType(MethodType.methodType(arrayType, Collections.<Class<?>>nCopies(nargs, elemType))); 1478 mh = makeIntrinsic(mh, Intrinsic.NEW_ARRAY); 1479 assert(assertCorrectArity(mh, nargs)); 1480 if (nargs < cache.length) 1481 cache[nargs] = mh; 1482 return mh; 1483 } 1484 1485 private static MethodHandle buildArrayProducer(Class<?> arrayType) { 1486 Class<?> elemType = arrayType.getComponentType(); 1487 assert(elemType.isPrimitive()); 1488 return Lazy.MH_copyAsPrimitiveArray.bindTo(Wrapper.forPrimitiveType(elemType)); 1489 } 1490 }