src/java.base/share/classes/java/lang/invoke/MethodHandleImpl.java
Index Unified diffs Context diffs Sdiffs Patch New Old Previous File Next File jdk Sdiff src/java.base/share/classes/java/lang/invoke

src/java.base/share/classes/java/lang/invoke/MethodHandleImpl.java

Print this page
rev 11254 : 8063137: Never-taken branches should be pruned when GWT LambdaForms are shared
Reviewed-by: ?
rev 11255 : [mq]: gwt.profile.1
rev 11256 : [mq]: gwt.profile.2
rev 11257 : [mq]: gwt.profile.3
rev 11258 : [mq]: gwt.profile.4


 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[]


src/java.base/share/classes/java/lang/invoke/MethodHandleImpl.java
Index Unified diffs Context diffs Sdiffs Patch New Old Previous File Next File