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 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 if (newType.lastParameterType() != type().lastParameterType()) 371 throw new InternalError(); 372 MethodHandle newTarget = asFixedArity().viewAsType(newType); 373 // put back the varargs bit: 374 return new AsVarargsCollector(newTarget, newType, arrayType); 375 } 376 377 @Override 378 MemberName internalMemberName() { 379 return asFixedArity().internalMemberName(); 380 } 381 382 /*non-public*/ 383 @Override 384 boolean isInvokeSpecial() { 385 return asFixedArity().isInvokeSpecial(); 386 } 387 388 389 @Override 390 MethodHandle bindArgument(int pos, char basicType, Object value) { 391 return asFixedArity().bindArgument(pos, basicType, value); 392 } 393 394 @Override 395 MethodHandle bindReceiver(Object receiver) { 396 return asFixedArity().bindReceiver(receiver); 397 } 398 399 @Override 400 MethodHandle dropArguments(MethodType srcType, int pos, int drops) { 401 return asFixedArity().dropArguments(srcType, pos, drops); 402 } 403 404 @Override 405 MethodHandle permuteArguments(MethodType newType, int[] reorder) { 406 return asFixedArity().permuteArguments(newType, reorder); 407 } 408 } 409 410 /** Factory method: Spread selected argument. */ 411 static MethodHandle makeSpreadArguments(MethodHandle target, 412 Class<?> spreadArgType, int spreadArgPos, int spreadArgCount) { 413 MethodType targetType = target.type(); 414 415 for (int i = 0; i < spreadArgCount; i++) { 416 Class<?> arg = VerifyType.spreadArgElementType(spreadArgType, i); 417 if (arg == null) arg = Object.class; 418 targetType = targetType.changeParameterType(spreadArgPos + i, arg); 419 } 420 target = target.asType(targetType); 421 422 MethodType srcType = targetType 423 .replaceParameterTypes(spreadArgPos, spreadArgPos + spreadArgCount, spreadArgType); 424 // Now build a LambdaForm. 425 MethodType lambdaType = srcType.invokerType(); 426 Name[] names = arguments(spreadArgCount + 2, lambdaType); 427 int nameCursor = lambdaType.parameterCount(); 428 int[] indexes = new int[targetType.parameterCount()]; 429 430 for (int i = 0, argIndex = 1; i < targetType.parameterCount() + 1; i++, argIndex++) { 431 Class<?> src = lambdaType.parameterType(i); 432 if (i == spreadArgPos) { 433 // Spread the array. 434 MethodHandle aload = MethodHandles.arrayElementGetter(spreadArgType); 435 Name array = names[argIndex]; 436 names[nameCursor++] = new Name(NF_checkSpreadArgument, array, spreadArgCount); 437 for (int j = 0; j < spreadArgCount; i++, j++) { 438 indexes[i] = nameCursor; 439 names[nameCursor++] = new Name(aload, array, j); 440 } 441 } else if (i < indexes.length) { 442 indexes[i] = argIndex; 443 } 444 } 445 assert(nameCursor == names.length-1); // leave room for the final call 446 447 // Build argument array for the call. 448 Name[] targetArgs = new Name[targetType.parameterCount()]; 449 for (int i = 0; i < targetType.parameterCount(); i++) { 450 int idx = indexes[i]; 451 targetArgs[i] = names[idx]; 452 } 453 names[names.length - 1] = new Name(target, (Object[]) targetArgs); 454 455 LambdaForm form = new LambdaForm("spread", lambdaType.parameterCount(), names); 456 return SimpleMethodHandle.make(srcType, form); 457 } 458 459 static void checkSpreadArgument(Object av, int n) { 460 // FIXME: regression test for bug 7141637 erroneously expects an NPE, and other tests may expect IAE 461 // but the actual exception raised by an arity mismatch should be WMTE 462 final boolean RAISE_RANDOM_EXCEPTIONS = true; // FIXME: delete in JSR 292 M1 463 if (av == null) { 464 if (n == 0) return; 465 int len; 466 if (RAISE_RANDOM_EXCEPTIONS) 467 len = ((Object[])av).length; // throw NPE; but delete this after tests are fixed 468 } else if (av instanceof Object[]) { 469 int len = ((Object[])av).length; 470 if (len == n) return; 471 } else { 472 int len = java.lang.reflect.Array.getLength(av); 473 if (len == n) return; 474 } 475 // fall through to error: 476 if (RAISE_RANDOM_EXCEPTIONS) 477 throw newIllegalArgumentException("Array is not of length "+n); 478 throw new WrongMethodTypeException("Array is not of length "+n); 479 } 480 481 private static final NamedFunction NF_checkSpreadArgument; 482 static { 483 try { 484 NF_checkSpreadArgument = new NamedFunction(MethodHandleImpl.class 485 .getDeclaredMethod("checkSpreadArgument", Object.class, int.class)); 486 NF_checkSpreadArgument.resolve(); 487 } catch (ReflectiveOperationException ex) { 488 throw newInternalError(ex); 489 } 490 } 491 492 /** Factory method: Collect or filter selected argument(s). */ 493 static MethodHandle makeCollectArguments(MethodHandle target, 494 MethodHandle collector, int collectArgPos, boolean retainOriginalArgs) { 495 MethodType targetType = target.type(); // (a..., c, [b...])=>r 496 MethodType collectorType = collector.type(); // (b...)=>c 497 int collectArgCount = collectorType.parameterCount(); 498 Class<?> collectValType = collectorType.returnType(); 499 int collectValCount = (collectValType == void.class ? 0 : 1); 500 MethodType srcType = targetType // (a..., [b...])=>r 501 .dropParameterTypes(collectArgPos, collectArgPos+collectValCount); 502 if (!retainOriginalArgs) { // (a..., b...)=>r 503 srcType = srcType.insertParameterTypes(collectArgPos, collectorType.parameterList()); 504 } 505 // in arglist: [0: ...keep1 | cpos: collect... | cpos+cacount: keep2... ] 506 // out arglist: [0: ...keep1 | cpos: collectVal? | cpos+cvcount: keep2... ] 507 // out(retain): [0: ...keep1 | cpos: cV? coll... | cpos+cvc+cac: keep2... ] 508 509 // Now build a LambdaForm. 510 MethodType lambdaType = srcType.invokerType(); 511 Name[] names = arguments(2, lambdaType); 512 final int collectNamePos = names.length - 2; 513 final int targetNamePos = names.length - 1; 514 515 Name[] collectorArgs = Arrays.copyOfRange(names, 1 + collectArgPos, 1 + collectArgPos + collectArgCount); 516 names[collectNamePos] = new Name(collector, (Object[]) collectorArgs); 517 518 // Build argument array for the target. 519 // Incoming LF args to copy are: [ (mh) headArgs collectArgs tailArgs ]. 520 // Output argument array is [ headArgs (collectVal)? (collectArgs)? tailArgs ]. 521 Name[] targetArgs = new Name[targetType.parameterCount()]; 522 int inputArgPos = 1; // incoming LF args to copy to target 523 int targetArgPos = 0; // fill pointer for targetArgs 524 int chunk = collectArgPos; // |headArgs| 525 System.arraycopy(names, inputArgPos, targetArgs, targetArgPos, chunk); 526 inputArgPos += chunk; 527 targetArgPos += chunk; 528 if (collectValType != void.class) { 529 targetArgs[targetArgPos++] = names[collectNamePos]; 530 } 531 chunk = collectArgCount; 532 if (retainOriginalArgs) { 533 System.arraycopy(names, inputArgPos, targetArgs, targetArgPos, chunk); 534 targetArgPos += chunk; // optionally pass on the collected chunk 535 } 536 inputArgPos += chunk; 537 chunk = targetArgs.length - targetArgPos; // all the rest 538 System.arraycopy(names, inputArgPos, targetArgs, targetArgPos, chunk); 539 assert(inputArgPos + chunk == collectNamePos); // use of rest of input args also 540 names[targetNamePos] = new Name(target, (Object[]) targetArgs); 541 542 LambdaForm form = new LambdaForm("collect", lambdaType.parameterCount(), names); 543 return SimpleMethodHandle.make(srcType, form); 544 } 545 546 static 547 MethodHandle selectAlternative(boolean testResult, MethodHandle target, MethodHandle fallback) { 548 return testResult ? target : fallback; 549 } 550 551 static MethodHandle SELECT_ALTERNATIVE; 552 static MethodHandle selectAlternative() { 553 if (SELECT_ALTERNATIVE != null) return SELECT_ALTERNATIVE; 554 try { 555 SELECT_ALTERNATIVE 556 = IMPL_LOOKUP.findStatic(MethodHandleImpl.class, "selectAlternative", 557 MethodType.methodType(MethodHandle.class, boolean.class, MethodHandle.class, MethodHandle.class)); 558 } catch (ReflectiveOperationException ex) { 559 throw new RuntimeException(ex); 560 } 561 return SELECT_ALTERNATIVE; 562 } 563 564 static 565 MethodHandle makeGuardWithTest(MethodHandle test, 566 MethodHandle target, 567 MethodHandle fallback) { 568 MethodType basicType = target.type().basicType(); 569 MethodHandle invokeBasic = MethodHandles.basicInvoker(basicType); 570 int arity = basicType.parameterCount(); 571 int extraNames = 3; 572 MethodType lambdaType = basicType.invokerType(); 573 Name[] names = arguments(extraNames, lambdaType); 574 575 Object[] testArgs = Arrays.copyOfRange(names, 1, 1 + arity, Object[].class); 576 Object[] targetArgs = Arrays.copyOfRange(names, 0, 1 + arity, Object[].class); 577 578 // call test 579 names[arity + 1] = new Name(test, testArgs); 580 581 // call selectAlternative 582 Object[] selectArgs = { names[arity + 1], target, fallback }; 583 names[arity + 2] = new Name(MethodHandleImpl.selectAlternative(), selectArgs); 584 targetArgs[0] = names[arity + 2]; 585 586 // call target or fallback 587 names[arity + 3] = new Name(new NamedFunction(invokeBasic), targetArgs); 588 589 LambdaForm form = new LambdaForm("guard", lambdaType.parameterCount(), names); 590 return SimpleMethodHandle.make(target.type(), form); 591 } 592 593 private static class GuardWithCatch { 594 private final MethodHandle target; 595 private final Class<? extends Throwable> exType; 596 private final MethodHandle catcher; 597 // FIXME: Build the control flow out of foldArguments. 598 GuardWithCatch(MethodHandle target, Class<? extends Throwable> exType, MethodHandle catcher) { 599 this.target = target; 600 this.exType = exType; 601 this.catcher = catcher; 602 } 603 @LambdaForm.Hidden 604 private Object invoke_V(Object... av) throws Throwable { 605 try { 606 return target.invokeExact(av); 607 } catch (Throwable t) { 608 if (!exType.isInstance(t)) throw t; 609 return catcher.invokeExact(t, av); 610 } 611 } 612 @LambdaForm.Hidden 613 private Object invoke_L0() throws Throwable { 614 try { 615 return target.invokeExact(); 616 } catch (Throwable t) { 617 if (!exType.isInstance(t)) throw t; 618 return catcher.invokeExact(t); 619 } 620 } 621 @LambdaForm.Hidden 622 private Object invoke_L1(Object a0) throws Throwable { 623 try { 624 return target.invokeExact(a0); 625 } catch (Throwable t) { 626 if (!exType.isInstance(t)) throw t; 627 return catcher.invokeExact(t, a0); 628 } 629 } 630 @LambdaForm.Hidden 631 private Object invoke_L2(Object a0, Object a1) throws Throwable { 632 try { 633 return target.invokeExact(a0, a1); 634 } catch (Throwable t) { 635 if (!exType.isInstance(t)) throw t; 636 return catcher.invokeExact(t, a0, a1); 637 } 638 } 639 @LambdaForm.Hidden 640 private Object invoke_L3(Object a0, Object a1, Object a2) throws Throwable { 641 try { 642 return target.invokeExact(a0, a1, a2); 643 } catch (Throwable t) { 644 if (!exType.isInstance(t)) throw t; 645 return catcher.invokeExact(t, a0, a1, a2); 646 } 647 } 648 @LambdaForm.Hidden 649 private Object invoke_L4(Object a0, Object a1, Object a2, Object a3) throws Throwable { 650 try { 651 return target.invokeExact(a0, a1, a2, a3); 652 } catch (Throwable t) { 653 if (!exType.isInstance(t)) throw t; 654 return catcher.invokeExact(t, a0, a1, a2, a3); 655 } 656 } 657 @LambdaForm.Hidden 658 private Object invoke_L5(Object a0, Object a1, Object a2, Object a3, Object a4) throws Throwable { 659 try { 660 return target.invokeExact(a0, a1, a2, a3, a4); 661 } catch (Throwable t) { 662 if (!exType.isInstance(t)) throw t; 663 return catcher.invokeExact(t, a0, a1, a2, a3, a4); 664 } 665 } 666 @LambdaForm.Hidden 667 private Object invoke_L6(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5) throws Throwable { 668 try { 669 return target.invokeExact(a0, a1, a2, a3, a4, a5); 670 } catch (Throwable t) { 671 if (!exType.isInstance(t)) throw t; 672 return catcher.invokeExact(t, a0, a1, a2, a3, a4, a5); 673 } 674 } 675 @LambdaForm.Hidden 676 private Object invoke_L7(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6) throws Throwable { 677 try { 678 return target.invokeExact(a0, a1, a2, a3, a4, a5, a6); 679 } catch (Throwable t) { 680 if (!exType.isInstance(t)) throw t; 681 return catcher.invokeExact(t, a0, a1, a2, a3, a4, a5, a6); 682 } 683 } 684 @LambdaForm.Hidden 685 private Object invoke_L8(Object a0, Object a1, Object a2, Object a3, Object a4, Object a5, Object a6, Object a7) throws Throwable { 686 try { 687 return target.invokeExact(a0, a1, a2, a3, a4, a5, a6, a7); 688 } catch (Throwable t) { 689 if (!exType.isInstance(t)) throw t; 690 return catcher.invokeExact(t, a0, a1, a2, a3, a4, a5, a6, a7); 691 } 692 } 693 static MethodHandle[] makeInvokes() { 694 ArrayList<MethodHandle> invokes = new ArrayList<>(); 695 MethodHandles.Lookup lookup = IMPL_LOOKUP; 696 for (;;) { 697 int nargs = invokes.size(); 698 String name = "invoke_L"+nargs; 699 MethodHandle invoke = null; 700 try { 701 invoke = lookup.findVirtual(GuardWithCatch.class, name, MethodType.genericMethodType(nargs)); 702 } catch (ReflectiveOperationException ex) { 703 } 704 if (invoke == null) break; 705 invokes.add(invoke); 706 } 707 assert(invokes.size() == 9); // current number of methods 708 return invokes.toArray(new MethodHandle[0]); 709 }; 710 static final MethodHandle[] INVOKES = makeInvokes(); 711 // For testing use this: 712 //static final MethodHandle[] INVOKES = Arrays.copyOf(makeInvokes(), 2); 713 static final MethodHandle VARARGS_INVOKE; 714 static { 715 try { 716 VARARGS_INVOKE = IMPL_LOOKUP.findVirtual(GuardWithCatch.class, "invoke_V", MethodType.genericMethodType(0, true)); 717 } catch (ReflectiveOperationException ex) { 718 throw uncaughtException(ex); 719 } 720 } 721 } 722 723 724 static 725 MethodHandle makeGuardWithCatch(MethodHandle target, 726 Class<? extends Throwable> exType, 727 MethodHandle catcher) { 728 MethodType type = target.type(); 729 MethodType ctype = catcher.type(); 730 int nargs = type.parameterCount(); 731 if (nargs < GuardWithCatch.INVOKES.length) { 732 MethodType gtype = type.generic(); 733 MethodType gcatchType = gtype.insertParameterTypes(0, Throwable.class); 734 // Note: convertArguments(...2) avoids interface casts present in convertArguments(...0) 735 MethodHandle gtarget = makePairwiseConvert(target, gtype, 2); 736 MethodHandle gcatcher = makePairwiseConvert(catcher, gcatchType, 2); 737 GuardWithCatch gguard = new GuardWithCatch(gtarget, exType, gcatcher); 738 if (gtarget == null || gcatcher == null) throw new InternalError(); 739 MethodHandle ginvoker = GuardWithCatch.INVOKES[nargs].bindReceiver(gguard); 740 return makePairwiseConvert(ginvoker, type, 2); 741 } else { 742 MethodHandle gtarget = makeSpreadArguments(target, Object[].class, 0, nargs); 743 catcher = catcher.asType(ctype.changeParameterType(0, Throwable.class)); 744 MethodHandle gcatcher = makeSpreadArguments(catcher, Object[].class, 1, nargs); 745 GuardWithCatch gguard = new GuardWithCatch(gtarget, exType, gcatcher); 746 if (gtarget == null || gcatcher == null) throw new InternalError(); 747 MethodHandle ginvoker = GuardWithCatch.VARARGS_INVOKE.bindReceiver(gguard); 748 return makeCollectArguments(ginvoker, ValueConversions.varargsArray(nargs), 0, false); 749 } 750 } 751 752 static 753 MethodHandle throwException(MethodType type) { 754 assert(Throwable.class.isAssignableFrom(type.parameterType(0))); 755 int arity = type.parameterCount(); 756 if (arity > 1) { 757 return throwException(type.dropParameterTypes(1, arity)).dropArguments(type, 1, arity-1); 758 } 759 return makePairwiseConvert(throwException(), type, 2); 760 } 761 762 static MethodHandle THROW_EXCEPTION; 763 static MethodHandle throwException() { 764 MethodHandle mh = THROW_EXCEPTION; 765 if (mh != null) return mh; 766 try { 767 mh 768 = IMPL_LOOKUP.findStatic(MethodHandleImpl.class, "throwException", 769 MethodType.methodType(Empty.class, Throwable.class)); 770 } catch (ReflectiveOperationException ex) { 771 throw new RuntimeException(ex); 772 } 773 THROW_EXCEPTION = mh; 774 return mh; 775 } 776 static <T extends Throwable> Empty throwException(T t) throws T { throw t; } 777 778 static MethodHandle FAKE_METHOD_HANDLE_INVOKE; 779 static 780 MethodHandle fakeMethodHandleInvoke(MemberName method) { 781 MethodType type = method.getInvocationType(); 782 assert(type.equals(MethodType.methodType(Object.class, Object[].class))); 783 MethodHandle mh = FAKE_METHOD_HANDLE_INVOKE; 784 if (mh != null) return mh; 785 mh = throwException(type.insertParameterTypes(0, UnsupportedOperationException.class)); 786 mh = mh.bindTo(new UnsupportedOperationException("cannot reflectively invoke MethodHandle")); 787 FAKE_METHOD_HANDLE_INVOKE = mh; 788 return mh; 789 } 790 791 /** 792 * Create an alias for the method handle which, when called, 793 * appears to be called from the same class loader and protection domain 794 * as hostClass. 795 * This is an expensive no-op unless the method which is called 796 * is sensitive to its caller. A small number of system methods 797 * are in this category, including Class.forName and Method.invoke. 798 */ 799 static 800 MethodHandle bindCaller(MethodHandle mh, Class<?> hostClass) { 801 return BindCaller.bindCaller(mh, hostClass); 802 } 803 804 // Put the whole mess into its own nested class. 805 // That way we can lazily load the code and set up the constants. 806 private static class BindCaller { 807 static 808 MethodHandle bindCaller(MethodHandle mh, Class<?> hostClass) { 809 // Do not use this function to inject calls into system classes. 810 if (hostClass == null) { 811 hostClass = C_Trampoline; 812 } else if (hostClass.isArray() || 813 hostClass.isPrimitive() || 814 hostClass.getName().startsWith("java.") || 815 hostClass.getName().startsWith("sun.")) { 816 throw new InternalError(); // does not happen, and should not anyway 817 } 818 // For simplicity, convert mh to a varargs-like method. 819 MethodHandle vamh = prepareForInvoker(mh); 820 // Cache the result of makeInjectedInvoker once per argument class. 821 MethodHandle bccInvoker = CV_makeInjectedInvoker.get(hostClass); 822 return restoreToType(bccInvoker.bindTo(vamh), mh.type()); 823 } 824 825 // This class ("Trampoline") is known to be inside a dead-end class loader. 826 // Inject all doubtful calls into this class. 827 private static Class<?> C_Trampoline; 828 static { 829 Class<?> tramp = null; 830 try { 831 final int FRAME_COUNT_ARG = 1; // [0] Reflection [1] Trampoline 832 java.lang.reflect.Method gcc = sun.reflect.Reflection.class.getMethod("getCallerClass", int.class); 833 tramp = (Class<?>) sun.reflect.misc.MethodUtil.invoke(gcc, null, new Object[]{ FRAME_COUNT_ARG }); 834 if (tramp.getClassLoader() == BindCaller.class.getClassLoader()) 835 throw new RuntimeException(tramp.getName()+" class loader"); 836 } catch (Throwable ex) { 837 throw new InternalError(ex); 838 } 839 C_Trampoline = tramp; 840 } 841 842 private static MethodHandle makeInjectedInvoker(Class<?> hostClass) { 843 Class<?> bcc = UNSAFE.defineAnonymousClass(hostClass, T_BYTES, null); 844 if (hostClass.getClassLoader() != bcc.getClassLoader()) 845 throw new InternalError(hostClass.getName()+" (CL)"); 846 try { 847 if (hostClass.getProtectionDomain() != bcc.getProtectionDomain()) 848 throw new InternalError(hostClass.getName()+" (PD)"); 849 } catch (SecurityException ex) { 850 // Self-check was blocked by security manager. This is OK. 851 // In fact the whole try body could be turned into an assertion. 852 } 853 try { 854 MethodHandle init = IMPL_LOOKUP.findStatic(bcc, "init", MethodType.methodType(void.class)); 855 init.invokeExact(); // force initialization of the class 856 } catch (Throwable ex) { 857 throw uncaughtException(ex); 858 } 859 MethodHandle bccInvoker; 860 try { 861 MethodType invokerMT = MethodType.methodType(Object.class, MethodHandle.class, Object[].class); 862 bccInvoker = IMPL_LOOKUP.findStatic(bcc, "invoke_V", invokerMT); 863 } catch (ReflectiveOperationException ex) { 864 throw uncaughtException(ex); 865 } 866 // Test the invoker, to ensure that it really injects into the right place. 867 try { 868 MethodHandle vamh = prepareForInvoker(MH_checkCallerClass); 869 Object ok = bccInvoker.invokeExact(vamh, new Object[]{hostClass, bcc}); 870 } catch (Throwable ex) { 871 throw new InternalError(ex); 872 } 873 return bccInvoker; 874 } 875 private static ClassValue<MethodHandle> CV_makeInjectedInvoker = new ClassValue<MethodHandle>() { 876 @Override protected MethodHandle computeValue(Class<?> hostClass) { 877 return makeInjectedInvoker(hostClass); 878 } 879 }; 880 881 // Adapt mh so that it can be called directly from an injected invoker: 882 private static MethodHandle prepareForInvoker(MethodHandle mh) { 883 mh = mh.asFixedArity(); 884 MethodType mt = mh.type(); 885 int arity = mt.parameterCount(); 886 MethodHandle vamh = mh.asType(mt.generic()); 887 vamh.internalForm().compileToBytecode(); // eliminate LFI stack frames 888 vamh = vamh.asSpreader(Object[].class, arity); 889 vamh.internalForm().compileToBytecode(); // eliminate LFI stack frames 890 return vamh; 891 } 892 893 // Undo the adapter effect of prepareForInvoker: 894 private static MethodHandle restoreToType(MethodHandle vamh, MethodType type) { 895 return vamh.asCollector(Object[].class, type.parameterCount()).asType(type); 896 } 897 898 private static final MethodHandle MH_checkCallerClass; 899 static { 900 final Class<?> THIS_CLASS = BindCaller.class; 901 assert(checkCallerClass(THIS_CLASS, THIS_CLASS)); 902 try { 903 MH_checkCallerClass = IMPL_LOOKUP 904 .findStatic(THIS_CLASS, "checkCallerClass", 905 MethodType.methodType(boolean.class, Class.class, Class.class)); 906 assert((boolean) MH_checkCallerClass.invokeExact(THIS_CLASS, THIS_CLASS)); 907 } catch (Throwable ex) { 908 throw new InternalError(ex); 909 } 910 } 911 912 private static boolean checkCallerClass(Class<?> expected, Class<?> expected2) { 913 final int FRAME_COUNT_ARG = 2; // [0] Reflection [1] BindCaller [2] Expected 914 Class<?> actual = sun.reflect.Reflection.getCallerClass(FRAME_COUNT_ARG); 915 if (actual != expected && actual != expected2) 916 throw new InternalError("found "+actual.getName()+", expected "+expected.getName() 917 +(expected == expected2 ? "" : ", or else "+expected2.getName())); 918 return true; 919 } 920 921 private static final byte[] T_BYTES; 922 static { 923 final Object[] values = {null}; 924 AccessController.doPrivileged(new PrivilegedAction<Void>() { 925 public Void run() { 926 try { 927 Class<T> tClass = T.class; 928 String tName = tClass.getName(); 929 String tResource = tName.substring(tName.lastIndexOf('.')+1)+".class"; 930 java.net.URLConnection uconn = tClass.getResource(tResource).openConnection(); 931 int len = uconn.getContentLength(); 932 byte[] bytes = new byte[len]; 933 try (java.io.InputStream str = uconn.getInputStream()) { 934 int nr = str.read(bytes); 935 if (nr != len) throw new java.io.IOException(tResource); 936 } 937 values[0] = bytes; 938 } catch (java.io.IOException ex) { 939 throw new InternalError(ex); 940 } 941 return null; 942 } 943 }); 944 T_BYTES = (byte[]) values[0]; 945 } 946 947 // The following class is used as a template for Unsafe.defineAnonymousClass: 948 private static class T { 949 static void init() { } // side effect: initializes this class 950 static Object invoke_V(MethodHandle vamh, Object[] args) throws Throwable { 951 return vamh.invokeExact(args); 952 } 953 } 954 } 955 }