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