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