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, Lazy.MH_castReference); 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 /** 297 * Identity function, with reference cast. 298 * @param t an arbitrary reference type 299 * @param x an arbitrary reference value 300 * @return the same value x 301 */ 302 @ForceInline 303 @SuppressWarnings("unchecked") 304 static <T,U> T castReference(Class<? extends T> t, U x) { 305 // inlined Class.cast because we can't ForceInline it 306 if (x != null && !t.isInstance(x)) 307 throw newClassCastException(t, x); 308 return (T) x; 309 } 310 311 private static ClassCastException newClassCastException(Class<?> t, Object obj) { 312 return new ClassCastException("Cannot cast " + obj.getClass().getName() + " to " + t.getName()); 313 } 314 315 static MethodHandle makeReferenceIdentity(Class<?> refType) { 316 MethodType lambdaType = MethodType.genericMethodType(1).invokerType(); 317 Name[] names = arguments(1, lambdaType); 318 names[names.length - 1] = new Name(ValueConversions.identity(), names[1]); 319 LambdaForm form = new LambdaForm("identity", lambdaType.parameterCount(), names); 320 return SimpleMethodHandle.make(MethodType.methodType(refType, refType), form); 321 } 322 323 static MethodHandle makeVarargsCollector(MethodHandle target, Class<?> arrayType) { 324 MethodType type = target.type(); 325 int last = type.parameterCount() - 1; 326 if (type.parameterType(last) != arrayType) 327 target = target.asType(type.changeParameterType(last, arrayType)); 328 target = target.asFixedArity(); // make sure this attribute is turned off 329 return new AsVarargsCollector(target, target.type(), arrayType); 330 } 331 332 static class AsVarargsCollector extends MethodHandle { 333 private final MethodHandle target; 334 private final Class<?> arrayType; 335 private /*@Stable*/ MethodHandle asCollectorCache; 336 337 AsVarargsCollector(MethodHandle target, MethodType type, Class<?> arrayType) { 338 super(type, reinvokerForm(target)); 339 this.target = target; 340 this.arrayType = arrayType; 341 this.asCollectorCache = target.asCollector(arrayType, 0); 342 } 343 344 @Override MethodHandle reinvokerTarget() { return target; } 345 346 @Override 347 public boolean isVarargsCollector() { 348 return true; 349 } 350 351 @Override 352 public MethodHandle asFixedArity() { 353 return target; 354 } 355 356 @Override 357 public MethodHandle asTypeUncached(MethodType newType) { 358 MethodType type = this.type(); 359 int collectArg = type.parameterCount() - 1; 360 int newArity = newType.parameterCount(); 361 if (newArity == collectArg+1 && 362 type.parameterType(collectArg).isAssignableFrom(newType.parameterType(collectArg))) { 363 // if arity and trailing parameter are compatible, do normal thing 364 return asTypeCache = asFixedArity().asType(newType); 365 } 366 // check cache 367 MethodHandle acc = asCollectorCache; 368 if (acc != null && acc.type().parameterCount() == newArity) 369 return asTypeCache = acc.asType(newType); 370 // build and cache a collector 371 int arrayLength = newArity - collectArg; 372 MethodHandle collector; 373 try { 374 collector = asFixedArity().asCollector(arrayType, arrayLength); 375 assert(collector.type().parameterCount() == newArity) : "newArity="+newArity+" but collector="+collector; 376 } catch (IllegalArgumentException ex) { 377 throw new WrongMethodTypeException("cannot build collector", ex); 378 } 379 asCollectorCache = collector; 380 return asTypeCache = collector.asType(newType); 381 } 382 383 @Override 384 MethodHandle setVarargs(MemberName member) { 385 if (member.isVarargs()) return this; 386 return asFixedArity(); 387 } 388 389 @Override 390 MethodHandle viewAsType(MethodType newType) { 391 if (newType.lastParameterType() != type().lastParameterType()) 392 throw new InternalError(); 393 MethodHandle newTarget = asFixedArity().viewAsType(newType); 394 // put back the varargs bit: 395 return new AsVarargsCollector(newTarget, newType, arrayType); 396 } 397 398 @Override 399 MemberName internalMemberName() { 400 return asFixedArity().internalMemberName(); 401 } 402 @Override 403 Class<?> internalCallerClass() { 404 return asFixedArity().internalCallerClass(); 405 } 406 407 /*non-public*/ 408 @Override 409 boolean isInvokeSpecial() { 410 return asFixedArity().isInvokeSpecial(); 411 } 412 413 414 @Override 415 MethodHandle bindArgument(int pos, BasicType basicType, Object value) { 416 return asFixedArity().bindArgument(pos, basicType, value); 417 } 418 419 @Override 420 MethodHandle bindReceiver(Object receiver) { 421 return asFixedArity().bindReceiver(receiver); 422 } 423 424 @Override 425 MethodHandle dropArguments(MethodType srcType, int pos, int drops) { 426 return asFixedArity().dropArguments(srcType, pos, drops); 427 } 428 429 @Override 430 MethodHandle permuteArguments(MethodType newType, int[] reorder) { 431 return asFixedArity().permuteArguments(newType, reorder); 432 } 433 } 434 435 /** Factory method: Spread selected argument. */ 436 static MethodHandle makeSpreadArguments(MethodHandle target, 437 Class<?> spreadArgType, int spreadArgPos, int spreadArgCount) { 438 MethodType targetType = target.type(); 439 440 for (int i = 0; i < spreadArgCount; i++) { 441 Class<?> arg = VerifyType.spreadArgElementType(spreadArgType, i); 442 if (arg == null) arg = Object.class; 443 targetType = targetType.changeParameterType(spreadArgPos + i, arg); 444 } 445 target = target.asType(targetType); 446 447 MethodType srcType = targetType 448 .replaceParameterTypes(spreadArgPos, spreadArgPos + spreadArgCount, spreadArgType); 449 // Now build a LambdaForm. 450 MethodType lambdaType = srcType.invokerType(); 451 Name[] names = arguments(spreadArgCount + 2, lambdaType); 452 int nameCursor = lambdaType.parameterCount(); 453 int[] indexes = new int[targetType.parameterCount()]; 454 455 for (int i = 0, argIndex = 1; i < targetType.parameterCount() + 1; i++, argIndex++) { 456 Class<?> src = lambdaType.parameterType(i); 457 if (i == spreadArgPos) { 458 // Spread the array. 459 MethodHandle aload = MethodHandles.arrayElementGetter(spreadArgType); 460 Name array = names[argIndex]; 461 names[nameCursor++] = new Name(Lazy.NF_checkSpreadArgument, array, spreadArgCount); 462 for (int j = 0; j < spreadArgCount; i++, j++) { 463 indexes[i] = nameCursor; 464 names[nameCursor++] = new Name(aload, array, j); 465 } 466 } else if (i < indexes.length) { 467 indexes[i] = argIndex; 468 } 469 } 470 assert(nameCursor == names.length-1); // leave room for the final call 471 472 // Build argument array for the call. 473 Name[] targetArgs = new Name[targetType.parameterCount()]; 474 for (int i = 0; i < targetType.parameterCount(); i++) { 475 int idx = indexes[i]; 476 targetArgs[i] = names[idx]; 477 } 478 names[names.length - 1] = new Name(target, (Object[]) targetArgs); 479 480 LambdaForm form = new LambdaForm("spread", lambdaType.parameterCount(), names); 481 return SimpleMethodHandle.make(srcType, form); 482 } 483 484 static void checkSpreadArgument(Object av, int n) { 485 if (av == null) { 486 if (n == 0) return; 487 } else if (av instanceof Object[]) { 488 int len = ((Object[])av).length; 489 if (len == n) return; 490 } else { 491 int len = java.lang.reflect.Array.getLength(av); 492 if (len == n) return; 493 } 494 // fall through to error: 495 throw newIllegalArgumentException("array is not of length "+n); 496 } 497 498 /** 499 * Pre-initialized NamedFunctions for bootstrapping purposes. 500 * Factored in an inner class to delay initialization until first usage. 501 */ 502 private static class Lazy { 503 private static final Class<?> MHI = MethodHandleImpl.class; 504 505 static final NamedFunction NF_checkSpreadArgument; 506 static final NamedFunction NF_guardWithCatch; 507 static final NamedFunction NF_selectAlternative; 508 static final NamedFunction NF_throwException; 509 510 static final MethodHandle MH_castReference; 511 512 static { 513 try { 514 NF_checkSpreadArgument = new NamedFunction(MHI.getDeclaredMethod("checkSpreadArgument", Object.class, int.class)); 515 NF_guardWithCatch = new NamedFunction(MHI.getDeclaredMethod("guardWithCatch", MethodHandle.class, Class.class, 516 MethodHandle.class, Object[].class)); 517 NF_selectAlternative = new NamedFunction(MHI.getDeclaredMethod("selectAlternative", boolean.class, MethodHandle.class, 518 MethodHandle.class)); 519 NF_throwException = new NamedFunction(MHI.getDeclaredMethod("throwException", Throwable.class)); 520 521 NF_checkSpreadArgument.resolve(); 522 NF_guardWithCatch.resolve(); 523 NF_selectAlternative.resolve(); 524 NF_throwException.resolve(); 525 526 MethodType mt = MethodType.methodType(Object.class, Class.class, Object.class); 527 MH_castReference = IMPL_LOOKUP.findStatic(MHI, "castReference", mt); 528 } catch (ReflectiveOperationException ex) { 529 throw newInternalError(ex); 530 } 531 } 532 } 533 534 /** Factory method: Collect or filter selected argument(s). */ 535 static MethodHandle makeCollectArguments(MethodHandle target, 536 MethodHandle collector, int collectArgPos, boolean retainOriginalArgs) { 537 MethodType targetType = target.type(); // (a..., c, [b...])=>r 538 MethodType collectorType = collector.type(); // (b...)=>c 539 int collectArgCount = collectorType.parameterCount(); 540 Class<?> collectValType = collectorType.returnType(); 541 int collectValCount = (collectValType == void.class ? 0 : 1); 542 MethodType srcType = targetType // (a..., [b...])=>r 543 .dropParameterTypes(collectArgPos, collectArgPos+collectValCount); 544 if (!retainOriginalArgs) { // (a..., b...)=>r 545 srcType = srcType.insertParameterTypes(collectArgPos, collectorType.parameterList()); 546 } 547 // in arglist: [0: ...keep1 | cpos: collect... | cpos+cacount: keep2... ] 548 // out arglist: [0: ...keep1 | cpos: collectVal? | cpos+cvcount: keep2... ] 549 // out(retain): [0: ...keep1 | cpos: cV? coll... | cpos+cvc+cac: keep2... ] 550 551 // Now build a LambdaForm. 552 MethodType lambdaType = srcType.invokerType(); 553 Name[] names = arguments(2, lambdaType); 554 final int collectNamePos = names.length - 2; 555 final int targetNamePos = names.length - 1; 556 557 Name[] collectorArgs = Arrays.copyOfRange(names, 1 + collectArgPos, 1 + collectArgPos + collectArgCount); 558 names[collectNamePos] = new Name(collector, (Object[]) collectorArgs); 559 560 // Build argument array for the target. 561 // Incoming LF args to copy are: [ (mh) headArgs collectArgs tailArgs ]. 562 // Output argument array is [ headArgs (collectVal)? (collectArgs)? tailArgs ]. 563 Name[] targetArgs = new Name[targetType.parameterCount()]; 564 int inputArgPos = 1; // incoming LF args to copy to target 565 int targetArgPos = 0; // fill pointer for targetArgs 566 int chunk = collectArgPos; // |headArgs| 567 System.arraycopy(names, inputArgPos, targetArgs, targetArgPos, chunk); 568 inputArgPos += chunk; 569 targetArgPos += chunk; 570 if (collectValType != void.class) { 571 targetArgs[targetArgPos++] = names[collectNamePos]; 572 } 573 chunk = collectArgCount; 574 if (retainOriginalArgs) { 575 System.arraycopy(names, inputArgPos, targetArgs, targetArgPos, chunk); 576 targetArgPos += chunk; // optionally pass on the collected chunk 577 } 578 inputArgPos += chunk; 579 chunk = targetArgs.length - targetArgPos; // all the rest 580 System.arraycopy(names, inputArgPos, targetArgs, targetArgPos, chunk); 581 assert(inputArgPos + chunk == collectNamePos); // use of rest of input args also 582 names[targetNamePos] = new Name(target, (Object[]) targetArgs); 583 584 LambdaForm form = new LambdaForm("collect", lambdaType.parameterCount(), names); 585 return SimpleMethodHandle.make(srcType, form); 586 } 587 588 @LambdaForm.Hidden 589 static 590 MethodHandle selectAlternative(boolean testResult, MethodHandle target, MethodHandle fallback) { 591 return testResult ? target : fallback; 592 } 593 594 static 595 MethodHandle makeGuardWithTest(MethodHandle test, 596 MethodHandle target, 597 MethodHandle fallback) { 598 MethodType basicType = target.type().basicType(); 599 MethodHandle invokeBasic = MethodHandles.basicInvoker(basicType); 600 int arity = basicType.parameterCount(); 601 int extraNames = 3; 602 MethodType lambdaType = basicType.invokerType(); 603 Name[] names = arguments(extraNames, lambdaType); 604 605 Object[] testArgs = Arrays.copyOfRange(names, 1, 1 + arity, Object[].class); 606 Object[] targetArgs = Arrays.copyOfRange(names, 0, 1 + arity, Object[].class); 607 608 // call test 609 names[arity + 1] = new Name(test, testArgs); 610 611 // call selectAlternative 612 Object[] selectArgs = { names[arity + 1], target, fallback }; 613 names[arity + 2] = new Name(Lazy.NF_selectAlternative, selectArgs); 614 targetArgs[0] = names[arity + 2]; 615 616 // call target or fallback 617 names[arity + 3] = new Name(new NamedFunction(invokeBasic), targetArgs); 618 619 LambdaForm form = new LambdaForm("guard", lambdaType.parameterCount(), names); 620 return SimpleMethodHandle.make(target.type(), form); 621 } 622 623 /** 624 * The LambaForm shape for catchException combinator is the following: 625 * <blockquote><pre>{@code 626 * guardWithCatch=Lambda(a0:L,a1:L,a2:L)=>{ 627 * t3:L=BoundMethodHandle$Species_LLLLL.argL0(a0:L); 628 * t4:L=BoundMethodHandle$Species_LLLLL.argL1(a0:L); 629 * t5:L=BoundMethodHandle$Species_LLLLL.argL2(a0:L); 630 * t6:L=BoundMethodHandle$Species_LLLLL.argL3(a0:L); 631 * t7:L=BoundMethodHandle$Species_LLLLL.argL4(a0:L); 632 * t8:L=MethodHandle.invokeBasic(t6:L,a1:L,a2:L); 633 * t9:L=MethodHandleImpl.guardWithCatch(t3:L,t4:L,t5:L,t8:L); 634 * t10:I=MethodHandle.invokeBasic(t7:L,t9:L);t10:I} 635 * }</pre></blockquote> 636 * 637 * argL0 and argL2 are target and catcher method handles. argL1 is exception class. 638 * argL3 and argL4 are auxiliary method handles: argL3 boxes arguments and wraps them into Object[] 639 * (ValueConversions.array()) and argL4 unboxes result if necessary (ValueConversions.unbox()). 640 * 641 * Having t8 and t10 passed outside and not hardcoded into a lambda form allows to share lambda forms 642 * among catchException combinators with the same basic type. 643 */ 644 private static LambdaForm makeGuardWithCatchForm(MethodType basicType) { 645 MethodType lambdaType = basicType.invokerType(); 646 647 LambdaForm lform = basicType.form().cachedLambdaForm(MethodTypeForm.LF_GWC); 648 if (lform != null) { 649 return lform; 650 } 651 final int THIS_MH = 0; // the BMH_LLLLL 652 final int ARG_BASE = 1; // start of incoming arguments 653 final int ARG_LIMIT = ARG_BASE + basicType.parameterCount(); 654 655 int nameCursor = ARG_LIMIT; 656 final int GET_TARGET = nameCursor++; 657 final int GET_CLASS = nameCursor++; 658 final int GET_CATCHER = nameCursor++; 659 final int GET_COLLECT_ARGS = nameCursor++; 660 final int GET_UNBOX_RESULT = nameCursor++; 661 final int BOXED_ARGS = nameCursor++; 662 final int TRY_CATCH = nameCursor++; 663 final int UNBOX_RESULT = nameCursor++; 664 665 Name[] names = arguments(nameCursor - ARG_LIMIT, lambdaType); 666 667 BoundMethodHandle.SpeciesData data = BoundMethodHandle.speciesData_LLLLL(); 668 names[GET_TARGET] = new Name(data.getterFunction(0), names[THIS_MH]); 669 names[GET_CLASS] = new Name(data.getterFunction(1), names[THIS_MH]); 670 names[GET_CATCHER] = new Name(data.getterFunction(2), names[THIS_MH]); 671 names[GET_COLLECT_ARGS] = new Name(data.getterFunction(3), names[THIS_MH]); 672 names[GET_UNBOX_RESULT] = new Name(data.getterFunction(4), names[THIS_MH]); 673 674 // FIXME: rework argument boxing/result unboxing logic for LF interpretation 675 676 // t_{i}:L=MethodHandle.invokeBasic(collectArgs:L,a1:L,...); 677 MethodType collectArgsType = basicType.changeReturnType(Object.class); 678 MethodHandle invokeBasic = MethodHandles.basicInvoker(collectArgsType); 679 Object[] args = new Object[invokeBasic.type().parameterCount()]; 680 args[0] = names[GET_COLLECT_ARGS]; 681 System.arraycopy(names, ARG_BASE, args, 1, ARG_LIMIT-ARG_BASE); 682 names[BOXED_ARGS] = new Name(new NamedFunction(invokeBasic), args); 683 684 // t_{i+1}:L=MethodHandleImpl.guardWithCatch(target:L,exType:L,catcher:L,t_{i}:L); 685 Object[] gwcArgs = new Object[] {names[GET_TARGET], names[GET_CLASS], names[GET_CATCHER], names[BOXED_ARGS]}; 686 names[TRY_CATCH] = new Name(Lazy.NF_guardWithCatch, gwcArgs); 687 688 // t_{i+2}:I=MethodHandle.invokeBasic(unbox:L,t_{i+1}:L); 689 MethodHandle invokeBasicUnbox = MethodHandles.basicInvoker(MethodType.methodType(basicType.rtype(), Object.class)); 690 Object[] unboxArgs = new Object[] {names[GET_UNBOX_RESULT], names[TRY_CATCH]}; 691 names[UNBOX_RESULT] = new Name(new NamedFunction(invokeBasicUnbox), unboxArgs); 692 693 lform = new LambdaForm("guardWithCatch", lambdaType.parameterCount(), names); 694 695 basicType.form().setCachedLambdaForm(MethodTypeForm.LF_GWC, lform); 696 return lform; 697 } 698 699 static 700 MethodHandle makeGuardWithCatch(MethodHandle target, 701 Class<? extends Throwable> exType, 702 MethodHandle catcher) { 703 MethodType type = target.type(); 704 LambdaForm form = makeGuardWithCatchForm(type.basicType()); 705 706 // Prepare auxiliary method handles used during LambdaForm interpreation. 707 // Box arguments and wrap them into Object[]: ValueConversions.array(). 708 MethodType varargsType = type.changeReturnType(Object[].class); 709 MethodHandle collectArgs = ValueConversions.varargsArray(type.parameterCount()) 710 .asType(varargsType); 711 // Result unboxing: ValueConversions.unbox() OR ValueConversions.identity() OR ValueConversions.ignore(). 712 MethodHandle unboxResult; 713 if (type.returnType().isPrimitive()) { 714 unboxResult = ValueConversions.unbox(type.returnType()); 715 } else { 716 unboxResult = ValueConversions.identity(); 717 } 718 719 BoundMethodHandle.SpeciesData data = BoundMethodHandle.speciesData_LLLLL(); 720 BoundMethodHandle mh; 721 try { 722 mh = (BoundMethodHandle) 723 data.constructor[0].invokeBasic(type, form, (Object) target, (Object) exType, (Object) catcher, 724 (Object) collectArgs, (Object) unboxResult); 725 } catch (Throwable ex) { 726 throw uncaughtException(ex); 727 } 728 assert(mh.type() == type); 729 return mh; 730 } 731 732 /** 733 * Intrinsified during LambdaForm compilation 734 * (see {@link InvokerBytecodeGenerator#emitGuardWithCatch emitGuardWithCatch}). 735 */ 736 @LambdaForm.Hidden 737 static Object guardWithCatch(MethodHandle target, Class<? extends Throwable> exType, MethodHandle catcher, 738 Object... av) throws Throwable { 739 // Use asFixedArity() to avoid unnecessary boxing of last argument for VarargsCollector case. 740 try { 741 return target.asFixedArity().invokeWithArguments(av); 742 } catch (Throwable t) { 743 if (!exType.isInstance(t)) throw t; 744 return catcher.asFixedArity().invokeWithArguments(prepend(t, av)); 745 } 746 } 747 748 /** Prepend an element {@code elem} to an {@code array}. */ 749 @LambdaForm.Hidden 750 private static Object[] prepend(Object elem, Object[] array) { 751 Object[] newArray = new Object[array.length+1]; 752 newArray[0] = elem; 753 System.arraycopy(array, 0, newArray, 1, array.length); 754 return newArray; 755 } 756 757 static 758 MethodHandle throwException(MethodType type) { 759 assert(Throwable.class.isAssignableFrom(type.parameterType(0))); 760 int arity = type.parameterCount(); 761 if (arity > 1) { 762 return throwException(type.dropParameterTypes(1, arity)).dropArguments(type, 1, arity-1); 763 } 764 return makePairwiseConvert(Lazy.NF_throwException.resolvedHandle(), type, 2); 765 } 766 767 static <T extends Throwable> Empty throwException(T t) throws T { throw t; } 768 769 static MethodHandle[] FAKE_METHOD_HANDLE_INVOKE = new MethodHandle[2]; 770 static MethodHandle fakeMethodHandleInvoke(MemberName method) { 771 int idx; 772 assert(method.isMethodHandleInvoke()); 773 switch (method.getName()) { 774 case "invoke": idx = 0; break; 775 case "invokeExact": idx = 1; break; 776 default: throw new InternalError(method.getName()); 777 } 778 MethodHandle mh = FAKE_METHOD_HANDLE_INVOKE[idx]; 779 if (mh != null) return mh; 780 MethodType type = MethodType.methodType(Object.class, UnsupportedOperationException.class, 781 MethodHandle.class, Object[].class); 782 mh = throwException(type); 783 mh = mh.bindTo(new UnsupportedOperationException("cannot reflectively invoke MethodHandle")); 784 if (!method.getInvocationType().equals(mh.type())) 785 throw new InternalError(method.toString()); 786 mh = mh.withInternalMemberName(method); 787 mh = mh.asVarargsCollector(Object[].class); 788 assert(method.isVarargs()); 789 FAKE_METHOD_HANDLE_INVOKE[idx] = mh; 790 return mh; 791 } 792 793 /** 794 * Create an alias for the method handle which, when called, 795 * appears to be called from the same class loader and protection domain 796 * as hostClass. 797 * This is an expensive no-op unless the method which is called 798 * is sensitive to its caller. A small number of system methods 799 * are in this category, including Class.forName and Method.invoke. 800 */ 801 static 802 MethodHandle bindCaller(MethodHandle mh, Class<?> hostClass) { 803 return BindCaller.bindCaller(mh, hostClass); 804 } 805 806 // Put the whole mess into its own nested class. 807 // That way we can lazily load the code and set up the constants. 808 private static class BindCaller { 809 static 810 MethodHandle bindCaller(MethodHandle mh, Class<?> hostClass) { 811 // Do not use this function to inject calls into system classes. 812 if (hostClass == null 813 || (hostClass.isArray() || 814 hostClass.isPrimitive() || 815 hostClass.getName().startsWith("java.") || 816 hostClass.getName().startsWith("sun."))) { 817 throw new InternalError(); // does not happen, and should not anyway 818 } 819 // For simplicity, convert mh to a varargs-like method. 820 MethodHandle vamh = prepareForInvoker(mh); 821 // Cache the result of makeInjectedInvoker once per argument class. 822 MethodHandle bccInvoker = CV_makeInjectedInvoker.get(hostClass); 823 return restoreToType(bccInvoker.bindTo(vamh), mh.type(), mh.internalMemberName(), hostClass); 824 } 825 826 private static MethodHandle makeInjectedInvoker(Class<?> hostClass) { 827 Class<?> bcc = UNSAFE.defineAnonymousClass(hostClass, T_BYTES, null); 828 if (hostClass.getClassLoader() != bcc.getClassLoader()) 829 throw new InternalError(hostClass.getName()+" (CL)"); 830 try { 831 if (hostClass.getProtectionDomain() != bcc.getProtectionDomain()) 832 throw new InternalError(hostClass.getName()+" (PD)"); 833 } catch (SecurityException ex) { 834 // Self-check was blocked by security manager. This is OK. 835 // In fact the whole try body could be turned into an assertion. 836 } 837 try { 838 MethodHandle init = IMPL_LOOKUP.findStatic(bcc, "init", MethodType.methodType(void.class)); 839 init.invokeExact(); // force initialization of the class 840 } catch (Throwable ex) { 841 throw uncaughtException(ex); 842 } 843 MethodHandle bccInvoker; 844 try { 845 MethodType invokerMT = MethodType.methodType(Object.class, MethodHandle.class, Object[].class); 846 bccInvoker = IMPL_LOOKUP.findStatic(bcc, "invoke_V", invokerMT); 847 } catch (ReflectiveOperationException ex) { 848 throw uncaughtException(ex); 849 } 850 // Test the invoker, to ensure that it really injects into the right place. 851 try { 852 MethodHandle vamh = prepareForInvoker(MH_checkCallerClass); 853 Object ok = bccInvoker.invokeExact(vamh, new Object[]{hostClass, bcc}); 854 } catch (Throwable ex) { 855 throw new InternalError(ex); 856 } 857 return bccInvoker; 858 } 859 private static ClassValue<MethodHandle> CV_makeInjectedInvoker = new ClassValue<MethodHandle>() { 860 @Override protected MethodHandle computeValue(Class<?> hostClass) { 861 return makeInjectedInvoker(hostClass); 862 } 863 }; 864 865 // Adapt mh so that it can be called directly from an injected invoker: 866 private static MethodHandle prepareForInvoker(MethodHandle mh) { 867 mh = mh.asFixedArity(); 868 MethodType mt = mh.type(); 869 int arity = mt.parameterCount(); 870 MethodHandle vamh = mh.asType(mt.generic()); 871 vamh.internalForm().compileToBytecode(); // eliminate LFI stack frames 872 vamh = vamh.asSpreader(Object[].class, arity); 873 vamh.internalForm().compileToBytecode(); // eliminate LFI stack frames 874 return vamh; 875 } 876 877 // Undo the adapter effect of prepareForInvoker: 878 private static MethodHandle restoreToType(MethodHandle vamh, MethodType type, 879 MemberName member, 880 Class<?> hostClass) { 881 MethodHandle mh = vamh.asCollector(Object[].class, type.parameterCount()); 882 mh = mh.asType(type); 883 mh = new WrappedMember(mh, type, member, hostClass); 884 return mh; 885 } 886 887 private static final MethodHandle MH_checkCallerClass; 888 static { 889 final Class<?> THIS_CLASS = BindCaller.class; 890 assert(checkCallerClass(THIS_CLASS, THIS_CLASS)); 891 try { 892 MH_checkCallerClass = IMPL_LOOKUP 893 .findStatic(THIS_CLASS, "checkCallerClass", 894 MethodType.methodType(boolean.class, Class.class, Class.class)); 895 assert((boolean) MH_checkCallerClass.invokeExact(THIS_CLASS, THIS_CLASS)); 896 } catch (Throwable ex) { 897 throw new InternalError(ex); 898 } 899 } 900 901 @CallerSensitive 902 private static boolean checkCallerClass(Class<?> expected, Class<?> expected2) { 903 // This method is called via MH_checkCallerClass and so it's 904 // correct to ask for the immediate caller here. 905 Class<?> actual = Reflection.getCallerClass(); 906 if (actual != expected && actual != expected2) 907 throw new InternalError("found "+actual.getName()+", expected "+expected.getName() 908 +(expected == expected2 ? "" : ", or else "+expected2.getName())); 909 return true; 910 } 911 912 private static final byte[] T_BYTES; 913 static { 914 final Object[] values = {null}; 915 AccessController.doPrivileged(new PrivilegedAction<Void>() { 916 public Void run() { 917 try { 918 Class<T> tClass = T.class; 919 String tName = tClass.getName(); 920 String tResource = tName.substring(tName.lastIndexOf('.')+1)+".class"; 921 java.net.URLConnection uconn = tClass.getResource(tResource).openConnection(); 922 int len = uconn.getContentLength(); 923 byte[] bytes = new byte[len]; 924 try (java.io.InputStream str = uconn.getInputStream()) { 925 int nr = str.read(bytes); 926 if (nr != len) throw new java.io.IOException(tResource); 927 } 928 values[0] = bytes; 929 } catch (java.io.IOException ex) { 930 throw new InternalError(ex); 931 } 932 return null; 933 } 934 }); 935 T_BYTES = (byte[]) values[0]; 936 } 937 938 // The following class is used as a template for Unsafe.defineAnonymousClass: 939 private static class T { 940 static void init() { } // side effect: initializes this class 941 static Object invoke_V(MethodHandle vamh, Object[] args) throws Throwable { 942 return vamh.invokeExact(args); 943 } 944 } 945 } 946 947 948 /** This subclass allows a wrapped method handle to be re-associated with an arbitrary member name. */ 949 static class WrappedMember extends MethodHandle { 950 private final MethodHandle target; 951 private final MemberName member; 952 private final Class<?> callerClass; 953 954 private WrappedMember(MethodHandle target, MethodType type, MemberName member, Class<?> callerClass) { 955 super(type, reinvokerForm(target)); 956 this.target = target; 957 this.member = member; 958 this.callerClass = callerClass; 959 } 960 961 @Override 962 MethodHandle reinvokerTarget() { 963 return target; 964 } 965 @Override 966 public MethodHandle asTypeUncached(MethodType newType) { 967 // This MH is an alias for target, except for the MemberName 968 // Drop the MemberName if there is any conversion. 969 return asTypeCache = target.asType(newType); 970 } 971 @Override 972 MemberName internalMemberName() { 973 return member; 974 } 975 @Override 976 Class<?> internalCallerClass() { 977 return callerClass; 978 } 979 @Override 980 boolean isInvokeSpecial() { 981 return target.isInvokeSpecial(); 982 } 983 @Override 984 MethodHandle viewAsType(MethodType newType) { 985 return new WrappedMember(target, newType, member, callerClass); 986 } 987 } 988 989 static MethodHandle makeWrappedMember(MethodHandle target, MemberName member) { 990 if (member.equals(target.internalMemberName())) 991 return target; 992 return new WrappedMember(target, target.type(), member, null); 993 } 994 995 }