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