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