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