< prev index next >

test/compiler/valhalla/valuetypes/ValueTypeTestBench.java

Print this page
rev 10493 : keep
rev 10511 : value type calling convention
rev 10513 : reviews


  12  * version 2 for more details (a copy is included in the LICENSE file that
  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 -noverify -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI



  33  *                   -XX:-TieredCompilation compiler.valhalla.valuetypes.ValueTypeTestBench
  34  */
  35 
  36 package compiler.valhalla.valuetypes;
  37 
  38 import compiler.whitebox.CompilerWhiteBoxTest;
  39 import jdk.internal.misc.Unsafe;
  40 import jdk.test.lib.Asserts;
  41 import jdk.test.lib.Platform;
  42 import jdk.test.lib.ProcessTools;
  43 import jdk.test.lib.OutputAnalyzer;
  44 import jdk.test.lib.Utils;
  45 import sun.hotspot.WhiteBox;
  46 
  47 import java.lang.annotation.Retention;
  48 import java.lang.annotation.RetentionPolicy;

  49 import java.lang.reflect.Method;
  50 import java.util.ArrayList;

  51 import java.util.Hashtable;

  52 import java.util.regex.Matcher;
  53 import java.util.regex.Pattern;
  54 
  55 // Test value types
  56 __ByValue final class MyValue1 {
  57     static int s;
  58     static final long sf = ValueTypeTestBench.rL;
  59     final int x;
  60     final long y;
  61     final MyValue2 v1;
  62     final MyValue2 v2;
  63     static final MyValue2 v3 = MyValue2.createInline(ValueTypeTestBench.rI, true);
  64     final int c;
  65 
  66     private MyValue1(int x, long y, MyValue2 v1, MyValue2 v2, int c) {
  67         s = x;
  68         this.x = x;
  69         this.y = y;
  70         this.v1 = v1;
  71         this.v2 = v2;
  72         this.c = c;
  73     }
  74 
  75     @DontInline
  76     public static MyValue1 createDontInline(int x, long y) {
  77         return __Make MyValue1(x, y, MyValue2.createInline(x, x < y), MyValue2.createInline(x, x > y), ValueTypeTestBench.rI);
  78     }
  79 
  80     @ForceInline
  81     public static MyValue1 createInline(int x, long y) {
  82         return __Make MyValue1(x, y, MyValue2.createInline(x, x < y), MyValue2.createInline(x, x > y), ValueTypeTestBench.rI);
  83     }
  84 
  85     @ForceInline
  86     public long hash() {
  87         return s + sf + x + y + c + v1.hash() + v2.hash() + v3.hash();
  88     }
  89 
  90     @DontCompile
  91     public long hashInterpreted() {
  92         return s + sf + x + y + c + v1.hash() + v2.hash() + v3.hash();
  93     }
  94 }
  95 
  96 __ByValue final class MyValue2 {
  97     final int x;
  98     final boolean b;
  99     final long c;
 100 
 101     private MyValue2(int x, boolean b, long c) {
 102         this.x = x;
 103         this.b = b;
 104         this.c = c;
 105     }
 106 
 107     @ForceInline
 108     public static MyValue2 createInline(int x, boolean b) {
 109         return __Make MyValue2(x, b, ValueTypeTestBench.rL);
 110     }
 111 
 112     @ForceInline
 113     public long hash() {
 114         return x + (b ? 0 : 1) + c;
 115     }





 116 }
 117 
 118 public class ValueTypeTestBench {
 119     // Print ideal graph after execution of each test
 120     private static final boolean PRINT_GRAPH = true;
 121 
 122     // Random test values
 123     public static final int  rI = Utils.getRandomInstance().nextInt() % 1000;
 124     public static final long rL = Utils.getRandomInstance().nextLong() % 1000;
 125 
 126     public ValueTypeTestBench() {
 127         val3 = MyValue1.createInline(rI, rL);
 128     }
 129 
 130     // ========== Helper methods ==========
 131 
 132     public long hash() {
 133         return hash(rI, rL);
 134     }
 135 


 149     @DontCompile
 150     public void test1_verifier(boolean warmup) {
 151         long result = test1();
 152         Asserts.assertEQ(result, hash());
 153     }
 154 
 155     // Receive value type from interpreter via parameter
 156     @Test(failOn = ALLOC + STORE + TRAP)
 157     public long test2(MyValue1 v) {
 158         return v.hash();
 159     }
 160 
 161     @DontCompile
 162     public void test2_verifier(boolean warmup) {
 163         MyValue1 v = MyValue1.createDontInline(rI, rL);
 164         long result = test2(v);
 165         Asserts.assertEQ(result, hash());
 166     }
 167 
 168     // Return incoming value type without accessing fields
 169     @Test(failOn = ALLOC + LOAD + STORE + TRAP)

 170     public MyValue1 test3(MyValue1 v) {
 171         return v;
 172     }
 173 
 174     @DontCompile
 175     public void test3_verifier(boolean warmup) {
 176         MyValue1 v1 = MyValue1.createDontInline(rI, rL);
 177         MyValue1 v2 = test3(v1);
 178         Asserts.assertEQ(v1.x, v2.x);
 179         Asserts.assertEQ(v1.y, v2.y);
 180     }
 181 
 182     // Create a value type in compiled code and only use fields.
 183     // Allocation should go away because value type does not escape.
 184     @Test(failOn = ALLOC + LOAD + STORE + TRAP)
 185     public long test4() {
 186         MyValue1 v = MyValue1.createInline(rI, rL);
 187         return v.hash();
 188     }
 189 


 197     // an inlined compiled method via a call.
 198     @Test(failOn = ALLOC + LOAD + STORE + TRAP)
 199     public long test5() {
 200         MyValue1 v = MyValue1.createInline(rI, rL);
 201         return test5Inline(v);
 202     }
 203 
 204     @ForceInline
 205     public long test5Inline(MyValue1 v) {
 206         return v.hash();
 207     }
 208 
 209     @DontCompile
 210     public void test5_verifier(boolean warmup) {
 211         long result = test5();
 212         Asserts.assertEQ(result, hash());
 213     }
 214 
 215     // Create a value type in compiled code and pass it to
 216     // the interpreter via a call.
 217     @Test(match = {ALLOC}, matchCount = {1}, failOn = LOAD + TRAP)

 218     public long test6() {
 219         MyValue1 v = MyValue1.createInline(rI, rL);
 220         // Pass to interpreter
 221         return v.hashInterpreted();
 222     }
 223 
 224     @DontCompile
 225     public void test6_verifier(boolean warmup) {
 226         long result = test6();
 227         Asserts.assertEQ(result, hash());
 228     }
 229 
 230     // Create a value type in compiled code and pass it to
 231     // the interpreter by returning.
 232     @Test(match = {ALLOC}, matchCount = {1}, failOn = LOAD + TRAP)
 233     public MyValue1 test7(int x, long y) {
 234         return MyValue1.createInline(x, y);
 235     }
 236 
 237     @DontCompile


 242 
 243     // Merge value types created from two branches
 244     @Test(failOn = ALLOC + STORE + TRAP)
 245     public long test8(boolean b) {
 246         MyValue1 v;
 247         if (b) {
 248             v = MyValue1.createInline(rI, rL);
 249         } else {
 250             v = MyValue1.createDontInline(rI + 1, rL + 1);
 251         }
 252         return v.hash();
 253     }
 254 
 255     @DontCompile
 256     public void test8_verifier(boolean warmup) {
 257         Asserts.assertEQ(test8(true), hash());
 258         Asserts.assertEQ(test8(false), hash(rI + 1, rL + 1));
 259     }
 260 
 261     // Merge value types created from two branches
 262     @Test(match = {ALLOC, STORE}, matchCount = {1, 9}, failOn = LOAD + TRAP)

 263     public MyValue1 test9(boolean b) {
 264         MyValue1 v;
 265         if (b) {
 266             // Value type is not allocated
 267             v = MyValue1.createInline(rI, rL);
 268         } else {
 269             // Value type is allocated by the callee
 270             v = MyValue1.createDontInline(rI + 1, rL + 1);
 271         }
 272         // Need to allocate value type if 'b' is true
 273         long sum = v.hashInterpreted();
 274         if (b) {
 275             v = MyValue1.createDontInline(rI, sum);
 276         } else {
 277             v = MyValue1.createDontInline(rI, sum + 1);
 278         }
 279         // Don't need to allocate value type because both branches allocate
 280         return v;
 281     }
 282 


 353         for (int i = 0; i < 1000; ++i) {
 354             if (b) {
 355                 result += v.x;
 356             } else {
 357                 // Uncommon trap referencing v. Should not allocate
 358                 // but just pass the existing oop to the uncommon trap.
 359                 result = v.hashInterpreted();
 360             }
 361         }
 362         return result;
 363     }
 364 
 365     @DontCompile
 366     public void test13_verifier(boolean warmup) {
 367         long result = test13(warmup);
 368         Asserts.assertEQ(result, warmup ? 42 + (1000*rI) : hash());
 369     }
 370 
 371     // Create a value type in a non-inlined method and then call a
 372     // non-inlined method on that value type.
 373     @Test(failOn = (ALLOC + LOAD + STORE + TRAP))

 374     public long test14() {
 375         MyValue1 v = MyValue1.createDontInline(rI, rL);
 376         return v.hashInterpreted();
 377     }
 378 
 379     @DontCompile
 380     public void test14_verifier(boolean b) {
 381         long result = test14();
 382         Asserts.assertEQ(result, hash());
 383     }
 384 
 385     // Create a value type in an inlined method and then call a
 386     // non-inlined method on that value type.
 387     @Test(failOn = (LOAD + TRAP), match = {ALLOC}, matchCount = {1})

 388     public long test15() {
 389         MyValue1 v = MyValue1.createInline(rI, rL);
 390         return v.hashInterpreted();
 391     }
 392 
 393     @DontCompile
 394     public void test15_verifier(boolean b) {
 395         long result = test15();
 396         Asserts.assertEQ(result, hash());
 397     }
 398 
 399     // Create a value type in a non-inlined method and then call an
 400     // inlined method on that value type.
 401     @Test(failOn = (ALLOC + STORE + TRAP))
 402     public long test16() {
 403         MyValue1 v = MyValue1.createDontInline(rI, rL);
 404         return v.hash();
 405     }
 406 
 407     @DontCompile


 410         Asserts.assertEQ(result, hash());
 411     }
 412 
 413     // Create a value type in an inlined method and then call an
 414     // inlined method on that value type.
 415     @Test(failOn = (ALLOC + LOAD + STORE + TRAP))
 416     public long test17() {
 417         MyValue1 v = MyValue1.createInline(rI, rL);
 418         return v.hash();
 419     }
 420 
 421     @DontCompile
 422     public void test17_verifier(boolean b) {
 423         long result = test17();
 424         Asserts.assertEQ(result, hash());
 425     }
 426 
 427     // Create a value type in compiled code and pass it to the
 428     // interpreter via a call. The value is live at the first call so
 429     // debug info should include a reference to all its fields.
 430     @Test(match = {ALLOC}, matchCount = {1}, failOn = LOAD + TRAP)

 431     public long test18() {
 432         MyValue1 v = MyValue1.createInline(rI, rL);
 433         v.hashInterpreted();
 434         return v.hashInterpreted();
 435     }
 436 
 437     @DontCompile
 438     public void test18_verifier(boolean warmup) {
 439         long result = test18();
 440         Asserts.assertEQ(result, hash());
 441     }
 442 
 443     // Create a value type in compiled code and pass it to the
 444     // interpreter via a call. The value type is passed twice but
 445     // should only be allocated once.
 446     @Test(match = {ALLOC}, matchCount = {1}, failOn = LOAD + TRAP)

 447     public long test19() {
 448         MyValue1 v = MyValue1.createInline(rI, rL);
 449         return sumValue(v, v);
 450     }
 451 
 452     @DontCompile
 453     public long sumValue(MyValue1 v, MyValue1 dummy) {
 454         return v.hash();
 455     }
 456 
 457     @DontCompile
 458     public void test19_verifier(boolean warmup) {
 459         long result = test19();
 460         Asserts.assertEQ(result, hash());
 461     }
 462 
 463     // Create a value type in compiled code and pass it to the
 464     // interpreter via a call. The value type is live at the uncommon
 465     // trap: verify that deoptimization causes the value type to be
 466     // correctly allocated.
 467     @Test(match = {ALLOC}, matchCount = {1}, failOn = LOAD)

 468     public long test20(boolean flag) {
 469         MyValue1 v = MyValue1.createInline(rI, rL);
 470         if (flag) {
 471             // uncommon trap
 472             WHITE_BOX.deoptimizeMethod(tests.get("ValueTypeTestBench::test16"));
 473         }
 474         return v.hashInterpreted();
 475     }
 476 
 477     @DontCompile
 478     public void test20_verifier(boolean warmup) {
 479         long result = test20(false);
 480         Asserts.assertEQ(result, hash());
 481         if (!warmup) {
 482             result = test20(true);
 483             Asserts.assertEQ(result, hash());
 484         }
 485     }
 486 
 487     // Value type fields in regular object
 488     MyValue1 val1;
 489     MyValue2 val2;
 490     final MyValue1 val3;
 491     static MyValue1 val4;
 492     static final MyValue1 val5 = MyValue1.createInline(rI, rL);


 535 
 536     // Test OSR compilation
 537     @Test(failOn = ALLOC + LOAD + STORE + LOOP + TRAP)
 538     public long test23() {
 539         MyValue1 v = MyValue1.createInline(rI, rL);
 540         long result = 0;
 541         // Long loop to trigger OSR compilation
 542         for (int i = 0 ; i < 100_000 ; ++i) {
 543             // Reference local value type in interpreter state
 544             result = v.hash();
 545         }
 546         return result;
 547     }
 548 
 549     @DontCompile
 550     public void test23_verifier(boolean warmup) {
 551         long result = test23();
 552         Asserts.assertEQ(result, hash());
 553     }
 554 











































































































































































































 555 
 556     // ========== Test infrastructure ==========
 557 
 558     private static final WhiteBox WHITE_BOX = WhiteBox.getWhiteBox();




 559     private static final int COMP_LEVEL_ANY = -1;
 560     private static final int COMP_LEVEL_FULL_OPTIMIZATION = 4;
 561     private static final Hashtable<String, Method> tests = new Hashtable<String, Method>();
 562     private static final int WARMUP = 10;
 563     private static boolean USE_COMPILER = WHITE_BOX.getBooleanVMFlag("UseCompiler");
 564     private static boolean PRINT_IDEAL  = WHITE_BOX.getBooleanVMFlag("PrintIdeal");
 565     // TODO use Platform.isComp() after merge with JDK 9
 566     private static boolean XCOMP = System.getProperty("java.vm.info").startsWith("compiled ");
 567 
 568     // Regular expressions used  to match nodes in the PrintIdeal output
 569     private static final String START = "(\\d+\\t(.*";
 570     private static final String MID = ".*)+\\t===.*";
 571     private static final String END = ")|";
 572     private static final String ALLOC = START + "CallStaticJava" + MID + "_new_instance_Java" + END;
 573     private static final String LOAD  = START + "Load" + MID + "valuetype\\*" + END;
 574     private static final String STORE = START + "Store" + MID + "valuetype\\*" + END;
 575     private static final String LOOP  = START + "Loop" + MID + "" + END;
 576     private static final String TRAP  = START + "CallStaticJava" + MID + "uncommon_trap" + END;
 577     // TODO: match field values of scalar replaced object
 578     private static final String SCOBJ = "(.*# ScObj.*" + END;
 579 
 580     static {
 581         // Gather all test methods and put them in Hashtable
 582         for (Method m : ValueTypeTestBench.class.getDeclaredMethods()) {
 583             if (m.isAnnotationPresent(Test.class)) {

 584                 tests.put("ValueTypeTestBench::" + m.getName(), m);
 585             }
 586         }
 587     }
 588 
 589     public static void main(String[] args) throws Throwable {
 590         if (args.length == 0) {
 591             // Run tests in own process and verify output
 592             OutputAnalyzer oa = ProcessTools.executeTestJvm("-noverify",
 593                     "-XX:+UnlockDiagnosticVMOptions", "-Xbootclasspath/a:.", "-XX:+WhiteBoxAPI",
 594                     "-XX:-TieredCompilation", "-XX:-BackgroundCompilation",
 595                     "-XX:+IgnoreUnrecognizedVMOptions", "-XX:+PrintCompilation", "-XX:+PrintIdeal", "-XX:+PrintOptoAssembly",
 596                     "-XX:CompileCommand=quiet", "-XX:CompileCommand=compileonly,compiler.valhalla.valuetypes.ValueTypeTestBench::*",
 597                     "-XX:CompileCommand=compileonly,compiler.valhalla.valuetypes.MyValue1::*",
 598                     "-XX:CompileCommand=compileonly,compiler.valhalla.valuetypes.MyValue2::*",
 599                     ValueTypeTestBench.class.getName(), "run");










 600             // If ideal graph printing is enabled/supported, verify output
 601             String output = oa.getOutput();
 602             oa.shouldHaveExitValue(0);
 603             if (output.contains("PrintIdeal enabled")) {
 604                 parseOutput(output);
 605             } else {
 606                 System.out.println("WARNING: IR verification disabled! Running with -Xint, -Xcomp or release build?");
 607             }
 608         } else {
 609             if (USE_COMPILER && PRINT_IDEAL && !XCOMP) {
 610                 System.out.println("PrintIdeal enabled");
 611             }
 612             // Execute tests
 613             ValueTypeTestBench bench = new ValueTypeTestBench();
 614             bench.run();
 615         }
 616     }
 617 
 618     public static void parseOutput(String output) throws Exception {
 619         String split = "b        compiler.valhalla.valuetypes.";
 620         String[] compilations = output.split(split);
 621         // Print header
 622         System.out.println(compilations[0]);
 623         // Iterate over compilation output
 624         for (String graph : compilations) {
 625             String[] lines = graph.split("\\n");
 626             if (lines[0].contains("@")) {
 627                 continue; // Ignore OSR compilations
 628             }
 629             String testName = lines[0].split(" ")[0];
 630             Method test = tests.get(testName);
 631             if (test == null) {
 632                 // Skip helper methods
 633                 continue;
 634             }
 635             if (PRINT_GRAPH) {
 636                 System.out.println("\nGraph for " + graph);
 637             }
 638             // Parse graph using regular expressions to determine if it contains forbidden nodes
 639             Test anno = test.getAnnotation(Test.class);











 640             String regexFail = anno.failOn();
 641             if (!regexFail.isEmpty()) {
 642                 Pattern pattern = Pattern.compile(regexFail.substring(0, regexFail.length()-1));
 643                 Matcher matcher = pattern.matcher(graph);
 644                 boolean fail = false;
 645                 while (matcher.find()) {
 646                     System.out.println("Graph for '" + testName + "' contains forbidden node:");
 647                     System.out.println(matcher.group());
 648                     fail = true;
 649                 }
 650                 Asserts.assertFalse(fail, "Graph for '" + testName + "' contains forbidden nodes");
 651             }
 652             String[] regexMatch = anno.match();
 653             int[] matchCount = anno.matchCount();
 654             for (int i = 0; i < regexMatch.length; ++i) {
 655                 Pattern pattern = Pattern.compile(regexMatch[i].substring(0, regexMatch[i].length()-1));
 656                 Matcher matcher = pattern.matcher(graph);
 657                 int count = 0;
 658                 String nodes = "";
 659                 while (matcher.find()) {


 706         //WHITE_BOX.enqueueInitializerForCompilation(this.getClass(), COMP_LEVEL_FULL_OPTIMIZATION);
 707 
 708         // Execute tests
 709         for (Method test : tests.values()) {
 710             Method verifier = getClass().getDeclaredMethod(test.getName() + "_verifier", boolean.class);
 711             // Warmup using verifier method
 712             for (int i = 0; i < WARMUP; ++i) {
 713                 verifier.invoke(this, true);
 714             }
 715             // Trigger compilation
 716             WHITE_BOX.enqueueMethodForCompilation(test, COMP_LEVEL_FULL_OPTIMIZATION);
 717             Asserts.assertTrue(!USE_COMPILER || WHITE_BOX.isMethodCompiled(test, false), test + " not compiled");
 718             // Check result
 719             verifier.invoke(this, false);
 720         }
 721     }
 722 }
 723 
 724 // Mark method as test
 725 @Retention(RetentionPolicy.RUNTIME)

 726 @interface Test {
 727     // Regular expression used to match forbidden IR nodes
 728     // in the C2 IR emitted for this test.
 729     String failOn() default "";
 730     // Regular expressions used to match and count IR nodes.
 731     String[] match() default { };
 732     int[] matchCount() default { };






 733 }
 734 
 735 // Force method inlining during compilation
 736 @Retention(RetentionPolicy.RUNTIME)
 737 @interface ForceInline { }
 738 
 739 // Prevent method inlining during compilation
 740 @Retention(RetentionPolicy.RUNTIME)
 741 @interface DontInline { }
 742 
 743 // Prevent method compilation
 744 @Retention(RetentionPolicy.RUNTIME)
 745 @interface DontCompile { }


  12  * version 2 for more details (a copy is included in the LICENSE file that
  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:-TieredCompilation compiler.valhalla.valuetypes.ValueTypeTestBench
  34  * @run main/othervm -ea -noverify -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI
  35  *                   -XX:+UnlockExperimentalVMOptions -XX:-ValueTypePassFieldsAsArgs
  36  *                   -XX:-TieredCompilation compiler.valhalla.valuetypes.ValueTypeTestBench
  37  */
  38 
  39 package compiler.valhalla.valuetypes;
  40 
  41 import compiler.whitebox.CompilerWhiteBoxTest;
  42 import jdk.internal.misc.Unsafe;
  43 import jdk.test.lib.Asserts;
  44 import jdk.test.lib.Platform;
  45 import jdk.test.lib.ProcessTools;
  46 import jdk.test.lib.OutputAnalyzer;
  47 import jdk.test.lib.Utils;
  48 import sun.hotspot.WhiteBox;
  49 
  50 import java.lang.annotation.Retention;
  51 import java.lang.annotation.RetentionPolicy;
  52 import java.lang.annotation.Repeatable;
  53 import java.lang.reflect.Method;
  54 import java.util.ArrayList;
  55 import java.util.Arrays;
  56 import java.util.Hashtable;
  57 import java.util.List;
  58 import java.util.regex.Matcher;
  59 import java.util.regex.Pattern;
  60 
  61 // Test value types
  62 __ByValue final class MyValue1 {
  63     static int s;
  64     static final long sf = ValueTypeTestBench.rL;
  65     final int x;
  66     final long y;
  67     final MyValue2 v1;
  68     final MyValue2 v2;
  69     static final MyValue2 v3 = MyValue2.createInline(ValueTypeTestBench.rI, true);
  70     final int c;
  71 
  72     private MyValue1(int x, long y, MyValue2 v1, MyValue2 v2, int c) {
  73         s = x;
  74         this.x = x;
  75         this.y = y;
  76         this.v1 = v1;
  77         this.v2 = v2;
  78         this.c = c;
  79     }
  80 
  81     @DontInline
  82     public static MyValue1 createDontInline(int x, long y) {
  83         return __Make MyValue1(x, y, MyValue2.createInline(x, x < y), MyValue2.createInline(x, x > y), ValueTypeTestBench.rI);
  84     }
  85 
  86     @ForceInline
  87     public static MyValue1 createInline(int x, long y) {
  88         return __Make MyValue1(x, y, MyValue2.createInline(x, x < y), MyValue2.createInline(x, x > y), ValueTypeTestBench.rI);
  89     }
  90 
  91     @ForceInline
  92     public long hash() {
  93         return s + sf + x + y + c + v1.hash() + v2.hash() + v3.hash();
  94     }
  95 
  96     @DontCompile
  97     public long hashInterpreted() {
  98         return s + sf + x + y + c + v1.hashInterpreted() + v2.hashInterpreted() + v3.hashInterpreted();
  99     }
 100 }
 101 
 102 __ByValue final class MyValue2 {
 103     final int x;
 104     final boolean b;
 105     final long c;
 106 
 107     private MyValue2(int x, boolean b, long c) {
 108         this.x = x;
 109         this.b = b;
 110         this.c = c;
 111     }
 112 
 113     @ForceInline
 114     public static MyValue2 createInline(int x, boolean b) {
 115         return __Make MyValue2(x, b, ValueTypeTestBench.rL);
 116     }
 117 
 118     @ForceInline
 119     public long hash() {
 120         return x + (b ? 0 : 1) + c;
 121     }
 122 
 123     @DontInline
 124     public long hashInterpreted() {
 125         return x + (b ? 0 : 1) + c;
 126     }
 127 }
 128 
 129 public class ValueTypeTestBench {
 130     // Print ideal graph after execution of each test
 131     private static final boolean PRINT_GRAPH = true;
 132 
 133     // Random test values
 134     public static final int  rI = Utils.getRandomInstance().nextInt() % 1000;
 135     public static final long rL = Utils.getRandomInstance().nextLong() % 1000;
 136 
 137     public ValueTypeTestBench() {
 138         val3 = MyValue1.createInline(rI, rL);
 139     }
 140 
 141     // ========== Helper methods ==========
 142 
 143     public long hash() {
 144         return hash(rI, rL);
 145     }
 146 


 160     @DontCompile
 161     public void test1_verifier(boolean warmup) {
 162         long result = test1();
 163         Asserts.assertEQ(result, hash());
 164     }
 165 
 166     // Receive value type from interpreter via parameter
 167     @Test(failOn = ALLOC + STORE + TRAP)
 168     public long test2(MyValue1 v) {
 169         return v.hash();
 170     }
 171 
 172     @DontCompile
 173     public void test2_verifier(boolean warmup) {
 174         MyValue1 v = MyValue1.createDontInline(rI, rL);
 175         long result = test2(v);
 176         Asserts.assertEQ(result, hash());
 177     }
 178 
 179     // Return incoming value type without accessing fields
 180     @Test(valid = ValueTypePassFieldsAsArgsOn, match = {ALLOC, STORE}, matchCount = {1, 9}, failOn = LOAD + TRAP)
 181     @Test(valid = ValueTypePassFieldsAsArgsOff, failOn = ALLOC + LOAD + STORE + TRAP)
 182     public MyValue1 test3(MyValue1 v) {
 183         return v;
 184     }
 185 
 186     @DontCompile
 187     public void test3_verifier(boolean warmup) {
 188         MyValue1 v1 = MyValue1.createDontInline(rI, rL);
 189         MyValue1 v2 = test3(v1);
 190         Asserts.assertEQ(v1.x, v2.x);
 191         Asserts.assertEQ(v1.y, v2.y);
 192     }
 193 
 194     // Create a value type in compiled code and only use fields.
 195     // Allocation should go away because value type does not escape.
 196     @Test(failOn = ALLOC + LOAD + STORE + TRAP)
 197     public long test4() {
 198         MyValue1 v = MyValue1.createInline(rI, rL);
 199         return v.hash();
 200     }
 201 


 209     // an inlined compiled method via a call.
 210     @Test(failOn = ALLOC + LOAD + STORE + TRAP)
 211     public long test5() {
 212         MyValue1 v = MyValue1.createInline(rI, rL);
 213         return test5Inline(v);
 214     }
 215 
 216     @ForceInline
 217     public long test5Inline(MyValue1 v) {
 218         return v.hash();
 219     }
 220 
 221     @DontCompile
 222     public void test5_verifier(boolean warmup) {
 223         long result = test5();
 224         Asserts.assertEQ(result, hash());
 225     }
 226 
 227     // Create a value type in compiled code and pass it to
 228     // the interpreter via a call.
 229     @Test(valid = ValueTypePassFieldsAsArgsOn, failOn = LOAD + TRAP + ALLOC)
 230     @Test(valid = ValueTypePassFieldsAsArgsOff, match = {ALLOC}, matchCount = {1}, failOn = LOAD + TRAP)
 231     public long test6() {
 232         MyValue1 v = MyValue1.createInline(rI, rL);
 233         // Pass to interpreter
 234         return v.hashInterpreted();
 235     }
 236 
 237     @DontCompile
 238     public void test6_verifier(boolean warmup) {
 239         long result = test6();
 240         Asserts.assertEQ(result, hash());
 241     }
 242 
 243     // Create a value type in compiled code and pass it to
 244     // the interpreter by returning.
 245     @Test(match = {ALLOC}, matchCount = {1}, failOn = LOAD + TRAP)
 246     public MyValue1 test7(int x, long y) {
 247         return MyValue1.createInline(x, y);
 248     }
 249 
 250     @DontCompile


 255 
 256     // Merge value types created from two branches
 257     @Test(failOn = ALLOC + STORE + TRAP)
 258     public long test8(boolean b) {
 259         MyValue1 v;
 260         if (b) {
 261             v = MyValue1.createInline(rI, rL);
 262         } else {
 263             v = MyValue1.createDontInline(rI + 1, rL + 1);
 264         }
 265         return v.hash();
 266     }
 267 
 268     @DontCompile
 269     public void test8_verifier(boolean warmup) {
 270         Asserts.assertEQ(test8(true), hash());
 271         Asserts.assertEQ(test8(false), hash(rI + 1, rL + 1));
 272     }
 273 
 274     // Merge value types created from two branches
 275     @Test(valid = ValueTypePassFieldsAsArgsOn, match = {LOAD}, matchCount = {9}, failOn = TRAP + ALLOC + STORE)
 276     @Test(valid = ValueTypePassFieldsAsArgsOff, match = {ALLOC, STORE}, matchCount = {1, 9}, failOn = LOAD + TRAP)
 277     public MyValue1 test9(boolean b) {
 278         MyValue1 v;
 279         if (b) {
 280             // Value type is not allocated
 281             v = MyValue1.createInline(rI, rL);
 282         } else {
 283             // Value type is allocated by the callee
 284             v = MyValue1.createDontInline(rI + 1, rL + 1);
 285         }
 286         // Need to allocate value type if 'b' is true
 287         long sum = v.hashInterpreted();
 288         if (b) {
 289             v = MyValue1.createDontInline(rI, sum);
 290         } else {
 291             v = MyValue1.createDontInline(rI, sum + 1);
 292         }
 293         // Don't need to allocate value type because both branches allocate
 294         return v;
 295     }
 296 


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


 426         Asserts.assertEQ(result, hash());
 427     }
 428 
 429     // Create a value type in an inlined method and then call an
 430     // inlined method on that value type.
 431     @Test(failOn = (ALLOC + LOAD + STORE + TRAP))
 432     public long test17() {
 433         MyValue1 v = MyValue1.createInline(rI, rL);
 434         return v.hash();
 435     }
 436 
 437     @DontCompile
 438     public void test17_verifier(boolean b) {
 439         long result = test17();
 440         Asserts.assertEQ(result, hash());
 441     }
 442 
 443     // Create a value type in compiled code and pass it to the
 444     // interpreter via a call. The value is live at the first call so
 445     // debug info should include a reference to all its fields.
 446     @Test(valid = ValueTypePassFieldsAsArgsOn, failOn = ALLOC + LOAD + TRAP)
 447     @Test(valid = ValueTypePassFieldsAsArgsOff, match = {ALLOC}, matchCount = {1}, failOn = LOAD + TRAP)
 448     public long test18() {
 449         MyValue1 v = MyValue1.createInline(rI, rL);
 450         v.hashInterpreted();
 451         return v.hashInterpreted();
 452     }
 453 
 454     @DontCompile
 455     public void test18_verifier(boolean warmup) {
 456         long result = test18();
 457         Asserts.assertEQ(result, hash());
 458     }
 459 
 460     // Create a value type in compiled code and pass it to the
 461     // interpreter via a call. The value type is passed twice but
 462     // should only be allocated once.
 463     @Test(valid = ValueTypePassFieldsAsArgsOn, failOn = ALLOC + LOAD + TRAP)
 464     @Test(valid = ValueTypePassFieldsAsArgsOff, match = {ALLOC}, matchCount = {1}, failOn = LOAD + TRAP)
 465     public long test19() {
 466         MyValue1 v = MyValue1.createInline(rI, rL);
 467         return sumValue(v, v);
 468     }
 469 
 470     @DontCompile
 471     public long sumValue(MyValue1 v, MyValue1 dummy) {
 472         return v.hash();
 473     }
 474 
 475     @DontCompile
 476     public void test19_verifier(boolean warmup) {
 477         long result = test19();
 478         Asserts.assertEQ(result, hash());
 479     }
 480 
 481     // Create a value type in compiled code and pass it to the
 482     // interpreter via a call. The value type is live at the uncommon
 483     // trap: verify that deoptimization causes the value type to be
 484     // correctly allocated.
 485     @Test(valid = ValueTypePassFieldsAsArgsOn, failOn = LOAD + ALLOC + STORE)
 486     @Test(valid = ValueTypePassFieldsAsArgsOff, match = {ALLOC}, matchCount = {1}, failOn = LOAD)
 487     public long test20(boolean flag) {
 488         MyValue1 v = MyValue1.createInline(rI, rL);
 489         if (flag) {
 490             // uncommon trap
 491             WHITE_BOX.deoptimizeMethod(tests.get("ValueTypeTestBench::test20"));
 492         }
 493         return v.hashInterpreted();
 494     }
 495 
 496     @DontCompile
 497     public void test20_verifier(boolean warmup) {
 498         long result = test20(false);
 499         Asserts.assertEQ(result, hash());
 500         if (!warmup) {
 501             result = test20(true);
 502             Asserts.assertEQ(result, hash());
 503         }
 504     }
 505 
 506     // Value type fields in regular object
 507     MyValue1 val1;
 508     MyValue2 val2;
 509     final MyValue1 val3;
 510     static MyValue1 val4;
 511     static final MyValue1 val5 = MyValue1.createInline(rI, rL);


 554 
 555     // Test OSR compilation
 556     @Test(failOn = ALLOC + LOAD + STORE + LOOP + TRAP)
 557     public long test23() {
 558         MyValue1 v = MyValue1.createInline(rI, rL);
 559         long result = 0;
 560         // Long loop to trigger OSR compilation
 561         for (int i = 0 ; i < 100_000 ; ++i) {
 562             // Reference local value type in interpreter state
 563             result = v.hash();
 564         }
 565         return result;
 566     }
 567 
 568     @DontCompile
 569     public void test23_verifier(boolean warmup) {
 570         long result = test23();
 571         Asserts.assertEQ(result, hash());
 572     }
 573 
 574     // Test interpreter to compiled code with various signatures
 575     @Test(failOn = ALLOC + STORE + TRAP)
 576     public long test24(MyValue2 v) {
 577         return v.hash();
 578     }
 579 
 580     @DontCompile
 581     public void test24_verifier(boolean warmup) {
 582         MyValue2 v = MyValue2.createInline(rI, true);
 583         long result = test24(v);
 584         Asserts.assertEQ(result, v.hashInterpreted());
 585     }
 586 
 587     @Test(failOn = ALLOC + STORE + TRAP)
 588     public long test25(int i1, MyValue2 v, int i2) {
 589         return v.hash() + i1 - i2;
 590     }
 591 
 592     @DontCompile
 593     public void test25_verifier(boolean warmup) {
 594         MyValue2 v = MyValue2.createInline(rI, true);
 595         long result = test25(rI, v, 2*rI);
 596         Asserts.assertEQ(result, v.hashInterpreted() - rI);
 597     }
 598 
 599     @Test(failOn = ALLOC + STORE + TRAP)
 600     public long test26(long l1, MyValue2 v, long l2) {
 601         return v.hash() + l1 - l2;
 602     }
 603 
 604     @DontCompile
 605     public void test26_verifier(boolean warmup) {
 606         MyValue2 v = MyValue2.createInline(rI, true);
 607         long result = test26(rL, v, 2*rL);
 608         Asserts.assertEQ(result, v.hashInterpreted() - rL);
 609     }
 610 
 611     @Test(failOn = ALLOC + STORE + TRAP)
 612     public long test27(int i, MyValue2 v, long l) {
 613         return v.hash() + i + l;
 614     }
 615 
 616     @DontCompile
 617     public void test27_verifier(boolean warmup) {
 618         MyValue2 v = MyValue2.createInline(rI, true);
 619         long result = test27(rI, v, rL);
 620         Asserts.assertEQ(result, v.hashInterpreted() + rL + rI);
 621     }
 622 
 623     @Test(failOn = ALLOC + STORE + TRAP)
 624     public long test28(long l, MyValue2 v, int i) {
 625         return v.hash() + i + l;
 626     }
 627 
 628     @DontCompile
 629     public void test28_verifier(boolean warmup) {
 630         MyValue2 v = MyValue2.createInline(rI, true);
 631         long result = test28(rL, v, rI);
 632         Asserts.assertEQ(result, v.hashInterpreted() + rL + rI);
 633     }
 634 
 635     @Test(failOn = ALLOC + STORE + TRAP)
 636     public long test29(long l, MyValue1 v1, int i, MyValue2 v2) {
 637         return v1.hash() + i + l + v2.hash();
 638     }
 639 
 640     @DontCompile
 641     public void test29_verifier(boolean warmup) {
 642         MyValue1 v1 = MyValue1.createDontInline(rI, rL);
 643         MyValue2 v2 = MyValue2.createInline(rI, true);
 644         long result = test29(rL, v1, rI, v2);
 645         Asserts.assertEQ(result, v1.hashInterpreted() + rL + rI + v2.hashInterpreted());
 646     }
 647 
 648     // Test compiled code to interpreter with various signatures
 649     @DontCompile
 650     public long test30_interp(MyValue2 v) {
 651         return v.hash();
 652     }
 653 
 654     @Test(failOn = ALLOC + STORE + TRAP)
 655     public long test30(MyValue2 v) {
 656         return test30_interp(v);
 657     }
 658 
 659     @DontCompile
 660     public void test30_verifier(boolean warmup) {
 661         MyValue2 v = MyValue2.createInline(rI, true);
 662         long result = test30(v);
 663         Asserts.assertEQ(result, v.hashInterpreted());
 664     }
 665 
 666     @DontCompile
 667     public long test31_interp(int i1, MyValue2 v, int i2) {
 668         return v.hash() + i1 - i2;
 669     }
 670 
 671     @Test(failOn = ALLOC + STORE + TRAP)
 672     public long test31(int i1, MyValue2 v, int i2) {
 673         return test31_interp(i1, v, i2);
 674     }
 675 
 676     @DontCompile
 677     public void test31_verifier(boolean warmup) {
 678         MyValue2 v = MyValue2.createInline(rI, true);
 679         long result = test31(rI, v, 2*rI);
 680         Asserts.assertEQ(result, v.hashInterpreted() - rI);
 681     }
 682 
 683     @DontCompile
 684     public long test32_interp(long l1, MyValue2 v, long l2) {
 685         return v.hash() + l1 - l2;
 686     }
 687 
 688     @Test(failOn = ALLOC + STORE + TRAP)
 689     public long test32(long l1, MyValue2 v, long l2) {
 690         return test32_interp(l1, v, l2);
 691     }
 692 
 693     @DontCompile
 694     public void test32_verifier(boolean warmup) {
 695         MyValue2 v = MyValue2.createInline(rI, true);
 696         long result = test32(rL, v, 2*rL);
 697         Asserts.assertEQ(result, v.hashInterpreted() - rL);
 698     }
 699 
 700     @DontCompile
 701     public long test33_interp(int i, MyValue2 v, long l) {
 702         return v.hash() + i + l;
 703     }
 704 
 705     @Test(failOn = ALLOC + STORE + TRAP)
 706     public long test33(int i, MyValue2 v, long l) {
 707         return test33_interp(i, v, l);
 708     }
 709 
 710     @DontCompile
 711     public void test33_verifier(boolean warmup) {
 712         MyValue2 v = MyValue2.createInline(rI, true);
 713         long result = test33(rI, v, rL);
 714         Asserts.assertEQ(result, v.hashInterpreted() + rL + rI);
 715     }
 716 
 717     @DontCompile
 718     public long test34_interp(long l, MyValue2 v, int i) {
 719         return v.hash() + i + l;
 720     }
 721 
 722     @Test(failOn = ALLOC + STORE + TRAP)
 723     public long test34(long l, MyValue2 v, int i) {
 724         return test34_interp(l, v, i);
 725     }
 726 
 727     @DontCompile
 728     public void test34_verifier(boolean warmup) {
 729         MyValue2 v = MyValue2.createInline(rI, true);
 730         long result = test34(rL, v, rI);
 731         Asserts.assertEQ(result, v.hashInterpreted() + rL + rI);
 732     }
 733 
 734     @DontCompile
 735     public long test35_interp(long l, MyValue1 v1, int i, MyValue2 v2) {
 736         return v1.hash() + i + l + v2.hash();
 737     }
 738 
 739     @Test(failOn = ALLOC + STORE + TRAP)
 740     public long test35(long l, MyValue1 v1, int i, MyValue2 v2) {
 741         return test35_interp(l, v1, i, v2);
 742     }
 743 
 744     @DontCompile
 745     public void test35_verifier(boolean warmup) {
 746         MyValue1 v1 = MyValue1.createDontInline(rI, rL);
 747         MyValue2 v2 = MyValue2.createInline(rI, true);
 748         long result = test35(rL, v1, rI, v2);
 749         Asserts.assertEQ(result, v1.hashInterpreted() + rL + rI + v2.hashInterpreted());
 750     }
 751 
 752     // test that debug info at a call is correct
 753     @DontCompile
 754     public long test36_interp(MyValue2 v, boolean flag) {
 755         if (flag) {
 756             // uncommon trap
 757             WHITE_BOX.deoptimizeMethod(tests.get("ValueTypeTestBench::test36"));
 758         }
 759         return v.hash();
 760     }
 761 
 762     @Test(failOn = ALLOC + STORE + TRAP)
 763     public long test36(MyValue2 v, boolean flag, long l) {
 764         return test36_interp(v, flag) + l;
 765     }
 766 
 767     @DontCompile
 768     public void test36_verifier(boolean warmup) {
 769         MyValue2 v = MyValue2.createInline(rI, true);
 770         long result = test36(v, false, rL);
 771         Asserts.assertEQ(result, v.hashInterpreted() + rL);
 772         if (!warmup) {
 773             result = test36(v, true, rL);
 774             Asserts.assertEQ(result, v.hashInterpreted() + rL);
 775         }
 776     }
 777 
 778     // ========== Test infrastructure ==========
 779 
 780     private static final WhiteBox WHITE_BOX = WhiteBox.getWhiteBox();
 781     private static final int ValueTypePassFieldsAsArgsOn = 0x1;
 782     private static final int ValueTypePassFieldsAsArgsOff = 0x2;
 783     static final int AllFlags = ValueTypePassFieldsAsArgsOn | ValueTypePassFieldsAsArgsOff;
 784     private static final boolean ValueTypePassFieldsAsArgs = (Boolean)WHITE_BOX.getVMFlag("ValueTypePassFieldsAsArgs");
 785     private static final int COMP_LEVEL_ANY = -1;
 786     private static final int COMP_LEVEL_FULL_OPTIMIZATION = 4;
 787     private static final Hashtable<String, Method> tests = new Hashtable<String, Method>();
 788     private static final int WARMUP = 10;
 789     private static boolean USE_COMPILER = WHITE_BOX.getBooleanVMFlag("UseCompiler");
 790     private static boolean PRINT_IDEAL  = WHITE_BOX.getBooleanVMFlag("PrintIdeal");
 791     // TODO use Platform.isComp() after merge with JDK 9
 792     private static boolean XCOMP = System.getProperty("java.vm.info").startsWith("compiled ");
 793 
 794     // Regular expressions used  to match nodes in the PrintIdeal output
 795     private static final String START = "(\\d+\\t(.*";
 796     private static final String MID = ".*)+\\t===.*";
 797     private static final String END = ")|";
 798     private static final String ALLOC = START + "CallStaticJava" + MID + "_new_instance_Java" + END;
 799     private static final String LOAD  = START + "Load" + MID + "valuetype\\*" + END;
 800     private static final String STORE = START + "Store" + MID + "valuetype\\*" + END;
 801     private static final String LOOP  = START + "Loop" + MID + "" + END;
 802     private static final String TRAP  = START + "CallStaticJava" + MID + "uncommon_trap" + END;
 803     // TODO: match field values of scalar replaced object
 804     private static final String SCOBJ = "(.*# ScObj.*" + END;
 805 
 806     static {
 807         // Gather all test methods and put them in Hashtable
 808         for (Method m : ValueTypeTestBench.class.getDeclaredMethods()) {
 809             Test[] annos = m.getAnnotationsByType(Test.class);
 810             if (annos.length != 0) {
 811                 tests.put("ValueTypeTestBench::" + m.getName(), m);
 812             }
 813         }
 814     }
 815 
 816     public static void main(String[] args) throws Throwable {
 817         if (args.length == 0) {
 818             ArrayList<String> all_args = new ArrayList(List.of(
 819                 "-noverify",
 820                 "-XX:+UnlockDiagnosticVMOptions", "-Xbootclasspath/a:.", "-XX:+WhiteBoxAPI",
 821                 "-XX:-TieredCompilation", "-XX:-BackgroundCompilation",
 822                 "-XX:+IgnoreUnrecognizedVMOptions", "-XX:+PrintCompilation", "-XX:+PrintIdeal", "-XX:+PrintOptoAssembly",
 823                 "-XX:CompileCommand=quiet", "-XX:CompileCommand=compileonly,compiler.valhalla.valuetypes.ValueTypeTestBench::*",
 824                 "-XX:CompileCommand=compileonly,compiler.valhalla.valuetypes.MyValue1::*",
 825                 "-XX:CompileCommand=compileonly,compiler.valhalla.valuetypes.MyValue2::*"
 826                                                                ));
 827             // Run tests in own process and verify output
 828             all_args.add("-XX:+UnlockExperimentalVMOptions");
 829             if ((Boolean)WHITE_BOX.getVMFlag("ValueTypePassFieldsAsArgs")) {
 830                 all_args.add("-XX:+ValueTypePassFieldsAsArgs");
 831             } else {
 832                 all_args.add("-XX:-ValueTypePassFieldsAsArgs");
 833             }
 834             all_args.add(ValueTypeTestBench.class.getName());
 835             all_args.add("run");
 836             OutputAnalyzer oa = ProcessTools.executeTestJvm(all_args.toArray(new String[0]));
 837             // If ideal graph printing is enabled/supported, verify output
 838             String output = oa.getOutput();
 839             oa.shouldHaveExitValue(0);
 840             if (output.contains("PrintIdeal enabled")) {
 841                 parseOutput(output);
 842             } else {
 843                 System.out.println("WARNING: IR verification disabled! Running with -Xint, -Xcomp or release build?");
 844             }
 845         } else {
 846             if (USE_COMPILER && PRINT_IDEAL && !XCOMP) {
 847                 System.out.println("PrintIdeal enabled");
 848             }
 849             // Execute tests
 850             ValueTypeTestBench bench = new ValueTypeTestBench();
 851             bench.run();
 852         }
 853     }
 854 
 855     public static void parseOutput(String output) throws Exception {
 856         String split = "b        compiler.valhalla.valuetypes.";
 857         String[] compilations = output.split(split);
 858         // Print header
 859         System.out.println(compilations[0]);
 860         // Iterate over compilation output
 861         for (String graph : compilations) {
 862             String[] lines = graph.split("\\n");
 863             if (lines[0].contains("@")) {
 864                 continue; // Ignore OSR compilations
 865             }
 866             String testName = lines[0].split(" ")[0];
 867             Method test = tests.get(testName);
 868             if (test == null) {
 869                 // Skip helper methods
 870                 continue;
 871             }
 872             if (PRINT_GRAPH) {
 873                 System.out.println("\nGraph for " + graph);
 874             }
 875             // Parse graph using regular expressions to determine if it contains forbidden nodes
 876             Test[] annos = test.getAnnotationsByType(Test.class);
 877             Test anno = null;
 878             for (Test a : annos) {
 879                 if ((a.valid() & ValueTypePassFieldsAsArgsOn) != 0 && ValueTypePassFieldsAsArgs) {
 880                     assert anno == null;
 881                     anno = a;
 882                 } else if ((a.valid() & ValueTypePassFieldsAsArgsOff) != 0 && !ValueTypePassFieldsAsArgs) {
 883                     assert anno == null;
 884                     anno = a;
 885                 }
 886             }
 887             assert anno != null;
 888             String regexFail = anno.failOn();
 889             if (!regexFail.isEmpty()) {
 890                 Pattern pattern = Pattern.compile(regexFail.substring(0, regexFail.length()-1));
 891                 Matcher matcher = pattern.matcher(graph);
 892                 boolean fail = false;
 893                 while (matcher.find()) {
 894                     System.out.println("Graph for '" + testName + "' contains forbidden node:");
 895                     System.out.println(matcher.group());
 896                     fail = true;
 897                 }
 898                 Asserts.assertFalse(fail, "Graph for '" + testName + "' contains forbidden nodes");
 899             }
 900             String[] regexMatch = anno.match();
 901             int[] matchCount = anno.matchCount();
 902             for (int i = 0; i < regexMatch.length; ++i) {
 903                 Pattern pattern = Pattern.compile(regexMatch[i].substring(0, regexMatch[i].length()-1));
 904                 Matcher matcher = pattern.matcher(graph);
 905                 int count = 0;
 906                 String nodes = "";
 907                 while (matcher.find()) {


 954         //WHITE_BOX.enqueueInitializerForCompilation(this.getClass(), COMP_LEVEL_FULL_OPTIMIZATION);
 955 
 956         // Execute tests
 957         for (Method test : tests.values()) {
 958             Method verifier = getClass().getDeclaredMethod(test.getName() + "_verifier", boolean.class);
 959             // Warmup using verifier method
 960             for (int i = 0; i < WARMUP; ++i) {
 961                 verifier.invoke(this, true);
 962             }
 963             // Trigger compilation
 964             WHITE_BOX.enqueueMethodForCompilation(test, COMP_LEVEL_FULL_OPTIMIZATION);
 965             Asserts.assertTrue(!USE_COMPILER || WHITE_BOX.isMethodCompiled(test, false), test + " not compiled");
 966             // Check result
 967             verifier.invoke(this, false);
 968         }
 969     }
 970 }
 971 
 972 // Mark method as test
 973 @Retention(RetentionPolicy.RUNTIME)
 974 @Repeatable(Tests.class)
 975 @interface Test {
 976     // Regular expression used to match forbidden IR nodes
 977     // in the C2 IR emitted for this test.
 978     String failOn() default "";
 979     // Regular expressions used to match and count IR nodes.
 980     String[] match() default { };
 981     int[] matchCount() default { };
 982     int valid() default ValueTypeTestBench.AllFlags;
 983 }
 984 
 985 @Retention(RetentionPolicy.RUNTIME)
 986 @interface Tests {
 987     Test[] value();
 988 }
 989 
 990 // Force method inlining during compilation
 991 @Retention(RetentionPolicy.RUNTIME)
 992 @interface ForceInline { }
 993 
 994 // Prevent method inlining during compilation
 995 @Retention(RetentionPolicy.RUNTIME)
 996 @interface DontInline { }
 997 
 998 // Prevent method compilation
 999 @Retention(RetentionPolicy.RUNTIME)
1000 @interface DontCompile { }
< prev index next >