< prev index next >

test/compiler/valhalla/valuetypes/ValueTypeTestBench.java

Print this page

        

@@ -28,14 +28,14 @@
  * @library /testlibrary /test/lib /compiler/whitebox /
  * @build compiler.valhalla.valuetypes.ValueTypeTestBench
  * @run main ClassFileInstaller sun.hotspot.WhiteBox
  * @run main ClassFileInstaller jdk.test.lib.Platform
  * @run main/othervm -ea -noverify -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI
- *                   -XX:+UnlockExperimentalVMOptions -XX:+ValueTypePassFieldsAsArgs
+ *                   -XX:+UnlockExperimentalVMOptions -XX:+ValueTypePassFieldsAsArgs -XX:+ValueArrayFlatten
  *                   -XX:-TieredCompilation compiler.valhalla.valuetypes.ValueTypeTestBench
  * @run main/othervm -ea -noverify -Xbootclasspath/a:. -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI
- *                   -XX:+UnlockExperimentalVMOptions -XX:-ValueTypePassFieldsAsArgs
+ *                   -XX:+UnlockExperimentalVMOptions -XX:-ValueTypePassFieldsAsArgs -XX:-ValueArrayFlatten
  *                   -XX:-TieredCompilation compiler.valhalla.valuetypes.ValueTypeTestBench
  */
 
 package compiler.valhalla.valuetypes;
 

@@ -98,10 +98,21 @@
 
     @DontCompile
     public long hashInterpreted() {
         return s + sf + x + y + c + v1.hashInterpreted() + v2.hashInterpreted() + v3.hashInterpreted();
     }
+
+    @ForceInline
+    public void print() {
+        System.out.print("s=" + s + ", sf=" + sf + ", x=" + x + ", y=" + y + ", v1[");
+        v1.print();
+        System.out.print("], v2[");
+        v2.print();
+        System.out.print("], v3[");
+        v3.print();
+        System.out.print("], c=" + c);
+    }
 }
 
 __ByValue final class MyValue2 {
     final int x;
     final boolean b;

@@ -125,10 +136,15 @@
 
     @DontInline
     public long hashInterpreted() {
         return x + (b ? 0 : 1) + c;
     }
+
+    @ForceInline
+    public void print() {
+        System.out.print("x=" + x + ", b=" + b + ", c=" + c);
+    }
 }
 
 public class ValueTypeTestBench {    
     // Print ideal graph after execution of each test
     private static final boolean PRINT_GRAPH = true;

@@ -281,11 +297,13 @@
         Asserts.assertEQ(test8(true), hash());
         Asserts.assertEQ(test8(false), hash(rI + 1, rL + 1));
     }
 
     // Merge value types created from two branches
-    @Test(valid = ValueTypePassFieldsAsArgsOn, match = {LOAD}, matchCount = {9}, failOn = TRAP + ALLOC + STORE)
+    @Test(valid = ValueTypePassFieldsAsArgsOn, match = {LOAD}, matchCount = {7}, failOn = TRAP + ALLOC + STORE)
+    // FIXME
+    //@Test(valid = ValueTypePassFieldsAsArgsOff, match = {ALLOC, STORE}, matchCount = {1, 9}, failOn = LOAD + TRAP)
     @Test(valid = ValueTypePassFieldsAsArgsOff, match = {ALLOC, STORE}, matchCount = {1, 3}, failOn = LOAD + TRAP)
     public MyValue1 test9(boolean b) {
         MyValue1 v;
         if (b) {
             // Value type is not allocated

@@ -393,11 +411,11 @@
         Asserts.assertEQ(result, warmup ? 42 + (1000*rI) : hash());
     }
 
     // Create a value type in a non-inlined method and then call a
     // non-inlined method on that value type.
-    @Test(valid = ValueTypePassFieldsAsArgsOn, failOn = (ALLOC + STORE + TRAP), match = {LOAD}, matchCount = {9})
+    @Test(valid = ValueTypePassFieldsAsArgsOn, failOn = (ALLOC + STORE + TRAP), match = {LOAD}, matchCount = {7})
     @Test(valid = ValueTypePassFieldsAsArgsOff, failOn = (ALLOC + LOAD + STORE + TRAP))
     public long test14() {
         MyValue1 v = MyValue1.createDontInline(rI, rL);
         return v.hashInterpreted();
     }

@@ -487,32 +505,35 @@
     public void test19_verifier(boolean warmup) {
         long result = test19();
         Asserts.assertEQ(result, hash());
     }
 
-    // Create a value type in compiled code and pass it to the
+    // Create a value type (array) in compiled code and pass it to the
     // interpreter via a call. The value type is live at the uncommon
     // trap: verify that deoptimization causes the value type to be
     // correctly allocated.
     @Test(valid = ValueTypePassFieldsAsArgsOn, failOn = LOAD + ALLOC + STORE)
     @Test(valid = ValueTypePassFieldsAsArgsOff, match = {ALLOC}, matchCount = {1}, failOn = LOAD)
     public long test20(boolean flag) {
         MyValue1 v = MyValue1.createInline(rI, rL);
+        // TODO add value type array testcase
+        // MyValue1[] va = new MyValue1[42];
         if (flag) {
             // uncommon trap
             WHITE_BOX.deoptimizeMethod(tests.get("ValueTypeTestBench::test20"));
         }
-        return v.hashInterpreted();
+        return v.hashInterpreted(); // + va[0].hashInterpreted();
     }
 
     @DontCompile
     public void test20_verifier(boolean warmup) {
+        MyValue1[] va = new MyValue1[42];
         long result = test20(false);
-        Asserts.assertEQ(result, hash());
+        Asserts.assertEQ(result, hash() /* + va[0].hash() */);
         if (!warmup) {
             result = test20(true);
-            Asserts.assertEQ(result, hash());
+            Asserts.assertEQ(result, hash() /* + va[0].hash() */);
         }
     }
 
     // Value type fields in regular object
     MyValue1 val1;

@@ -565,23 +586,26 @@
 
     // Test OSR compilation
     @Test(failOn = ALLOC + LOAD + STORE + LOOP + TRAP)
     public long test23() {
         MyValue1 v = MyValue1.createInline(rI, rL);
+        // TODO add OSR testcase for value type arrays
+        //MyValue1[] va = new MyValue1[10];
         long result = 0;
         // Long loop to trigger OSR compilation
         for (int i = 0 ; i < 100_000 ; ++i) {
             // Reference local value type in interpreter state
-            result = v.hash();
+            result = v.hash(); // + va[0].hash();
         }
         return result;
     }
 
     @DontCompile
     public void test23_verifier(boolean warmup) {
+        //MyValue1[] va = new MyValue1[10];
         long result = test23();
-        Asserts.assertEQ(result, hash());
+        Asserts.assertEQ(result, hash() /* + va[0].hash() */);
     }
 
     // Test interpreter to compiled code with various signatures
     @Test(failOn = ALLOC + STORE + TRAP)
     public long test24(MyValue2 v) {

@@ -816,11 +840,10 @@
                                                     lreturn();
                                             }
                                             );  
     }
 
-
     @Test
     public int test38() throws Throwable {
         return (int)vccUnboxLoadIntMH.invokeExact(vcc);
     }
 

@@ -910,19 +933,186 @@
                                                     vbox(ValueCapableClass1.class).
                                                     getfield(ValueCapableClass1.class, "x", "I").
                                                     ireturn();
                                             }
                                             );
+
+    }
+
+    // Test value type array creation and initialization
+    @Test(valid = ValueTypeArrayFlattenOff, failOn = (LOAD))
+    @Test(valid = ValueTypeArrayFlattenOn)
+    public MyValue1[] test41(int len) {
+        MyValue1[] va = new MyValue1[len];
+        for (int i = 0; i < len; ++i) {
+            va[i] = MyValue1.createDontInline(rI, rL);
+        }
+        return va;
+    }
+
+    @DontCompile
+    public void test41_verifier(boolean warmup) {
+        int len = Math.abs(rI % 10);
+        MyValue1[] va = test41(len);
+        for (int i = 0; i < len; ++i) {
+            Asserts.assertEQ(va[i].hash(), hash());
+        }
+    }
+
+    // Test creation of a value type array and element access
+    @Test(failOn = (LOOP + LOAD + TRAP))
+    public long test42() {
+        MyValue1[] va = new MyValue1[1];
+        va[0] = MyValue1.createInline(rI, rL);
+        return va[0].hash();
+    }
+
+    @DontCompile
+    public void test42_verifier(boolean warmup) {
+        long result = test42();
+        Asserts.assertEQ(result, hash());
+    }
+
+    // Test receiving a value type array from the interpreter,
+    // updating its elements in a loop and computing a hash.
+    @Test(failOn = (ALLOCA))
+    public long test43(MyValue1[] va) {
+        long result = 0;
+        for (int i = 0; i < 10; ++i) {
+            result += va[i].hash();
+            va[i] = MyValue1.createInline(rI + 1, rL + 1);
+        }
+        return result;
+    }
+
+    @DontCompile
+    public void test43_verifier(boolean warmup) {
+        MyValue1[] va = new MyValue1[10];
+        long expected = 0;
+        for (int i = 0; i < 10; ++i) {
+            va[i] = MyValue1.createDontInline(rI + i, rL + i);
+            expected += va[i].hash();
+        }
+        long result = test43(va);
+        Asserts.assertEQ(expected, result);
+        for (int i = 0; i < 10; ++i) {
+            if (va[i].hash() != hash(rI + 1, rL + 1)) {
+                Asserts.assertEQ(va[i].hash(), hash(rI + 1, rL + 1));
+            }
+        }
+    }
+
+    // Test returning a value type array received from the interpreter
+    @Test(failOn = ALLOC + ALLOCA + LOAD + LOADP + STORE + LOOP + TRAP)
+    public MyValue1[] test44(MyValue1[] va) {
+        return va;
+    }
+
+    @DontCompile
+    public void test44_verifier(boolean warmup) {
+        MyValue1[] va = new MyValue1[10];
+        for (int i = 0; i < 10; ++i) {
+            va[i] = MyValue1.createDontInline(rI + i, rL + i);
+        }
+        va = test44(va);
+        for (int i = 0; i < 10; ++i) {
+            Asserts.assertEQ(va[i].hash(), hash(rI + i, rL + i));
+        }
+    }
+
+    // TODO add match rules
+    @Test()
+    public MyValue1[] test45(boolean b) {
+        MyValue1[] va;
+        if (b) {
+            va = new MyValue1[5];
+            for (int i = 0; i < 5; ++i) {
+                va[i] = MyValue1.createInline(rI, rL);
+            }
+        } else {
+            va = new MyValue1[10];
+            for (int i = 0; i < 10; ++i) {
+                va[i] = MyValue1.createInline(rI + i, rL + i);
+            }
+        }
+        long sum = va[0].hashInterpreted();
+        if (b) {
+            va[0] = MyValue1.createDontInline(rI, sum);
+        } else {
+            va[0] = MyValue1.createDontInline(rI + 1, sum + 1);
+        }
+        return va;
+    }
+
+    @DontCompile
+    public void test45_verifier(boolean warmup) {
+        MyValue1[] va = test45(true);
+        Asserts.assertEQ(va.length, 5);
+        Asserts.assertEQ(va[0].hash(), hash(rI, hash()));
+        for (int i = 1; i < 5; ++i) {
+            Asserts.assertEQ(va[i].hash(), hash());
+        }
+        va = test45(false);
+        Asserts.assertEQ(va.length, 10);
+        Asserts.assertEQ(va[0].hash(), hash(rI + 1, hash(rI, rL) + 1));
+        for (int i = 1; i < 10; ++i) {
+            Asserts.assertEQ(va[i].hash(), hash(rI + i, rL + i));
+        }
+    }
+
+    // Test creation of value type array with single element
+    @Test(failOn = LOOP + TRAP)
+    public MyValue1 test46() {
+        MyValue1[] va = new MyValue1[1];
+        return va[0];
+    }
+
+    @DontCompile
+    public void test46_verifier(boolean warmup) {
+        MyValue1[] va = new MyValue1[1];
+        MyValue1 v = test46();
+        Asserts.assertEQ(v.hash(), va[0].hash());
+    }
+
+    // Test default initialization of value type arrays
+    @Test(failOn = LOAD)
+    public MyValue1[] test47(int len) {
+        return new MyValue1[len];
+    }
+
+    @DontCompile
+    public void test47_verifier(boolean warmup) {
+        int len = Math.abs(rI % 10);
+        MyValue1[] va = new MyValue1[len];
+        MyValue1[] var = test47(len);
+        for (int i = 0; i < len; ++i) {
+            Asserts.assertEQ(va[i].hash(), var[i].hash());
+        }
+    }
+
+    // Test creation of value type array with zero length
+    @Test(failOn = ALLOC + LOAD + STORE + LOOP + TRAP)
+    public MyValue1[] test48() {
+        return new MyValue1[0];
+    }
+
+    @DontCompile
+    public void test48_verifier(boolean warmup) {
+        MyValue1[] va = test48();
+        Asserts.assertEQ(va.length, 0);
     }
 
     // ========== Test infrastructure ==========
 
     private static final WhiteBox WHITE_BOX = WhiteBox.getWhiteBox();
     private static final int ValueTypePassFieldsAsArgsOn = 0x1;
     private static final int ValueTypePassFieldsAsArgsOff = 0x2;
-    static final int AllFlags = ValueTypePassFieldsAsArgsOn | ValueTypePassFieldsAsArgsOff;
+    private static final int ValueTypeArrayFlattenOn = 0x4;
+    private static final int ValueTypeArrayFlattenOff = 0x8;
+    static final int AllFlags = ValueTypePassFieldsAsArgsOn | ValueTypePassFieldsAsArgsOff | ValueTypeArrayFlattenOn | ValueTypeArrayFlattenOff;
     private static final boolean ValueTypePassFieldsAsArgs = (Boolean)WHITE_BOX.getVMFlag("ValueTypePassFieldsAsArgs");
+    private static final boolean ValueTypeArrayFlatten = (Boolean)WHITE_BOX.getVMFlag("ValueArrayFlatten");
     private static final int COMP_LEVEL_ANY = -1;
     private static final int COMP_LEVEL_FULL_OPTIMIZATION = 4;
     private static final Hashtable<String, Method> tests = new Hashtable<String, Method>();
     private static final int WARMUP = 250;
     private static boolean USE_COMPILER = WHITE_BOX.getBooleanVMFlag("UseCompiler");

@@ -933,12 +1123,15 @@
     // Regular expressions used  to match nodes in the PrintIdeal output
     private static final String START = "(\\d+\\t(.*";
     private static final String MID = ".*)+\\t===.*";
     private static final String END = ")|";
     private static final String ALLOC = START + "CallStaticJava" + MID + "_new_instance_Java" + END;
-    private static final String LOAD  = START + "Load" + MID + "valuetype\\*" + END;
-    private static final String STORE = START + "Store" + MID + "valuetype\\*" + END;
+    private static final String ALLOCA = START + "CallStaticJava" + MID + "_new_array_Java" + END;
+    private static final String LOAD   = START + "Load(B|S|I|L|F|D)" + MID + "valuetype\\*" + END;
+    private static final String LOADP  = START + "Load(P|N)" + MID + "valuetype\\*" + END;
+    private static final String STORE  = START + "Store(B|S|I|L|F|D)" + MID + "valuetype\\*" + END;
+    private static final String STOREP = START + "Store(P|N)" + MID + "valuetype\\*" + END;
     private static final String LOOP  = START + "Loop" + MID + "" + END;
     private static final String TRAP  = START + "CallStaticJava" + MID + "uncommon_trap" + END;
     // TODO: match field values of scalar replaced object
     private static final String SCOBJ = "(.*# ScObj.*" + END;
 

@@ -978,17 +1171,23 @@
     }
 
     public static void main(String[] args) throws Throwable {
         if (args.length == 0) {
             String field_as_args;
-            if ((Boolean)WHITE_BOX.getVMFlag("ValueTypePassFieldsAsArgs")) {
+            String array_flatten;
+            if (ValueTypePassFieldsAsArgs) {
                 field_as_args = "-XX:+ValueTypePassFieldsAsArgs";
             } else {
                 field_as_args = "-XX:-ValueTypePassFieldsAsArgs";
             }
-            execute_vm("-XX:+UnlockExperimentalVMOptions", field_as_args);
-            execute_vm("-XX:+AlwaysIncrementalInline", "-XX:+UnlockExperimentalVMOptions", field_as_args);
+            if (ValueTypeArrayFlatten) {
+                array_flatten = "-XX:+ValueArrayFlatten";
+            } else {
+                array_flatten = "-XX:-ValueArrayFlatten";
+            }
+            execute_vm("-XX:+UnlockExperimentalVMOptions", field_as_args, array_flatten);
+            execute_vm("-XX:+AlwaysIncrementalInline", "-XX:+UnlockExperimentalVMOptions", field_as_args, array_flatten);
         } else {
             if (USE_COMPILER && PRINT_IDEAL && !XCOMP) {
                 System.out.println("PrintIdeal enabled");
             }
             // Execute tests

@@ -1025,24 +1224,25 @@
                     assert anno == null;
                     anno = a;
                 } else if ((a.valid() & ValueTypePassFieldsAsArgsOff) != 0 && !ValueTypePassFieldsAsArgs) {
                     assert anno == null;
                     anno = a;
+                } else if ((a.valid() & ValueTypeArrayFlattenOn) != 0 && ValueTypeArrayFlatten) {
+                    assert anno == null;
+                    anno = a;
+                } else if ((a.valid() & ValueTypeArrayFlattenOff) != 0 && !ValueTypeArrayFlatten) {
+                    assert anno == null;
+                    anno = a;
                 }
             }
             assert anno != null;
             String regexFail = anno.failOn();
             if (!regexFail.isEmpty()) {
                 Pattern pattern = Pattern.compile(regexFail.substring(0, regexFail.length()-1));
                 Matcher matcher = pattern.matcher(graph);
-                boolean fail = false;
-                while (matcher.find()) {
-                    System.out.println("Graph for '" + testName + "' contains forbidden node:");
-                    System.out.println(matcher.group());
-                    fail = true;
-                }
-                Asserts.assertFalse(fail, "Graph for '" + testName + "' contains forbidden nodes");
+                boolean found = matcher.find();
+                Asserts.assertFalse(found, "Graph for '" + testName + "' contains forbidden node:\n" + (found ? matcher.group() : ""));
             }
             String[] regexMatch = anno.match();
             int[] matchCount = anno.matchCount();
             for (int i = 0; i < regexMatch.length; ++i) {
                 Pattern pattern = Pattern.compile(regexMatch[i].substring(0, regexMatch[i].length()-1));

@@ -1051,15 +1251,11 @@
                 String nodes = "";
                 while (matcher.find()) {
                     count++;
                     nodes += matcher.group() + "\n";
                 }
-                if (matchCount[i] != count) {
-                    System.out.println("Graph for '" + testName + "' contains different number of match nodes:");
-                    System.out.println(nodes);
-                }
-                Asserts.assertEQ(matchCount[i], count, "Graph for '" + testName + "' contains different number of match nodes");
+                Asserts.assertEQ(matchCount[i], count, "Graph for '" + testName + "' contains different number of match nodes:\n" + nodes);
             }
             tests.remove(testName);
             System.out.println(testName + " passed");
         }
         // Check if all tests were compiled
< prev index next >