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 11254 : 8063137: Never-taken branches should be pruned when GWT LambdaForms are shared
Reviewed-by: ?
rev 11255 : [mq]: gwt.profile.1
rev 11258 : 8069591: Customize LambdaForms which are invoked using MH.invoke/invokeExact
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     volatile 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, /*forceInline=*/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, /*forceInline=*/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, /*forceInline=*/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         // Make a blank lambda form, which returns a constant zero or null.
 295         // It is used as a template for managing the invocation of similar forms that are non-empty.
 296         // Called only from getPreparedForm.
 297         assert(isValidSignature(sig));
 298         this.arity = signatureArity(sig);
 299         this.result = (signatureReturn(sig) == V_TYPE ? -1 : arity);
 300         this.names = buildEmptyNames(arity, sig);
 301         this.debugName = "LF.zero";
 302         this.forceInline = true;

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


 354                 if (under < length)
 355                     buf.append('_').append(debugName, under, length);
 356             }
 357             return buf.toString();
 358         }
 359         return debugName;
 360     }
 361 
 362     private static boolean namesOK(int arity, Name[] names) {
 363         for (int i = 0; i < names.length; i++) {
 364             Name n = names[i];
 365             assert(n != null) : "n is null";
 366             if (i < arity)
 367                 assert( n.isParam()) : n + " is not param at " + i;
 368             else
 369                 assert(!n.isParam()) : n + " is param at " + i;
 370         }
 371         return true;
 372     }
 373 





















 374     /** Renumber and/or replace params so that they are interned and canonically numbered.
 375      *  @return maximum argument list length among the names (since we have to pass over them anyway)
 376      */
 377     private int normalize() {
 378         Name[] oldNames = null;
 379         int maxOutArity = 0;
 380         int changesStart = 0;
 381         for (int i = 0; i < names.length; i++) {
 382             Name n = names[i];
 383             if (!n.initIndex(i)) {
 384                 if (oldNames == null) {
 385                     oldNames = names.clone();
 386                     changesStart = i;
 387                 }
 388                 names[i] = n.cloneWithIndex(i);
 389             }
 390             if (n.arguments != null && maxOutArity < n.arguments.length)
 391                 maxOutArity = n.arguments.length;
 392         }
 393         if (oldNames != null) {


 396                 startFixing = changesStart+1;
 397             for (int i = startFixing; i < names.length; i++) {
 398                 Name fixed = names[i].replaceNames(oldNames, names, changesStart, i);
 399                 names[i] = fixed.newIndex(i);
 400             }
 401         }
 402         assert(nameRefsAreLegal());
 403         int maxInterned = Math.min(arity, INTERNED_ARGUMENT_LIMIT);
 404         boolean needIntern = false;
 405         for (int i = 0; i < maxInterned; i++) {
 406             Name n = names[i], n2 = internArgument(n);
 407             if (n != n2) {
 408                 names[i] = n2;
 409                 needIntern = true;
 410             }
 411         }
 412         if (needIntern) {
 413             for (int i = arity; i < names.length; i++) {
 414                 names[i].internArguments();
 415             }
 416             assert(nameRefsAreLegal());
 417         }

 418         return maxOutArity;
 419     }
 420 
 421     /**
 422      * Check that all embedded Name references are localizable to this lambda,
 423      * and are properly ordered after their corresponding definitions.
 424      * <p>
 425      * Note that a Name can be local to multiple lambdas, as long as
 426      * it possesses the same index in each use site.
 427      * This allows Name references to be freely reused to construct
 428      * fresh lambdas, without confusion.
 429      */
 430     boolean nameRefsAreLegal() {
 431         assert(arity >= 0 && arity <= names.length);
 432         assert(result >= -1 && result < names.length);
 433         // Do all names possess an index consistent with their local definition order?
 434         for (int i = 0; i < arity; i++) {
 435             Name n = names[i];
 436             assert(n.index() == i) : Arrays.asList(n.index(), i);
 437             assert(n.isParam());




 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 MethodHandle customized;
 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     volatile 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, /*customized=*/null);
 249     }
 250     LambdaForm(String debugName,
 251                int arity, Name[] names, int result, boolean forceInline, MethodHandle customized) {
 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.customized = customized;
 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, /*customized=*/null);
 269     }
 270     LambdaForm(String debugName,
 271                int arity, Name[] names, boolean forceInline) {
 272         this(debugName, arity, names, LAST_RESULT, forceInline, /*customized=*/null);
 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, /*customized=*/null);
 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, /*customized=*/null);
 283     }
 284 
 285     private static Name[] buildNames(Name[] formals, Name[] temps, Name result) {
 286         int arity = formals.length;
 287         int length = arity + temps.length + (result == null ? 0 : 1);
 288         Name[] names = Arrays.copyOf(formals, length);
 289         System.arraycopy(temps, 0, names, arity, temps.length);
 290         if (result != null)
 291             names[length - 1] = result;
 292         return names;
 293     }
 294 
 295     private LambdaForm(String sig) {
 296         // Make a blank lambda form, which returns a constant zero or null.
 297         // It is used as a template for managing the invocation of similar forms that are non-empty.
 298         // Called only from getPreparedForm.
 299         assert(isValidSignature(sig));
 300         this.arity = signatureArity(sig);
 301         this.result = (signatureReturn(sig) == V_TYPE ? -1 : arity);
 302         this.names = buildEmptyNames(arity, sig);
 303         this.debugName = "LF.zero";
 304         this.forceInline = true;
 305         this.customized = null;
 306         assert(nameRefsAreLegal());
 307         assert(isEmpty());
 308         assert(sig.equals(basicTypeSignature())) : sig + " != " + basicTypeSignature();
 309     }
 310 
 311     private static Name[] buildEmptyNames(int arity, String basicTypeSignature) {
 312         assert(isValidSignature(basicTypeSignature));
 313         int resultPos = arity + 1;  // skip '_'
 314         if (arity < 0 || basicTypeSignature.length() != resultPos+1)
 315             throw new IllegalArgumentException("bad arity for "+basicTypeSignature);
 316         int numRes = (basicType(basicTypeSignature.charAt(resultPos)) == V_TYPE ? 0 : 1);
 317         Name[] names = arguments(numRes, basicTypeSignature.substring(0, arity));
 318         for (int i = 0; i < numRes; i++) {
 319             Name zero = new Name(constantZero(basicType(basicTypeSignature.charAt(resultPos + i))));
 320             names[arity + i] = zero.newIndex(arity + i);
 321         }
 322         return names;
 323     }
 324 
 325     private static int fixResult(int result, Name[] names) {


 357                 if (under < length)
 358                     buf.append('_').append(debugName, under, length);
 359             }
 360             return buf.toString();
 361         }
 362         return debugName;
 363     }
 364 
 365     private static boolean namesOK(int arity, Name[] names) {
 366         for (int i = 0; i < names.length; i++) {
 367             Name n = names[i];
 368             assert(n != null) : "n is null";
 369             if (i < arity)
 370                 assert( n.isParam()) : n + " is not param at " + i;
 371             else
 372                 assert(!n.isParam()) : n + " is param at " + i;
 373         }
 374         return true;
 375     }
 376 
 377     LambdaForm customize(MethodHandle mh) {
 378         LambdaForm customForm = new LambdaForm(debugName, arity, names, result, forceInline, mh);
 379         if (COMPILE_THRESHOLD > 0 && isCompiled) {
 380             // If shared LambdaForm has been compiled, compile customized version as well.
 381             customForm.compileToBytecode();
 382         }
 383         return customForm;
 384     }
 385 
 386     LambdaForm uncustomize() {
 387         if (customized == null) {
 388             return this;
 389         }
 390         LambdaForm uncustomizedForm  = new LambdaForm(debugName, arity, names, result, forceInline, null);
 391         if (COMPILE_THRESHOLD > 0 && isCompiled) {
 392             // If customized LambdaForm has been compiled, compile uncustomized version as well.
 393             uncustomizedForm.compileToBytecode();
 394         }
 395         return uncustomizedForm;
 396     }
 397 
 398     /** Renumber and/or replace params so that they are interned and canonically numbered.
 399      *  @return maximum argument list length among the names (since we have to pass over them anyway)
 400      */
 401     private int normalize() {
 402         Name[] oldNames = null;
 403         int maxOutArity = 0;
 404         int changesStart = 0;
 405         for (int i = 0; i < names.length; i++) {
 406             Name n = names[i];
 407             if (!n.initIndex(i)) {
 408                 if (oldNames == null) {
 409                     oldNames = names.clone();
 410                     changesStart = i;
 411                 }
 412                 names[i] = n.cloneWithIndex(i);
 413             }
 414             if (n.arguments != null && maxOutArity < n.arguments.length)
 415                 maxOutArity = n.arguments.length;
 416         }
 417         if (oldNames != null) {


 420                 startFixing = changesStart+1;
 421             for (int i = startFixing; i < names.length; i++) {
 422                 Name fixed = names[i].replaceNames(oldNames, names, changesStart, i);
 423                 names[i] = fixed.newIndex(i);
 424             }
 425         }
 426         assert(nameRefsAreLegal());
 427         int maxInterned = Math.min(arity, INTERNED_ARGUMENT_LIMIT);
 428         boolean needIntern = false;
 429         for (int i = 0; i < maxInterned; i++) {
 430             Name n = names[i], n2 = internArgument(n);
 431             if (n != n2) {
 432                 names[i] = n2;
 433                 needIntern = true;
 434             }
 435         }
 436         if (needIntern) {
 437             for (int i = arity; i < names.length; i++) {
 438                 names[i].internArguments();
 439             }

 440         }
 441         assert(nameRefsAreLegal());
 442         return maxOutArity;
 443     }
 444 
 445     /**
 446      * Check that all embedded Name references are localizable to this lambda,
 447      * and are properly ordered after their corresponding definitions.
 448      * <p>
 449      * Note that a Name can be local to multiple lambdas, as long as
 450      * it possesses the same index in each use site.
 451      * This allows Name references to be freely reused to construct
 452      * fresh lambdas, without confusion.
 453      */
 454     boolean nameRefsAreLegal() {
 455         assert(arity >= 0 && arity <= names.length);
 456         assert(result >= -1 && result < names.length);
 457         // Do all names possess an index consistent with their local definition order?
 458         for (int i = 0; i < arity; i++) {
 459             Name n = names[i];
 460             assert(n.index() == i) : Arrays.asList(n.index(), i);
 461             assert(n.isParam());


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