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 11011 : 8063137: Never-taken branches should be pruned when GWT LambdaForms are shared
Reviewed-by: ?


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


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