src/java.base/share/classes/java/lang/invoke/LambdaForm.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/LambdaForm.java

Print this page
rev 11011 : 8063137: Never-taken branches should be pruned when GWT LambdaForms are shared
Reviewed-by: ?


 103  *                 t3:L = MethodHandle#invoke(t2, a1);
 104  *                 t4:L = FilterMethodHandle#target(a0);
 105  *                 t5:L = MethodHandle#invoke(t4, t3); t5 }
 106  *     == general invoker for unary filterArgument combination
 107  * (a0:L, a1:L)=>{ ...(same as previous example)...
 108  *                 t5:L = MethodHandle#invoke(t4, t3, a1); t5 }
 109  *     == general invoker for unary/unary foldArgument combination
 110  * (a0:L, a1:I)=>{ t2:I = identity(long).asType((int)->long)(a1); t2 }
 111  *     == invoker for identity method handle which performs i2l
 112  * (a0:L, a1:L)=>{ t2:L = BoundMethodHandle#argument(a0);
 113  *                 t3:L = Class#cast(t2,a1); t3 }
 114  *     == invoker for identity method handle which performs cast
 115  * }</pre></blockquote>
 116  * <p>
 117  * @author John Rose, JSR 292 EG
 118  */
 119 class LambdaForm {
 120     final int arity;
 121     final int result;
 122     final boolean forceInline;

 123     @Stable final Name[] names;
 124     final String debugName;
 125     MemberName vmentry;   // low-level behavior, or null if not yet prepared
 126     private boolean isCompiled;
 127 
 128     Object transformCache;  // managed by LambdaFormEditor
 129 
 130     public static final int VOID_RESULT = -1, LAST_RESULT = -2;
 131 
 132     enum BasicType {
 133         L_TYPE('L', Object.class, Wrapper.OBJECT),  // all reference types
 134         I_TYPE('I', int.class,    Wrapper.INT),
 135         J_TYPE('J', long.class,   Wrapper.LONG),
 136         F_TYPE('F', float.class,  Wrapper.FLOAT),
 137         D_TYPE('D', double.class, Wrapper.DOUBLE),  // all primitive types
 138         V_TYPE('V', void.class,   Wrapper.VOID);    // not valid in all contexts
 139 
 140         static final BasicType[] ALL_TYPES = BasicType.values();
 141         static final BasicType[] ARG_TYPES = Arrays.copyOf(ALL_TYPES, ALL_TYPES.length-1);
 142 


 227             return "LIJFD".indexOf(c) >= 0;
 228         }
 229 
 230         static { assert(checkBasicType()); }
 231         private static boolean checkBasicType() {
 232             for (int i = 0; i < ARG_TYPE_LIMIT; i++) {
 233                 assert ARG_TYPES[i].ordinal() == i;
 234                 assert ARG_TYPES[i] == ALL_TYPES[i];
 235             }
 236             for (int i = 0; i < TYPE_LIMIT; i++) {
 237                 assert ALL_TYPES[i].ordinal() == i;
 238             }
 239             assert ALL_TYPES[TYPE_LIMIT - 1] == V_TYPE;
 240             assert !Arrays.asList(ARG_TYPES).contains(V_TYPE);
 241             return true;
 242         }
 243     }
 244 
 245     LambdaForm(String debugName,
 246                int arity, Name[] names, int result) {
 247         this(debugName, arity, names, result, true);
 248     }
 249     LambdaForm(String debugName,
 250                int arity, Name[] names, int result, boolean forceInline) {
 251         assert(namesOK(arity, names));
 252         this.arity = arity;
 253         this.result = fixResult(result, names);
 254         this.names = names.clone();
 255         this.debugName = fixDebugName(debugName);
 256         this.forceInline = forceInline;

 257         int maxOutArity = normalize();
 258         if (maxOutArity > MethodType.MAX_MH_INVOKER_ARITY) {
 259             // Cannot use LF interpreter on very high arity expressions.
 260             assert(maxOutArity <= MethodType.MAX_JVM_ARITY);
 261             compileToBytecode();
 262         }
 263     }
 264     LambdaForm(String debugName,
 265                int arity, Name[] names) {
 266         this(debugName, arity, names, LAST_RESULT, true);
 267     }
 268     LambdaForm(String debugName,
 269                int arity, Name[] names, boolean forceInline) {
 270         this(debugName, arity, names, LAST_RESULT, forceInline);
 271     }
 272     LambdaForm(String debugName,
 273                Name[] formals, Name[] temps, Name result) {
 274         this(debugName,
 275              formals.length, buildNames(formals, temps, result), LAST_RESULT, true);
 276     }
 277     LambdaForm(String debugName,
 278                Name[] formals, Name[] temps, Name result, boolean forceInline) {
 279         this(debugName,
 280              formals.length, buildNames(formals, temps, result), LAST_RESULT, forceInline);




 281     }
 282 
 283     private static Name[] buildNames(Name[] formals, Name[] temps, Name result) {
 284         int arity = formals.length;
 285         int length = arity + temps.length + (result == null ? 0 : 1);
 286         Name[] names = Arrays.copyOf(formals, length);
 287         System.arraycopy(temps, 0, names, arity, temps.length);
 288         if (result != null)
 289             names[length - 1] = result;
 290         return names;
 291     }
 292 
 293     private LambdaForm(String sig) {
 294         this(sig, true);
 295     }
 296 
 297     private LambdaForm(String sig, boolean forceInline) {
 298         // Make a blank lambda form, which returns a constant zero or null.
 299         // It is used as a template for managing the invocation of similar forms that are non-empty.
 300         // Called only from getPreparedForm.
 301         assert(isValidSignature(sig));
 302         this.arity = signatureArity(sig);
 303         this.result = (signatureReturn(sig) == V_TYPE ? -1 : arity);
 304         this.names = buildEmptyNames(arity, sig);
 305         this.debugName = "LF.zero";
 306         this.forceInline = forceInline;

 307         assert(nameRefsAreLegal());
 308         assert(isEmpty());
 309         assert(sig.equals(basicTypeSignature())) : sig + " != " + basicTypeSignature();
 310     }
 311 
 312     private static Name[] buildEmptyNames(int arity, String basicTypeSignature) {
 313         assert(isValidSignature(basicTypeSignature));
 314         int resultPos = arity + 1;  // skip '_'
 315         if (arity < 0 || basicTypeSignature.length() != resultPos+1)
 316             throw new IllegalArgumentException("bad arity for "+basicTypeSignature);
 317         int numRes = (basicType(basicTypeSignature.charAt(resultPos)) == V_TYPE ? 0 : 1);
 318         Name[] names = arguments(numRes, basicTypeSignature.substring(0, arity));
 319         for (int i = 0; i < numRes; i++) {
 320             Name zero = new Name(constantZero(basicType(basicTypeSignature.charAt(resultPos + i))));
 321             names[arity + i] = zero.newIndex(arity + i);
 322         }
 323         return names;
 324     }
 325 
 326     private static int fixResult(int result, Name[] names) {


1778     private static void zero_V() { return; }
1779 
1780     /**
1781      * Internal marker for byte-compiled LambdaForms.
1782      */
1783     /*non-public*/
1784     @Target(ElementType.METHOD)
1785     @Retention(RetentionPolicy.RUNTIME)
1786     @interface Compiled {
1787     }
1788 
1789     /**
1790      * Internal marker for LambdaForm interpreter frames.
1791      */
1792     /*non-public*/
1793     @Target(ElementType.METHOD)
1794     @Retention(RetentionPolicy.RUNTIME)
1795     @interface Hidden {
1796     }
1797 









1798     private static final HashMap<String,Integer> DEBUG_NAME_COUNTERS;
1799     static {
1800         if (debugEnabled())
1801             DEBUG_NAME_COUNTERS = new HashMap<>();
1802         else
1803             DEBUG_NAME_COUNTERS = null;
1804     }
1805 
1806     // Put this last, so that previous static inits can run before.
1807     static {
1808         createIdentityForms();
1809         if (USE_PREDEFINED_INTERPRET_METHODS)
1810             computeInitialPreparedForms();
1811         NamedFunction.initializeInvokers();
1812     }
1813 
1814     // The following hack is necessary in order to suppress TRACE_INTERPRETER
1815     // during execution of the static initializes of this class.
1816     // Turning on TRACE_INTERPRETER too early will cause
1817     // stack overflows and other misbehavior during attempts to trace events


 103  *                 t3:L = MethodHandle#invoke(t2, a1);
 104  *                 t4:L = FilterMethodHandle#target(a0);
 105  *                 t5:L = MethodHandle#invoke(t4, t3); t5 }
 106  *     == general invoker for unary filterArgument combination
 107  * (a0:L, a1:L)=>{ ...(same as previous example)...
 108  *                 t5:L = MethodHandle#invoke(t4, t3, a1); t5 }
 109  *     == general invoker for unary/unary foldArgument combination
 110  * (a0:L, a1:I)=>{ t2:I = identity(long).asType((int)->long)(a1); t2 }
 111  *     == invoker for identity method handle which performs i2l
 112  * (a0:L, a1:L)=>{ t2:L = BoundMethodHandle#argument(a0);
 113  *                 t3:L = Class#cast(t2,a1); t3 }
 114  *     == invoker for identity method handle which performs cast
 115  * }</pre></blockquote>
 116  * <p>
 117  * @author John Rose, JSR 292 EG
 118  */
 119 class LambdaForm {
 120     final int arity;
 121     final int result;
 122     final boolean forceInline;
 123     final boolean isGWT;
 124     @Stable final Name[] names;
 125     final String debugName;
 126     MemberName vmentry;   // low-level behavior, or null if not yet prepared
 127     private boolean isCompiled;
 128 
 129     Object transformCache;  // managed by LambdaFormEditor
 130 
 131     public static final int VOID_RESULT = -1, LAST_RESULT = -2;
 132 
 133     enum BasicType {
 134         L_TYPE('L', Object.class, Wrapper.OBJECT),  // all reference types
 135         I_TYPE('I', int.class,    Wrapper.INT),
 136         J_TYPE('J', long.class,   Wrapper.LONG),
 137         F_TYPE('F', float.class,  Wrapper.FLOAT),
 138         D_TYPE('D', double.class, Wrapper.DOUBLE),  // all primitive types
 139         V_TYPE('V', void.class,   Wrapper.VOID);    // not valid in all contexts
 140 
 141         static final BasicType[] ALL_TYPES = BasicType.values();
 142         static final BasicType[] ARG_TYPES = Arrays.copyOf(ALL_TYPES, ALL_TYPES.length-1);
 143 


 228             return "LIJFD".indexOf(c) >= 0;
 229         }
 230 
 231         static { assert(checkBasicType()); }
 232         private static boolean checkBasicType() {
 233             for (int i = 0; i < ARG_TYPE_LIMIT; i++) {
 234                 assert ARG_TYPES[i].ordinal() == i;
 235                 assert ARG_TYPES[i] == ALL_TYPES[i];
 236             }
 237             for (int i = 0; i < TYPE_LIMIT; i++) {
 238                 assert ALL_TYPES[i].ordinal() == i;
 239             }
 240             assert ALL_TYPES[TYPE_LIMIT - 1] == V_TYPE;
 241             assert !Arrays.asList(ARG_TYPES).contains(V_TYPE);
 242             return true;
 243         }
 244     }
 245 
 246     LambdaForm(String debugName,
 247                int arity, Name[] names, int result) {
 248         this(debugName, arity, names, result, /*forceInline=*/true, /*isGWT=*/false);
 249     }
 250     LambdaForm(String debugName,
 251                int arity, Name[] names, int result, boolean forceInline, boolean isGWT) {
 252         assert(namesOK(arity, names));
 253         this.arity = arity;
 254         this.result = fixResult(result, names);
 255         this.names = names.clone();
 256         this.debugName = fixDebugName(debugName);
 257         this.forceInline = forceInline;
 258         this.isGWT = isGWT;
 259         int maxOutArity = normalize();
 260         if (maxOutArity > MethodType.MAX_MH_INVOKER_ARITY) {
 261             // Cannot use LF interpreter on very high arity expressions.
 262             assert(maxOutArity <= MethodType.MAX_JVM_ARITY);
 263             compileToBytecode();
 264         }
 265     }
 266     LambdaForm(String debugName,
 267                int arity, Name[] names) {
 268         this(debugName, arity, names, LAST_RESULT, /*forceInline=*/true, /*isGWT=*/false);
 269     }
 270     LambdaForm(String debugName,
 271                int arity, Name[] names, boolean forceInline, boolean isGWT) {
 272         this(debugName, arity, names, LAST_RESULT, forceInline, isGWT);
 273     }
 274     LambdaForm(String debugName,
 275                Name[] formals, Name[] temps, Name result) {
 276         this(debugName,
 277              formals.length, buildNames(formals, temps, result), LAST_RESULT, /*forceInline=*/true, /*isGWT=*/false);
 278     }
 279     LambdaForm(String debugName,
 280                Name[] formals, Name[] temps, Name result, boolean forceInline) {
 281         this(debugName,
 282              formals.length, buildNames(formals, temps, result), LAST_RESULT, forceInline, /*isGWT=*/false);
 283     }
 284 
 285     static LambdaForm makeGuardWithTestForm(int paramCount, Name[] names) {
 286         return new LambdaForm("guard", paramCount, names, /*forceInline=*/true, /*isGWT=*/true);
 287     }
 288 
 289     private static Name[] buildNames(Name[] formals, Name[] temps, Name result) {
 290         int arity = formals.length;
 291         int length = arity + temps.length + (result == null ? 0 : 1);
 292         Name[] names = Arrays.copyOf(formals, length);
 293         System.arraycopy(temps, 0, names, arity, temps.length);
 294         if (result != null)
 295             names[length - 1] = result;
 296         return names;
 297     }
 298 
 299     private LambdaForm(String sig) {




 300         // Make a blank lambda form, which returns a constant zero or null.
 301         // It is used as a template for managing the invocation of similar forms that are non-empty.
 302         // Called only from getPreparedForm.
 303         assert(isValidSignature(sig));
 304         this.arity = signatureArity(sig);
 305         this.result = (signatureReturn(sig) == V_TYPE ? -1 : arity);
 306         this.names = buildEmptyNames(arity, sig);
 307         this.debugName = "LF.zero";
 308         this.forceInline = true;
 309         this.isGWT = false;
 310         assert(nameRefsAreLegal());
 311         assert(isEmpty());
 312         assert(sig.equals(basicTypeSignature())) : sig + " != " + basicTypeSignature();
 313     }
 314 
 315     private static Name[] buildEmptyNames(int arity, String basicTypeSignature) {
 316         assert(isValidSignature(basicTypeSignature));
 317         int resultPos = arity + 1;  // skip '_'
 318         if (arity < 0 || basicTypeSignature.length() != resultPos+1)
 319             throw new IllegalArgumentException("bad arity for "+basicTypeSignature);
 320         int numRes = (basicType(basicTypeSignature.charAt(resultPos)) == V_TYPE ? 0 : 1);
 321         Name[] names = arguments(numRes, basicTypeSignature.substring(0, arity));
 322         for (int i = 0; i < numRes; i++) {
 323             Name zero = new Name(constantZero(basicType(basicTypeSignature.charAt(resultPos + i))));
 324             names[arity + i] = zero.newIndex(arity + i);
 325         }
 326         return names;
 327     }
 328 
 329     private static int fixResult(int result, Name[] names) {


1781     private static void zero_V() { return; }
1782 
1783     /**
1784      * Internal marker for byte-compiled LambdaForms.
1785      */
1786     /*non-public*/
1787     @Target(ElementType.METHOD)
1788     @Retention(RetentionPolicy.RUNTIME)
1789     @interface Compiled {
1790     }
1791 
1792     /**
1793      * Internal marker for LambdaForm interpreter frames.
1794      */
1795     /*non-public*/
1796     @Target(ElementType.METHOD)
1797     @Retention(RetentionPolicy.RUNTIME)
1798     @interface Hidden {
1799     }
1800 
1801     /**
1802      * Internal marker which signals JIT that gathered profile is useless.
1803      */
1804     /*non-public*/
1805     @Target(ElementType.METHOD)
1806     @Retention(RetentionPolicy.RUNTIME)
1807     @interface IgnoreProfile {
1808     }
1809 
1810     private static final HashMap<String,Integer> DEBUG_NAME_COUNTERS;
1811     static {
1812         if (debugEnabled())
1813             DEBUG_NAME_COUNTERS = new HashMap<>();
1814         else
1815             DEBUG_NAME_COUNTERS = null;
1816     }
1817 
1818     // Put this last, so that previous static inits can run before.
1819     static {
1820         createIdentityForms();
1821         if (USE_PREDEFINED_INTERPRET_METHODS)
1822             computeInitialPreparedForms();
1823         NamedFunction.initializeInvokers();
1824     }
1825 
1826     // The following hack is necessary in order to suppress TRACE_INTERPRETER
1827     // during execution of the static initializes of this class.
1828     // Turning on TRACE_INTERPRETER too early will cause
1829     // stack overflows and other misbehavior during attempts to trace events
src/java.base/share/classes/java/lang/invoke/LambdaForm.java
Index Unified diffs Context diffs Sdiffs Patch New Old Previous File Next File