< prev index next >

test/compiler/valhalla/valuetypes/ValueTypeTestBench.java

Print this page




  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * questions.
  22  */
  23 
  24 // TODO add bugid and summary
  25 
  26 /*
  27  * @test
  28  * @library /testlibrary /test/lib /compiler/whitebox /
  29  * @build compiler.valhalla.valuetypes.ValueTypeTestBench
  30  * @run main ClassFileInstaller sun.hotspot.WhiteBox
  31  * @run main ClassFileInstaller jdk.test.lib.Platform
  32  * @run main/othervm -ea -noverify -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI
  33  *                   -XX:+UnlockExperimentalVMOptions -XX:+ValueTypePassFieldsAsArgs
  34  *                   -XX:-TieredCompilation compiler.valhalla.valuetypes.ValueTypeTestBench
  35  * @run main/othervm -ea -noverify -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI
  36  *                   -XX:+UnlockExperimentalVMOptions -XX:-ValueTypePassFieldsAsArgs
  37  *                   -XX:-TieredCompilation compiler.valhalla.valuetypes.ValueTypeTestBench
  38  */
  39 
  40 package compiler.valhalla.valuetypes;
  41 
  42 import compiler.whitebox.CompilerWhiteBoxTest;
  43 import jdk.internal.misc.Unsafe;
  44 import jdk.test.lib.Asserts;
  45 import jdk.test.lib.Platform;
  46 import jdk.test.lib.ProcessTools;
  47 import jdk.test.lib.OutputAnalyzer;
  48 import jdk.test.lib.Utils;
  49 import sun.hotspot.WhiteBox;
  50 
  51 import java.lang.annotation.Retention;
  52 import java.lang.annotation.RetentionPolicy;
  53 import java.lang.annotation.Repeatable;
  54 import java.lang.invoke.*;
  55 import java.lang.reflect.Method;
  56 import java.util.ArrayList;


  83 
  84     @DontInline
  85     public static MyValue1 createDontInline(int x, long y) {
  86         return __Make MyValue1(x, y, MyValue2.createInline(x, true), MyValue2.createInline(x, false), ValueTypeTestBench.rI);
  87     }
  88 
  89     @ForceInline
  90     public static MyValue1 createInline(int x, long y) {
  91         return __Make MyValue1(x, y, MyValue2.createInline(x, true), MyValue2.createInline(x, false), ValueTypeTestBench.rI);
  92     }
  93 
  94     @ForceInline
  95     public long hash() {
  96         return s + sf + x + y + c + v1.hash() + v2.hash() + v3.hash();
  97     }
  98 
  99     @DontCompile
 100     public long hashInterpreted() {
 101         return s + sf + x + y + c + v1.hashInterpreted() + v2.hashInterpreted() + v3.hashInterpreted();
 102     }











 103 }
 104 
 105 __ByValue final class MyValue2 {
 106     final int x;
 107     final boolean b;
 108     final long c;
 109 
 110     private MyValue2(int x, boolean b, long c) {
 111         this.x = x;
 112         this.b = b;
 113         this.c = c;
 114     }
 115 
 116     @ForceInline
 117     public static MyValue2 createInline(int x, boolean b) {
 118         return __Make MyValue2(x, b, ValueTypeTestBench.rL);
 119     }
 120 
 121     @ForceInline
 122     public long hash() {
 123         return x + (b ? 0 : 1) + c;
 124     }
 125 
 126     @DontInline
 127     public long hashInterpreted() {
 128         return x + (b ? 0 : 1) + c;
 129     }





 130 }
 131 
 132 public class ValueTypeTestBench {    
 133     // Print ideal graph after execution of each test
 134     private static final boolean PRINT_GRAPH = true;
 135 
 136     // Random test values
 137     public static final int  rI = Utils.getRandomInstance().nextInt() % 1000;
 138     public static final long rL = Utils.getRandomInstance().nextLong() % 1000;
 139 
 140     public ValueTypeTestBench() {
 141         val3 = MyValue1.createInline(rI, rL);
 142     }
 143 
 144     // MethodHandles and value-capable class instance needed for testing vbox/vunbox
 145     private static final MethodHandle vccUnboxLoadLongMH = generateVCCUnboxLoadLongMH();
 146     private static final MethodHandle vccUnboxLoadIntMH = generateVCCUnboxLoadIntMH();
 147     private static final MethodHandle vccUnboxBoxMH = generateVCCUnboxBoxMH();
 148     private static final MethodHandle vccUnboxBoxLoadIntMH = generateVCCUnboxBoxLoadIntMH();
 149 


 266 
 267     // Merge value types created from two branches
 268     @Test(failOn = ALLOC + STORE + TRAP)
 269     public long test8(boolean b) {
 270         MyValue1 v;
 271         if (b) {
 272             v = MyValue1.createInline(rI, rL);
 273         } else {
 274             v = MyValue1.createDontInline(rI + 1, rL + 1);
 275         }
 276         return v.hash();
 277     }
 278 
 279     @DontCompile
 280     public void test8_verifier(boolean warmup) {
 281         Asserts.assertEQ(test8(true), hash());
 282         Asserts.assertEQ(test8(false), hash(rI + 1, rL + 1));
 283     }
 284 
 285     // Merge value types created from two branches
 286     @Test(valid = ValueTypePassFieldsAsArgsOn, match = {LOAD}, matchCount = {9}, failOn = TRAP + ALLOC + STORE)


 287     @Test(valid = ValueTypePassFieldsAsArgsOff, match = {ALLOC, STORE}, matchCount = {1, 3}, failOn = LOAD + TRAP)
 288     public MyValue1 test9(boolean b) {
 289         MyValue1 v;
 290         if (b) {
 291             // Value type is not allocated
 292             v = MyValue1.createInline(rI, rL);
 293         } else {
 294             // Value type is allocated by the callee
 295             v = MyValue1.createDontInline(rI + 1, rL + 1);
 296         }
 297         // Need to allocate value type if 'b' is true
 298         long sum = v.hashInterpreted();
 299         if (b) {
 300             v = MyValue1.createDontInline(rI, sum);
 301         } else {
 302             v = MyValue1.createDontInline(rI, sum + 1);
 303         }
 304         // Don't need to allocate value type because both branches allocate
 305         return v;
 306     }


 378         for (int i = 0; i < 1000; ++i) {
 379             if (b) {
 380                 result += v.x;
 381             } else {
 382                 // Uncommon trap referencing v. Should not allocate
 383                 // but just pass the existing oop to the uncommon trap.
 384                 result = v.hashInterpreted();
 385             }
 386         }
 387         return result;
 388     }
 389 
 390     @DontCompile
 391     public void test13_verifier(boolean warmup) {
 392         long result = test13(warmup);
 393         Asserts.assertEQ(result, warmup ? 42 + (1000*rI) : hash());
 394     }
 395 
 396     // Create a value type in a non-inlined method and then call a
 397     // non-inlined method on that value type.
 398     @Test(valid = ValueTypePassFieldsAsArgsOn, failOn = (ALLOC + STORE + TRAP), match = {LOAD}, matchCount = {9})
 399     @Test(valid = ValueTypePassFieldsAsArgsOff, failOn = (ALLOC + LOAD + STORE + TRAP))
 400     public long test14() {
 401         MyValue1 v = MyValue1.createDontInline(rI, rL);
 402         return v.hashInterpreted();
 403     }
 404 
 405     @DontCompile
 406     public void test14_verifier(boolean b) {
 407         long result = test14();
 408         Asserts.assertEQ(result, hash());
 409     }
 410 
 411     // Create a value type in an inlined method and then call a
 412     // non-inlined method on that value type.
 413     @Test(valid = ValueTypePassFieldsAsArgsOn, failOn = (LOAD + TRAP + ALLOC))
 414     @Test(valid = ValueTypePassFieldsAsArgsOff, failOn = (LOAD + TRAP), match = {ALLOC}, matchCount = {1})
 415     public long test15() {
 416         MyValue1 v = MyValue1.createInline(rI, rL);
 417         return v.hashInterpreted();
 418     }


 472     // interpreter via a call. The value type is passed twice but
 473     // should only be allocated once.
 474     @Test(valid = ValueTypePassFieldsAsArgsOn, failOn = ALLOC + LOAD + TRAP)
 475     @Test(valid = ValueTypePassFieldsAsArgsOff, match = {ALLOC}, matchCount = {1}, failOn = LOAD + TRAP)
 476     public long test19() {
 477         MyValue1 v = MyValue1.createInline(rI, rL);
 478         return sumValue(v, v);
 479     }
 480 
 481     @DontCompile
 482     public long sumValue(MyValue1 v, MyValue1 dummy) {
 483         return v.hash();
 484     }
 485 
 486     @DontCompile
 487     public void test19_verifier(boolean warmup) {
 488         long result = test19();
 489         Asserts.assertEQ(result, hash());
 490     }
 491 
 492     // Create a value type in compiled code and pass it to the
 493     // interpreter via a call. The value type is live at the uncommon
 494     // trap: verify that deoptimization causes the value type to be
 495     // correctly allocated.
 496     @Test(valid = ValueTypePassFieldsAsArgsOn, failOn = LOAD + ALLOC + STORE)
 497     @Test(valid = ValueTypePassFieldsAsArgsOff, match = {ALLOC}, matchCount = {1}, failOn = LOAD)
 498     public long test20(boolean flag) {
 499         MyValue1 v = MyValue1.createInline(rI, rL);


 500         if (flag) {
 501             // uncommon trap
 502             WHITE_BOX.deoptimizeMethod(tests.get("ValueTypeTestBench::test20"));
 503         }
 504         return v.hashInterpreted();
 505     }
 506 
 507     @DontCompile
 508     public void test20_verifier(boolean warmup) {

 509         long result = test20(false);
 510         Asserts.assertEQ(result, hash());
 511         if (!warmup) {
 512             result = test20(true);
 513             Asserts.assertEQ(result, hash());
 514         }
 515     }
 516 
 517     // Value type fields in regular object
 518     MyValue1 val1;
 519     MyValue2 val2;
 520     final MyValue1 val3;
 521     static MyValue1 val4;
 522     static final MyValue1 val5 = MyValue1.createInline(rI, rL);
 523 
 524     // Test value type fields in objects
 525     @Test(match = {ALLOC}, matchCount = {1}, failOn = (TRAP))
 526     public long test21(int x, long y) {
 527         // Compute hash of value type fields
 528         long result = val1.hash() + val2.hash() + val3.hash() + val4.hash() + val5.hash();
 529         // Update fields
 530         val1 = MyValue1.createInline(x, y);
 531         val2 = MyValue2.createInline(x, true);
 532         val4 = MyValue1.createInline(x, y);
 533         return result;


 550         Asserts.assertEQ(val4.hash(), hash(rI + 1, rL + 1));
 551     }
 552 
 553     // Test folding of constant value type fields
 554     @Test(failOn = ALLOC + LOAD + STORE + LOOP + TRAP)
 555     public long test22() {
 556         // This should be constant folded
 557         return val5.hash() + val5.v3.hash();
 558     }
 559 
 560     @DontCompile
 561     public void test22_verifier(boolean warmup) {
 562         long result = test22();
 563         Asserts.assertEQ(result, val5.hash() + val5.v3.hash());
 564     }
 565 
 566     // Test OSR compilation
 567     @Test(failOn = ALLOC + LOAD + STORE + LOOP + TRAP)
 568     public long test23() {
 569         MyValue1 v = MyValue1.createInline(rI, rL);


 570         long result = 0;
 571         // Long loop to trigger OSR compilation
 572         for (int i = 0 ; i < 100_000 ; ++i) {
 573             // Reference local value type in interpreter state
 574             result = v.hash();
 575         }
 576         return result;
 577     }
 578 
 579     @DontCompile
 580     public void test23_verifier(boolean warmup) {

 581         long result = test23();
 582         Asserts.assertEQ(result, hash());
 583     }
 584 
 585     // Test interpreter to compiled code with various signatures
 586     @Test(failOn = ALLOC + STORE + TRAP)
 587     public long test24(MyValue2 v) {
 588         return v.hash();
 589     }
 590 
 591     @DontCompile
 592     public void test24_verifier(boolean warmup) {
 593         MyValue2 v = MyValue2.createInline(rI, true);
 594         long result = test24(v);
 595         Asserts.assertEQ(result, v.hashInterpreted());
 596     }
 597 
 598     @Test(failOn = ALLOC + STORE + TRAP)
 599     public long test25(int i1, MyValue2 v, int i2) {
 600         return v.hash() + i1 - i2;
 601     }
 602 


 801             throw new RuntimeException("test 37 failed", t);
 802         }
 803     }
 804 
 805     // Generate a MethodHandle that obtains field t of the
 806     // derived value type       
 807     private static MethodHandle generateVCCUnboxLoadLongMH() {
 808         return MethodHandleBuilder.loadCode(MethodHandles.lookup(),
 809                                             "vccUnboxLoadLong",
 810                                             MethodType.methodType(long.class, ValueCapableClass1.class),
 811                                             CODE -> {
 812                                                 CODE.
 813                                                     aload_0().
 814                                                     vunbox(ValueType.forClass(ValueCapableClass1.class).valueClass()).
 815                                                     vgetfield(ValueType.forClass(ValueCapableClass1.class).valueClass(), "t", "J").
 816                                                     lreturn();
 817                                             }
 818                                             );  
 819     }
 820 
 821 
 822     @Test
 823     public int test38() throws Throwable {
 824         return (int)vccUnboxLoadIntMH.invokeExact(vcc);
 825     }
 826 
 827     @DontCompile
 828     public void test38_verifier(boolean warmup) {
 829         try {
 830             int result = test38();
 831             Asserts.assertEQ(vcc.x, result, "Field x of input and result must be equal.");
 832         } catch (Throwable t) {
 833             throw new RuntimeException("test 38 failed", t);
 834         }
 835     }
 836 
 837     // Generate a MethodHandle that obtains field x of the
 838     // derived value type       
 839     private static MethodHandle generateVCCUnboxLoadIntMH() {
 840         return MethodHandleBuilder.loadCode(MethodHandles.lookup(),
 841                                             "vccUnboxLoadInt",


 895             throw new RuntimeException("Test failed in the interpeter", t);
 896         }
 897     }
 898 
 899     // Generate a MethodHandle that takes a value-capable class,
 900     // unboxes it, boxes it, reads a field from it, and returns the
 901     // field.
 902     private static MethodHandle generateVCCUnboxBoxLoadIntMH() {
 903         return MethodHandleBuilder.loadCode(MethodHandles.lookup(),
 904                                             "vccUnboxBoxLoadInt",
 905                                             MethodType.methodType(int.class, ValueCapableClass1.class),
 906                                             CODE -> {
 907                                                 CODE.
 908                                                     aload_0().
 909                                                     vunbox(ValueType.forClass(ValueCapableClass1.class).valueClass()).
 910                                                     vbox(ValueCapableClass1.class).
 911                                                     getfield(ValueCapableClass1.class, "x", "I").
 912                                                     ireturn();
 913                                             }
 914                                             );




































































































































































 915     }
 916 
 917     // ========== Test infrastructure ==========
 918 
 919     private static final WhiteBox WHITE_BOX = WhiteBox.getWhiteBox();
 920     private static final int ValueTypePassFieldsAsArgsOn = 0x1;
 921     private static final int ValueTypePassFieldsAsArgsOff = 0x2;
 922     static final int AllFlags = ValueTypePassFieldsAsArgsOn | ValueTypePassFieldsAsArgsOff;


 923     private static final boolean ValueTypePassFieldsAsArgs = (Boolean)WHITE_BOX.getVMFlag("ValueTypePassFieldsAsArgs");

 924     private static final int COMP_LEVEL_ANY = -1;
 925     private static final int COMP_LEVEL_FULL_OPTIMIZATION = 4;
 926     private static final Hashtable<String, Method> tests = new Hashtable<String, Method>();
 927     private static final int WARMUP = 250;
 928     private static boolean USE_COMPILER = WHITE_BOX.getBooleanVMFlag("UseCompiler");
 929     private static boolean PRINT_IDEAL  = WHITE_BOX.getBooleanVMFlag("PrintIdeal");
 930     // TODO use Platform.isComp() after merge with JDK 9
 931     private static boolean XCOMP = System.getProperty("java.vm.info").startsWith("compiled ");
 932 
 933     // Regular expressions used  to match nodes in the PrintIdeal output
 934     private static final String START = "(\\d+\\t(.*";
 935     private static final String MID = ".*)+\\t===.*";
 936     private static final String END = ")|";
 937     private static final String ALLOC = START + "CallStaticJava" + MID + "_new_instance_Java" + END;
 938     private static final String LOAD  = START + "Load" + MID + "valuetype\\*" + END;
 939     private static final String STORE = START + "Store" + MID + "valuetype\\*" + END;



 940     private static final String LOOP  = START + "Loop" + MID + "" + END;
 941     private static final String TRAP  = START + "CallStaticJava" + MID + "uncommon_trap" + END;
 942     // TODO: match field values of scalar replaced object
 943     private static final String SCOBJ = "(.*# ScObj.*" + END;
 944 
 945     static {
 946         // Gather all test methods and put them in Hashtable
 947         for (Method m : ValueTypeTestBench.class.getDeclaredMethods()) {
 948             Test[] annos = m.getAnnotationsByType(Test.class);
 949             if (annos.length != 0) {
 950                 tests.put("ValueTypeTestBench::" + m.getName(), m);
 951             }
 952         }
 953     }
 954 
 955     private static void execute_vm(String... extra_args) throws Throwable {
 956         ArrayList<String> all_args = new ArrayList(List.of(
 957                 "-noverify",
 958                 "-XX:+UnlockDiagnosticVMOptions", "-Xbootclasspath/a:.", "-XX:+WhiteBoxAPI",
 959                 "-XX:-TieredCompilation", "-XX:-BackgroundCompilation",


 963                 "-XX:CompileCommand=compileonly,compiler.valhalla.valuetypes.MyValue2::*"
 964                                                                ));
 965         all_args.addAll(List.of(extra_args));
 966         // Run tests in own process and verify output
 967         all_args.add(ValueTypeTestBench.class.getName());
 968         all_args.add("run");
 969         OutputAnalyzer oa = ProcessTools.executeTestJvm(all_args.toArray(new String[0]));
 970         // If ideal graph printing is enabled/supported, verify output
 971         String output = oa.getOutput();
 972         oa.shouldHaveExitValue(0);
 973         if (output.contains("PrintIdeal enabled")) {
 974             parseOutput(output);
 975         } else {
 976             System.out.println("WARNING: IR verification disabled! Running with -Xint, -Xcomp or release build?");
 977         }
 978     }
 979 
 980     public static void main(String[] args) throws Throwable {
 981         if (args.length == 0) {
 982             String field_as_args;
 983             if ((Boolean)WHITE_BOX.getVMFlag("ValueTypePassFieldsAsArgs")) {

 984                 field_as_args = "-XX:+ValueTypePassFieldsAsArgs";
 985             } else {
 986                 field_as_args = "-XX:-ValueTypePassFieldsAsArgs";
 987             }
 988             execute_vm("-XX:+UnlockExperimentalVMOptions", field_as_args);
 989             execute_vm("-XX:+AlwaysIncrementalInline", "-XX:+UnlockExperimentalVMOptions", field_as_args);





 990         } else {
 991             if (USE_COMPILER && PRINT_IDEAL && !XCOMP) {
 992                 System.out.println("PrintIdeal enabled");
 993             }
 994             // Execute tests
 995             ValueTypeTestBench bench = new ValueTypeTestBench();
 996             bench.run();
 997         }
 998     }
 999 
1000     public static void parseOutput(String output) throws Exception {
1001         String split = "b        compiler.valhalla.valuetypes.";
1002         String[] compilations = output.split(split);
1003         // Print header
1004         System.out.println(compilations[0]);
1005         // Iterate over compilation output
1006         for (String graph : compilations) {
1007             String[] lines = graph.split("\\n");
1008             if (lines[0].contains("@")) {
1009                 continue; // Ignore OSR compilations
1010             }
1011             String testName = lines[0].split(" ")[0];
1012             Method test = tests.get(testName);
1013             if (test == null) {
1014                 // Skip helper methods
1015                 continue;
1016             }
1017             if (PRINT_GRAPH) {
1018                 System.out.println("\nGraph for " + graph);
1019             }
1020             // Parse graph using regular expressions to determine if it contains forbidden nodes
1021             Test[] annos = test.getAnnotationsByType(Test.class);
1022             Test anno = null;
1023             for (Test a : annos) {
1024                 if ((a.valid() & ValueTypePassFieldsAsArgsOn) != 0 && ValueTypePassFieldsAsArgs) {
1025                     assert anno == null;
1026                     anno = a;
1027                 } else if ((a.valid() & ValueTypePassFieldsAsArgsOff) != 0 && !ValueTypePassFieldsAsArgs) {
1028                     assert anno == null;
1029                     anno = a;






1030                 }
1031             }
1032             assert anno != null;
1033             String regexFail = anno.failOn();
1034             if (!regexFail.isEmpty()) {
1035                 Pattern pattern = Pattern.compile(regexFail.substring(0, regexFail.length()-1));
1036                 Matcher matcher = pattern.matcher(graph);
1037                 boolean fail = false;
1038                 while (matcher.find()) {
1039                     System.out.println("Graph for '" + testName + "' contains forbidden node:");
1040                     System.out.println(matcher.group());
1041                     fail = true;
1042                 }
1043                 Asserts.assertFalse(fail, "Graph for '" + testName + "' contains forbidden nodes");
1044             }
1045             String[] regexMatch = anno.match();
1046             int[] matchCount = anno.matchCount();
1047             for (int i = 0; i < regexMatch.length; ++i) {
1048                 Pattern pattern = Pattern.compile(regexMatch[i].substring(0, regexMatch[i].length()-1));
1049                 Matcher matcher = pattern.matcher(graph);
1050                 int count = 0;
1051                 String nodes = "";
1052                 while (matcher.find()) {
1053                     count++;
1054                     nodes += matcher.group() + "\n";
1055                 }
1056                 if (matchCount[i] != count) {
1057                     System.out.println("Graph for '" + testName + "' contains different number of match nodes:");
1058                     System.out.println(nodes);
1059                 }
1060                 Asserts.assertEQ(matchCount[i], count, "Graph for '" + testName + "' contains different number of match nodes");
1061             }
1062             tests.remove(testName);
1063             System.out.println(testName + " passed");
1064         }
1065         // Check if all tests were compiled
1066         if (tests.size() != 0) {
1067             for (String name : tests.keySet()) {
1068                 System.out.println("Test '" + name + "' not compiled!");
1069             }
1070             throw new RuntimeException("Not all tests were compiled");
1071         }
1072     }
1073 
1074     public void setup(Method[] methods) {
1075         for (Method m : methods) {
1076             if (m.isAnnotationPresent(Test.class)) {
1077                 // Don't inline tests
1078                 WHITE_BOX.testSetDontInlineMethod(m, true);
1079             }
1080             if (m.isAnnotationPresent(DontCompile.class)) {




  13  * accompanied this code).
  14  *
  15  * You should have received a copy of the GNU General Public License version
  16  * 2 along with this work; if not, write to the Free Software Foundation,
  17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
  18  *
  19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
  20  * or visit www.oracle.com if you need additional information or have any
  21  * questions.
  22  */
  23 
  24 // TODO add bugid and summary
  25 
  26 /*
  27  * @test
  28  * @library /testlibrary /test/lib /compiler/whitebox /
  29  * @build compiler.valhalla.valuetypes.ValueTypeTestBench
  30  * @run main ClassFileInstaller sun.hotspot.WhiteBox
  31  * @run main ClassFileInstaller jdk.test.lib.Platform
  32  * @run main/othervm -ea -noverify -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI
  33  *                   -XX:+UnlockExperimentalVMOptions -XX:+ValueTypePassFieldsAsArgs -XX:+ValueArrayFlatten
  34  *                   -XX:-TieredCompilation compiler.valhalla.valuetypes.ValueTypeTestBench
  35  * @run main/othervm -ea -noverify -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI
  36  *                   -XX:+UnlockExperimentalVMOptions -XX:-ValueTypePassFieldsAsArgs -XX:-ValueArrayFlatten
  37  *                   -XX:-TieredCompilation compiler.valhalla.valuetypes.ValueTypeTestBench
  38  */
  39 
  40 package compiler.valhalla.valuetypes;
  41 
  42 import compiler.whitebox.CompilerWhiteBoxTest;
  43 import jdk.internal.misc.Unsafe;
  44 import jdk.test.lib.Asserts;
  45 import jdk.test.lib.Platform;
  46 import jdk.test.lib.ProcessTools;
  47 import jdk.test.lib.OutputAnalyzer;
  48 import jdk.test.lib.Utils;
  49 import sun.hotspot.WhiteBox;
  50 
  51 import java.lang.annotation.Retention;
  52 import java.lang.annotation.RetentionPolicy;
  53 import java.lang.annotation.Repeatable;
  54 import java.lang.invoke.*;
  55 import java.lang.reflect.Method;
  56 import java.util.ArrayList;


  83 
  84     @DontInline
  85     public static MyValue1 createDontInline(int x, long y) {
  86         return __Make MyValue1(x, y, MyValue2.createInline(x, true), MyValue2.createInline(x, false), ValueTypeTestBench.rI);
  87     }
  88 
  89     @ForceInline
  90     public static MyValue1 createInline(int x, long y) {
  91         return __Make MyValue1(x, y, MyValue2.createInline(x, true), MyValue2.createInline(x, false), ValueTypeTestBench.rI);
  92     }
  93 
  94     @ForceInline
  95     public long hash() {
  96         return s + sf + x + y + c + v1.hash() + v2.hash() + v3.hash();
  97     }
  98 
  99     @DontCompile
 100     public long hashInterpreted() {
 101         return s + sf + x + y + c + v1.hashInterpreted() + v2.hashInterpreted() + v3.hashInterpreted();
 102     }
 103 
 104     @ForceInline
 105     public void print() {
 106         System.out.print("s=" + s + ", sf=" + sf + ", x=" + x + ", y=" + y + ", v1[");
 107         v1.print();
 108         System.out.print("], v2[");
 109         v2.print();
 110         System.out.print("], v3[");
 111         v3.print();
 112         System.out.print("], c=" + c);
 113     }
 114 }
 115 
 116 __ByValue final class MyValue2 {
 117     final int x;
 118     final boolean b;
 119     final long c;
 120 
 121     private MyValue2(int x, boolean b, long c) {
 122         this.x = x;
 123         this.b = b;
 124         this.c = c;
 125     }
 126 
 127     @ForceInline
 128     public static MyValue2 createInline(int x, boolean b) {
 129         return __Make MyValue2(x, b, ValueTypeTestBench.rL);
 130     }
 131 
 132     @ForceInline
 133     public long hash() {
 134         return x + (b ? 0 : 1) + c;
 135     }
 136 
 137     @DontInline
 138     public long hashInterpreted() {
 139         return x + (b ? 0 : 1) + c;
 140     }
 141 
 142     @ForceInline
 143     public void print() {
 144         System.out.print("x=" + x + ", b=" + b + ", c=" + c);
 145     }
 146 }
 147 
 148 public class ValueTypeTestBench {
 149     // Print ideal graph after execution of each test
 150     private static final boolean PRINT_GRAPH = true;
 151 
 152     // Random test values
 153     public static final int  rI = Utils.getRandomInstance().nextInt() % 1000;
 154     public static final long rL = Utils.getRandomInstance().nextLong() % 1000;
 155 
 156     public ValueTypeTestBench() {
 157         val3 = MyValue1.createInline(rI, rL);
 158     }
 159 
 160     // MethodHandles and value-capable class instance needed for testing vbox/vunbox
 161     private static final MethodHandle vccUnboxLoadLongMH = generateVCCUnboxLoadLongMH();
 162     private static final MethodHandle vccUnboxLoadIntMH = generateVCCUnboxLoadIntMH();
 163     private static final MethodHandle vccUnboxBoxMH = generateVCCUnboxBoxMH();
 164     private static final MethodHandle vccUnboxBoxLoadIntMH = generateVCCUnboxBoxLoadIntMH();
 165 


 282 
 283     // Merge value types created from two branches
 284     @Test(failOn = ALLOC + STORE + TRAP)
 285     public long test8(boolean b) {
 286         MyValue1 v;
 287         if (b) {
 288             v = MyValue1.createInline(rI, rL);
 289         } else {
 290             v = MyValue1.createDontInline(rI + 1, rL + 1);
 291         }
 292         return v.hash();
 293     }
 294 
 295     @DontCompile
 296     public void test8_verifier(boolean warmup) {
 297         Asserts.assertEQ(test8(true), hash());
 298         Asserts.assertEQ(test8(false), hash(rI + 1, rL + 1));
 299     }
 300 
 301     // Merge value types created from two branches
 302     @Test(valid = ValueTypePassFieldsAsArgsOn, match = {LOAD}, matchCount = {7}, failOn = TRAP + ALLOC + STORE)
 303     // FIXME
 304     //@Test(valid = ValueTypePassFieldsAsArgsOff, match = {ALLOC, STORE}, matchCount = {1, 9}, failOn = LOAD + TRAP)
 305     @Test(valid = ValueTypePassFieldsAsArgsOff, match = {ALLOC, STORE}, matchCount = {1, 3}, failOn = LOAD + TRAP)
 306     public MyValue1 test9(boolean b) {
 307         MyValue1 v;
 308         if (b) {
 309             // Value type is not allocated
 310             v = MyValue1.createInline(rI, rL);
 311         } else {
 312             // Value type is allocated by the callee
 313             v = MyValue1.createDontInline(rI + 1, rL + 1);
 314         }
 315         // Need to allocate value type if 'b' is true
 316         long sum = v.hashInterpreted();
 317         if (b) {
 318             v = MyValue1.createDontInline(rI, sum);
 319         } else {
 320             v = MyValue1.createDontInline(rI, sum + 1);
 321         }
 322         // Don't need to allocate value type because both branches allocate
 323         return v;
 324     }


 396         for (int i = 0; i < 1000; ++i) {
 397             if (b) {
 398                 result += v.x;
 399             } else {
 400                 // Uncommon trap referencing v. Should not allocate
 401                 // but just pass the existing oop to the uncommon trap.
 402                 result = v.hashInterpreted();
 403             }
 404         }
 405         return result;
 406     }
 407 
 408     @DontCompile
 409     public void test13_verifier(boolean warmup) {
 410         long result = test13(warmup);
 411         Asserts.assertEQ(result, warmup ? 42 + (1000*rI) : hash());
 412     }
 413 
 414     // Create a value type in a non-inlined method and then call a
 415     // non-inlined method on that value type.
 416     @Test(valid = ValueTypePassFieldsAsArgsOn, failOn = (ALLOC + STORE + TRAP), match = {LOAD}, matchCount = {7})
 417     @Test(valid = ValueTypePassFieldsAsArgsOff, failOn = (ALLOC + LOAD + STORE + TRAP))
 418     public long test14() {
 419         MyValue1 v = MyValue1.createDontInline(rI, rL);
 420         return v.hashInterpreted();
 421     }
 422 
 423     @DontCompile
 424     public void test14_verifier(boolean b) {
 425         long result = test14();
 426         Asserts.assertEQ(result, hash());
 427     }
 428 
 429     // Create a value type in an inlined method and then call a
 430     // non-inlined method on that value type.
 431     @Test(valid = ValueTypePassFieldsAsArgsOn, failOn = (LOAD + TRAP + ALLOC))
 432     @Test(valid = ValueTypePassFieldsAsArgsOff, failOn = (LOAD + TRAP), match = {ALLOC}, matchCount = {1})
 433     public long test15() {
 434         MyValue1 v = MyValue1.createInline(rI, rL);
 435         return v.hashInterpreted();
 436     }


 490     // interpreter via a call. The value type is passed twice but
 491     // should only be allocated once.
 492     @Test(valid = ValueTypePassFieldsAsArgsOn, failOn = ALLOC + LOAD + TRAP)
 493     @Test(valid = ValueTypePassFieldsAsArgsOff, match = {ALLOC}, matchCount = {1}, failOn = LOAD + TRAP)
 494     public long test19() {
 495         MyValue1 v = MyValue1.createInline(rI, rL);
 496         return sumValue(v, v);
 497     }
 498 
 499     @DontCompile
 500     public long sumValue(MyValue1 v, MyValue1 dummy) {
 501         return v.hash();
 502     }
 503 
 504     @DontCompile
 505     public void test19_verifier(boolean warmup) {
 506         long result = test19();
 507         Asserts.assertEQ(result, hash());
 508     }
 509 
 510     // Create a value type (array) in compiled code and pass it to the
 511     // interpreter via a call. The value type is live at the uncommon
 512     // trap: verify that deoptimization causes the value type to be
 513     // correctly allocated.
 514     @Test(valid = ValueTypePassFieldsAsArgsOn, failOn = LOAD + ALLOC + STORE)
 515     @Test(valid = ValueTypePassFieldsAsArgsOff, match = {ALLOC}, matchCount = {1}, failOn = LOAD)
 516     public long test20(boolean flag) {
 517         MyValue1 v = MyValue1.createInline(rI, rL);
 518         // TODO add value type array testcase
 519         // MyValue1[] va = new MyValue1[42];
 520         if (flag) {
 521             // uncommon trap
 522             WHITE_BOX.deoptimizeMethod(tests.get("ValueTypeTestBench::test20"));
 523         }
 524         return v.hashInterpreted(); // + va[0].hashInterpreted();
 525     }
 526 
 527     @DontCompile
 528     public void test20_verifier(boolean warmup) {
 529         MyValue1[] va = new MyValue1[42];
 530         long result = test20(false);
 531         Asserts.assertEQ(result, hash() /* + va[0].hash() */);
 532         if (!warmup) {
 533             result = test20(true);
 534             Asserts.assertEQ(result, hash() /* + va[0].hash() */);
 535         }
 536     }
 537 
 538     // Value type fields in regular object
 539     MyValue1 val1;
 540     MyValue2 val2;
 541     final MyValue1 val3;
 542     static MyValue1 val4;
 543     static final MyValue1 val5 = MyValue1.createInline(rI, rL);
 544 
 545     // Test value type fields in objects
 546     @Test(match = {ALLOC}, matchCount = {1}, failOn = (TRAP))
 547     public long test21(int x, long y) {
 548         // Compute hash of value type fields
 549         long result = val1.hash() + val2.hash() + val3.hash() + val4.hash() + val5.hash();
 550         // Update fields
 551         val1 = MyValue1.createInline(x, y);
 552         val2 = MyValue2.createInline(x, true);
 553         val4 = MyValue1.createInline(x, y);
 554         return result;


 571         Asserts.assertEQ(val4.hash(), hash(rI + 1, rL + 1));
 572     }
 573 
 574     // Test folding of constant value type fields
 575     @Test(failOn = ALLOC + LOAD + STORE + LOOP + TRAP)
 576     public long test22() {
 577         // This should be constant folded
 578         return val5.hash() + val5.v3.hash();
 579     }
 580 
 581     @DontCompile
 582     public void test22_verifier(boolean warmup) {
 583         long result = test22();
 584         Asserts.assertEQ(result, val5.hash() + val5.v3.hash());
 585     }
 586 
 587     // Test OSR compilation
 588     @Test(failOn = ALLOC + LOAD + STORE + LOOP + TRAP)
 589     public long test23() {
 590         MyValue1 v = MyValue1.createInline(rI, rL);
 591         // TODO add OSR testcase for value type arrays
 592         //MyValue1[] va = new MyValue1[10];
 593         long result = 0;
 594         // Long loop to trigger OSR compilation
 595         for (int i = 0 ; i < 100_000 ; ++i) {
 596             // Reference local value type in interpreter state
 597             result = v.hash(); // + va[0].hash();
 598         }
 599         return result;
 600     }
 601 
 602     @DontCompile
 603     public void test23_verifier(boolean warmup) {
 604         //MyValue1[] va = new MyValue1[10];
 605         long result = test23();
 606         Asserts.assertEQ(result, hash() /* + va[0].hash() */);
 607     }
 608 
 609     // Test interpreter to compiled code with various signatures
 610     @Test(failOn = ALLOC + STORE + TRAP)
 611     public long test24(MyValue2 v) {
 612         return v.hash();
 613     }
 614 
 615     @DontCompile
 616     public void test24_verifier(boolean warmup) {
 617         MyValue2 v = MyValue2.createInline(rI, true);
 618         long result = test24(v);
 619         Asserts.assertEQ(result, v.hashInterpreted());
 620     }
 621 
 622     @Test(failOn = ALLOC + STORE + TRAP)
 623     public long test25(int i1, MyValue2 v, int i2) {
 624         return v.hash() + i1 - i2;
 625     }
 626 


 825             throw new RuntimeException("test 37 failed", t);
 826         }
 827     }
 828 
 829     // Generate a MethodHandle that obtains field t of the
 830     // derived value type
 831     private static MethodHandle generateVCCUnboxLoadLongMH() {
 832         return MethodHandleBuilder.loadCode(MethodHandles.lookup(),
 833                 "vccUnboxLoadLong",
 834                 MethodType.methodType(long.class, ValueCapableClass1.class),
 835                 CODE -> {
 836                     CODE.
 837                     aload_0().
 838                     vunbox(ValueType.forClass(ValueCapableClass1.class).valueClass()).
 839                     vgetfield(ValueType.forClass(ValueCapableClass1.class).valueClass(), "t", "J").
 840                     lreturn();
 841                 }
 842                 );
 843     }
 844 

 845     @Test
 846     public int test38() throws Throwable {
 847         return (int)vccUnboxLoadIntMH.invokeExact(vcc);
 848     }
 849 
 850     @DontCompile
 851     public void test38_verifier(boolean warmup) {
 852         try {
 853             int result = test38();
 854             Asserts.assertEQ(vcc.x, result, "Field x of input and result must be equal.");
 855         } catch (Throwable t) {
 856             throw new RuntimeException("test 38 failed", t);
 857         }
 858     }
 859 
 860     // Generate a MethodHandle that obtains field x of the
 861     // derived value type
 862     private static MethodHandle generateVCCUnboxLoadIntMH() {
 863         return MethodHandleBuilder.loadCode(MethodHandles.lookup(),
 864                 "vccUnboxLoadInt",


 918             throw new RuntimeException("Test failed in the interpeter", t);
 919         }
 920     }
 921 
 922     // Generate a MethodHandle that takes a value-capable class,
 923     // unboxes it, boxes it, reads a field from it, and returns the
 924     // field.
 925     private static MethodHandle generateVCCUnboxBoxLoadIntMH() {
 926         return MethodHandleBuilder.loadCode(MethodHandles.lookup(),
 927                 "vccUnboxBoxLoadInt",
 928                 MethodType.methodType(int.class, ValueCapableClass1.class),
 929                 CODE -> {
 930                     CODE.
 931                     aload_0().
 932                     vunbox(ValueType.forClass(ValueCapableClass1.class).valueClass()).
 933                     vbox(ValueCapableClass1.class).
 934                     getfield(ValueCapableClass1.class, "x", "I").
 935                     ireturn();
 936                 }
 937                 );
 938 
 939     }
 940 
 941     // Test value type array creation and initialization
 942     @Test(valid = ValueTypeArrayFlattenOff, failOn = (LOAD))
 943     @Test(valid = ValueTypeArrayFlattenOn)
 944     public MyValue1[] test41(int len) {
 945         MyValue1[] va = new MyValue1[len];
 946         for (int i = 0; i < len; ++i) {
 947             va[i] = MyValue1.createDontInline(rI, rL);
 948         }
 949         return va;
 950     }
 951 
 952     @DontCompile
 953     public void test41_verifier(boolean warmup) {
 954         int len = Math.abs(rI % 10);
 955         MyValue1[] va = test41(len);
 956         for (int i = 0; i < len; ++i) {
 957             Asserts.assertEQ(va[i].hash(), hash());
 958         }
 959     }
 960 
 961     // Test creation of a value type array and element access
 962     @Test(failOn = (LOOP + LOAD + TRAP))
 963     public long test42() {
 964         MyValue1[] va = new MyValue1[1];
 965         va[0] = MyValue1.createInline(rI, rL);
 966         return va[0].hash();
 967     }
 968 
 969     @DontCompile
 970     public void test42_verifier(boolean warmup) {
 971         long result = test42();
 972         Asserts.assertEQ(result, hash());
 973     }
 974 
 975     // Test receiving a value type array from the interpreter,
 976     // updating its elements in a loop and computing a hash.
 977     @Test(failOn = (ALLOCA))
 978     public long test43(MyValue1[] va) {
 979         long result = 0;
 980         for (int i = 0; i < 10; ++i) {
 981             result += va[i].hash();
 982             va[i] = MyValue1.createInline(rI + 1, rL + 1);
 983         }
 984         return result;
 985     }
 986 
 987     @DontCompile
 988     public void test43_verifier(boolean warmup) {
 989         MyValue1[] va = new MyValue1[10];
 990         long expected = 0;
 991         for (int i = 0; i < 10; ++i) {
 992             va[i] = MyValue1.createDontInline(rI + i, rL + i);
 993             expected += va[i].hash();
 994         }
 995         long result = test43(va);
 996         Asserts.assertEQ(expected, result);
 997         for (int i = 0; i < 10; ++i) {
 998             if (va[i].hash() != hash(rI + 1, rL + 1)) {
 999                 Asserts.assertEQ(va[i].hash(), hash(rI + 1, rL + 1));
1000             }
1001         }
1002     }
1003 
1004     // Test returning a value type array received from the interpreter
1005     @Test(failOn = ALLOC + ALLOCA + LOAD + LOADP + STORE + LOOP + TRAP)
1006     public MyValue1[] test44(MyValue1[] va) {
1007         return va;
1008     }
1009 
1010     @DontCompile
1011     public void test44_verifier(boolean warmup) {
1012         MyValue1[] va = new MyValue1[10];
1013         for (int i = 0; i < 10; ++i) {
1014             va[i] = MyValue1.createDontInline(rI + i, rL + i);
1015         }
1016         va = test44(va);
1017         for (int i = 0; i < 10; ++i) {
1018             Asserts.assertEQ(va[i].hash(), hash(rI + i, rL + i));
1019         }
1020     }
1021 
1022     // TODO add match rules
1023     @Test()
1024     public MyValue1[] test45(boolean b) {
1025         MyValue1[] va;
1026         if (b) {
1027             va = new MyValue1[5];
1028             for (int i = 0; i < 5; ++i) {
1029                 va[i] = MyValue1.createInline(rI, rL);
1030             }
1031         } else {
1032             va = new MyValue1[10];
1033             for (int i = 0; i < 10; ++i) {
1034                 va[i] = MyValue1.createInline(rI + i, rL + i);
1035             }
1036         }
1037         long sum = va[0].hashInterpreted();
1038         if (b) {
1039             va[0] = MyValue1.createDontInline(rI, sum);
1040         } else {
1041             va[0] = MyValue1.createDontInline(rI + 1, sum + 1);
1042         }
1043         return va;
1044     }
1045 
1046     @DontCompile
1047     public void test45_verifier(boolean warmup) {
1048         MyValue1[] va = test45(true);
1049         Asserts.assertEQ(va.length, 5);
1050         Asserts.assertEQ(va[0].hash(), hash(rI, hash()));
1051         for (int i = 1; i < 5; ++i) {
1052             Asserts.assertEQ(va[i].hash(), hash());
1053         }
1054         va = test45(false);
1055         Asserts.assertEQ(va.length, 10);
1056         Asserts.assertEQ(va[0].hash(), hash(rI + 1, hash(rI, rL) + 1));
1057         for (int i = 1; i < 10; ++i) {
1058             Asserts.assertEQ(va[i].hash(), hash(rI + i, rL + i));
1059         }
1060     }
1061 
1062     // Test creation of value type array with single element
1063     @Test(failOn = LOOP + TRAP)
1064     public MyValue1 test46() {
1065         MyValue1[] va = new MyValue1[1];
1066         return va[0];
1067     }
1068 
1069     @DontCompile
1070     public void test46_verifier(boolean warmup) {
1071         MyValue1[] va = new MyValue1[1];
1072         MyValue1 v = test46();
1073         Asserts.assertEQ(v.hash(), va[0].hash());
1074     }
1075 
1076     // Test default initialization of value type arrays
1077     @Test(failOn = LOAD)
1078     public MyValue1[] test47(int len) {
1079         return new MyValue1[len];
1080     }
1081 
1082     @DontCompile
1083     public void test47_verifier(boolean warmup) {
1084         int len = Math.abs(rI % 10);
1085         MyValue1[] va = new MyValue1[len];
1086         MyValue1[] var = test47(len);
1087         for (int i = 0; i < len; ++i) {
1088             Asserts.assertEQ(va[i].hash(), var[i].hash());
1089         }
1090     }
1091 
1092     // Test creation of value type array with zero length
1093     @Test(failOn = ALLOC + LOAD + STORE + LOOP + TRAP)
1094     public MyValue1[] test48() {
1095         return new MyValue1[0];
1096     }
1097 
1098     @DontCompile
1099     public void test48_verifier(boolean warmup) {
1100         MyValue1[] va = test48();
1101         Asserts.assertEQ(va.length, 0);
1102     }
1103 
1104     // ========== Test infrastructure ==========
1105 
1106     private static final WhiteBox WHITE_BOX = WhiteBox.getWhiteBox();
1107     private static final int ValueTypePassFieldsAsArgsOn = 0x1;
1108     private static final int ValueTypePassFieldsAsArgsOff = 0x2;
1109     private static final int ValueTypeArrayFlattenOn = 0x4;
1110     private static final int ValueTypeArrayFlattenOff = 0x8;
1111     static final int AllFlags = ValueTypePassFieldsAsArgsOn | ValueTypePassFieldsAsArgsOff | ValueTypeArrayFlattenOn | ValueTypeArrayFlattenOff;
1112     private static final boolean ValueTypePassFieldsAsArgs = (Boolean)WHITE_BOX.getVMFlag("ValueTypePassFieldsAsArgs");
1113     private static final boolean ValueTypeArrayFlatten = (Boolean)WHITE_BOX.getVMFlag("ValueArrayFlatten");
1114     private static final int COMP_LEVEL_ANY = -1;
1115     private static final int COMP_LEVEL_FULL_OPTIMIZATION = 4;
1116     private static final Hashtable<String, Method> tests = new Hashtable<String, Method>();
1117     private static final int WARMUP = 250;
1118     private static boolean USE_COMPILER = WHITE_BOX.getBooleanVMFlag("UseCompiler");
1119     private static boolean PRINT_IDEAL  = WHITE_BOX.getBooleanVMFlag("PrintIdeal");
1120     // TODO use Platform.isComp() after merge with JDK 9
1121     private static boolean XCOMP = System.getProperty("java.vm.info").startsWith("compiled ");
1122 
1123     // Regular expressions used  to match nodes in the PrintIdeal output
1124     private static final String START = "(\\d+\\t(.*";
1125     private static final String MID = ".*)+\\t===.*";
1126     private static final String END = ")|";
1127     private static final String ALLOC  = START + "CallStaticJava" + MID + "_new_instance_Java" + END;
1128     private static final String ALLOCA = START + "CallStaticJava" + MID + "_new_array_Java" + END;
1129     private static final String LOAD   = START + "Load(B|S|I|L|F|D)" + MID + "valuetype\\*" + END;
1130     private static final String LOADP  = START + "Load(P|N)" + MID + "valuetype\\*" + END;
1131     private static final String STORE  = START + "Store(B|S|I|L|F|D)" + MID + "valuetype\\*" + END;
1132     private static final String STOREP = START + "Store(P|N)" + MID + "valuetype\\*" + END;
1133     private static final String LOOP   = START + "Loop" + MID + "" + END;
1134     private static final String TRAP   = START + "CallStaticJava" + MID + "uncommon_trap" + END;
1135     // TODO: match field values of scalar replaced object
1136     private static final String SCOBJ = "(.*# ScObj.*" + END;
1137 
1138     static {
1139         // Gather all test methods and put them in Hashtable
1140         for (Method m : ValueTypeTestBench.class.getDeclaredMethods()) {
1141             Test[] annos = m.getAnnotationsByType(Test.class);
1142             if (annos.length != 0) {
1143                 tests.put("ValueTypeTestBench::" + m.getName(), m);
1144             }
1145         }
1146     }
1147 
1148     private static void execute_vm(String... extra_args) throws Throwable {
1149         ArrayList<String> all_args = new ArrayList(List.of(
1150                 "-noverify",
1151                 "-XX:+UnlockDiagnosticVMOptions", "-Xbootclasspath/a:.", "-XX:+WhiteBoxAPI",
1152                 "-XX:-TieredCompilation", "-XX:-BackgroundCompilation",


1156                 "-XX:CompileCommand=compileonly,compiler.valhalla.valuetypes.MyValue2::*"
1157                 ));
1158         all_args.addAll(List.of(extra_args));
1159         // Run tests in own process and verify output
1160         all_args.add(ValueTypeTestBench.class.getName());
1161         all_args.add("run");
1162         OutputAnalyzer oa = ProcessTools.executeTestJvm(all_args.toArray(new String[0]));
1163         // If ideal graph printing is enabled/supported, verify output
1164         String output = oa.getOutput();
1165         oa.shouldHaveExitValue(0);
1166         if (output.contains("PrintIdeal enabled")) {
1167             parseOutput(output);
1168         } else {
1169             System.out.println("WARNING: IR verification disabled! Running with -Xint, -Xcomp or release build?");
1170         }
1171     }
1172 
1173     public static void main(String[] args) throws Throwable {
1174         if (args.length == 0) {
1175             String field_as_args;
1176             String array_flatten;
1177             if (ValueTypePassFieldsAsArgs) {
1178                 field_as_args = "-XX:+ValueTypePassFieldsAsArgs";
1179             } else {
1180                 field_as_args = "-XX:-ValueTypePassFieldsAsArgs";
1181             }
1182             if (ValueTypeArrayFlatten) {
1183                 array_flatten = "-XX:+ValueArrayFlatten";
1184             } else {
1185                 array_flatten = "-XX:-ValueArrayFlatten";
1186             }
1187             execute_vm("-XX:+UnlockExperimentalVMOptions", field_as_args, array_flatten);
1188             execute_vm("-XX:+AlwaysIncrementalInline", "-XX:+UnlockExperimentalVMOptions", field_as_args, array_flatten);
1189         } else {
1190             if (USE_COMPILER && PRINT_IDEAL && !XCOMP) {
1191                 System.out.println("PrintIdeal enabled");
1192             }
1193             // Execute tests
1194             ValueTypeTestBench bench = new ValueTypeTestBench();
1195             bench.run();
1196         }
1197     }
1198 
1199     public static void parseOutput(String output) throws Exception {
1200         String split = "b        compiler.valhalla.valuetypes.";
1201         String[] compilations = output.split(split);
1202         // Print header
1203         System.out.println(compilations[0]);
1204         // Iterate over compilation output
1205         for (String graph : compilations) {
1206             String[] lines = graph.split("\\n");
1207             if (lines[0].contains("@")) {
1208                 continue; // Ignore OSR compilations
1209             }
1210             String testName = lines[0].split(" ")[0];
1211             Method test = tests.get(testName);
1212             if (test == null) {
1213                 // Skip helper methods
1214                 continue;
1215             }
1216             if (PRINT_GRAPH) {
1217                 System.out.println("\nGraph for " + graph);
1218             }
1219             // Parse graph using regular expressions to determine if it contains forbidden nodes
1220             Test[] annos = test.getAnnotationsByType(Test.class);
1221             Test anno = null;
1222             for (Test a : annos) {
1223                 if ((a.valid() & ValueTypePassFieldsAsArgsOn) != 0 && ValueTypePassFieldsAsArgs) {
1224                     assert anno == null;
1225                     anno = a;
1226                 } else if ((a.valid() & ValueTypePassFieldsAsArgsOff) != 0 && !ValueTypePassFieldsAsArgs) {
1227                     assert anno == null;
1228                     anno = a;
1229                 } else if ((a.valid() & ValueTypeArrayFlattenOn) != 0 && ValueTypeArrayFlatten) {
1230                     assert anno == null;
1231                     anno = a;
1232                 } else if ((a.valid() & ValueTypeArrayFlattenOff) != 0 && !ValueTypeArrayFlatten) {
1233                     assert anno == null;
1234                     anno = a;
1235                 }
1236             }
1237             assert anno != null;
1238             String regexFail = anno.failOn();
1239             if (!regexFail.isEmpty()) {
1240                 Pattern pattern = Pattern.compile(regexFail.substring(0, regexFail.length()-1));
1241                 Matcher matcher = pattern.matcher(graph);
1242                 boolean found = matcher.find();
1243                 Asserts.assertFalse(found, "Graph for '" + testName + "' contains forbidden node:\n" + (found ? matcher.group() : ""));





1244             }
1245             String[] regexMatch = anno.match();
1246             int[] matchCount = anno.matchCount();
1247             for (int i = 0; i < regexMatch.length; ++i) {
1248                 Pattern pattern = Pattern.compile(regexMatch[i].substring(0, regexMatch[i].length()-1));
1249                 Matcher matcher = pattern.matcher(graph);
1250                 int count = 0;
1251                 String nodes = "";
1252                 while (matcher.find()) {
1253                     count++;
1254                     nodes += matcher.group() + "\n";
1255                 }
1256                 Asserts.assertEQ(matchCount[i], count, "Graph for '" + testName + "' contains different number of match nodes:\n" + nodes);




1257             }
1258             tests.remove(testName);
1259             System.out.println(testName + " passed");
1260         }
1261         // Check if all tests were compiled
1262         if (tests.size() != 0) {
1263             for (String name : tests.keySet()) {
1264                 System.out.println("Test '" + name + "' not compiled!");
1265             }
1266             throw new RuntimeException("Not all tests were compiled");
1267         }
1268     }
1269 
1270     public void setup(Method[] methods) {
1271         for (Method m : methods) {
1272             if (m.isAnnotationPresent(Test.class)) {
1273                 // Don't inline tests
1274                 WHITE_BOX.testSetDontInlineMethod(m, true);
1275             }
1276             if (m.isAnnotationPresent(DontCompile.class)) {


< prev index next >