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.LambdaForm.arguments; 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 @LambdaForm.Hidden 552 static 553 MethodHandle selectAlternative(boolean testResult, MethodHandle target, MethodHandle fallback) { 554 return testResult ? target : fallback; 555 } 556 557 static MethodHandle SELECT_ALTERNATIVE; 558 static MethodHandle selectAlternative() { 559 if (SELECT_ALTERNATIVE != null) return SELECT_ALTERNATIVE; 560 try { 561 SELECT_ALTERNATIVE 562 = IMPL_LOOKUP.findStatic(MethodHandleImpl.class, "selectAlternative", 563 MethodType.methodType(MethodHandle.class, boolean.class, MethodHandle.class, MethodHandle.class)); 564 } catch (ReflectiveOperationException ex) { 565 throw new RuntimeException(ex); 566 } 567 return SELECT_ALTERNATIVE; 568 } 569 570 static 571 MethodHandle makeGuardWithTest(MethodHandle test, 572 MethodHandle target, 573 MethodHandle fallback) { 574 MethodType basicType = target.type().basicType(); 575 MethodHandle invokeBasic = MethodHandles.basicInvoker(basicType); 576 int arity = basicType.parameterCount(); 577 int extraNames = 3; 578 MethodType lambdaType = basicType.invokerType(); 579 Name[] names = arguments(extraNames, lambdaType); 580 581 Object[] testArgs = Arrays.copyOfRange(names, 1, 1 + arity, Object[].class); 582 Object[] targetArgs = Arrays.copyOfRange(names, 0, 1 + arity, Object[].class); 583 584 // call test 585 names[arity + 1] = new Name(test, testArgs); 586 587 // call selectAlternative 588 Object[] selectArgs = { names[arity + 1], target, fallback }; 589 names[arity + 2] = new Name(MethodHandleImpl.selectAlternative(), selectArgs); 590 targetArgs[0] = names[arity + 2]; 591 592 // call target or fallback 593 names[arity + 3] = new Name(new NamedFunction(invokeBasic), targetArgs); 594 595 LambdaForm form = new LambdaForm("guard", lambdaType.parameterCount(), names); 596 return SimpleMethodHandle.make(target.type(), form); 597 } 598 599 private static LambdaForm makeGuardWithCatchForm(MethodType type) { 600 MethodType basicType = type.basicType(); 601 MethodType lambdaType = basicType.invokerType(); 602 603 LambdaForm lform; 604 final int THIS_MH = 0; // the BMH_LLL 605 final int ARG_BASE = 1; // start of incoming arguments 606 final int ARG_LIMIT = ARG_BASE + basicType.parameterCount(); 607 608 int nameCursor = ARG_LIMIT; 609 final int GET_TARGET = nameCursor++; 610 final int GET_CLASS = nameCursor++; 611 final int GET_CATCHER = nameCursor++; 612 final int BOX_ARGS = nameCursor++; 613 final int TRY_CATCH = nameCursor++; 614 final int UNBOX_RESULT = nameCursor++; 615 616 Name[] names = arguments(nameCursor - ARG_LIMIT, lambdaType); 617 618 BoundMethodHandle.SpeciesData data = BoundMethodHandle.speciesData_LLL(); 619 names[GET_TARGET] = new Name(data.getterFunction(0), names[THIS_MH]); 620 names[GET_CLASS] = new Name(data.getterFunction(1), names[THIS_MH]); 621 names[GET_CATCHER] = new Name(data.getterFunction(2), names[THIS_MH]); 622 623 // t_{i}:L=ValueConversions.array(a4:L,...) 624 Object[] args = Arrays.copyOfRange(names, ARG_BASE, ARG_LIMIT, Object[].class); 625 MethodType varargsType = type.changeReturnType(Object[].class); 626 MethodHandle varargsArray = ValueConversions.varargsArray(args.length) 627 .asType(varargsType); 628 names[BOX_ARGS] = new Name(varargsArray, args); 629 630 // t_{i+1}:L=MethodHandleImpl.guardWithCatch(a0:L, target, class, catcher, t_{i}:L); 631 Object[] gwcArgs = new Object[] {names[GET_TARGET], names[GET_CLASS], names[GET_CATCHER], names[BOX_ARGS]}; 632 names[TRY_CATCH] = new Name(MethodHandleImpl.guardWithCatch(), gwcArgs); 633 634 // t_{i+2}:L=ValueConversions.unbox(t_{i+1}) OR ValueConversions.identity(t_{i+1}) 635 if (type.returnType().isPrimitive()) { 636 names[UNBOX_RESULT] = new Name(ValueConversions.unbox(type.returnType()), 637 names[TRY_CATCH]); 638 } else { 639 names[UNBOX_RESULT] = new Name(ValueConversions.identity(), 640 names[TRY_CATCH]); 641 } 642 643 lform = new LambdaForm("guardWithCatch", lambdaType.parameterCount(), names); 644 645 //TODO: cache created lambda form on the level of basic types. Right now LF representation doesn't support that. 646 647 return lform; 648 } 649 650 static 651 MethodHandle makeGuardWithCatch(MethodHandle target, 652 Class<? extends Throwable> exType, 653 MethodHandle catcher) { 654 MethodType type = target.type(); 655 LambdaForm form = makeGuardWithCatchForm(type); 656 BoundMethodHandle.SpeciesData data = BoundMethodHandle.speciesData_LLL(); 657 BoundMethodHandle mh; 658 try { 659 mh = (BoundMethodHandle) 660 data.constructor[0].invokeBasic(type, form, (Object) target, (Object) exType, (Object) catcher); 661 } catch (Throwable ex) { 662 throw uncaughtException(ex); 663 } 664 assert(mh.type() == type); 665 return mh; 666 } 667 668 /** 669 * CatchException combinator implementation used during LambdaForm interpretation. 670 * Intrinsified during LambdaForm compilation 671 * (see {@link InvokerBytecodeGenerator#emitGuardWithCatch emitGuardWithCatch}). 672 */ 673 @LambdaForm.Hidden 674 static Object guardWithCatch(MethodHandle target, Class exType, MethodHandle catcher, 675 Object... av) throws Throwable { 676 int nargs = target.type().parameterCount(); 677 678 MethodHandle ctarget = makePairwiseConvert(target, target.type().generic(), 1); 679 MethodHandle gtarget = makeSpreadArguments(ctarget, Object[].class, 0, nargs); 680 681 MethodType ccatcherType = catcher.type().generic() 682 .changeParameterType(0, Throwable.class); 683 MethodHandle ccatcher = makePairwiseConvert(catcher, ccatcherType, 1); 684 MethodHandle gcatcher = makeSpreadArguments(ccatcher, Object[].class, 1, nargs); 685 686 try { 687 return gtarget.invokeExact(av); 688 } catch (Throwable t) { 689 if (!exType.isInstance(t)) throw t; 690 return gcatcher.invokeExact(t, av); 691 } 692 } 693 694 private static MethodHandle GUARD_WITH_CATCH; 695 static MethodHandle guardWithCatch() { 696 if (GUARD_WITH_CATCH != null) { 697 return GUARD_WITH_CATCH; 698 } 699 try { 700 GUARD_WITH_CATCH 701 = IMPL_LOOKUP.findStatic(MethodHandleImpl.class, "guardWithCatch", 702 MethodType.methodType(Object.class, MethodHandle.class, Class.class, MethodHandle.class, Object[].class)); 703 } catch (ReflectiveOperationException ex) { 704 throw new RuntimeException(ex); 705 } 706 return GUARD_WITH_CATCH; 707 } 708 709 static 710 MethodHandle throwException(MethodType type) { 711 assert(Throwable.class.isAssignableFrom(type.parameterType(0))); 712 int arity = type.parameterCount(); 713 if (arity > 1) { 714 return throwException(type.dropParameterTypes(1, arity)).dropArguments(type, 1, arity-1); 715 } 716 return makePairwiseConvert(throwException(), type, 2); 717 } 718 719 static MethodHandle THROW_EXCEPTION; 720 static MethodHandle throwException() { 721 MethodHandle mh = THROW_EXCEPTION; 722 if (mh != null) return mh; 723 try { 724 mh 725 = IMPL_LOOKUP.findStatic(MethodHandleImpl.class, "throwException", 726 MethodType.methodType(Empty.class, Throwable.class)); 727 } catch (ReflectiveOperationException ex) { 728 throw new RuntimeException(ex); 729 } 730 THROW_EXCEPTION = mh; 731 return mh; 732 } 733 static <T extends Throwable> Empty throwException(T t) throws T { throw t; } 734 735 static MethodHandle[] FAKE_METHOD_HANDLE_INVOKE = new MethodHandle[2]; 736 static MethodHandle fakeMethodHandleInvoke(MemberName method) { 737 int idx; 738 assert(method.isMethodHandleInvoke()); 739 switch (method.getName()) { 740 case "invoke": idx = 0; break; 741 case "invokeExact": idx = 1; break; 742 default: throw new InternalError(method.getName()); 743 } 744 MethodHandle mh = FAKE_METHOD_HANDLE_INVOKE[idx]; 745 if (mh != null) return mh; 746 MethodType type = MethodType.methodType(Object.class, UnsupportedOperationException.class, 747 MethodHandle.class, Object[].class); 748 mh = throwException(type); 749 mh = mh.bindTo(new UnsupportedOperationException("cannot reflectively invoke MethodHandle")); 750 if (!method.getInvocationType().equals(mh.type())) 751 throw new InternalError(method.toString()); 752 mh = mh.withInternalMemberName(method); 753 mh = mh.asVarargsCollector(Object[].class); 754 assert(method.isVarargs()); 755 FAKE_METHOD_HANDLE_INVOKE[idx] = mh; 756 return mh; 757 } 758 759 /** 760 * Create an alias for the method handle which, when called, 761 * appears to be called from the same class loader and protection domain 762 * as hostClass. 763 * This is an expensive no-op unless the method which is called 764 * is sensitive to its caller. A small number of system methods 765 * are in this category, including Class.forName and Method.invoke. 766 */ 767 static 768 MethodHandle bindCaller(MethodHandle mh, Class<?> hostClass) { 769 return BindCaller.bindCaller(mh, hostClass); 770 } 771 772 // Put the whole mess into its own nested class. 773 // That way we can lazily load the code and set up the constants. 774 private static class BindCaller { 775 static 776 MethodHandle bindCaller(MethodHandle mh, Class<?> hostClass) { 777 // Do not use this function to inject calls into system classes. 778 if (hostClass == null 779 || (hostClass.isArray() || 780 hostClass.isPrimitive() || 781 hostClass.getName().startsWith("java.") || 782 hostClass.getName().startsWith("sun."))) { 783 throw new InternalError(); // does not happen, and should not anyway 784 } 785 // For simplicity, convert mh to a varargs-like method. 786 MethodHandle vamh = prepareForInvoker(mh); 787 // Cache the result of makeInjectedInvoker once per argument class. 788 MethodHandle bccInvoker = CV_makeInjectedInvoker.get(hostClass); 789 return restoreToType(bccInvoker.bindTo(vamh), mh.type(), mh.internalMemberName(), hostClass); 790 } 791 792 private static MethodHandle makeInjectedInvoker(Class<?> hostClass) { 793 Class<?> bcc = UNSAFE.defineAnonymousClass(hostClass, T_BYTES, null); 794 if (hostClass.getClassLoader() != bcc.getClassLoader()) 795 throw new InternalError(hostClass.getName()+" (CL)"); 796 try { 797 if (hostClass.getProtectionDomain() != bcc.getProtectionDomain()) 798 throw new InternalError(hostClass.getName()+" (PD)"); 799 } catch (SecurityException ex) { 800 // Self-check was blocked by security manager. This is OK. 801 // In fact the whole try body could be turned into an assertion. 802 } 803 try { 804 MethodHandle init = IMPL_LOOKUP.findStatic(bcc, "init", MethodType.methodType(void.class)); 805 init.invokeExact(); // force initialization of the class 806 } catch (Throwable ex) { 807 throw uncaughtException(ex); 808 } 809 MethodHandle bccInvoker; 810 try { 811 MethodType invokerMT = MethodType.methodType(Object.class, MethodHandle.class, Object[].class); 812 bccInvoker = IMPL_LOOKUP.findStatic(bcc, "invoke_V", invokerMT); 813 } catch (ReflectiveOperationException ex) { 814 throw uncaughtException(ex); 815 } 816 // Test the invoker, to ensure that it really injects into the right place. 817 try { 818 MethodHandle vamh = prepareForInvoker(MH_checkCallerClass); 819 Object ok = bccInvoker.invokeExact(vamh, new Object[]{hostClass, bcc}); 820 } catch (Throwable ex) { 821 throw new InternalError(ex); 822 } 823 return bccInvoker; 824 } 825 private static ClassValue<MethodHandle> CV_makeInjectedInvoker = new ClassValue<MethodHandle>() { 826 @Override protected MethodHandle computeValue(Class<?> hostClass) { 827 return makeInjectedInvoker(hostClass); 828 } 829 }; 830 831 // Adapt mh so that it can be called directly from an injected invoker: 832 private static MethodHandle prepareForInvoker(MethodHandle mh) { 833 mh = mh.asFixedArity(); 834 MethodType mt = mh.type(); 835 int arity = mt.parameterCount(); 836 MethodHandle vamh = mh.asType(mt.generic()); 837 vamh.internalForm().compileToBytecode(); // eliminate LFI stack frames 838 vamh = vamh.asSpreader(Object[].class, arity); 839 vamh.internalForm().compileToBytecode(); // eliminate LFI stack frames 840 return vamh; 841 } 842 843 // Undo the adapter effect of prepareForInvoker: 844 private static MethodHandle restoreToType(MethodHandle vamh, MethodType type, 845 MemberName member, 846 Class<?> hostClass) { 847 MethodHandle mh = vamh.asCollector(Object[].class, type.parameterCount()); 848 mh = mh.asType(type); 849 mh = new WrappedMember(mh, type, member, hostClass); 850 return mh; 851 } 852 853 private static final MethodHandle MH_checkCallerClass; 854 static { 855 final Class<?> THIS_CLASS = BindCaller.class; 856 assert(checkCallerClass(THIS_CLASS, THIS_CLASS)); 857 try { 858 MH_checkCallerClass = IMPL_LOOKUP 859 .findStatic(THIS_CLASS, "checkCallerClass", 860 MethodType.methodType(boolean.class, Class.class, Class.class)); 861 assert((boolean) MH_checkCallerClass.invokeExact(THIS_CLASS, THIS_CLASS)); 862 } catch (Throwable ex) { 863 throw new InternalError(ex); 864 } 865 } 866 867 @CallerSensitive 868 private static boolean checkCallerClass(Class<?> expected, Class<?> expected2) { 869 // This method is called via MH_checkCallerClass and so it's 870 // correct to ask for the immediate caller here. 871 Class<?> actual = Reflection.getCallerClass(); 872 if (actual != expected && actual != expected2) 873 throw new InternalError("found "+actual.getName()+", expected "+expected.getName() 874 +(expected == expected2 ? "" : ", or else "+expected2.getName())); 875 return true; 876 } 877 878 private static final byte[] T_BYTES; 879 static { 880 final Object[] values = {null}; 881 AccessController.doPrivileged(new PrivilegedAction<Void>() { 882 public Void run() { 883 try { 884 Class<T> tClass = T.class; 885 String tName = tClass.getName(); 886 String tResource = tName.substring(tName.lastIndexOf('.')+1)+".class"; 887 java.net.URLConnection uconn = tClass.getResource(tResource).openConnection(); 888 int len = uconn.getContentLength(); 889 byte[] bytes = new byte[len]; 890 try (java.io.InputStream str = uconn.getInputStream()) { 891 int nr = str.read(bytes); 892 if (nr != len) throw new java.io.IOException(tResource); 893 } 894 values[0] = bytes; 895 } catch (java.io.IOException ex) { 896 throw new InternalError(ex); 897 } 898 return null; 899 } 900 }); 901 T_BYTES = (byte[]) values[0]; 902 } 903 904 // The following class is used as a template for Unsafe.defineAnonymousClass: 905 private static class T { 906 static void init() { } // side effect: initializes this class 907 static Object invoke_V(MethodHandle vamh, Object[] args) throws Throwable { 908 return vamh.invokeExact(args); 909 } 910 } 911 } 912 913 914 /** This subclass allows a wrapped method handle to be re-associated with an arbitrary member name. */ 915 static class WrappedMember extends MethodHandle { 916 private final MethodHandle target; 917 private final MemberName member; 918 private final Class<?> callerClass; 919 920 private WrappedMember(MethodHandle target, MethodType type, MemberName member, Class<?> callerClass) { 921 super(type, reinvokerForm(target)); 922 this.target = target; 923 this.member = member; 924 this.callerClass = callerClass; 925 } 926 927 @Override 928 MethodHandle reinvokerTarget() { 929 return target; 930 } 931 @Override 932 public MethodHandle asTypeUncached(MethodType newType) { 933 // This MH is an alias for target, except for the MemberName 934 // Drop the MemberName if there is any conversion. 935 return asTypeCache = target.asType(newType); 936 } 937 @Override 938 MemberName internalMemberName() { 939 return member; 940 } 941 @Override 942 Class<?> internalCallerClass() { 943 return callerClass; 944 } 945 @Override 946 boolean isInvokeSpecial() { 947 return target.isInvokeSpecial(); 948 } 949 @Override 950 MethodHandle viewAsType(MethodType newType) { 951 return new WrappedMember(target, newType, member, callerClass); 952 } 953 } 954 955 static MethodHandle makeWrappedMember(MethodHandle target, MemberName member) { 956 if (member.equals(target.internalMemberName())) 957 return target; 958 return new WrappedMember(target, target.type(), member, null); 959 } 960 961 }