580 int len = java.lang.reflect.Array.getLength(av);
581 if (len == n) return;
582 }
583 // fall through to error:
584 throw newIllegalArgumentException("array is not of length "+n);
585 }
586
587 /**
588 * Pre-initialized NamedFunctions for bootstrapping purposes.
589 * Factored in an inner class to delay initialization until first usage.
590 */
591 static class Lazy {
592 private static final Class<?> MHI = MethodHandleImpl.class;
593
594 private static final MethodHandle[] ARRAYS;
595 private static final MethodHandle[] FILL_ARRAYS;
596
597 static final NamedFunction NF_checkSpreadArgument;
598 static final NamedFunction NF_guardWithCatch;
599 static final NamedFunction NF_throwException;
600
601 static final MethodHandle MH_castReference;
602 static final MethodHandle MH_selectAlternative;
603 static final MethodHandle MH_copyAsPrimitiveArray;
604 static final MethodHandle MH_fillNewTypedArray;
605 static final MethodHandle MH_fillNewArray;
606 static final MethodHandle MH_arrayIdentity;
607
608 static {
609 ARRAYS = makeArrays();
610 FILL_ARRAYS = makeFillArrays();
611
612 try {
613 NF_checkSpreadArgument = new NamedFunction(MHI.getDeclaredMethod("checkSpreadArgument", Object.class, int.class));
614 NF_guardWithCatch = new NamedFunction(MHI.getDeclaredMethod("guardWithCatch", MethodHandle.class, Class.class,
615 MethodHandle.class, Object[].class));
616 NF_throwException = new NamedFunction(MHI.getDeclaredMethod("throwException", Throwable.class));
617
618 NF_checkSpreadArgument.resolve();
619 NF_guardWithCatch.resolve();
620 NF_throwException.resolve();
621
622 MH_castReference = IMPL_LOOKUP.findStatic(MHI, "castReference",
623 MethodType.methodType(Object.class, Class.class, Object.class));
624 MH_copyAsPrimitiveArray = IMPL_LOOKUP.findStatic(MHI, "copyAsPrimitiveArray",
625 MethodType.methodType(Object.class, Wrapper.class, Object[].class));
626 MH_arrayIdentity = IMPL_LOOKUP.findStatic(MHI, "identity",
627 MethodType.methodType(Object[].class, Object[].class));
628 MH_fillNewArray = IMPL_LOOKUP.findStatic(MHI, "fillNewArray",
629 MethodType.methodType(Object[].class, Integer.class, Object[].class));
630 MH_fillNewTypedArray = IMPL_LOOKUP.findStatic(MHI, "fillNewTypedArray",
631 MethodType.methodType(Object[].class, Object[].class, Integer.class, Object[].class));
632
633 MH_selectAlternative = makeIntrinsic(
634 IMPL_LOOKUP.findStatic(MHI, "selectAlternative",
635 MethodType.methodType(MethodHandle.class, boolean.class, MethodHandle.class, MethodHandle.class)),
636 Intrinsic.SELECT_ALTERNATIVE);
637 } catch (ReflectiveOperationException ex) {
638 throw newInternalError(ex);
639 }
640 }
680 targetArgs[targetArgPos++] = names[collectNamePos];
681 }
682 chunk = collectArgCount;
683 if (retainOriginalArgs) {
684 System.arraycopy(names, inputArgPos, targetArgs, targetArgPos, chunk);
685 targetArgPos += chunk; // optionally pass on the collected chunk
686 }
687 inputArgPos += chunk;
688 chunk = targetArgs.length - targetArgPos; // all the rest
689 System.arraycopy(names, inputArgPos, targetArgs, targetArgPos, chunk);
690 assert(inputArgPos + chunk == collectNamePos); // use of rest of input args also
691 names[targetNamePos] = new Name(target, (Object[]) targetArgs);
692
693 LambdaForm form = new LambdaForm("collect", lambdaType.parameterCount(), names);
694 return SimpleMethodHandle.make(srcType, form);
695 }
696
697 @LambdaForm.Hidden
698 static
699 MethodHandle selectAlternative(boolean testResult, MethodHandle target, MethodHandle fallback) {
700 return testResult ? target : fallback;
701 }
702
703 static
704 MethodHandle makeGuardWithTest(MethodHandle test,
705 MethodHandle target,
706 MethodHandle fallback) {
707 MethodType type = target.type();
708 assert(test.type().equals(type.changeReturnType(boolean.class)) && fallback.type().equals(type));
709 MethodType basicType = type.basicType();
710 LambdaForm form = makeGuardWithTestForm(basicType);
711 BoundMethodHandle.SpeciesData data = BoundMethodHandle.speciesData_LLL();
712 BoundMethodHandle mh;
713
714 try {
715 mh = (BoundMethodHandle)
716 data.constructor().invokeBasic(type, form,
717 (Object) test, (Object) profile(target), (Object) profile(fallback));
718 } catch (Throwable ex) {
719 throw uncaughtException(ex);
720 }
721 assert(mh.type() == type);
722 return mh;
723 }
724
725
726 static
727 MethodHandle profile(MethodHandle target) {
728 if (DONT_INLINE_THRESHOLD >= 0) {
729 return makeBlockInlningWrapper(target);
730 } else {
731 return target;
732 }
733 }
734
735 /**
736 * Block inlining during JIT-compilation of a target method handle if it hasn't been invoked enough times.
737 * Corresponding LambdaForm has @DontInline when compiled into bytecode.
839 Class<?> THIS_CLASS = CountingWrapper.class;
840 try {
841 NF_maybeStopCounting = new NamedFunction(THIS_CLASS.getDeclaredMethod("maybeStopCounting", Object.class));
842 } catch (ReflectiveOperationException ex) {
843 throw newInternalError(ex);
844 }
845 }
846 }
847
848 static
849 LambdaForm makeGuardWithTestForm(MethodType basicType) {
850 LambdaForm lform = basicType.form().cachedLambdaForm(MethodTypeForm.LF_GWT);
851 if (lform != null) return lform;
852 final int THIS_MH = 0; // the BMH_LLL
853 final int ARG_BASE = 1; // start of incoming arguments
854 final int ARG_LIMIT = ARG_BASE + basicType.parameterCount();
855 int nameCursor = ARG_LIMIT;
856 final int GET_TEST = nameCursor++;
857 final int GET_TARGET = nameCursor++;
858 final int GET_FALLBACK = nameCursor++;
859 final int CALL_TEST = nameCursor++;
860 final int SELECT_ALT = nameCursor++;
861 final int CALL_TARGET = nameCursor++;
862 assert(CALL_TARGET == SELECT_ALT+1); // must be true to trigger IBG.emitSelectAlternative
863
864 MethodType lambdaType = basicType.invokerType();
865 Name[] names = arguments(nameCursor - ARG_LIMIT, lambdaType);
866
867 BoundMethodHandle.SpeciesData data = BoundMethodHandle.speciesData_LLL();
868 names[THIS_MH] = names[THIS_MH].withConstraint(data);
869 names[GET_TEST] = new Name(data.getterFunction(0), names[THIS_MH]);
870 names[GET_TARGET] = new Name(data.getterFunction(1), names[THIS_MH]);
871 names[GET_FALLBACK] = new Name(data.getterFunction(2), names[THIS_MH]);
872
873 Object[] invokeArgs = Arrays.copyOfRange(names, 0, ARG_LIMIT, Object[].class);
874
875 // call test
876 MethodType testType = basicType.changeReturnType(boolean.class).basicType();
877 invokeArgs[0] = names[GET_TEST];
878 names[CALL_TEST] = new Name(testType, invokeArgs);
879
880 // call selectAlternative
881 names[SELECT_ALT] = new Name(Lazy.MH_selectAlternative, names[CALL_TEST],
882 names[GET_TARGET], names[GET_FALLBACK]);
883
884 // call target or fallback
885 invokeArgs[0] = names[SELECT_ALT];
886 names[CALL_TARGET] = new Name(basicType, invokeArgs);
887
888 lform = new LambdaForm("guard", lambdaType.parameterCount(), names);
889
890 return basicType.form().setCachedLambdaForm(MethodTypeForm.LF_GWT, lform);
891 }
892
893 /**
894 * The LambdaForm shape for catchException combinator is the following:
895 * <blockquote><pre>{@code
896 * guardWithCatch=Lambda(a0:L,a1:L,a2:L)=>{
897 * t3:L=BoundMethodHandle$Species_LLLLL.argL0(a0:L);
898 * t4:L=BoundMethodHandle$Species_LLLLL.argL1(a0:L);
899 * t5:L=BoundMethodHandle$Species_LLLLL.argL2(a0:L);
900 * t6:L=BoundMethodHandle$Species_LLLLL.argL3(a0:L);
901 * t7:L=BoundMethodHandle$Species_LLLLL.argL4(a0:L);
902 * t8:L=MethodHandle.invokeBasic(t6:L,a1:L,a2:L);
903 * t9:L=MethodHandleImpl.guardWithCatch(t3:L,t4:L,t5:L,t8:L);
904 * t10:I=MethodHandle.invokeBasic(t7:L,t9:L);t10:I}
905 * }</pre></blockquote>
906 *
907 * argL0 and argL2 are target and catcher method handles. argL1 is exception class.
908 * argL3 and argL4 are auxiliary method handles: argL3 boxes arguments and wraps them into Object[]
|
580 int len = java.lang.reflect.Array.getLength(av);
581 if (len == n) return;
582 }
583 // fall through to error:
584 throw newIllegalArgumentException("array is not of length "+n);
585 }
586
587 /**
588 * Pre-initialized NamedFunctions for bootstrapping purposes.
589 * Factored in an inner class to delay initialization until first usage.
590 */
591 static class Lazy {
592 private static final Class<?> MHI = MethodHandleImpl.class;
593
594 private static final MethodHandle[] ARRAYS;
595 private static final MethodHandle[] FILL_ARRAYS;
596
597 static final NamedFunction NF_checkSpreadArgument;
598 static final NamedFunction NF_guardWithCatch;
599 static final NamedFunction NF_throwException;
600 static final NamedFunction NF_profileBoolean;
601
602 static final MethodHandle MH_castReference;
603 static final MethodHandle MH_selectAlternative;
604 static final MethodHandle MH_copyAsPrimitiveArray;
605 static final MethodHandle MH_fillNewTypedArray;
606 static final MethodHandle MH_fillNewArray;
607 static final MethodHandle MH_arrayIdentity;
608
609 static {
610 ARRAYS = makeArrays();
611 FILL_ARRAYS = makeFillArrays();
612
613 try {
614 NF_checkSpreadArgument = new NamedFunction(MHI.getDeclaredMethod("checkSpreadArgument", Object.class, int.class));
615 NF_guardWithCatch = new NamedFunction(MHI.getDeclaredMethod("guardWithCatch", MethodHandle.class, Class.class,
616 MethodHandle.class, Object[].class));
617 NF_throwException = new NamedFunction(MHI.getDeclaredMethod("throwException", Throwable.class));
618 NF_profileBoolean = new NamedFunction(MHI.getDeclaredMethod("profileBoolean", boolean.class, int[].class));
619
620 NF_checkSpreadArgument.resolve();
621 NF_guardWithCatch.resolve();
622 NF_throwException.resolve();
623 NF_profileBoolean.resolve();
624
625 MH_castReference = IMPL_LOOKUP.findStatic(MHI, "castReference",
626 MethodType.methodType(Object.class, Class.class, Object.class));
627 MH_copyAsPrimitiveArray = IMPL_LOOKUP.findStatic(MHI, "copyAsPrimitiveArray",
628 MethodType.methodType(Object.class, Wrapper.class, Object[].class));
629 MH_arrayIdentity = IMPL_LOOKUP.findStatic(MHI, "identity",
630 MethodType.methodType(Object[].class, Object[].class));
631 MH_fillNewArray = IMPL_LOOKUP.findStatic(MHI, "fillNewArray",
632 MethodType.methodType(Object[].class, Integer.class, Object[].class));
633 MH_fillNewTypedArray = IMPL_LOOKUP.findStatic(MHI, "fillNewTypedArray",
634 MethodType.methodType(Object[].class, Object[].class, Integer.class, Object[].class));
635
636 MH_selectAlternative = makeIntrinsic(
637 IMPL_LOOKUP.findStatic(MHI, "selectAlternative",
638 MethodType.methodType(MethodHandle.class, boolean.class, MethodHandle.class, MethodHandle.class)),
639 Intrinsic.SELECT_ALTERNATIVE);
640 } catch (ReflectiveOperationException ex) {
641 throw newInternalError(ex);
642 }
643 }
683 targetArgs[targetArgPos++] = names[collectNamePos];
684 }
685 chunk = collectArgCount;
686 if (retainOriginalArgs) {
687 System.arraycopy(names, inputArgPos, targetArgs, targetArgPos, chunk);
688 targetArgPos += chunk; // optionally pass on the collected chunk
689 }
690 inputArgPos += chunk;
691 chunk = targetArgs.length - targetArgPos; // all the rest
692 System.arraycopy(names, inputArgPos, targetArgs, targetArgPos, chunk);
693 assert(inputArgPos + chunk == collectNamePos); // use of rest of input args also
694 names[targetNamePos] = new Name(target, (Object[]) targetArgs);
695
696 LambdaForm form = new LambdaForm("collect", lambdaType.parameterCount(), names);
697 return SimpleMethodHandle.make(srcType, form);
698 }
699
700 @LambdaForm.Hidden
701 static
702 MethodHandle selectAlternative(boolean testResult, MethodHandle target, MethodHandle fallback) {
703 if (testResult) {
704 return target;
705 } else {
706 return fallback;
707 }
708 }
709
710 // Intrinsified by C2. Counters are used during parsing to calculate branch frequencies.
711 @LambdaForm.Hidden
712 static
713 boolean profileBoolean(boolean result, int[] counters) {
714 // Profile is int[2] where [0] and [1] correspond to false and true occurrences respectively.
715 int idx = result ? 1 : 0;
716 try {
717 counters[idx] = Math.addExact(counters[idx], 1);
718 } catch (ArithmeticException e) {
719 // Avoid continuous overflow by halving the problematic count.
720 counters[idx] = counters[idx] / 2;
721 }
722 return result;
723 }
724
725 static
726 MethodHandle makeGuardWithTest(MethodHandle test,
727 MethodHandle target,
728 MethodHandle fallback) {
729 MethodType type = target.type();
730 assert(test.type().equals(type.changeReturnType(boolean.class)) && fallback.type().equals(type));
731 MethodType basicType = type.basicType();
732 LambdaForm form = makeGuardWithTestForm(basicType);
733 BoundMethodHandle mh;
734 try {
735 if (PROFILE_GWT) {
736 int[] counts = new int[2];
737 mh = (BoundMethodHandle)
738 BoundMethodHandle.speciesData_LLLL().constructor().invokeBasic(type, form,
739 (Object) test, (Object) profile(target), (Object) profile(fallback), counts);
740 } else {
741 mh = (BoundMethodHandle)
742 BoundMethodHandle.speciesData_LLL().constructor().invokeBasic(type, form,
743 (Object) test, (Object) profile(target), (Object) profile(fallback));
744 }
745 } catch (Throwable ex) {
746 throw uncaughtException(ex);
747 }
748 assert(mh.type() == type);
749 return mh;
750 }
751
752
753 static
754 MethodHandle profile(MethodHandle target) {
755 if (DONT_INLINE_THRESHOLD >= 0) {
756 return makeBlockInlningWrapper(target);
757 } else {
758 return target;
759 }
760 }
761
762 /**
763 * Block inlining during JIT-compilation of a target method handle if it hasn't been invoked enough times.
764 * Corresponding LambdaForm has @DontInline when compiled into bytecode.
866 Class<?> THIS_CLASS = CountingWrapper.class;
867 try {
868 NF_maybeStopCounting = new NamedFunction(THIS_CLASS.getDeclaredMethod("maybeStopCounting", Object.class));
869 } catch (ReflectiveOperationException ex) {
870 throw newInternalError(ex);
871 }
872 }
873 }
874
875 static
876 LambdaForm makeGuardWithTestForm(MethodType basicType) {
877 LambdaForm lform = basicType.form().cachedLambdaForm(MethodTypeForm.LF_GWT);
878 if (lform != null) return lform;
879 final int THIS_MH = 0; // the BMH_LLL
880 final int ARG_BASE = 1; // start of incoming arguments
881 final int ARG_LIMIT = ARG_BASE + basicType.parameterCount();
882 int nameCursor = ARG_LIMIT;
883 final int GET_TEST = nameCursor++;
884 final int GET_TARGET = nameCursor++;
885 final int GET_FALLBACK = nameCursor++;
886 final int GET_COUNTERS = PROFILE_GWT ? nameCursor++ : -1;
887 final int CALL_TEST = nameCursor++;
888 final int PROFILE = (GET_COUNTERS != -1) ? nameCursor++ : -1;
889 final int TEST = nameCursor-1; // previous statement: either PROFILE or CALL_TEST
890 final int SELECT_ALT = nameCursor++;
891 final int CALL_TARGET = nameCursor++;
892 assert(CALL_TARGET == SELECT_ALT+1); // must be true to trigger IBG.emitSelectAlternative
893
894 MethodType lambdaType = basicType.invokerType();
895 Name[] names = arguments(nameCursor - ARG_LIMIT, lambdaType);
896
897 BoundMethodHandle.SpeciesData data =
898 (GET_COUNTERS != -1) ? BoundMethodHandle.speciesData_LLLL()
899 : BoundMethodHandle.speciesData_LLL();
900 names[THIS_MH] = names[THIS_MH].withConstraint(data);
901 names[GET_TEST] = new Name(data.getterFunction(0), names[THIS_MH]);
902 names[GET_TARGET] = new Name(data.getterFunction(1), names[THIS_MH]);
903 names[GET_FALLBACK] = new Name(data.getterFunction(2), names[THIS_MH]);
904 if (GET_COUNTERS != -1) {
905 names[GET_COUNTERS] = new Name(data.getterFunction(3), names[THIS_MH]);
906 }
907 Object[] invokeArgs = Arrays.copyOfRange(names, 0, ARG_LIMIT, Object[].class);
908
909 // call test
910 MethodType testType = basicType.changeReturnType(boolean.class).basicType();
911 invokeArgs[0] = names[GET_TEST];
912 names[CALL_TEST] = new Name(testType, invokeArgs);
913
914 // profile branch
915 if (PROFILE != -1) {
916 names[PROFILE] = new Name(Lazy.NF_profileBoolean, names[CALL_TEST], names[GET_COUNTERS]);
917 }
918 // call selectAlternative
919 names[SELECT_ALT] = new Name(Lazy.MH_selectAlternative, names[TEST], names[GET_TARGET], names[GET_FALLBACK]);
920
921 // call target or fallback
922 invokeArgs[0] = names[SELECT_ALT];
923 names[CALL_TARGET] = new Name(basicType, invokeArgs);
924
925 lform = new LambdaForm("guard", lambdaType.parameterCount(), names, /*forceInline=*/true);
926
927 return basicType.form().setCachedLambdaForm(MethodTypeForm.LF_GWT, lform);
928 }
929
930 /**
931 * The LambdaForm shape for catchException combinator is the following:
932 * <blockquote><pre>{@code
933 * guardWithCatch=Lambda(a0:L,a1:L,a2:L)=>{
934 * t3:L=BoundMethodHandle$Species_LLLLL.argL0(a0:L);
935 * t4:L=BoundMethodHandle$Species_LLLLL.argL1(a0:L);
936 * t5:L=BoundMethodHandle$Species_LLLLL.argL2(a0:L);
937 * t6:L=BoundMethodHandle$Species_LLLLL.argL3(a0:L);
938 * t7:L=BoundMethodHandle$Species_LLLLL.argL4(a0:L);
939 * t8:L=MethodHandle.invokeBasic(t6:L,a1:L,a2:L);
940 * t9:L=MethodHandleImpl.guardWithCatch(t3:L,t4:L,t5:L,t8:L);
941 * t10:I=MethodHandle.invokeBasic(t7:L,t9:L);t10:I}
942 * }</pre></blockquote>
943 *
944 * argL0 and argL2 are target and catcher method handles. argL1 is exception class.
945 * argL3 and argL4 are auxiliary method handles: argL3 boxes arguments and wraps them into Object[]
|