< prev index next >

test/compiler/valhalla/valuetypes/ValueTypeTestBench.java

Print this page
rev 10493 : keep
rev 10504 : value type calling convention


  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  *                   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     final int x;
  58     final long y;
  59     final MyValue2 v1;
  60     final MyValue2 v2;
  61     final int c;
  62 
  63     private MyValue1(int x, long y, MyValue2 v1, MyValue2 v2, int c) {
  64         this.x = x;
  65         this.y = y;
  66         this.v1 = v1;
  67         this.v2 = v2;
  68         this.c = c;
  69     }
  70 
  71     @DontInline
  72     public static MyValue1 createDontInline(int x, long y) {
  73         return __Make MyValue1(x, y, MyValue2.createInline(x, x < y), MyValue2.createInline(x, x > y), ValueTypeTestBench.rI);
  74     }
  75 
  76     @ForceInline
  77     public static MyValue1 createInline(int x, long y) {
  78         return __Make MyValue1(x, y, MyValue2.createInline(x, x < y), MyValue2.createInline(x, x > y), ValueTypeTestBench.rI);
  79     }
  80 
  81     @ForceInline
  82     public long hash() {
  83         return x + y + c + v1.hash() + v2.hash();
  84     }
  85 
  86     @DontCompile
  87     public long hashInterpreted() {
  88         return x + y + c + v1.hash() + v2.hash();
  89     }
  90 }
  91 
  92 __ByValue final class MyValue2 {
  93     final int x;
  94     final boolean b;
  95     final long c;
  96 
  97     private MyValue2(int x, boolean b, long c) {
  98         this.x = x;
  99         this.b = b;
 100         this.c = c;
 101     }
 102 
 103     @ForceInline
 104     public static MyValue2 createInline(int x, boolean b) {
 105         return __Make MyValue2(x, b, ValueTypeTestBench.rL);
 106     }
 107 
 108     @ForceInline
 109     public long hash() {
 110         return x + (b ? 0 : 1) + c;
 111     }





 112 }
 113 
 114 public class ValueTypeTestBench {
 115     // Print ideal graph after execution of each test
 116     private static final boolean PRINT_GRAPH = true;
 117 
 118     // ========== Helper methods ==========
 119 
 120     public long hash() {
 121         return hash(rI, rL);
 122     }
 123 
 124     public long hash(int x, long y) {
 125         return MyValue1.createInline(x, y).hash();
 126     }
 127 
 128     // ========== Test definitions ==========
 129 
 130     // Receive value type through call to interpreter
 131     @Test(failOn = ALLOC + STORE + TRAP)


 137     @DontCompile
 138     public void test1_verifier(boolean warmup) {
 139         long result = test1();
 140         Asserts.assertEQ(result, hash());
 141     }
 142 
 143     // Receive value type from interpreter via parameter
 144     @Test(failOn = ALLOC + STORE + TRAP)
 145     public long test2(MyValue1 v) {
 146         return v.hash();
 147     }
 148 
 149     @DontCompile
 150     public void test2_verifier(boolean warmup) {
 151         MyValue1 v = MyValue1.createDontInline(rI, rL);
 152         long result = test2(v);
 153         Asserts.assertEQ(result, hash());
 154     }
 155 
 156     // Return incoming value type without accessing fields
 157     @Test(failOn = ALLOC + LOAD + STORE + TRAP)

 158     public MyValue1 test3(MyValue1 v) {
 159         return v;
 160     }
 161 
 162     @DontCompile
 163     public void test3_verifier(boolean warmup) {
 164         MyValue1 v1 = MyValue1.createDontInline(rI, rL);
 165         MyValue1 v2 = test3(v1);
 166         Asserts.assertEQ(v1.x, v2.x);
 167         Asserts.assertEQ(v1.y, v2.y);
 168     }
 169 
 170     // Create a value type in compiled code and only use fields.
 171     // Allocation should go away because value type does not escape.
 172     @Test(failOn = ALLOC + LOAD + STORE + TRAP)
 173     public long test4() {
 174         MyValue1 v = MyValue1.createInline(rI, rL);
 175         return v.hash();
 176     }
 177 


 185     // an inlined compiled method via a call.
 186     @Test(failOn = ALLOC + LOAD + STORE + TRAP)
 187     public long test5() {
 188         MyValue1 v = MyValue1.createInline(rI, rL);
 189         return test5Inline(v);
 190     }
 191 
 192     @ForceInline
 193     public long test5Inline(MyValue1 v) {
 194         return v.hash();
 195     }
 196 
 197     @DontCompile
 198     public void test5_verifier(boolean warmup) {
 199         long result = test5();
 200         Asserts.assertEQ(result, hash());
 201     }
 202 
 203     // Create a value type in compiled code and pass it to
 204     // the interpreter via a call.
 205     @Test(match = {ALLOC}, matchCount = {1}, failOn = LOAD + TRAP)

 206     public long test6() {
 207         MyValue1 v = MyValue1.createInline(rI, rL);
 208         // Pass to interpreter
 209         return v.hashInterpreted();
 210     }
 211 
 212     @DontCompile
 213     public void test6_verifier(boolean warmup) {
 214         long result = test6();
 215         Asserts.assertEQ(result, hash());
 216     }
 217 
 218     // Create a value type in compiled code and pass it to
 219     // the interpreter by returning.
 220     @Test(match = {ALLOC}, matchCount = {1}, failOn = LOAD + TRAP)
 221     public MyValue1 test7(int x, long y) {
 222         return MyValue1.createInline(x, y);
 223     }
 224 
 225     @DontCompile


 230 
 231     // Merge value types created from two branches
 232     @Test(failOn = ALLOC + STORE + TRAP)
 233     public long test8(boolean b) {
 234         MyValue1 v;
 235         if (b) {
 236             v = MyValue1.createInline(rI, rL);
 237         } else {
 238             v = MyValue1.createDontInline(rI + 1, rL + 1);
 239         }
 240         return v.hash();
 241     }
 242 
 243     @DontCompile
 244     public void test8_verifier(boolean warmup) {
 245         Asserts.assertEQ(test8(true), hash());
 246         Asserts.assertEQ(test8(false), hash(rI + 1, rL + 1));
 247     }
 248 
 249     // Merge value types created from two branches
 250     @Test(match = {ALLOC, STORE}, matchCount = {1, 9}, failOn = LOAD + TRAP)

 251     public MyValue1 test9(boolean b) {
 252         MyValue1 v;
 253         if (b) {
 254             // Value type is not allocated
 255             v = MyValue1.createInline(rI, rL);
 256         } else {
 257             // Value type is allocated by the callee
 258             v = MyValue1.createDontInline(rI + 1, rL + 1);
 259         }
 260         // Need to allocate value type if 'b' is true
 261         long sum = v.hashInterpreted();
 262         if (b) {
 263             v = MyValue1.createDontInline(rI, sum);
 264         } else {
 265             v = MyValue1.createDontInline(rI, sum + 1);
 266         }
 267         // Don't need to allocate value type because both branches allocate
 268         return v;
 269     }
 270 


 341         for (int i = 0; i < 1000; ++i) {
 342             if (b) {
 343                 result += v.x;
 344             } else {
 345                 // Uncommon trap referencing v. Should not allocate
 346                 // but just pass the existing oop to the uncommon trap.
 347                 result = v.hashInterpreted();
 348             }
 349         }
 350         return result;
 351     }
 352 
 353     @DontCompile
 354     public void test13_verifier(boolean warmup) {
 355         long result = test13(warmup);
 356         Asserts.assertEQ(result, warmup ? 42 + (1000*rI) : hash());
 357     }
 358 
 359     // Create a value type in a non-inlined method and then call a
 360     // non-inlined method on that value type.
 361     @Test(failOn = (ALLOC + LOAD + STORE + TRAP))

 362     public long test14() {
 363         MyValue1 v = MyValue1.createDontInline(rI, rL);
 364         return v.hashInterpreted();
 365     }
 366 
 367     @DontCompile
 368     public void test14_verifier(boolean b) {
 369         long result = test14();
 370         Asserts.assertEQ(result, hash());
 371     }
 372 
 373     // Create a value type in an inlined method and then call a
 374     // non-inlined method on that value type.
 375     @Test(failOn = (LOAD + TRAP), match = {ALLOC}, matchCount = {1})

 376     public long test15() {
 377         MyValue1 v = MyValue1.createInline(rI, rL);
 378         return v.hashInterpreted();
 379     }
 380 
 381     @DontCompile
 382     public void test15_verifier(boolean b) {
 383         long result = test15();
 384         Asserts.assertEQ(result, hash());
 385     }
 386 
 387     // Create a value type in a non-inlined method and then call an
 388     // inlined method on that value type.
 389     @Test(failOn = (ALLOC + STORE + TRAP))
 390     public long test16() {
 391         MyValue1 v = MyValue1.createDontInline(rI, rL);
 392         return v.hash();
 393     }
 394 
 395     @DontCompile


 398         Asserts.assertEQ(result, hash());
 399     }
 400 
 401     // Create a value type in an inlined method and then call an
 402     // inlined method on that value type.
 403     @Test(failOn = (ALLOC + LOAD + STORE + TRAP))
 404     public long test17() {
 405         MyValue1 v = MyValue1.createInline(rI, rL);
 406         return v.hash();
 407     }
 408 
 409     @DontCompile
 410     public void test17_verifier(boolean b) {
 411         long result = test17();
 412         Asserts.assertEQ(result, hash());
 413     }
 414 
 415     // Create a value type in compiled code and pass it to the
 416     // interpreter via a call. The value is live at the first call so
 417     // debug info should include a reference to all its fields.
 418     @Test(match = {ALLOC}, matchCount = {1}, failOn = LOAD + TRAP)

 419     public long test18() {
 420         MyValue1 v = MyValue1.createInline(rI, rL);
 421         v.hashInterpreted();
 422         return v.hashInterpreted();
 423     }
 424 
 425     @DontCompile
 426     public void test18_verifier(boolean warmup) {
 427         long result = test18();
 428         Asserts.assertEQ(result, hash());
 429     }
 430 
 431     // Create a value type in compiled code and pass it to the
 432     // interpreter via a call. The value type is passed twice but
 433     // should only be allocated once.
 434     @Test(match = {ALLOC}, matchCount = {1}, failOn = LOAD + TRAP)

 435     public long test19() {
 436         MyValue1 v = MyValue1.createInline(rI, rL);
 437         return sumValue(v, v);
 438     }
 439 
 440     @DontCompile
 441     public long sumValue(MyValue1 v, MyValue1 dummy) {
 442         return v.hash();
 443     }
 444 
 445     @DontCompile
 446     public void test19_verifier(boolean warmup) {
 447         long result = test19();
 448         Asserts.assertEQ(result, hash());
 449     }
 450 
 451     // Create a value type in compiled code and pass it to the
 452     // interpreter via a call. The value type is live at the uncommon
 453     // trap: verify that deoptimization causes the value type to be
 454     // correctly allocated.
 455     @Test(match = {ALLOC}, matchCount = {1}, failOn = LOAD)

 456     public long test20(boolean flag) {
 457         MyValue1 v = MyValue1.createInline(rI, rL);
 458         if (flag) {
 459             // uncommon trap
 460             WHITE_BOX.deoptimizeMethod(tests.get("ValueTypeTestBench::test16"));
 461         }
 462         return v.hashInterpreted();
 463     }
 464 
 465     @DontCompile
 466     public void test20_verifier(boolean warmup) {
 467         long result = test20(false);
 468         Asserts.assertEQ(result, hash());
 469         if (!warmup) {
 470             result = test20(true);
 471             Asserts.assertEQ(result, hash());
 472         }
 473     }
 474 
 475     // Value type fields in regular object
 476     MyValue1 val1;
 477     MyValue2 val2;
 478 
 479     // Test value type fields in objects
 480     @Test(failOn = (ALLOC + TRAP))


 483         long result = val1.hash() + val2.hash();
 484         // Update fields
 485         val1 = MyValue1.createInline(x, y);
 486         val2 = MyValue2.createInline(x, true);
 487         return result;
 488     }
 489 
 490     @DontCompile
 491     public void test21_verifier(boolean warmup) {
 492         // Check if hash computed by test18 is correct
 493         val1 = MyValue1.createInline(rI, rL);
 494         val2 = val1.v2;
 495         long hash = val1.hash() + val2.hash();
 496         long result = test21(rI + 1, rL + 1);
 497         Asserts.assertEQ(result, hash);
 498         // Check if value type fields were updated
 499         Asserts.assertEQ(val1.hash(), hash(rI + 1, rL + 1));
 500         Asserts.assertEQ(val2.hash(), MyValue2.createInline(rI + 1, true).hash());
 501     }
 502 











































































































































































































 503 
 504     // ========== Test infrastructure ==========
 505 
 506     private static final WhiteBox WHITE_BOX = WhiteBox.getWhiteBox();




 507     private static final int COMP_LEVEL_ANY = -1;
 508     private static final int COMP_LEVEL_FULL_OPTIMIZATION = 4;
 509     private static final Hashtable<String, Method> tests = new Hashtable<String, Method>();
 510     private static final int WARMUP = 10;
 511     private static boolean USE_COMPILER = WHITE_BOX.getBooleanVMFlag("UseCompiler");
 512     private static boolean PRINT_IDEAL  = WHITE_BOX.getBooleanVMFlag("PrintIdeal");
 513 
 514     // Regular expressions used  to match nodes in the PrintIdeal output
 515     private static final String START = "(\\d+\\t(.*";
 516     private static final String MID = ".*)+\\t===.*";
 517     private static final String END = ")|";
 518     private static final String ALLOC = START + "CallStaticJava" + MID + "_new_instance_Java" + END;
 519     private static final String LOAD  = START + "Load" + MID + "valuetype\\*" + END;
 520     private static final String STORE = START + "Store" + MID + "valuetype\\*" + END;
 521     private static final String LOOP  = START + "Loop" + MID + "" + END;
 522     private static final String TRAP  = START + "CallStaticJava" + MID + "uncommon_trap" + END;
 523     // TODO: match field values of scalar replaced object
 524     private static final String SCOBJ = "(.*# ScObj.*" + END;
 525 
 526     // Random test values
 527     public static final int  rI = Utils.getRandomInstance().nextInt() % 1000;
 528     public static final long rL = Utils.getRandomInstance().nextLong() % 1000;
 529 
 530     static {
 531         // Gather all test methods and put them in Hashtable
 532         for (Method m : ValueTypeTestBench.class.getDeclaredMethods()) {
 533             if (m.isAnnotationPresent(Test.class)) {

 534                 tests.put("ValueTypeTestBench::" + m.getName(), m);
 535             }
 536         }
 537     }
 538 
 539     public static void main(String[] args) throws Throwable {
 540         if (args.length == 0) {
 541             // Run tests in own process and verify output
 542             OutputAnalyzer oa = ProcessTools.executeTestJvm("-noverify",
 543                     "-XX:+UnlockDiagnosticVMOptions", "-Xbootclasspath/a:.", "-XX:+WhiteBoxAPI",
 544                     "-XX:-TieredCompilation", "-XX:-BackgroundCompilation", "-XX:-UseOnStackReplacement",
 545                     "-XX:+IgnoreUnrecognizedVMOptions", "-XX:+PrintCompilation", "-XX:+PrintIdeal", "-XX:+PrintOptoAssembly",
 546                     "-XX:CompileCommand=quiet", "-XX:CompileCommand=compileonly,compiler.valhalla.valuetypes.ValueTypeTestBench::*",
 547                     "-XX:CompileCommand=compileonly,compiler.valhalla.valuetypes.MyValue1::*",
 548                     "-XX:CompileCommand=compileonly,compiler.valhalla.valuetypes.MyValue2::*",
 549                     ValueTypeTestBench.class.getName(), "run");










 550             // If ideal graph printing is enabled/supported, verify output
 551             String output = oa.getOutput();
 552             oa.shouldHaveExitValue(0);
 553             if (output.contains("PrintIdeal enabled")) {
 554                 parseOutput(output);
 555             } else {
 556                 System.out.println("WARNING: test methods not compiled or PrintIdeal disabled! Running with -Xint or release build?");
 557             }
 558         } else {
 559             if (USE_COMPILER && PRINT_IDEAL) {
 560                 System.out.println("PrintIdeal enabled");
 561             }
 562             // Execute tests
 563             ValueTypeTestBench bench = new ValueTypeTestBench();
 564             bench.run();
 565         }
 566     }
 567 
 568     public static void parseOutput(String output) throws Exception {
 569         String split = "b        compiler.valhalla.valuetypes.";
 570         String[] compilations = output.split(split);
 571         // Print header
 572         System.out.println(compilations[0]);
 573         // Iterate over compilation output
 574         for (String graph : compilations) {
 575             String[] lines = graph.split("\\n");
 576             String testName = lines[0].split(" ")[0];
 577             Method test = tests.get(testName);
 578             if (test == null) {
 579                 // Skip helper methods
 580                 continue;
 581             }
 582             if (PRINT_GRAPH) {
 583                 System.out.println("\nGraph for " + graph);
 584             }
 585             // Parse graph using regular expressions to determine if it contains forbidden nodes
 586             Test anno = test.getAnnotation(Test.class);











 587             String regexFail = anno.failOn();
 588             if (!regexFail.isEmpty()) {
 589                 Pattern pattern = Pattern.compile(regexFail.substring(0, regexFail.length()-1));
 590                 Matcher matcher = pattern.matcher(graph);
 591                 boolean fail = false;
 592                 while (matcher.find()) {
 593                     System.out.println("Graph for '" + testName + "' contains forbidden node:");
 594                     System.out.println(matcher.group());
 595                     fail = true;
 596                 }
 597                 Asserts.assertFalse(fail, "Graph for '" + testName + "' contains forbidden nodes");
 598             }
 599             String[] regexMatch = anno.match();
 600             int[] matchCount = anno.matchCount();
 601             for (int i = 0; i < regexMatch.length; ++i) {
 602                 Pattern pattern = Pattern.compile(regexMatch[i].substring(0, regexMatch[i].length()-1));
 603                 Matcher matcher = pattern.matcher(graph);
 604                 int count = 0;
 605                 String nodes = "";
 606                 while (matcher.find()) {


 650         setup(MyValue2.class.getDeclaredMethods());
 651 
 652         // Execute tests
 653         for (Method test : tests.values()) {
 654             Method verifier = getClass().getDeclaredMethod(test.getName() + "_verifier", boolean.class);
 655             // Warmup using verifier method
 656             for (int i = 0; i < WARMUP; ++i) {
 657                 verifier.invoke(this, true);
 658             }
 659             // Trigger compilation
 660             WHITE_BOX.enqueueMethodForCompilation(test, COMP_LEVEL_FULL_OPTIMIZATION);
 661             Asserts.assertTrue(!USE_COMPILER || WHITE_BOX.isMethodCompiled(test, false), test + " not compiled");
 662             // Check result
 663             verifier.invoke(this, false);
 664         }
 665     }
 666 }
 667 
 668 // Mark method as test
 669 @Retention(RetentionPolicy.RUNTIME)

 670 @interface Test {
 671     // Regular expression used to match forbidden IR nodes
 672     // in the C2 IR emitted for this test.
 673     String failOn() default "";
 674     // Regular expressions used to match and count IR nodes.
 675     String[] match() default { };
 676     int[] matchCount() default { };






 677 }
 678 
 679 // Force method inlining during compilation
 680 @Retention(RetentionPolicy.RUNTIME)
 681 @interface ForceInline { }
 682 
 683 // Prevent method inlining during compilation
 684 @Retention(RetentionPolicy.RUNTIME)
 685 @interface DontInline { }
 686 
 687 // Prevent method compilation
 688 @Retention(RetentionPolicy.RUNTIME)
 689 @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  *                   compiler.valhalla.valuetypes.ValueTypeTestBench
  34  * @run main/othervm -ea -noverify -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI
  35  *                   -XX:+UnlockExperimentalVMOptions -XX:-ValueTypePassFieldsAsArgs
  36  *                   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     final int x;
  64     final long y;
  65     final MyValue2 v1;
  66     final MyValue2 v2;
  67     final int c;
  68 
  69     private MyValue1(int x, long y, MyValue2 v1, MyValue2 v2, int c) {
  70         this.x = x;
  71         this.y = y;
  72         this.v1 = v1;
  73         this.v2 = v2;
  74         this.c = c;
  75     }
  76 
  77     @DontInline
  78     public static MyValue1 createDontInline(int x, long y) {
  79         return __Make MyValue1(x, y, MyValue2.createInline(x, x < y), MyValue2.createInline(x, x > y), ValueTypeTestBench.rI);
  80     }
  81 
  82     @ForceInline
  83     public static MyValue1 createInline(int x, long y) {
  84         return __Make MyValue1(x, y, MyValue2.createInline(x, x < y), MyValue2.createInline(x, x > y), ValueTypeTestBench.rI);
  85     }
  86 
  87     @ForceInline
  88     public long hash() {
  89         return x + y + c + v1.hash() + v2.hash();
  90     }
  91 
  92     @DontCompile
  93     public long hashInterpreted() {
  94         return x + y + c + v1.hashInterpreted() + v2.hashInterpreted();
  95     }
  96 }
  97 
  98 __ByValue final class MyValue2 {
  99     final int x;
 100     final boolean b;
 101     final long c;
 102 
 103     private MyValue2(int x, boolean b, long c) {
 104         this.x = x;
 105         this.b = b;
 106         this.c = c;
 107     }
 108 
 109     @ForceInline
 110     public static MyValue2 createInline(int x, boolean b) {
 111         return __Make MyValue2(x, b, ValueTypeTestBench.rL);
 112     }
 113 
 114     @ForceInline
 115     public long hash() {
 116         return x + (b ? 0 : 1) + c;
 117     }
 118 
 119     @DontInline
 120     public long hashInterpreted() {
 121         return x + (b ? 0 : 1) + c;
 122     }
 123 }
 124 
 125 public class ValueTypeTestBench {
 126     // Print ideal graph after execution of each test
 127     private static final boolean PRINT_GRAPH = true;
 128 
 129     // ========== Helper methods ==========
 130 
 131     public long hash() {
 132         return hash(rI, rL);
 133     }
 134 
 135     public long hash(int x, long y) {
 136         return MyValue1.createInline(x, y).hash();
 137     }
 138 
 139     // ========== Test definitions ==========
 140 
 141     // Receive value type through call to interpreter
 142     @Test(failOn = ALLOC + STORE + TRAP)


 148     @DontCompile
 149     public void test1_verifier(boolean warmup) {
 150         long result = test1();
 151         Asserts.assertEQ(result, hash());
 152     }
 153 
 154     // Receive value type from interpreter via parameter
 155     @Test(failOn = ALLOC + STORE + TRAP)
 156     public long test2(MyValue1 v) {
 157         return v.hash();
 158     }
 159 
 160     @DontCompile
 161     public void test2_verifier(boolean warmup) {
 162         MyValue1 v = MyValue1.createDontInline(rI, rL);
 163         long result = test2(v);
 164         Asserts.assertEQ(result, hash());
 165     }
 166 
 167     // Return incoming value type without accessing fields
 168     @Test(valid = ValueTypePassFieldsAsArgsOn, match = {ALLOC, STORE}, matchCount = {1, 9}, failOn = LOAD + TRAP)
 169     @Test(valid = ValueTypePassFieldsAsArgsOff, 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(valid = ValueTypePassFieldsAsArgsOn, failOn = LOAD + TRAP + ALLOC)
 218     @Test(valid = ValueTypePassFieldsAsArgsOff, match = {ALLOC}, matchCount = {1}, failOn = LOAD + TRAP)
 219     public long test6() {
 220         MyValue1 v = MyValue1.createInline(rI, rL);
 221         // Pass to interpreter
 222         return v.hashInterpreted();
 223     }
 224 
 225     @DontCompile
 226     public void test6_verifier(boolean warmup) {
 227         long result = test6();
 228         Asserts.assertEQ(result, hash());
 229     }
 230 
 231     // Create a value type in compiled code and pass it to
 232     // the interpreter by returning.
 233     @Test(match = {ALLOC}, matchCount = {1}, failOn = LOAD + TRAP)
 234     public MyValue1 test7(int x, long y) {
 235         return MyValue1.createInline(x, y);
 236     }
 237 
 238     @DontCompile


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


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


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


 502         long result = val1.hash() + val2.hash();
 503         // Update fields
 504         val1 = MyValue1.createInline(x, y);
 505         val2 = MyValue2.createInline(x, true);
 506         return result;
 507     }
 508 
 509     @DontCompile
 510     public void test21_verifier(boolean warmup) {
 511         // Check if hash computed by test18 is correct
 512         val1 = MyValue1.createInline(rI, rL);
 513         val2 = val1.v2;
 514         long hash = val1.hash() + val2.hash();
 515         long result = test21(rI + 1, rL + 1);
 516         Asserts.assertEQ(result, hash);
 517         // Check if value type fields were updated
 518         Asserts.assertEQ(val1.hash(), hash(rI + 1, rL + 1));
 519         Asserts.assertEQ(val2.hash(), MyValue2.createInline(rI + 1, true).hash());
 520     }
 521 
 522     // Test interpreter to compiled code with various signatures
 523     @Test(failOn = ALLOC + STORE + TRAP)
 524     public long test22(MyValue2 v) {
 525         return v.hash();
 526     }
 527 
 528     @DontCompile
 529     public void test22_verifier(boolean warmup) {
 530         MyValue2 v = MyValue2.createInline(rI, true);
 531         long result = test22(v);
 532         Asserts.assertEQ(result, v.hashInterpreted());
 533     }
 534 
 535     @Test(failOn = ALLOC + STORE + TRAP)
 536     public long test23(int i1, MyValue2 v, int i2) {
 537         return v.hash() + i1 - i2;
 538     }
 539 
 540     @DontCompile
 541     public void test23_verifier(boolean warmup) {
 542         MyValue2 v = MyValue2.createInline(rI, true);
 543         long result = test23(rI, v, 2*rI);
 544         Asserts.assertEQ(result, v.hashInterpreted() - rI);
 545     }
 546 
 547     @Test(failOn = ALLOC + STORE + TRAP)
 548     public long test24(long l1, MyValue2 v, long l2) {
 549         return v.hash() + l1 - l2;
 550     }
 551 
 552     @DontCompile
 553     public void test24_verifier(boolean warmup) {
 554         MyValue2 v = MyValue2.createInline(rI, true);
 555         long result = test24(rL, v, 2*rL);
 556         Asserts.assertEQ(result, v.hashInterpreted() - rL);
 557     }
 558 
 559     @Test(failOn = ALLOC + STORE + TRAP)
 560     public long test25(int i, MyValue2 v, long l) {
 561         return v.hash() + i + l;
 562     }
 563 
 564     @DontCompile
 565     public void test25_verifier(boolean warmup) {
 566         MyValue2 v = MyValue2.createInline(rI, true);
 567         long result = test25(rI, v, rL);
 568         Asserts.assertEQ(result, v.hashInterpreted() + rL + rI);
 569     }
 570 
 571     @Test(failOn = ALLOC + STORE + TRAP)
 572     public long test26(long l, MyValue2 v, int i) {
 573         return v.hash() + i + l;
 574     }
 575 
 576     @DontCompile
 577     public void test26_verifier(boolean warmup) {
 578         MyValue2 v = MyValue2.createInline(rI, true);
 579         long result = test26(rL, v, rI);
 580         Asserts.assertEQ(result, v.hashInterpreted() + rL + rI);
 581     }
 582 
 583     @Test(failOn = ALLOC + STORE + TRAP)
 584     public long test27(long l, MyValue1 v1, int i, MyValue2 v2) {
 585         return v1.hash() + i + l + v2.hash();
 586     }
 587 
 588     @DontCompile
 589     public void test27_verifier(boolean warmup) {
 590         MyValue1 v1 = MyValue1.createDontInline(rI, rL);
 591         MyValue2 v2 = MyValue2.createInline(rI, true);
 592         long result = test27(rL, v1, rI, v2);
 593         Asserts.assertEQ(result, v1.hashInterpreted() + rL + rI + v2.hashInterpreted());
 594     }
 595 
 596     // Test compiled code to interpreter with various signatures
 597     @DontCompile
 598     public long test28_interp(MyValue2 v) {
 599         return v.hash();
 600     }
 601 
 602     @Test(failOn = ALLOC + STORE + TRAP)
 603     public long test28(MyValue2 v) {
 604         return test28_interp(v);
 605     }
 606 
 607     @DontCompile
 608     public void test28_verifier(boolean warmup) {
 609         MyValue2 v = MyValue2.createInline(rI, true);
 610         long result = test28(v);
 611         Asserts.assertEQ(result, v.hashInterpreted());
 612     }
 613 
 614     @DontCompile
 615     public long test29_interp(int i1, MyValue2 v, int i2) {
 616         return v.hash() + i1 - i2;
 617     }
 618 
 619     @Test(failOn = ALLOC + STORE + TRAP)
 620     public long test29(int i1, MyValue2 v, int i2) {
 621         return test29_interp(i1, v, i2);
 622     }
 623 
 624     @DontCompile
 625     public void test29_verifier(boolean warmup) {
 626         MyValue2 v = MyValue2.createInline(rI, true);
 627         long result = test29(rI, v, 2*rI);
 628         Asserts.assertEQ(result, v.hashInterpreted() - rI);
 629     }
 630 
 631     @DontCompile
 632     public long test30_interp(long l1, MyValue2 v, long l2) {
 633         return v.hash() + l1 - l2;
 634     }
 635 
 636     @Test(failOn = ALLOC + STORE + TRAP)
 637     public long test30(long l1, MyValue2 v, long l2) {
 638         return test30_interp(l1, v, l2);
 639     }
 640 
 641     @DontCompile
 642     public void test30_verifier(boolean warmup) {
 643         MyValue2 v = MyValue2.createInline(rI, true);
 644         long result = test30(rL, v, 2*rL);
 645         Asserts.assertEQ(result, v.hashInterpreted() - rL);
 646     }
 647 
 648     @DontCompile
 649     public long test31_interp(int i, MyValue2 v, long l) {
 650         return v.hash() + i + l;
 651     }
 652 
 653     @Test(failOn = ALLOC + STORE + TRAP)
 654     public long test31(int i, MyValue2 v, long l) {
 655         return test31_interp(i, v, l);
 656     }
 657 
 658     @DontCompile
 659     public void test31_verifier(boolean warmup) {
 660         MyValue2 v = MyValue2.createInline(rI, true);
 661         long result = test31(rI, v, rL);
 662         Asserts.assertEQ(result, v.hashInterpreted() + rL + rI);
 663     }
 664 
 665     @DontCompile
 666     public long test32_interp(long l, MyValue2 v, int i) {
 667         return v.hash() + i + l;
 668     }
 669 
 670     @Test(failOn = ALLOC + STORE + TRAP)
 671     public long test32(long l, MyValue2 v, int i) {
 672         return test32_interp(l, v, i);
 673     }
 674 
 675     @DontCompile
 676     public void test32_verifier(boolean warmup) {
 677         MyValue2 v = MyValue2.createInline(rI, true);
 678         long result = test32(rL, v, rI);
 679         Asserts.assertEQ(result, v.hashInterpreted() + rL + rI);
 680     }
 681 
 682     @DontCompile
 683     public long test33_interp(long l, MyValue1 v1, int i, MyValue2 v2) {
 684         return v1.hash() + i + l + v2.hash();
 685     }
 686 
 687     @Test(failOn = ALLOC + STORE + TRAP)
 688     public long test33(long l, MyValue1 v1, int i, MyValue2 v2) {
 689         return test33_interp(l, v1, i, v2);
 690     }
 691 
 692     @DontCompile
 693     public void test33_verifier(boolean warmup) {
 694         MyValue1 v1 = MyValue1.createDontInline(rI, rL);
 695         MyValue2 v2 = MyValue2.createInline(rI, true);
 696         long result = test33(rL, v1, rI, v2);
 697         Asserts.assertEQ(result, v1.hashInterpreted() + rL + rI + v2.hashInterpreted());
 698     }
 699 
 700     // test that debug info at a call is correct
 701     @DontCompile
 702     public long test34_interp(MyValue2 v, boolean flag) {
 703         if (flag) {
 704             // uncommon trap
 705             WHITE_BOX.deoptimizeMethod(tests.get("ValueTypeTestBench::test34"));
 706         }
 707         return v.hash();
 708     }
 709 
 710     @Test(failOn = ALLOC + STORE + TRAP)
 711     public long test34(MyValue2 v, boolean flag, long l) {
 712         return test34_interp(v, flag) + l;
 713     }
 714 
 715     @DontCompile
 716     public void test34_verifier(boolean warmup) {
 717         MyValue2 v = MyValue2.createInline(rI, true);
 718         long result = test34(v, false, rL);
 719         Asserts.assertEQ(result, v.hashInterpreted() + rL);
 720         if (!warmup) {
 721             result = test34(v, true, rL);
 722             Asserts.assertEQ(result, v.hashInterpreted() + rL);
 723         }
 724     }
 725 
 726     // ========== Test infrastructure ==========
 727 
 728     private static final WhiteBox WHITE_BOX = WhiteBox.getWhiteBox();
 729     private static final int ValueTypePassFieldsAsArgsOn = 0x1;
 730     private static final int ValueTypePassFieldsAsArgsOff = 0x2;
 731     static final int AllFlags = ValueTypePassFieldsAsArgsOn | ValueTypePassFieldsAsArgsOff;
 732     private static final boolean ValueTypePassFieldsAsArgs = (Boolean)WHITE_BOX.getVMFlag("ValueTypePassFieldsAsArgs");
 733     private static final int COMP_LEVEL_ANY = -1;
 734     private static final int COMP_LEVEL_FULL_OPTIMIZATION = 4;
 735     private static final Hashtable<String, Method> tests = new Hashtable<String, Method>();
 736     private static final int WARMUP = 10;
 737     private static boolean USE_COMPILER = WHITE_BOX.getBooleanVMFlag("UseCompiler");
 738     private static boolean PRINT_IDEAL  = WHITE_BOX.getBooleanVMFlag("PrintIdeal");
 739 
 740     // Regular expressions used  to match nodes in the PrintIdeal output
 741     private static final String START = "(\\d+\\t(.*";
 742     private static final String MID = ".*)+\\t===.*";
 743     private static final String END = ")|";
 744     private static final String ALLOC = START + "CallStaticJava" + MID + "_new_instance_Java" + END;
 745     private static final String LOAD  = START + "Load" + MID + "valuetype\\*" + END;
 746     private static final String STORE = START + "Store" + MID + "valuetype\\*" + END;
 747     private static final String LOOP  = START + "Loop" + MID + "" + END;
 748     private static final String TRAP  = START + "CallStaticJava" + MID + "uncommon_trap" + END;
 749     // TODO: match field values of scalar replaced object
 750     private static final String SCOBJ = "(.*# ScObj.*" + END;
 751 
 752     // Random test values
 753     public static final int  rI = Utils.getRandomInstance().nextInt() % 1000;
 754     public static final long rL = Utils.getRandomInstance().nextLong() % 1000;
 755 
 756     static {
 757         // Gather all test methods and put them in Hashtable
 758         for (Method m : ValueTypeTestBench.class.getDeclaredMethods()) {
 759             Test[] annos = m.getAnnotationsByType(Test.class);
 760             if (annos.length != 0) {
 761                 tests.put("ValueTypeTestBench::" + m.getName(), m);
 762             }
 763         }
 764     }
 765 
 766     public static void main(String[] args) throws Throwable {
 767         if (args.length == 0) {
 768             ArrayList<String> all_args = new ArrayList(List.of(
 769                 "-noverify",
 770                 "-XX:+UnlockDiagnosticVMOptions", "-Xbootclasspath/a:.", "-XX:+WhiteBoxAPI",
 771                 "-XX:-TieredCompilation", "-XX:-BackgroundCompilation", "-XX:-UseOnStackReplacement",
 772                 "-XX:+IgnoreUnrecognizedVMOptions", "-XX:+PrintCompilation", "-XX:+PrintIdeal", "-XX:+PrintOptoAssembly",
 773                 "-XX:CompileCommand=quiet", "-XX:CompileCommand=compileonly,compiler.valhalla.valuetypes.ValueTypeTestBench::*",
 774                 "-XX:CompileCommand=compileonly,compiler.valhalla.valuetypes.MyValue1::*",
 775                 "-XX:CompileCommand=compileonly,compiler.valhalla.valuetypes.MyValue2::*"
 776                                                                ));
 777             // Run tests in own process and verify output
 778             all_args.add("-XX:+UnlockExperimentalVMOptions");
 779             if ((Boolean)WHITE_BOX.getVMFlag("ValueTypePassFieldsAsArgs")) {
 780                 all_args.add("-XX:+ValueTypePassFieldsAsArgs");
 781             } else {
 782                 all_args.add("-XX:-ValueTypePassFieldsAsArgs");
 783             }
 784             all_args.add(ValueTypeTestBench.class.getName());
 785             all_args.add("run");
 786             OutputAnalyzer oa = ProcessTools.executeTestJvm(all_args.toArray(new String[0]));
 787             // If ideal graph printing is enabled/supported, verify output
 788             String output = oa.getOutput();
 789             oa.shouldHaveExitValue(0);
 790             if (output.contains("PrintIdeal enabled")) {
 791                 parseOutput(output);
 792             } else {
 793                 System.out.println("WARNING: test methods not compiled or PrintIdeal disabled! Running with -Xint or release build?");
 794             }
 795         } else {
 796             if (USE_COMPILER && PRINT_IDEAL) {
 797                 System.out.println("PrintIdeal enabled");
 798             }
 799             // Execute tests
 800             ValueTypeTestBench bench = new ValueTypeTestBench();
 801             bench.run();
 802         }
 803     }
 804 
 805     public static void parseOutput(String output) throws Exception {
 806         String split = "b        compiler.valhalla.valuetypes.";
 807         String[] compilations = output.split(split);
 808         // Print header
 809         System.out.println(compilations[0]);
 810         // Iterate over compilation output
 811         for (String graph : compilations) {
 812             String[] lines = graph.split("\\n");
 813             String testName = lines[0].split(" ")[0];
 814             Method test = tests.get(testName);
 815             if (test == null) {
 816                 // Skip helper methods
 817                 continue;
 818             }
 819             if (PRINT_GRAPH) {
 820                 System.out.println("\nGraph for " + graph);
 821             }
 822             // Parse graph using regular expressions to determine if it contains forbidden nodes
 823             Test[] annos = test.getAnnotationsByType(Test.class);
 824             Test anno = null;
 825             for (Test a : annos) {
 826                 if ((a.valid() & ValueTypePassFieldsAsArgsOn) != 0 && ValueTypePassFieldsAsArgs) {
 827                     assert anno == null;
 828                     anno = a;
 829                 } else if ((a.valid() & ValueTypePassFieldsAsArgsOff) != 0 && !ValueTypePassFieldsAsArgs) {
 830                     assert anno == null;
 831                     anno = a;
 832                 }
 833             }
 834             assert anno != null;
 835             String regexFail = anno.failOn();
 836             if (!regexFail.isEmpty()) {
 837                 Pattern pattern = Pattern.compile(regexFail.substring(0, regexFail.length()-1));
 838                 Matcher matcher = pattern.matcher(graph);
 839                 boolean fail = false;
 840                 while (matcher.find()) {
 841                     System.out.println("Graph for '" + testName + "' contains forbidden node:");
 842                     System.out.println(matcher.group());
 843                     fail = true;
 844                 }
 845                 Asserts.assertFalse(fail, "Graph for '" + testName + "' contains forbidden nodes");
 846             }
 847             String[] regexMatch = anno.match();
 848             int[] matchCount = anno.matchCount();
 849             for (int i = 0; i < regexMatch.length; ++i) {
 850                 Pattern pattern = Pattern.compile(regexMatch[i].substring(0, regexMatch[i].length()-1));
 851                 Matcher matcher = pattern.matcher(graph);
 852                 int count = 0;
 853                 String nodes = "";
 854                 while (matcher.find()) {


 898         setup(MyValue2.class.getDeclaredMethods());
 899 
 900         // Execute tests
 901         for (Method test : tests.values()) {
 902             Method verifier = getClass().getDeclaredMethod(test.getName() + "_verifier", boolean.class);
 903             // Warmup using verifier method
 904             for (int i = 0; i < WARMUP; ++i) {
 905                 verifier.invoke(this, true);
 906             }
 907             // Trigger compilation
 908             WHITE_BOX.enqueueMethodForCompilation(test, COMP_LEVEL_FULL_OPTIMIZATION);
 909             Asserts.assertTrue(!USE_COMPILER || WHITE_BOX.isMethodCompiled(test, false), test + " not compiled");
 910             // Check result
 911             verifier.invoke(this, false);
 912         }
 913     }
 914 }
 915 
 916 // Mark method as test
 917 @Retention(RetentionPolicy.RUNTIME)
 918 @Repeatable(Tests.class)
 919 @interface Test {
 920     // Regular expression used to match forbidden IR nodes
 921     // in the C2 IR emitted for this test.
 922     String failOn() default "";
 923     // Regular expressions used to match and count IR nodes.
 924     String[] match() default { };
 925     int[] matchCount() default { };
 926     int valid() default ValueTypeTestBench.AllFlags;
 927 }
 928 
 929 @Retention(RetentionPolicy.RUNTIME)
 930 @interface Tests {
 931     Test[] value();
 932 }
 933 
 934 // Force method inlining during compilation
 935 @Retention(RetentionPolicy.RUNTIME)
 936 @interface ForceInline { }
 937 
 938 // Prevent method inlining during compilation
 939 @Retention(RetentionPolicy.RUNTIME)
 940 @interface DontInline { }
 941 
 942 // Prevent method compilation
 943 @Retention(RetentionPolicy.RUNTIME)
 944 @interface DontCompile { }
< prev index next >