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 }
641 }
642
643 /** Factory method: Collect or filter selected argument(s). */
644 static MethodHandle makeCollectArguments(MethodHandle target,
645 MethodHandle collector, int collectArgPos, boolean retainOriginalArgs) {
646 MethodType targetType = target.type(); // (a..., c, [b...])=>r
647 MethodType collectorType = collector.type(); // (b...)=>c
648 int collectArgCount = collectorType.parameterCount();
649 Class<?> collectValType = collectorType.returnType();
650 int collectValCount = (collectValType == void.class ? 0 : 1);
651 MethodType srcType = targetType // (a..., [b...])=>r
652 .dropParameterTypes(collectArgPos, collectArgPos+collectValCount);
653 if (!retainOriginalArgs) { // (a..., b...)=>r
654 srcType = srcType.insertParameterTypes(collectArgPos, collectorType.parameterList());
655 }
679 if (collectValType != void.class) {
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[]
|
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, int[].class)),
636 Intrinsic.SELECT_ALTERNATIVE);
637 } catch (ReflectiveOperationException ex) {
638 throw newInternalError(ex);
639 }
640 }
641 }
642
643 /** Factory method: Collect or filter selected argument(s). */
644 static MethodHandle makeCollectArguments(MethodHandle target,
645 MethodHandle collector, int collectArgPos, boolean retainOriginalArgs) {
646 MethodType targetType = target.type(); // (a..., c, [b...])=>r
647 MethodType collectorType = collector.type(); // (b...)=>c
648 int collectArgCount = collectorType.parameterCount();
649 Class<?> collectValType = collectorType.returnType();
650 int collectValCount = (collectValType == void.class ? 0 : 1);
651 MethodType srcType = targetType // (a..., [b...])=>r
652 .dropParameterTypes(collectArgPos, collectArgPos+collectValCount);
653 if (!retainOriginalArgs) { // (a..., b...)=>r
654 srcType = srcType.insertParameterTypes(collectArgPos, collectorType.parameterList());
655 }
679 if (collectValType != void.class) {
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, int[] counters) {
700 if (counters != null) {
701 updateCounters(counters, testResult);
702 }
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 profileBranch(boolean result, int[] counters) {
714 updateCounters(counters, result);
715 return result;
716 }
717
718 @LambdaForm.Hidden
719 @ForceInline
720 static
721 void updateCounters(int[] counters, boolean result) {
722 int idx = result ? 0 : 1;
723 try {
724 counters[idx] = Math.addExact(counters[idx], 1);
725 } catch (ArithmeticException e) {
726 // skip update when the counter overflows
727 }
728 }
729
730 static
731 MethodHandle makeGuardWithTest(MethodHandle test,
732 MethodHandle target,
733 MethodHandle fallback) {
734 MethodType type = target.type();
735 assert(test.type().equals(type.changeReturnType(boolean.class)) && fallback.type().equals(type));
736 MethodType basicType = type.basicType();
737 int[] counters = PROFILE_GWT ? new int[2] : null;
738 LambdaForm form = makeGuardWithTestForm(basicType);
739 BoundMethodHandle.SpeciesData data = BoundMethodHandle.speciesData_LLLL();
740 BoundMethodHandle mh;
741
742 try {
743 mh = (BoundMethodHandle)
744 data.constructor().invokeBasic(type, form,
745 (Object) test, (Object) profile(target), (Object) profile(fallback), counters);
746 } catch (Throwable ex) {
747 throw uncaughtException(ex);
748 }
749 assert(mh.type() == type);
750 return mh;
751 }
752
753
754 static
755 MethodHandle profile(MethodHandle target) {
756 if (DONT_INLINE_THRESHOLD >= 0) {
757 return makeBlockInlningWrapper(target);
758 } else {
759 return target;
760 }
761 }
762
763 /**
764 * Block inlining during JIT-compilation of a target method handle if it hasn't been invoked enough times.
765 * Corresponding LambdaForm has @DontInline when compiled into bytecode.
867 Class<?> THIS_CLASS = CountingWrapper.class;
868 try {
869 NF_maybeStopCounting = new NamedFunction(THIS_CLASS.getDeclaredMethod("maybeStopCounting", Object.class));
870 } catch (ReflectiveOperationException ex) {
871 throw newInternalError(ex);
872 }
873 }
874 }
875
876 static
877 LambdaForm makeGuardWithTestForm(MethodType basicType) {
878 LambdaForm lform = basicType.form().cachedLambdaForm(MethodTypeForm.LF_GWT);
879 if (lform != null) return lform;
880 final int THIS_MH = 0; // the BMH_LLL
881 final int ARG_BASE = 1; // start of incoming arguments
882 final int ARG_LIMIT = ARG_BASE + basicType.parameterCount();
883 int nameCursor = ARG_LIMIT;
884 final int GET_TEST = nameCursor++;
885 final int GET_TARGET = nameCursor++;
886 final int GET_FALLBACK = nameCursor++;
887 final int GET_COUNTERS = nameCursor++;
888 final int CALL_TEST = nameCursor++;
889 final int SELECT_ALT = nameCursor++;
890 final int CALL_TARGET = nameCursor++;
891 assert(CALL_TARGET == SELECT_ALT+1); // must be true to trigger IBG.emitSelectAlternative
892
893 MethodType lambdaType = basicType.invokerType();
894 Name[] names = arguments(nameCursor - ARG_LIMIT, lambdaType);
895
896 BoundMethodHandle.SpeciesData data = BoundMethodHandle.speciesData_LLLL();
897 names[THIS_MH] = names[THIS_MH].withConstraint(data);
898 names[GET_TEST] = new Name(data.getterFunction(0), names[THIS_MH]);
899 names[GET_TARGET] = new Name(data.getterFunction(1), names[THIS_MH]);
900 names[GET_FALLBACK] = new Name(data.getterFunction(2), names[THIS_MH]);
901 names[GET_COUNTERS] = new Name(data.getterFunction(3), names[THIS_MH]);
902 Object[] invokeArgs = Arrays.copyOfRange(names, 0, ARG_LIMIT, Object[].class);
903
904 // call test
905 MethodType testType = basicType.changeReturnType(boolean.class).basicType();
906 invokeArgs[0] = names[GET_TEST];
907 names[CALL_TEST] = new Name(testType, invokeArgs);
908
909 // call selectAlternative
910 names[SELECT_ALT] = new Name(Lazy.MH_selectAlternative, names[CALL_TEST],
911 names[GET_TARGET], names[GET_FALLBACK], names[GET_COUNTERS]);
912
913 // call target or fallback
914 invokeArgs[0] = names[SELECT_ALT];
915 names[CALL_TARGET] = new Name(basicType, invokeArgs);
916
917 lform = LambdaForm.makeGuardWithTestForm(lambdaType.parameterCount(), names);
918
919 return basicType.form().setCachedLambdaForm(MethodTypeForm.LF_GWT, lform);
920 }
921
922 /**
923 * The LambdaForm shape for catchException combinator is the following:
924 * <blockquote><pre>{@code
925 * guardWithCatch=Lambda(a0:L,a1:L,a2:L)=>{
926 * t3:L=BoundMethodHandle$Species_LLLLL.argL0(a0:L);
927 * t4:L=BoundMethodHandle$Species_LLLLL.argL1(a0:L);
928 * t5:L=BoundMethodHandle$Species_LLLLL.argL2(a0:L);
929 * t6:L=BoundMethodHandle$Species_LLLLL.argL3(a0:L);
930 * t7:L=BoundMethodHandle$Species_LLLLL.argL4(a0:L);
931 * t8:L=MethodHandle.invokeBasic(t6:L,a1:L,a2:L);
932 * t9:L=MethodHandleImpl.guardWithCatch(t3:L,t4:L,t5:L,t8:L);
933 * t10:I=MethodHandle.invokeBasic(t7:L,t9:L);t10:I}
934 * }</pre></blockquote>
935 *
936 * argL0 and argL2 are target and catcher method handles. argL1 is exception class.
937 * argL3 and argL4 are auxiliary method handles: argL3 boxes arguments and wraps them into Object[]
|