202 }
203 return count;
204 }
205
206 static MethodHandle makePairwiseConvertByEditor(MethodHandle target, MethodType srcType,
207 boolean strict, boolean monobox) {
208 Object[] convSpecs = computeValueConversions(srcType, target.type(), strict, monobox);
209 int convCount = countNonNull(convSpecs);
210 if (convCount == 0)
211 return target.viewAsType(srcType, strict);
212 MethodType basicSrcType = srcType.basicType();
213 MethodType midType = target.type().basicType();
214 BoundMethodHandle mh = target.rebind();
215 // FIXME: Reduce number of bindings when there is more than one Class conversion.
216 // FIXME: Reduce number of bindings when there are repeated conversions.
217 for (int i = 0; i < convSpecs.length-1; i++) {
218 Object convSpec = convSpecs[i];
219 if (convSpec == null) continue;
220 MethodHandle fn;
221 if (convSpec instanceof Class) {
222 fn = Lazy.MH_cast.bindTo(convSpec);
223 } else {
224 fn = (MethodHandle) convSpec;
225 }
226 Class<?> newType = basicSrcType.parameterType(i);
227 if (--convCount == 0)
228 midType = srcType;
229 else
230 midType = midType.changeParameterType(i, newType);
231 LambdaForm form2 = mh.editor().filterArgumentForm(1+i, BasicType.basicType(newType));
232 mh = mh.copyWithExtendL(midType, form2, fn);
233 mh = mh.rebind();
234 }
235 Object convSpec = convSpecs[convSpecs.length-1];
236 if (convSpec != null) {
237 MethodHandle fn;
238 if (convSpec instanceof Class) {
239 if (convSpec == void.class)
240 fn = null;
241 else
242 fn = Lazy.MH_cast.bindTo(convSpec);
243 } else {
244 fn = (MethodHandle) convSpec;
245 }
246 Class<?> newType = basicSrcType.returnType();
247 assert(--convCount == 0);
248 midType = srcType;
249 if (fn != null) {
250 mh = mh.rebind(); // rebind if too complex
251 LambdaForm form2 = mh.editor().filterReturnForm(BasicType.basicType(newType), false);
252 mh = mh.copyWithExtendL(midType, form2, fn);
253 } else {
254 LambdaForm form2 = mh.editor().filterReturnForm(BasicType.basicType(newType), true);
255 mh = mh.copyWith(midType, form2);
256 }
257 }
258 assert(convCount == 0);
259 assert(mh.type().equals(srcType));
260 return mh;
261 }
262
285 // Now build a LambdaForm.
286 MethodType lambdaType = srcType.basicType().invokerType();
287 Name[] names = arguments(NAME_LIMIT - INARG_LIMIT, lambdaType);
288
289 // Collect the arguments to the outgoing call, maybe with conversions:
290 final int OUTARG_BASE = 0; // target MH is Name.function, name Name.arguments[0]
291 Object[] outArgs = new Object[OUTARG_BASE + INARG_COUNT];
292
293 int nameCursor = INARG_LIMIT;
294 for (int i = 0; i < INARG_COUNT; i++) {
295 Object convSpec = convSpecs[i];
296 if (convSpec == null) {
297 // do nothing: difference is trivial
298 outArgs[OUTARG_BASE + i] = names[INARG_BASE + i];
299 continue;
300 }
301
302 Name conv;
303 if (convSpec instanceof Class) {
304 Class<?> convClass = (Class<?>) convSpec;
305 conv = new Name(Lazy.MH_cast, convClass, names[INARG_BASE + i]);
306 } else {
307 MethodHandle fn = (MethodHandle) convSpec;
308 conv = new Name(fn, names[INARG_BASE + i]);
309 }
310 assert(names[nameCursor] == null);
311 names[nameCursor++] = conv;
312 assert(outArgs[OUTARG_BASE + i] == null);
313 outArgs[OUTARG_BASE + i] = conv;
314 }
315
316 // Build argument array for the call.
317 assert(nameCursor == OUT_CALL);
318 names[OUT_CALL] = new Name(target, outArgs);
319
320 Object convSpec = convSpecs[INARG_COUNT];
321 if (!retConv) {
322 assert(OUT_CALL == names.length-1);
323 } else {
324 Name conv;
325 if (convSpec == void.class) {
326 conv = new Name(LambdaForm.constantZero(BasicType.basicType(srcType.returnType())));
327 } else if (convSpec instanceof Class) {
328 Class<?> convClass = (Class<?>) convSpec;
329 conv = new Name(Lazy.MH_cast, convClass, names[OUT_CALL]);
330 } else {
331 MethodHandle fn = (MethodHandle) convSpec;
332 if (fn.type().parameterCount() == 0)
333 conv = new Name(fn); // don't pass retval to void conversion
334 else
335 conv = new Name(fn, names[OUT_CALL]);
336 }
337 assert(names[RETURN_CONV] == null);
338 names[RETURN_CONV] = conv;
339 assert(RETURN_CONV == names.length-1);
340 }
341
342 LambdaForm form = new LambdaForm("convert", lambdaType.parameterCount(), names, RESULT);
343 return SimpleMethodHandle.make(srcType, form);
344 }
345
346 static Object[] computeValueConversions(MethodType srcType, MethodType dstType,
347 boolean strict, boolean monobox) {
348 final int INARG_COUNT = srcType.parameterCount();
349 Object[] convSpecs = new Object[INARG_COUNT+1];
512 Class<?> arg = VerifyType.spreadArgElementType(spreadArgType, i);
513 if (arg == null) arg = Object.class;
514 targetType = targetType.changeParameterType(spreadArgPos + i, arg);
515 }
516 target = target.asType(targetType);
517
518 MethodType srcType = targetType
519 .replaceParameterTypes(spreadArgPos, spreadArgPos + spreadArgCount, spreadArgType);
520 // Now build a LambdaForm.
521 MethodType lambdaType = srcType.invokerType();
522 Name[] names = arguments(spreadArgCount + 2, lambdaType);
523 int nameCursor = lambdaType.parameterCount();
524 int[] indexes = new int[targetType.parameterCount()];
525
526 for (int i = 0, argIndex = 1; i < targetType.parameterCount() + 1; i++, argIndex++) {
527 Class<?> src = lambdaType.parameterType(i);
528 if (i == spreadArgPos) {
529 // Spread the array.
530 MethodHandle aload = MethodHandles.arrayElementGetter(spreadArgType);
531 Name array = names[argIndex];
532 names[nameCursor++] = new Name(Lazy.NF_checkSpreadArgument, array, spreadArgCount);
533 for (int j = 0; j < spreadArgCount; i++, j++) {
534 indexes[i] = nameCursor;
535 names[nameCursor++] = new Name(aload, array, j);
536 }
537 } else if (i < indexes.length) {
538 indexes[i] = argIndex;
539 }
540 }
541 assert(nameCursor == names.length-1); // leave room for the final call
542
543 // Build argument array for the call.
544 Name[] targetArgs = new Name[targetType.parameterCount()];
545 for (int i = 0; i < targetType.parameterCount(); i++) {
546 int idx = indexes[i];
547 targetArgs[i] = names[idx];
548 }
549 names[names.length - 1] = new Name(target, (Object[]) targetArgs);
550
551 LambdaForm form = new LambdaForm("spread", lambdaType.parameterCount(), names);
552 return SimpleMethodHandle.make(srcType, form);
553 }
554
555 static void checkSpreadArgument(Object av, int n) {
556 if (av == null) {
557 if (n == 0) return;
558 } else if (av instanceof Object[]) {
559 int len = ((Object[])av).length;
560 if (len == n) return;
561 } else {
562 int len = java.lang.reflect.Array.getLength(av);
563 if (len == n) return;
564 }
565 // fall through to error:
566 throw newIllegalArgumentException("array is not of length "+n);
567 }
568
569 /**
570 * Pre-initialized NamedFunctions for bootstrapping purposes.
571 * Factored in an inner class to delay initialization until first usage.
572 */
573 static class Lazy {
574 private static final Class<?> MHI = MethodHandleImpl.class;
575 private static final Class<?> CLS = Class.class;
576
577 private static final MethodHandle[] ARRAYS;
578 private static final MethodHandle[] FILL_ARRAYS;
579
580 static final NamedFunction NF_checkSpreadArgument;
581 static final NamedFunction NF_guardWithCatch;
582 static final NamedFunction NF_throwException;
583 static final NamedFunction NF_profileBoolean;
584
585 static final MethodHandle MH_cast;
586 static final MethodHandle MH_selectAlternative;
587 static final MethodHandle MH_copyAsPrimitiveArray;
588 static final MethodHandle MH_fillNewTypedArray;
589 static final MethodHandle MH_fillNewArray;
590 static final MethodHandle MH_arrayIdentity;
591
592 static {
593 ARRAYS = makeArrays();
594 FILL_ARRAYS = makeFillArrays();
595
596 try {
597 NF_checkSpreadArgument = new NamedFunction(MHI.getDeclaredMethod("checkSpreadArgument", Object.class, int.class));
598 NF_guardWithCatch = new NamedFunction(MHI.getDeclaredMethod("guardWithCatch", MethodHandle.class, Class.class,
599 MethodHandle.class, Object[].class));
600 NF_throwException = new NamedFunction(MHI.getDeclaredMethod("throwException", Throwable.class));
601 NF_profileBoolean = new NamedFunction(MHI.getDeclaredMethod("profileBoolean", boolean.class, int[].class));
602
603 NF_checkSpreadArgument.resolve();
604 NF_guardWithCatch.resolve();
605 NF_throwException.resolve();
606 NF_profileBoolean.resolve();
607
608 MH_cast = IMPL_LOOKUP.findVirtual(CLS, "cast",
609 MethodType.methodType(Object.class, Object.class));
610 MH_copyAsPrimitiveArray = IMPL_LOOKUP.findStatic(MHI, "copyAsPrimitiveArray",
611 MethodType.methodType(Object.class, Wrapper.class, Object[].class));
612 MH_arrayIdentity = IMPL_LOOKUP.findStatic(MHI, "identity",
613 MethodType.methodType(Object[].class, Object[].class));
614 MH_fillNewArray = IMPL_LOOKUP.findStatic(MHI, "fillNewArray",
615 MethodType.methodType(Object[].class, Integer.class, Object[].class));
616 MH_fillNewTypedArray = IMPL_LOOKUP.findStatic(MHI, "fillNewTypedArray",
617 MethodType.methodType(Object[].class, Object[].class, Integer.class, Object[].class));
618
619 MH_selectAlternative = makeIntrinsic(
620 IMPL_LOOKUP.findStatic(MHI, "selectAlternative",
621 MethodType.methodType(MethodHandle.class, boolean.class, MethodHandle.class, MethodHandle.class)),
622 Intrinsic.SELECT_ALTERNATIVE);
623 } catch (ReflectiveOperationException ex) {
624 throw newInternalError(ex);
625 }
626 }
627 }
628
629 /** Factory method: Collect or filter selected argument(s). */
630 static MethodHandle makeCollectArguments(MethodHandle target,
631 MethodHandle collector, int collectArgPos, boolean retainOriginalArgs) {
632 MethodType targetType = target.type(); // (a..., c, [b...])=>r
633 MethodType collectorType = collector.type(); // (b...)=>c
634 int collectArgCount = collectorType.parameterCount();
635 Class<?> collectValType = collectorType.returnType();
636 int collectValCount = (collectValType == void.class ? 0 : 1);
637 MethodType srcType = targetType // (a..., [b...])=>r
638 .dropParameterTypes(collectArgPos, collectArgPos+collectValCount);
639 if (!retainOriginalArgs) { // (a..., b...)=>r
640 srcType = srcType.insertParameterTypes(collectArgPos, collectorType.parameterList());
641 }
642 // in arglist: [0: ...keep1 | cpos: collect... | cpos+cacount: keep2... ]
643 // out arglist: [0: ...keep1 | cpos: collectVal? | cpos+cvcount: keep2... ]
644 // out(retain): [0: ...keep1 | cpos: cV? coll... | cpos+cvc+cac: keep2... ]
645
646 // Now build a LambdaForm.
647 MethodType lambdaType = srcType.invokerType();
648 Name[] names = arguments(2, lambdaType);
894
895 BoundMethodHandle.SpeciesData data =
896 (GET_COUNTERS != -1) ? BoundMethodHandle.speciesData_LLLL()
897 : BoundMethodHandle.speciesData_LLL();
898 names[THIS_MH] = names[THIS_MH].withConstraint(data);
899 names[GET_TEST] = new Name(data.getterFunction(0), names[THIS_MH]);
900 names[GET_TARGET] = new Name(data.getterFunction(1), names[THIS_MH]);
901 names[GET_FALLBACK] = new Name(data.getterFunction(2), names[THIS_MH]);
902 if (GET_COUNTERS != -1) {
903 names[GET_COUNTERS] = new Name(data.getterFunction(3), names[THIS_MH]);
904 }
905 Object[] invokeArgs = Arrays.copyOfRange(names, 0, ARG_LIMIT, Object[].class);
906
907 // call test
908 MethodType testType = basicType.changeReturnType(boolean.class).basicType();
909 invokeArgs[0] = names[GET_TEST];
910 names[CALL_TEST] = new Name(testType, invokeArgs);
911
912 // profile branch
913 if (PROFILE != -1) {
914 names[PROFILE] = new Name(Lazy.NF_profileBoolean, names[CALL_TEST], names[GET_COUNTERS]);
915 }
916 // call selectAlternative
917 names[SELECT_ALT] = new Name(Lazy.MH_selectAlternative, names[TEST], names[GET_TARGET], names[GET_FALLBACK]);
918
919 // call target or fallback
920 invokeArgs[0] = names[SELECT_ALT];
921 names[CALL_TARGET] = new Name(basicType, invokeArgs);
922
923 lform = new LambdaForm("guard", lambdaType.parameterCount(), names, /*forceInline=*/true);
924
925 return basicType.form().setCachedLambdaForm(MethodTypeForm.LF_GWT, lform);
926 }
927
928 /**
929 * The LambdaForm shape for catchException combinator is the following:
930 * <blockquote><pre>{@code
931 * guardWithCatch=Lambda(a0:L,a1:L,a2:L)=>{
932 * t3:L=BoundMethodHandle$Species_LLLLL.argL0(a0:L);
933 * t4:L=BoundMethodHandle$Species_LLLLL.argL1(a0:L);
934 * t5:L=BoundMethodHandle$Species_LLLLL.argL2(a0:L);
935 * t6:L=BoundMethodHandle$Species_LLLLL.argL3(a0:L);
936 * t7:L=BoundMethodHandle$Species_LLLLL.argL4(a0:L);
937 * t8:L=MethodHandle.invokeBasic(t6:L,a1:L,a2:L);
972 BoundMethodHandle.SpeciesData data = BoundMethodHandle.speciesData_LLLLL();
973 names[THIS_MH] = names[THIS_MH].withConstraint(data);
974 names[GET_TARGET] = new Name(data.getterFunction(0), names[THIS_MH]);
975 names[GET_CLASS] = new Name(data.getterFunction(1), names[THIS_MH]);
976 names[GET_CATCHER] = new Name(data.getterFunction(2), names[THIS_MH]);
977 names[GET_COLLECT_ARGS] = new Name(data.getterFunction(3), names[THIS_MH]);
978 names[GET_UNBOX_RESULT] = new Name(data.getterFunction(4), names[THIS_MH]);
979
980 // FIXME: rework argument boxing/result unboxing logic for LF interpretation
981
982 // t_{i}:L=MethodHandle.invokeBasic(collectArgs:L,a1:L,...);
983 MethodType collectArgsType = basicType.changeReturnType(Object.class);
984 MethodHandle invokeBasic = MethodHandles.basicInvoker(collectArgsType);
985 Object[] args = new Object[invokeBasic.type().parameterCount()];
986 args[0] = names[GET_COLLECT_ARGS];
987 System.arraycopy(names, ARG_BASE, args, 1, ARG_LIMIT-ARG_BASE);
988 names[BOXED_ARGS] = new Name(makeIntrinsic(invokeBasic, Intrinsic.GUARD_WITH_CATCH), args);
989
990 // t_{i+1}:L=MethodHandleImpl.guardWithCatch(target:L,exType:L,catcher:L,t_{i}:L);
991 Object[] gwcArgs = new Object[] {names[GET_TARGET], names[GET_CLASS], names[GET_CATCHER], names[BOXED_ARGS]};
992 names[TRY_CATCH] = new Name(Lazy.NF_guardWithCatch, gwcArgs);
993
994 // t_{i+2}:I=MethodHandle.invokeBasic(unbox:L,t_{i+1}:L);
995 MethodHandle invokeBasicUnbox = MethodHandles.basicInvoker(MethodType.methodType(basicType.rtype(), Object.class));
996 Object[] unboxArgs = new Object[] {names[GET_UNBOX_RESULT], names[TRY_CATCH]};
997 names[UNBOX_RESULT] = new Name(invokeBasicUnbox, unboxArgs);
998
999 lform = new LambdaForm("guardWithCatch", lambdaType.parameterCount(), names);
1000
1001 return basicType.form().setCachedLambdaForm(MethodTypeForm.LF_GWC, lform);
1002 }
1003
1004 static
1005 MethodHandle makeGuardWithCatch(MethodHandle target,
1006 Class<? extends Throwable> exType,
1007 MethodHandle catcher) {
1008 MethodType type = target.type();
1009 LambdaForm form = makeGuardWithCatchForm(type.basicType());
1010
1011 // Prepare auxiliary method handles used during LambdaForm interpretation.
1012 // Box arguments and wrap them into Object[]: ValueConversions.array().
1056 }
1057
1058 /** Prepend an element {@code elem} to an {@code array}. */
1059 @LambdaForm.Hidden
1060 private static Object[] prepend(Object elem, Object[] array) {
1061 Object[] newArray = new Object[array.length+1];
1062 newArray[0] = elem;
1063 System.arraycopy(array, 0, newArray, 1, array.length);
1064 return newArray;
1065 }
1066
1067 static
1068 MethodHandle throwException(MethodType type) {
1069 assert(Throwable.class.isAssignableFrom(type.parameterType(0)));
1070 int arity = type.parameterCount();
1071 if (arity > 1) {
1072 MethodHandle mh = throwException(type.dropParameterTypes(1, arity));
1073 mh = MethodHandles.dropArguments(mh, 1, type.parameterList().subList(1, arity));
1074 return mh;
1075 }
1076 return makePairwiseConvert(Lazy.NF_throwException.resolvedHandle(), type, false, true);
1077 }
1078
1079 static <T extends Throwable> Empty throwException(T t) throws T { throw t; }
1080
1081 static MethodHandle[] FAKE_METHOD_HANDLE_INVOKE = new MethodHandle[2];
1082 static MethodHandle fakeMethodHandleInvoke(MemberName method) {
1083 int idx;
1084 assert(method.isMethodHandleInvoke());
1085 switch (method.getName()) {
1086 case "invoke": idx = 0; break;
1087 case "invokeExact": idx = 1; break;
1088 default: throw new InternalError(method.getName());
1089 }
1090 MethodHandle mh = FAKE_METHOD_HANDLE_INVOKE[idx];
1091 if (mh != null) return mh;
1092 MethodType type = MethodType.methodType(Object.class, UnsupportedOperationException.class,
1093 MethodHandle.class, Object[].class);
1094 mh = throwException(type);
1095 mh = mh.bindTo(new UnsupportedOperationException("cannot reflectively invoke MethodHandle"));
1096 if (!method.getInvocationType().equals(mh.type()))
1404 { return makeArray(a0, a1, a2, a3, a4); }
1405 private static Object[] array(Object a0, Object a1, Object a2, Object a3,
1406 Object a4, Object a5)
1407 { return makeArray(a0, a1, a2, a3, a4, a5); }
1408 private static Object[] array(Object a0, Object a1, Object a2, Object a3,
1409 Object a4, Object a5, Object a6)
1410 { return makeArray(a0, a1, a2, a3, a4, a5, a6); }
1411 private static Object[] array(Object a0, Object a1, Object a2, Object a3,
1412 Object a4, Object a5, Object a6, Object a7)
1413 { return makeArray(a0, a1, a2, a3, a4, a5, a6, a7); }
1414 private static Object[] array(Object a0, Object a1, Object a2, Object a3,
1415 Object a4, Object a5, Object a6, Object a7,
1416 Object a8)
1417 { return makeArray(a0, a1, a2, a3, a4, a5, a6, a7, a8); }
1418 private static Object[] array(Object a0, Object a1, Object a2, Object a3,
1419 Object a4, Object a5, Object a6, Object a7,
1420 Object a8, Object a9)
1421 { return makeArray(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9); }
1422
1423 private static final int ARRAYS_COUNT = 11;
1424
1425 private static MethodHandle[] makeArrays() {
1426 MethodHandle[] mhs = new MethodHandle[MAX_ARITY + 1];
1427 for (int i = 0; i < ARRAYS_COUNT; i++) {
1428 MethodHandle mh = findCollector("array", i, Object[].class);
1429 mh = makeIntrinsic(mh, Intrinsic.NEW_ARRAY);
1430 mhs[i] = mh;
1431 }
1432 assert(assertArrayMethodCount(mhs));
1433 return mhs;
1434 }
1435
1436 private static boolean assertArrayMethodCount(MethodHandle[] mhs) {
1437 assert(findCollector("array", ARRAYS_COUNT, Object[].class) == null);
1438 for (int i = 0; i < ARRAYS_COUNT; i++) {
1439 assert(mhs[i] != null);
1440 }
1441 return true;
1442 }
1443
1444 // filling versions of the above:
1445 // using Integer len instead of int len and no varargs to avoid bootstrapping problems
1446 private static Object[] fillNewArray(Integer len, Object[] /*not ...*/ args) {
1447 Object[] a = new Object[len];
1448 fillWithArguments(a, 0, args);
1449 return a;
1450 }
1451 private static Object[] fillNewTypedArray(Object[] example, Integer len, Object[] /*not ...*/ args) {
1452 Object[] a = Arrays.copyOf(example, len);
1453 assert(a.getClass() != Object[].class);
1454 fillWithArguments(a, 0, args);
1455 return a;
1456 }
1457 private static void fillWithArguments(Object[] a, int pos, Object... args) {
1458 System.arraycopy(args, 0, a, pos, args.length);
1459 }
1460 // using Integer pos instead of int pos to avoid bootstrapping problems
1461 private static Object[] fillArray(Integer pos, Object[] a, Object a0)
1462 { fillWithArguments(a, pos, a0); return a; }
1471 { fillWithArguments(a, pos, a0, a1, a2, a3, a4); return a; }
1472 private static Object[] fillArray(Integer pos, Object[] a, Object a0, Object a1, Object a2, Object a3,
1473 Object a4, Object a5)
1474 { fillWithArguments(a, pos, a0, a1, a2, a3, a4, a5); return a; }
1475 private static Object[] fillArray(Integer pos, Object[] a, Object a0, Object a1, Object a2, Object a3,
1476 Object a4, Object a5, Object a6)
1477 { fillWithArguments(a, pos, a0, a1, a2, a3, a4, a5, a6); return a; }
1478 private static Object[] fillArray(Integer pos, Object[] a, Object a0, Object a1, Object a2, Object a3,
1479 Object a4, Object a5, Object a6, Object a7)
1480 { fillWithArguments(a, pos, a0, a1, a2, a3, a4, a5, a6, a7); return a; }
1481 private static Object[] fillArray(Integer pos, Object[] a, Object a0, Object a1, Object a2, Object a3,
1482 Object a4, Object a5, Object a6, Object a7,
1483 Object a8)
1484 { fillWithArguments(a, pos, a0, a1, a2, a3, a4, a5, a6, a7, a8); return a; }
1485 private static Object[] fillArray(Integer pos, Object[] a, Object a0, Object a1, Object a2, Object a3,
1486 Object a4, Object a5, Object a6, Object a7,
1487 Object a8, Object a9)
1488 { fillWithArguments(a, pos, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9); return a; }
1489
1490 private static final int FILL_ARRAYS_COUNT = 11; // current number of fillArray methods
1491
1492 private static MethodHandle[] makeFillArrays() {
1493 MethodHandle[] mhs = new MethodHandle[FILL_ARRAYS_COUNT];
1494 mhs[0] = null; // there is no empty fill; at least a0 is required
1495 for (int i = 1; i < FILL_ARRAYS_COUNT; i++) {
1496 MethodHandle mh = findCollector("fillArray", i, Object[].class, Integer.class, Object[].class);
1497 mhs[i] = mh;
1498 }
1499 assert(assertFillArrayMethodCount(mhs));
1500 return mhs;
1501 }
1502
1503 private static boolean assertFillArrayMethodCount(MethodHandle[] mhs) {
1504 assert(findCollector("fillArray", FILL_ARRAYS_COUNT, Object[].class, Integer.class, Object[].class) == null);
1505 for (int i = 1; i < FILL_ARRAYS_COUNT; i++) {
1506 assert(mhs[i] != null);
1507 }
1508 return true;
1509 }
1510
1511 private static Object copyAsPrimitiveArray(Wrapper w, Object... boxes) {
1512 Object a = w.makeArray(boxes.length);
1513 w.copyArrayUnboxing(boxes, 0, a, 0, boxes.length);
1514 return a;
1515 }
1516
1517 /** Return a method handle that takes the indicated number of Object
1518 * arguments and returns an Object array of them, as if for varargs.
1519 */
1520 static MethodHandle varargsArray(int nargs) {
1521 MethodHandle mh = Lazy.ARRAYS[nargs];
1522 if (mh != null) return mh;
1523 mh = buildVarargsArray(Lazy.MH_fillNewArray, Lazy.MH_arrayIdentity, nargs);
1524 assert(assertCorrectArity(mh, nargs));
1525 mh = makeIntrinsic(mh, Intrinsic.NEW_ARRAY);
1526 return Lazy.ARRAYS[nargs] = mh;
1527 }
1528
1529 private static boolean assertCorrectArity(MethodHandle mh, int arity) {
1530 assert(mh.type().parameterCount() == arity) : "arity != "+arity+": "+mh;
1531 return true;
1532 }
1533
1534 // Array identity function (used as Lazy.MH_arrayIdentity).
1535 static <T> T[] identity(T[] x) {
1536 return x;
1537 }
1538
1539 private static MethodHandle buildVarargsArray(MethodHandle newArray, MethodHandle finisher, int nargs) {
1540 // Build up the result mh as a sequence of fills like this:
1541 // finisher(fill(fill(newArrayWA(23,x1..x10),10,x11..x20),20,x21..x23))
1542 // The various fill(_,10*I,___*[J]) are reusable.
1543 int leftLen = Math.min(nargs, LEFT_ARGS); // absorb some arguments immediately
1544 int rightLen = nargs - leftLen;
1545 MethodHandle leftCollector = newArray.bindTo(nargs);
1546 leftCollector = leftCollector.asCollector(Object[].class, leftLen);
1547 MethodHandle mh = finisher;
1548 if (rightLen > 0) {
1549 MethodHandle rightFiller = fillToRight(LEFT_ARGS + rightLen);
1550 if (mh == Lazy.MH_arrayIdentity)
1551 mh = rightFiller;
1552 else
1553 mh = MethodHandles.collectArguments(mh, 0, rightFiller);
1554 }
1555 if (mh == Lazy.MH_arrayIdentity)
1556 mh = leftCollector;
1557 else
1558 mh = MethodHandles.collectArguments(mh, 0, leftCollector);
1559 return mh;
1560 }
1561
1562 private static final int LEFT_ARGS = FILL_ARRAYS_COUNT - 1;
1563 private static final MethodHandle[] FILL_ARRAY_TO_RIGHT = new MethodHandle[MAX_ARITY+1];
1564 /** fill_array_to_right(N).invoke(a, argL..arg[N-1])
1565 * fills a[L]..a[N-1] with corresponding arguments,
1566 * and then returns a. The value L is a global constant (LEFT_ARGS).
1567 */
1568 private static MethodHandle fillToRight(int nargs) {
1569 MethodHandle filler = FILL_ARRAY_TO_RIGHT[nargs];
1570 if (filler != null) return filler;
1571 filler = buildFiller(nargs);
1572 assert(assertCorrectArity(filler, nargs - LEFT_ARGS + 1));
1573 return FILL_ARRAY_TO_RIGHT[nargs] = filler;
1574 }
1575 private static MethodHandle buildFiller(int nargs) {
1576 if (nargs <= LEFT_ARGS)
1577 return Lazy.MH_arrayIdentity; // no args to fill; return the array unchanged
1578 // we need room for both mh and a in mh.invoke(a, arg*[nargs])
1579 final int CHUNK = LEFT_ARGS;
1580 int rightLen = nargs % CHUNK;
1581 int midLen = nargs - rightLen;
1582 if (rightLen == 0) {
1583 midLen = nargs - (rightLen = CHUNK);
1584 if (FILL_ARRAY_TO_RIGHT[midLen] == null) {
1585 // build some precursors from left to right
1586 for (int j = LEFT_ARGS % CHUNK; j < midLen; j += CHUNK)
1587 if (j > LEFT_ARGS) fillToRight(j);
1588 }
1589 }
1590 if (midLen < LEFT_ARGS) rightLen = nargs - (midLen = LEFT_ARGS);
1591 assert(rightLen > 0);
1592 MethodHandle midFill = fillToRight(midLen); // recursive fill
1593 MethodHandle rightFill = Lazy.FILL_ARRAYS[rightLen].bindTo(midLen); // [midLen..nargs-1]
1594 assert(midFill.type().parameterCount() == 1 + midLen - LEFT_ARGS);
1595 assert(rightFill.type().parameterCount() == 1 + rightLen);
1596
1597 // Combine the two fills:
1598 // right(mid(a, x10..x19), x20..x23)
1599 // The final product will look like this:
1600 // right(mid(newArrayLeft(24, x0..x9), x10..x19), x20..x23)
1601 if (midLen == LEFT_ARGS)
1602 return rightFill;
1603 else
1604 return MethodHandles.collectArguments(rightFill, 0, midFill);
1605 }
1606
1607 // Type-polymorphic version of varargs maker.
1608 private static final ClassValue<MethodHandle[]> TYPED_COLLECTORS
1609 = new ClassValue<MethodHandle[]>() {
1610 @Override
1611 protected MethodHandle[] computeValue(Class<?> type) {
1612 return new MethodHandle[256];
1613 }
1624 if (elemType == null) throw new IllegalArgumentException("not an array: "+arrayType);
1625 // FIXME: Need more special casing and caching here.
1626 if (nargs >= MAX_JVM_ARITY/2 - 1) {
1627 int slots = nargs;
1628 final int MAX_ARRAY_SLOTS = MAX_JVM_ARITY - 1; // 1 for receiver MH
1629 if (slots <= MAX_ARRAY_SLOTS && elemType.isPrimitive())
1630 slots *= Wrapper.forPrimitiveType(elemType).stackSlots();
1631 if (slots > MAX_ARRAY_SLOTS)
1632 throw new IllegalArgumentException("too many arguments: "+arrayType.getSimpleName()+", length "+nargs);
1633 }
1634 if (elemType == Object.class)
1635 return varargsArray(nargs);
1636 // other cases: primitive arrays, subtypes of Object[]
1637 MethodHandle cache[] = TYPED_COLLECTORS.get(elemType);
1638 MethodHandle mh = nargs < cache.length ? cache[nargs] : null;
1639 if (mh != null) return mh;
1640 if (nargs == 0) {
1641 Object example = java.lang.reflect.Array.newInstance(arrayType.getComponentType(), 0);
1642 mh = MethodHandles.constant(arrayType, example);
1643 } else if (elemType.isPrimitive()) {
1644 MethodHandle builder = Lazy.MH_fillNewArray;
1645 MethodHandle producer = buildArrayProducer(arrayType);
1646 mh = buildVarargsArray(builder, producer, nargs);
1647 } else {
1648 Class<? extends Object[]> objArrayType = arrayType.asSubclass(Object[].class);
1649 Object[] example = Arrays.copyOf(NO_ARGS_ARRAY, 0, objArrayType);
1650 MethodHandle builder = Lazy.MH_fillNewTypedArray.bindTo(example);
1651 MethodHandle producer = Lazy.MH_arrayIdentity; // must be weakly typed
1652 mh = buildVarargsArray(builder, producer, nargs);
1653 }
1654 mh = mh.asType(MethodType.methodType(arrayType, Collections.<Class<?>>nCopies(nargs, elemType)));
1655 mh = makeIntrinsic(mh, Intrinsic.NEW_ARRAY);
1656 assert(assertCorrectArity(mh, nargs));
1657 if (nargs < cache.length)
1658 cache[nargs] = mh;
1659 return mh;
1660 }
1661
1662 private static MethodHandle buildArrayProducer(Class<?> arrayType) {
1663 Class<?> elemType = arrayType.getComponentType();
1664 assert(elemType.isPrimitive());
1665 return Lazy.MH_copyAsPrimitiveArray.bindTo(Wrapper.forPrimitiveType(elemType));
1666 }
1667
1668 /*non-public*/ static void assertSame(Object mh1, Object mh2) {
1669 if (mh1 != mh2) {
1670 String msg = String.format("mh1 != mh2: mh1 = %s (form: %s); mh2 = %s (form: %s)",
1671 mh1, ((MethodHandle)mh1).form,
1672 mh2, ((MethodHandle)mh2).form);
1673 throw newInternalError(msg);
1674 }
1675 }
1676 }
|
202 }
203 return count;
204 }
205
206 static MethodHandle makePairwiseConvertByEditor(MethodHandle target, MethodType srcType,
207 boolean strict, boolean monobox) {
208 Object[] convSpecs = computeValueConversions(srcType, target.type(), strict, monobox);
209 int convCount = countNonNull(convSpecs);
210 if (convCount == 0)
211 return target.viewAsType(srcType, strict);
212 MethodType basicSrcType = srcType.basicType();
213 MethodType midType = target.type().basicType();
214 BoundMethodHandle mh = target.rebind();
215 // FIXME: Reduce number of bindings when there is more than one Class conversion.
216 // FIXME: Reduce number of bindings when there are repeated conversions.
217 for (int i = 0; i < convSpecs.length-1; i++) {
218 Object convSpec = convSpecs[i];
219 if (convSpec == null) continue;
220 MethodHandle fn;
221 if (convSpec instanceof Class) {
222 fn = getConstantHandle(MH_cast).bindTo(convSpec);
223 } else {
224 fn = (MethodHandle) convSpec;
225 }
226 Class<?> newType = basicSrcType.parameterType(i);
227 if (--convCount == 0)
228 midType = srcType;
229 else
230 midType = midType.changeParameterType(i, newType);
231 LambdaForm form2 = mh.editor().filterArgumentForm(1+i, BasicType.basicType(newType));
232 mh = mh.copyWithExtendL(midType, form2, fn);
233 mh = mh.rebind();
234 }
235 Object convSpec = convSpecs[convSpecs.length-1];
236 if (convSpec != null) {
237 MethodHandle fn;
238 if (convSpec instanceof Class) {
239 if (convSpec == void.class)
240 fn = null;
241 else
242 fn = getConstantHandle(MH_cast).bindTo(convSpec);
243 } else {
244 fn = (MethodHandle) convSpec;
245 }
246 Class<?> newType = basicSrcType.returnType();
247 assert(--convCount == 0);
248 midType = srcType;
249 if (fn != null) {
250 mh = mh.rebind(); // rebind if too complex
251 LambdaForm form2 = mh.editor().filterReturnForm(BasicType.basicType(newType), false);
252 mh = mh.copyWithExtendL(midType, form2, fn);
253 } else {
254 LambdaForm form2 = mh.editor().filterReturnForm(BasicType.basicType(newType), true);
255 mh = mh.copyWith(midType, form2);
256 }
257 }
258 assert(convCount == 0);
259 assert(mh.type().equals(srcType));
260 return mh;
261 }
262
285 // Now build a LambdaForm.
286 MethodType lambdaType = srcType.basicType().invokerType();
287 Name[] names = arguments(NAME_LIMIT - INARG_LIMIT, lambdaType);
288
289 // Collect the arguments to the outgoing call, maybe with conversions:
290 final int OUTARG_BASE = 0; // target MH is Name.function, name Name.arguments[0]
291 Object[] outArgs = new Object[OUTARG_BASE + INARG_COUNT];
292
293 int nameCursor = INARG_LIMIT;
294 for (int i = 0; i < INARG_COUNT; i++) {
295 Object convSpec = convSpecs[i];
296 if (convSpec == null) {
297 // do nothing: difference is trivial
298 outArgs[OUTARG_BASE + i] = names[INARG_BASE + i];
299 continue;
300 }
301
302 Name conv;
303 if (convSpec instanceof Class) {
304 Class<?> convClass = (Class<?>) convSpec;
305 conv = new Name(getConstantHandle(MH_cast), convClass, names[INARG_BASE + i]);
306 } else {
307 MethodHandle fn = (MethodHandle) convSpec;
308 conv = new Name(fn, names[INARG_BASE + i]);
309 }
310 assert(names[nameCursor] == null);
311 names[nameCursor++] = conv;
312 assert(outArgs[OUTARG_BASE + i] == null);
313 outArgs[OUTARG_BASE + i] = conv;
314 }
315
316 // Build argument array for the call.
317 assert(nameCursor == OUT_CALL);
318 names[OUT_CALL] = new Name(target, outArgs);
319
320 Object convSpec = convSpecs[INARG_COUNT];
321 if (!retConv) {
322 assert(OUT_CALL == names.length-1);
323 } else {
324 Name conv;
325 if (convSpec == void.class) {
326 conv = new Name(LambdaForm.constantZero(BasicType.basicType(srcType.returnType())));
327 } else if (convSpec instanceof Class) {
328 Class<?> convClass = (Class<?>) convSpec;
329 conv = new Name(getConstantHandle(MH_cast), convClass, names[OUT_CALL]);
330 } else {
331 MethodHandle fn = (MethodHandle) convSpec;
332 if (fn.type().parameterCount() == 0)
333 conv = new Name(fn); // don't pass retval to void conversion
334 else
335 conv = new Name(fn, names[OUT_CALL]);
336 }
337 assert(names[RETURN_CONV] == null);
338 names[RETURN_CONV] = conv;
339 assert(RETURN_CONV == names.length-1);
340 }
341
342 LambdaForm form = new LambdaForm("convert", lambdaType.parameterCount(), names, RESULT);
343 return SimpleMethodHandle.make(srcType, form);
344 }
345
346 static Object[] computeValueConversions(MethodType srcType, MethodType dstType,
347 boolean strict, boolean monobox) {
348 final int INARG_COUNT = srcType.parameterCount();
349 Object[] convSpecs = new Object[INARG_COUNT+1];
512 Class<?> arg = VerifyType.spreadArgElementType(spreadArgType, i);
513 if (arg == null) arg = Object.class;
514 targetType = targetType.changeParameterType(spreadArgPos + i, arg);
515 }
516 target = target.asType(targetType);
517
518 MethodType srcType = targetType
519 .replaceParameterTypes(spreadArgPos, spreadArgPos + spreadArgCount, spreadArgType);
520 // Now build a LambdaForm.
521 MethodType lambdaType = srcType.invokerType();
522 Name[] names = arguments(spreadArgCount + 2, lambdaType);
523 int nameCursor = lambdaType.parameterCount();
524 int[] indexes = new int[targetType.parameterCount()];
525
526 for (int i = 0, argIndex = 1; i < targetType.parameterCount() + 1; i++, argIndex++) {
527 Class<?> src = lambdaType.parameterType(i);
528 if (i == spreadArgPos) {
529 // Spread the array.
530 MethodHandle aload = MethodHandles.arrayElementGetter(spreadArgType);
531 Name array = names[argIndex];
532 names[nameCursor++] = new Name(NF_checkSpreadArgument, array, spreadArgCount);
533 for (int j = 0; j < spreadArgCount; i++, j++) {
534 indexes[i] = nameCursor;
535 names[nameCursor++] = new Name(aload, array, j);
536 }
537 } else if (i < indexes.length) {
538 indexes[i] = argIndex;
539 }
540 }
541 assert(nameCursor == names.length-1); // leave room for the final call
542
543 // Build argument array for the call.
544 Name[] targetArgs = new Name[targetType.parameterCount()];
545 for (int i = 0; i < targetType.parameterCount(); i++) {
546 int idx = indexes[i];
547 targetArgs[i] = names[idx];
548 }
549 names[names.length - 1] = new Name(target, (Object[]) targetArgs);
550
551 LambdaForm form = new LambdaForm("spread", lambdaType.parameterCount(), names);
552 return SimpleMethodHandle.make(srcType, form);
553 }
554
555 static void checkSpreadArgument(Object av, int n) {
556 if (av == null) {
557 if (n == 0) return;
558 } else if (av instanceof Object[]) {
559 int len = ((Object[])av).length;
560 if (len == n) return;
561 } else {
562 int len = java.lang.reflect.Array.getLength(av);
563 if (len == n) return;
564 }
565 // fall through to error:
566 throw newIllegalArgumentException("array is not of length "+n);
567 }
568
569 /** Factory method: Collect or filter selected argument(s). */
570 static MethodHandle makeCollectArguments(MethodHandle target,
571 MethodHandle collector, int collectArgPos, boolean retainOriginalArgs) {
572 MethodType targetType = target.type(); // (a..., c, [b...])=>r
573 MethodType collectorType = collector.type(); // (b...)=>c
574 int collectArgCount = collectorType.parameterCount();
575 Class<?> collectValType = collectorType.returnType();
576 int collectValCount = (collectValType == void.class ? 0 : 1);
577 MethodType srcType = targetType // (a..., [b...])=>r
578 .dropParameterTypes(collectArgPos, collectArgPos+collectValCount);
579 if (!retainOriginalArgs) { // (a..., b...)=>r
580 srcType = srcType.insertParameterTypes(collectArgPos, collectorType.parameterList());
581 }
582 // in arglist: [0: ...keep1 | cpos: collect... | cpos+cacount: keep2... ]
583 // out arglist: [0: ...keep1 | cpos: collectVal? | cpos+cvcount: keep2... ]
584 // out(retain): [0: ...keep1 | cpos: cV? coll... | cpos+cvc+cac: keep2... ]
585
586 // Now build a LambdaForm.
587 MethodType lambdaType = srcType.invokerType();
588 Name[] names = arguments(2, lambdaType);
834
835 BoundMethodHandle.SpeciesData data =
836 (GET_COUNTERS != -1) ? BoundMethodHandle.speciesData_LLLL()
837 : BoundMethodHandle.speciesData_LLL();
838 names[THIS_MH] = names[THIS_MH].withConstraint(data);
839 names[GET_TEST] = new Name(data.getterFunction(0), names[THIS_MH]);
840 names[GET_TARGET] = new Name(data.getterFunction(1), names[THIS_MH]);
841 names[GET_FALLBACK] = new Name(data.getterFunction(2), names[THIS_MH]);
842 if (GET_COUNTERS != -1) {
843 names[GET_COUNTERS] = new Name(data.getterFunction(3), names[THIS_MH]);
844 }
845 Object[] invokeArgs = Arrays.copyOfRange(names, 0, ARG_LIMIT, Object[].class);
846
847 // call test
848 MethodType testType = basicType.changeReturnType(boolean.class).basicType();
849 invokeArgs[0] = names[GET_TEST];
850 names[CALL_TEST] = new Name(testType, invokeArgs);
851
852 // profile branch
853 if (PROFILE != -1) {
854 names[PROFILE] = new Name(NF_profileBoolean, names[CALL_TEST], names[GET_COUNTERS]);
855 }
856 // call selectAlternative
857 names[SELECT_ALT] = new Name(getConstantHandle(MH_selectAlternative), names[TEST], names[GET_TARGET], names[GET_FALLBACK]);
858
859 // call target or fallback
860 invokeArgs[0] = names[SELECT_ALT];
861 names[CALL_TARGET] = new Name(basicType, invokeArgs);
862
863 lform = new LambdaForm("guard", lambdaType.parameterCount(), names, /*forceInline=*/true);
864
865 return basicType.form().setCachedLambdaForm(MethodTypeForm.LF_GWT, lform);
866 }
867
868 /**
869 * The LambdaForm shape for catchException combinator is the following:
870 * <blockquote><pre>{@code
871 * guardWithCatch=Lambda(a0:L,a1:L,a2:L)=>{
872 * t3:L=BoundMethodHandle$Species_LLLLL.argL0(a0:L);
873 * t4:L=BoundMethodHandle$Species_LLLLL.argL1(a0:L);
874 * t5:L=BoundMethodHandle$Species_LLLLL.argL2(a0:L);
875 * t6:L=BoundMethodHandle$Species_LLLLL.argL3(a0:L);
876 * t7:L=BoundMethodHandle$Species_LLLLL.argL4(a0:L);
877 * t8:L=MethodHandle.invokeBasic(t6:L,a1:L,a2:L);
912 BoundMethodHandle.SpeciesData data = BoundMethodHandle.speciesData_LLLLL();
913 names[THIS_MH] = names[THIS_MH].withConstraint(data);
914 names[GET_TARGET] = new Name(data.getterFunction(0), names[THIS_MH]);
915 names[GET_CLASS] = new Name(data.getterFunction(1), names[THIS_MH]);
916 names[GET_CATCHER] = new Name(data.getterFunction(2), names[THIS_MH]);
917 names[GET_COLLECT_ARGS] = new Name(data.getterFunction(3), names[THIS_MH]);
918 names[GET_UNBOX_RESULT] = new Name(data.getterFunction(4), names[THIS_MH]);
919
920 // FIXME: rework argument boxing/result unboxing logic for LF interpretation
921
922 // t_{i}:L=MethodHandle.invokeBasic(collectArgs:L,a1:L,...);
923 MethodType collectArgsType = basicType.changeReturnType(Object.class);
924 MethodHandle invokeBasic = MethodHandles.basicInvoker(collectArgsType);
925 Object[] args = new Object[invokeBasic.type().parameterCount()];
926 args[0] = names[GET_COLLECT_ARGS];
927 System.arraycopy(names, ARG_BASE, args, 1, ARG_LIMIT-ARG_BASE);
928 names[BOXED_ARGS] = new Name(makeIntrinsic(invokeBasic, Intrinsic.GUARD_WITH_CATCH), args);
929
930 // t_{i+1}:L=MethodHandleImpl.guardWithCatch(target:L,exType:L,catcher:L,t_{i}:L);
931 Object[] gwcArgs = new Object[] {names[GET_TARGET], names[GET_CLASS], names[GET_CATCHER], names[BOXED_ARGS]};
932 names[TRY_CATCH] = new Name(NF_guardWithCatch, gwcArgs);
933
934 // t_{i+2}:I=MethodHandle.invokeBasic(unbox:L,t_{i+1}:L);
935 MethodHandle invokeBasicUnbox = MethodHandles.basicInvoker(MethodType.methodType(basicType.rtype(), Object.class));
936 Object[] unboxArgs = new Object[] {names[GET_UNBOX_RESULT], names[TRY_CATCH]};
937 names[UNBOX_RESULT] = new Name(invokeBasicUnbox, unboxArgs);
938
939 lform = new LambdaForm("guardWithCatch", lambdaType.parameterCount(), names);
940
941 return basicType.form().setCachedLambdaForm(MethodTypeForm.LF_GWC, lform);
942 }
943
944 static
945 MethodHandle makeGuardWithCatch(MethodHandle target,
946 Class<? extends Throwable> exType,
947 MethodHandle catcher) {
948 MethodType type = target.type();
949 LambdaForm form = makeGuardWithCatchForm(type.basicType());
950
951 // Prepare auxiliary method handles used during LambdaForm interpretation.
952 // Box arguments and wrap them into Object[]: ValueConversions.array().
996 }
997
998 /** Prepend an element {@code elem} to an {@code array}. */
999 @LambdaForm.Hidden
1000 private static Object[] prepend(Object elem, Object[] array) {
1001 Object[] newArray = new Object[array.length+1];
1002 newArray[0] = elem;
1003 System.arraycopy(array, 0, newArray, 1, array.length);
1004 return newArray;
1005 }
1006
1007 static
1008 MethodHandle throwException(MethodType type) {
1009 assert(Throwable.class.isAssignableFrom(type.parameterType(0)));
1010 int arity = type.parameterCount();
1011 if (arity > 1) {
1012 MethodHandle mh = throwException(type.dropParameterTypes(1, arity));
1013 mh = MethodHandles.dropArguments(mh, 1, type.parameterList().subList(1, arity));
1014 return mh;
1015 }
1016 return makePairwiseConvert(NF_throwException.resolvedHandle(), type, false, true);
1017 }
1018
1019 static <T extends Throwable> Empty throwException(T t) throws T { throw t; }
1020
1021 static MethodHandle[] FAKE_METHOD_HANDLE_INVOKE = new MethodHandle[2];
1022 static MethodHandle fakeMethodHandleInvoke(MemberName method) {
1023 int idx;
1024 assert(method.isMethodHandleInvoke());
1025 switch (method.getName()) {
1026 case "invoke": idx = 0; break;
1027 case "invokeExact": idx = 1; break;
1028 default: throw new InternalError(method.getName());
1029 }
1030 MethodHandle mh = FAKE_METHOD_HANDLE_INVOKE[idx];
1031 if (mh != null) return mh;
1032 MethodType type = MethodType.methodType(Object.class, UnsupportedOperationException.class,
1033 MethodHandle.class, Object[].class);
1034 mh = throwException(type);
1035 mh = mh.bindTo(new UnsupportedOperationException("cannot reflectively invoke MethodHandle"));
1036 if (!method.getInvocationType().equals(mh.type()))
1344 { return makeArray(a0, a1, a2, a3, a4); }
1345 private static Object[] array(Object a0, Object a1, Object a2, Object a3,
1346 Object a4, Object a5)
1347 { return makeArray(a0, a1, a2, a3, a4, a5); }
1348 private static Object[] array(Object a0, Object a1, Object a2, Object a3,
1349 Object a4, Object a5, Object a6)
1350 { return makeArray(a0, a1, a2, a3, a4, a5, a6); }
1351 private static Object[] array(Object a0, Object a1, Object a2, Object a3,
1352 Object a4, Object a5, Object a6, Object a7)
1353 { return makeArray(a0, a1, a2, a3, a4, a5, a6, a7); }
1354 private static Object[] array(Object a0, Object a1, Object a2, Object a3,
1355 Object a4, Object a5, Object a6, Object a7,
1356 Object a8)
1357 { return makeArray(a0, a1, a2, a3, a4, a5, a6, a7, a8); }
1358 private static Object[] array(Object a0, Object a1, Object a2, Object a3,
1359 Object a4, Object a5, Object a6, Object a7,
1360 Object a8, Object a9)
1361 { return makeArray(a0, a1, a2, a3, a4, a5, a6, a7, a8, a9); }
1362
1363 private static final int ARRAYS_COUNT = 11;
1364 private static final @Stable MethodHandle[] ARRAYS = new MethodHandle[MAX_ARITY + 1];
1365
1366 // filling versions of the above:
1367 // using Integer len instead of int len and no varargs to avoid bootstrapping problems
1368 private static Object[] fillNewArray(Integer len, Object[] /*not ...*/ args) {
1369 Object[] a = new Object[len];
1370 fillWithArguments(a, 0, args);
1371 return a;
1372 }
1373 private static Object[] fillNewTypedArray(Object[] example, Integer len, Object[] /*not ...*/ args) {
1374 Object[] a = Arrays.copyOf(example, len);
1375 assert(a.getClass() != Object[].class);
1376 fillWithArguments(a, 0, args);
1377 return a;
1378 }
1379 private static void fillWithArguments(Object[] a, int pos, Object... args) {
1380 System.arraycopy(args, 0, a, pos, args.length);
1381 }
1382 // using Integer pos instead of int pos to avoid bootstrapping problems
1383 private static Object[] fillArray(Integer pos, Object[] a, Object a0)
1384 { fillWithArguments(a, pos, a0); return a; }
1393 { fillWithArguments(a, pos, a0, a1, a2, a3, a4); return a; }
1394 private static Object[] fillArray(Integer pos, Object[] a, Object a0, Object a1, Object a2, Object a3,
1395 Object a4, Object a5)
1396 { fillWithArguments(a, pos, a0, a1, a2, a3, a4, a5); return a; }
1397 private static Object[] fillArray(Integer pos, Object[] a, Object a0, Object a1, Object a2, Object a3,
1398 Object a4, Object a5, Object a6)
1399 { fillWithArguments(a, pos, a0, a1, a2, a3, a4, a5, a6); return a; }
1400 private static Object[] fillArray(Integer pos, Object[] a, Object a0, Object a1, Object a2, Object a3,
1401 Object a4, Object a5, Object a6, Object a7)
1402 { fillWithArguments(a, pos, a0, a1, a2, a3, a4, a5, a6, a7); return a; }
1403 private static Object[] fillArray(Integer pos, Object[] a, Object a0, Object a1, Object a2, Object a3,
1404 Object a4, Object a5, Object a6, Object a7,
1405 Object a8)
1406 { fillWithArguments(a, pos, a0, a1, a2, a3, a4, a5, a6, a7, a8); return a; }
1407 private static Object[] fillArray(Integer pos, Object[] a, Object a0, Object a1, Object a2, Object a3,
1408 Object a4, Object a5, Object a6, Object a7,
1409 Object a8, Object a9)
1410 { fillWithArguments(a, pos, a0, a1, a2, a3, a4, a5, a6, a7, a8, a9); return a; }
1411
1412 private static final int FILL_ARRAYS_COUNT = 11; // current number of fillArray methods
1413 private static final @Stable MethodHandle[] FILL_ARRAYS = new MethodHandle[FILL_ARRAYS_COUNT];
1414
1415 private static MethodHandle getFillArray(int count) {
1416 assert (count > 0 && count < FILL_ARRAYS_COUNT);
1417 MethodHandle mh = FILL_ARRAYS[count];
1418 if (mh != null) {
1419 return mh;
1420 }
1421 mh = findCollector("fillArray", count, Object[].class, Integer.class, Object[].class);
1422 FILL_ARRAYS[count] = mh;
1423 return mh;
1424 }
1425
1426 private static Object copyAsPrimitiveArray(Wrapper w, Object... boxes) {
1427 Object a = w.makeArray(boxes.length);
1428 w.copyArrayUnboxing(boxes, 0, a, 0, boxes.length);
1429 return a;
1430 }
1431
1432 /** Return a method handle that takes the indicated number of Object
1433 * arguments and returns an Object array of them, as if for varargs.
1434 */
1435 static MethodHandle varargsArray(int nargs) {
1436 MethodHandle mh = ARRAYS[nargs];
1437 if (mh != null) {
1438 return mh;
1439 }
1440 if (nargs < ARRAYS_COUNT) {
1441 mh = findCollector("array", nargs, Object[].class);
1442 } else {
1443 mh = buildVarargsArray(getConstantHandle(MH_fillNewArray),
1444 getConstantHandle(MH_arrayIdentity), nargs);
1445 }
1446 assert(assertCorrectArity(mh, nargs));
1447 mh = makeIntrinsic(mh, Intrinsic.NEW_ARRAY);
1448 return ARRAYS[nargs] = mh;
1449 }
1450
1451 private static boolean assertCorrectArity(MethodHandle mh, int arity) {
1452 assert(mh.type().parameterCount() == arity) : "arity != "+arity+": "+mh;
1453 return true;
1454 }
1455
1456 // Array identity function (used as getConstantHandle(MH_arrayIdentity)).
1457 static <T> T[] identity(T[] x) {
1458 return x;
1459 }
1460
1461 private static MethodHandle buildVarargsArray(MethodHandle newArray, MethodHandle finisher, int nargs) {
1462 // Build up the result mh as a sequence of fills like this:
1463 // finisher(fill(fill(newArrayWA(23,x1..x10),10,x11..x20),20,x21..x23))
1464 // The various fill(_,10*I,___*[J]) are reusable.
1465 int leftLen = Math.min(nargs, LEFT_ARGS); // absorb some arguments immediately
1466 int rightLen = nargs - leftLen;
1467 MethodHandle leftCollector = newArray.bindTo(nargs);
1468 leftCollector = leftCollector.asCollector(Object[].class, leftLen);
1469 MethodHandle mh = finisher;
1470 if (rightLen > 0) {
1471 MethodHandle rightFiller = fillToRight(LEFT_ARGS + rightLen);
1472 if (mh.equals(getConstantHandle(MH_arrayIdentity)))
1473 mh = rightFiller;
1474 else
1475 mh = MethodHandles.collectArguments(mh, 0, rightFiller);
1476 }
1477 if (mh.equals(getConstantHandle(MH_arrayIdentity)))
1478 mh = leftCollector;
1479 else
1480 mh = MethodHandles.collectArguments(mh, 0, leftCollector);
1481 return mh;
1482 }
1483
1484 private static final int LEFT_ARGS = FILL_ARRAYS_COUNT - 1;
1485 private static final @Stable MethodHandle[] FILL_ARRAY_TO_RIGHT = new MethodHandle[MAX_ARITY+1];
1486 /** fill_array_to_right(N).invoke(a, argL..arg[N-1])
1487 * fills a[L]..a[N-1] with corresponding arguments,
1488 * and then returns a. The value L is a global constant (LEFT_ARGS).
1489 */
1490 private static MethodHandle fillToRight(int nargs) {
1491 MethodHandle filler = FILL_ARRAY_TO_RIGHT[nargs];
1492 if (filler != null) return filler;
1493 filler = buildFiller(nargs);
1494 assert(assertCorrectArity(filler, nargs - LEFT_ARGS + 1));
1495 return FILL_ARRAY_TO_RIGHT[nargs] = filler;
1496 }
1497 private static MethodHandle buildFiller(int nargs) {
1498 if (nargs <= LEFT_ARGS)
1499 return getConstantHandle(MH_arrayIdentity); // no args to fill; return the array unchanged
1500 // we need room for both mh and a in mh.invoke(a, arg*[nargs])
1501 final int CHUNK = LEFT_ARGS;
1502 int rightLen = nargs % CHUNK;
1503 int midLen = nargs - rightLen;
1504 if (rightLen == 0) {
1505 midLen = nargs - (rightLen = CHUNK);
1506 if (FILL_ARRAY_TO_RIGHT[midLen] == null) {
1507 // build some precursors from left to right
1508 for (int j = LEFT_ARGS % CHUNK; j < midLen; j += CHUNK)
1509 if (j > LEFT_ARGS) fillToRight(j);
1510 }
1511 }
1512 if (midLen < LEFT_ARGS) rightLen = nargs - (midLen = LEFT_ARGS);
1513 assert(rightLen > 0);
1514 MethodHandle midFill = fillToRight(midLen); // recursive fill
1515 MethodHandle rightFill = getFillArray(rightLen).bindTo(midLen); // [midLen..nargs-1]
1516 assert(midFill.type().parameterCount() == 1 + midLen - LEFT_ARGS);
1517 assert(rightFill.type().parameterCount() == 1 + rightLen);
1518
1519 // Combine the two fills:
1520 // right(mid(a, x10..x19), x20..x23)
1521 // The final product will look like this:
1522 // right(mid(newArrayLeft(24, x0..x9), x10..x19), x20..x23)
1523 if (midLen == LEFT_ARGS)
1524 return rightFill;
1525 else
1526 return MethodHandles.collectArguments(rightFill, 0, midFill);
1527 }
1528
1529 // Type-polymorphic version of varargs maker.
1530 private static final ClassValue<MethodHandle[]> TYPED_COLLECTORS
1531 = new ClassValue<MethodHandle[]>() {
1532 @Override
1533 protected MethodHandle[] computeValue(Class<?> type) {
1534 return new MethodHandle[256];
1535 }
1546 if (elemType == null) throw new IllegalArgumentException("not an array: "+arrayType);
1547 // FIXME: Need more special casing and caching here.
1548 if (nargs >= MAX_JVM_ARITY/2 - 1) {
1549 int slots = nargs;
1550 final int MAX_ARRAY_SLOTS = MAX_JVM_ARITY - 1; // 1 for receiver MH
1551 if (slots <= MAX_ARRAY_SLOTS && elemType.isPrimitive())
1552 slots *= Wrapper.forPrimitiveType(elemType).stackSlots();
1553 if (slots > MAX_ARRAY_SLOTS)
1554 throw new IllegalArgumentException("too many arguments: "+arrayType.getSimpleName()+", length "+nargs);
1555 }
1556 if (elemType == Object.class)
1557 return varargsArray(nargs);
1558 // other cases: primitive arrays, subtypes of Object[]
1559 MethodHandle cache[] = TYPED_COLLECTORS.get(elemType);
1560 MethodHandle mh = nargs < cache.length ? cache[nargs] : null;
1561 if (mh != null) return mh;
1562 if (nargs == 0) {
1563 Object example = java.lang.reflect.Array.newInstance(arrayType.getComponentType(), 0);
1564 mh = MethodHandles.constant(arrayType, example);
1565 } else if (elemType.isPrimitive()) {
1566 MethodHandle builder = getConstantHandle(MH_fillNewArray);
1567 MethodHandle producer = buildArrayProducer(arrayType);
1568 mh = buildVarargsArray(builder, producer, nargs);
1569 } else {
1570 Class<? extends Object[]> objArrayType = arrayType.asSubclass(Object[].class);
1571 Object[] example = Arrays.copyOf(NO_ARGS_ARRAY, 0, objArrayType);
1572 MethodHandle builder = getConstantHandle(MH_fillNewTypedArray).bindTo(example);
1573 MethodHandle producer = getConstantHandle(MH_arrayIdentity); // must be weakly typed
1574 mh = buildVarargsArray(builder, producer, nargs);
1575 }
1576 mh = mh.asType(MethodType.methodType(arrayType, Collections.<Class<?>>nCopies(nargs, elemType)));
1577 mh = makeIntrinsic(mh, Intrinsic.NEW_ARRAY);
1578 assert(assertCorrectArity(mh, nargs));
1579 if (nargs < cache.length)
1580 cache[nargs] = mh;
1581 return mh;
1582 }
1583
1584 private static MethodHandle buildArrayProducer(Class<?> arrayType) {
1585 Class<?> elemType = arrayType.getComponentType();
1586 assert(elemType.isPrimitive());
1587 return getConstantHandle(MH_copyAsPrimitiveArray).bindTo(Wrapper.forPrimitiveType(elemType));
1588 }
1589
1590 /*non-public*/ static void assertSame(Object mh1, Object mh2) {
1591 if (mh1 != mh2) {
1592 String msg = String.format("mh1 != mh2: mh1 = %s (form: %s); mh2 = %s (form: %s)",
1593 mh1, ((MethodHandle)mh1).form,
1594 mh2, ((MethodHandle)mh2).form);
1595 throw newInternalError(msg);
1596 }
1597 }
1598
1599 // Local constant functions:
1600 /*non-public*/ static final NamedFunction
1601 NF_checkSpreadArgument,
1602 NF_guardWithCatch,
1603 NF_throwException,
1604 NF_profileBoolean;
1605
1606 static {
1607 try {
1608 NamedFunction nfs[] = {
1609 NF_checkSpreadArgument = new NamedFunction(MethodHandleImpl.class
1610 .getDeclaredMethod("checkSpreadArgument", Object.class, int.class)),
1611 NF_guardWithCatch = new NamedFunction(MethodHandleImpl.class
1612 .getDeclaredMethod("guardWithCatch", MethodHandle.class, Class.class,
1613 MethodHandle.class, Object[].class)),
1614 NF_throwException = new NamedFunction(MethodHandleImpl.class
1615 .getDeclaredMethod("throwException", Throwable.class)),
1616 NF_profileBoolean = new NamedFunction(MethodHandleImpl.class
1617 .getDeclaredMethod("profileBoolean", boolean.class, int[].class))
1618 };
1619 // Each nf must be statically invocable or we get tied up in our bootstraps.
1620 assert(InvokerBytecodeGenerator.isStaticallyInvocable(nfs));
1621 } catch (ReflectiveOperationException ex) {
1622 throw newInternalError(ex);
1623 }
1624 }
1625
1626 // Indexes into constant method handles:
1627 private static final int
1628 MH_cast = 0,
1629 MH_selectAlternative = 1,
1630 MH_copyAsPrimitiveArray = 2,
1631 MH_fillNewTypedArray = 3,
1632 MH_fillNewArray = 4,
1633 MH_arrayIdentity = 5,
1634 MH_LIMIT = 6;
1635
1636 private static MethodHandle getConstantHandle(int idx) {
1637 MethodHandle handle = HANDLES[idx];
1638 if (handle != null) {
1639 return handle;
1640 }
1641 return setCachedHandle(idx, makeConstantHandle(idx));
1642 }
1643
1644 private static synchronized MethodHandle setCachedHandle(int idx, final MethodHandle method) {
1645 // Simulate a CAS, to avoid racy duplication of results.
1646 MethodHandle prev = HANDLES[idx];
1647 if (prev != null) {
1648 return prev;
1649 }
1650 HANDLES[idx] = method;
1651 return method;
1652 }
1653
1654 // Local constant method handles:
1655 private static final @Stable MethodHandle[] HANDLES = new MethodHandle[MH_LIMIT];
1656
1657 private static MethodHandle makeConstantHandle(int idx) {
1658 try {
1659 switch (idx) {
1660 case MH_cast:
1661 return IMPL_LOOKUP.findVirtual(Class.class, "cast",
1662 MethodType.methodType(Object.class, Object.class));
1663 case MH_copyAsPrimitiveArray:
1664 return IMPL_LOOKUP.findStatic(MethodHandleImpl.class, "copyAsPrimitiveArray",
1665 MethodType.methodType(Object.class, Wrapper.class, Object[].class));
1666 case MH_arrayIdentity:
1667 return IMPL_LOOKUP.findStatic(MethodHandleImpl.class, "identity",
1668 MethodType.methodType(Object[].class, Object[].class));
1669 case MH_fillNewArray:
1670 return IMPL_LOOKUP.findStatic(MethodHandleImpl.class, "fillNewArray",
1671 MethodType.methodType(Object[].class, Integer.class, Object[].class));
1672 case MH_fillNewTypedArray:
1673 return IMPL_LOOKUP.findStatic(MethodHandleImpl.class, "fillNewTypedArray",
1674 MethodType.methodType(Object[].class, Object[].class, Integer.class, Object[].class));
1675 case MH_selectAlternative:
1676 return makeIntrinsic(IMPL_LOOKUP.findStatic(MethodHandleImpl.class, "selectAlternative",
1677 MethodType.methodType(MethodHandle.class, boolean.class, MethodHandle.class, MethodHandle.class)),
1678 Intrinsic.SELECT_ALTERNATIVE);
1679 }
1680 } catch (ReflectiveOperationException ex) {
1681 throw newInternalError(ex);
1682 }
1683 throw newInternalError("Unknown function index: " + idx);
1684 }
1685 }
|