< prev index next >

test/compiler/valhalla/valuetypes/ValueTypeTestBench.java

Print this page

        

@@ -31,20 +31,20 @@
  * @compile -XDenableValueTypes ValueCapableClass1.java ValueCapableClass2.java ValueTypeTestBench.java
  * @run main ClassFileInstaller sun.hotspot.WhiteBox
  * @run main ClassFileInstaller jdk.test.lib.Platform
  * @run main/othervm -Xbootclasspath/a:. -ea -noverify -XX:+IgnoreUnrecognizedVMOptions -XX:+UnlockDiagnosticVMOptions
  *                   -XX:+UnlockExperimentalVMOptions -XX:+WhiteBoxAPI -XX:-TieredCompilation -XX:+VerifyAdapterSharing
- *                   -XX:+EnableValhalla -XX:+EnableMVT -XX:+ValueTypePassFieldsAsArgs -XX:+ValueArrayFlatten
+ *                   -XX:+EnableValhalla -XX:+EnableMVT -XX:+ValueTypePassFieldsAsArgs -XX:+ValueTypeReturnedAsFields -XX:+ValueArrayFlatten
  *                   -XX:ValueArrayElemMaxFlatSize=-1 -XX:ValueArrayElemMaxFlatOops=-1 -XX:+FullGCALotWithValueTypes
  *                   compiler.valhalla.valuetypes.ValueTypeTestBench
  * @run main/othervm -Xbootclasspath/a:. -ea -noverify -XX:+IgnoreUnrecognizedVMOptions -XX:+UnlockDiagnosticVMOptions
  *                   -XX:+UnlockExperimentalVMOptions -XX:+WhiteBoxAPI -XX:-TieredCompilation
- *                   -XX:+EnableValhalla -XX:+EnableMVT -XX:-ValueTypePassFieldsAsArgs -XX:-ValueArrayFlatten
+ *                   -XX:+EnableValhalla -XX:+EnableMVT -XX:-ValueTypePassFieldsAsArgs -XX:-ValueTypeReturnedAsFields -XX:-ValueArrayFlatten
  *                   compiler.valhalla.valuetypes.ValueTypeTestBench
  * @run main/othervm -Xbootclasspath/a:. -ea -noverify -XX:+IgnoreUnrecognizedVMOptions -XX:+UnlockDiagnosticVMOptions
  *                   -XX:+UnlockExperimentalVMOptions -XX:+WhiteBoxAPI -XX:-TieredCompilation -XX:+AlwaysIncrementalInline
- *                   -XX:+EnableValhalla -XX:+EnableMVT -XX:+ValueTypePassFieldsAsArgs -XX:+ValueArrayFlatten
+ *                   -XX:+EnableValhalla -XX:+EnableMVT -XX:+ValueTypePassFieldsAsArgs -XX:+ValueTypeReturnedAsFields -XX:+ValueArrayFlatten
  *                   -XX:ValueArrayElemMaxFlatSize=-1 -XX:ValueArrayElemMaxFlatOops=-1
  *                   compiler.valhalla.valuetypes.ValueTypeTestBench
  */
 
 package compiler.valhalla.valuetypes;

@@ -65,11 +65,13 @@
 import java.lang.invoke.*;
 import java.lang.reflect.Method;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Hashtable;
+import java.util.LinkedHashMap;
 import java.util.List;
+import java.util.Map;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 import jdk.experimental.value.*;
 
 // Test value types

@@ -299,10 +301,252 @@
         v.b = b;
         return v;
     }
 }
 
+// Value type definition to stress test return of a value in registers
+// (uses all registers of calling convention on x86_64)
+__ByValue final class MyValue3 {
+    final char c;
+    final byte bb;
+    final short s;
+    final int i;
+    final long l;
+    final Object o;
+    final float f1;
+    final double f2;
+    final float f3;
+    final double f4;
+    final float f5;
+    final double f6;
+    final float f7;
+    final double f8;
+
+    private MyValue3(char c,
+                     byte bb,
+                     short s,
+                     int i,
+                     long l,
+                     Object o,
+                     float f1,
+                     double f2,
+                     float f3,
+                     double f4,
+                     float f5,
+                     double f6,
+                     float f7,
+                     double f8) {
+        this.c = c;
+        this.bb = bb;
+        this.s = s;
+        this.i = i;
+        this.l = l;
+        this.o = o;
+        this.f1 = f1;
+        this.f2 = f2;
+        this.f3 = f3;
+        this.f4 = f4;
+        this.f5 = f5;
+        this.f6 = f6;
+        this.f7 = f7;
+        this.f8 = f8;
+    }
+
+    private MyValue3() {
+        this.c = 0;
+        this.bb = 0;
+        this.s = 0;
+        this.i = 0;
+        this.l = 0;
+        this.o = null;
+        this.f1 = 0;
+        this.f2 = 0;
+        this.f3 = 0;
+        this.f4 = 0;
+        this.f5 = 0;
+        this.f6 = 0;
+        this.f7 = 0;
+        this.f8 = 0;
+    }
+
+    @ForceInline
+    __ValueFactory static MyValue3 setC(MyValue3 v, char c) {
+        v.c = c;
+        return v;
+    }
+
+    @ForceInline
+    __ValueFactory static MyValue3 setBB(MyValue3 v, byte bb) {
+        v.bb = bb;
+        return v;
+    }
+
+    @ForceInline
+    __ValueFactory static MyValue3 setS(MyValue3 v, short s) {
+        v.s = s;
+        return v;
+    }
+
+    @ForceInline
+    __ValueFactory static MyValue3 setI(MyValue3 v, int i) {
+        v.i = i;
+        return v;
+    }
+
+    @ForceInline
+    __ValueFactory static MyValue3 setL(MyValue3 v, long l) {
+        v.l = l;
+        return v;
+    }
+
+    @ForceInline
+    __ValueFactory static MyValue3 setO(MyValue3 v, Object o) {
+        v.o = o;
+        return v;
+    }
+
+    @ForceInline
+    __ValueFactory static MyValue3 setF1(MyValue3 v, float f1) {
+        v.f1 = f1;
+        return v;
+    }
+
+    @ForceInline
+    __ValueFactory static MyValue3 setF2(MyValue3 v, double f2) {
+        v.f2 = f2;
+        return v;
+    }
+
+    @ForceInline
+    __ValueFactory static MyValue3 setF3(MyValue3 v, float f3) {
+        v.f3 = f3;
+        return v;
+    }
+
+    @ForceInline
+    __ValueFactory static MyValue3 setF4(MyValue3 v, double f4) {
+        v.f4 = f4;
+        return v;
+    }
+
+    @ForceInline
+    __ValueFactory static MyValue3 setF5(MyValue3 v, float f5) {
+        v.f5 = f5;
+        return v;
+    }
+
+    @ForceInline
+    __ValueFactory static MyValue3 setF6(MyValue3 v, double f6) {
+        v.f6 = f6;
+        return v;
+    }
+
+    @ForceInline
+    __ValueFactory static MyValue3 setF7(MyValue3 v, float f7) {
+        v.f7 = f7;
+        return v;
+    }
+
+    @ForceInline
+    __ValueFactory static MyValue3 setF8(MyValue3 v, double f8) {
+        v.f8 = f8;
+        return v;
+    }
+
+    @ForceInline
+    __ValueFactory public static MyValue3 createDefault() {
+        return __MakeDefault MyValue3();
+    }
+
+    @ForceInline
+    public static MyValue3 create() {
+        java.util.Random r = Utils.getRandomInstance();
+        MyValue3 v = createDefault();
+        v = setC(v, (char)r.nextInt());
+        v = setBB(v, (byte)r.nextInt());
+        v = setS(v, (short)r.nextInt());
+        v = setI(v, r.nextInt());
+        v = setL(v, r.nextLong());
+        v = setO(v, new Object());
+        v = setF1(v, r.nextFloat());
+        v = setF2(v, r.nextDouble());
+        v = setF3(v, r.nextFloat());
+        v = setF4(v, r.nextDouble());
+        v = setF5(v, r.nextFloat());
+        v = setF6(v, r.nextDouble());
+        v = setF7(v, r.nextFloat());
+        v = setF8(v, r.nextDouble());
+        return v;
+    }
+
+    public void verify(MyValue3 other) {
+        Asserts.assertEQ(c, other.c);
+        Asserts.assertEQ(bb, other.bb);
+        Asserts.assertEQ(s, other.s);
+        Asserts.assertEQ(i, other.i);
+        Asserts.assertEQ(l, other.l);
+        Asserts.assertEQ(o, other.o);
+        Asserts.assertEQ(f1, other.f1);
+        Asserts.assertEQ(f2, other.f2);
+        Asserts.assertEQ(f3, other.f3);
+        Asserts.assertEQ(f4, other.f4);
+        Asserts.assertEQ(f5, other.f5);
+        Asserts.assertEQ(f6, other.f6);
+        Asserts.assertEQ(f7, other.f7);
+        Asserts.assertEQ(f8, other.f8);
+    }
+}
+
+// Value type definition with too many fields to return in registers
+__ByValue final class MyValue4 {
+    final MyValue3 v1;
+    final MyValue3 v2;
+
+    private MyValue4(MyValue3 v1, MyValue3 v2) {
+        this.v1 = v1;
+        this.v2 = v2;
+    }
+
+    private MyValue4() {
+        this.v1 = MyValue3.createDefault();
+        this.v2 = MyValue3.createDefault();
+    }
+
+    @ForceInline
+    __ValueFactory static MyValue4 setV1(MyValue4 v, MyValue3 v1) {
+        v.v1 = v1;
+        return v;
+    }
+
+    @ForceInline
+    __ValueFactory static MyValue4 setV2(MyValue4 v, MyValue3 v2) {
+        v.v2 = v2;
+        return v;
+    }
+
+    @ForceInline
+    __ValueFactory public static MyValue4 createDefault() {
+        return __MakeDefault MyValue4();
+    }
+
+    @ForceInline
+    public static MyValue4 create() {
+        MyValue4 v = createDefault();
+        MyValue3 v1 = MyValue3.create();
+        v = setV1(v, v1);
+        MyValue3 v2 = MyValue3.create();
+        v = setV2(v, v2);
+        return v;
+    }
+
+    public void verify(MyValue4 other) {
+        v1.verify(other.v1);
+        v2.verify(other.v2);
+    }
+}
+
+
 public class ValueTypeTestBench {
     // Print ideal graph after execution of each test
     private static final boolean PRINT_GRAPH = true;
 
     // Random test values

@@ -1503,12 +1747,11 @@
 
     /* The compiler is supposed to determine that the value to be
      * unboxed in nullcvvUnboxLoadLong is always null. Therefore, the
      * compiler generates only the path leading to the corresponding
      * uncommon trap. */
-    @Test(valid = AlwaysIncrementalInlineOff, failOn = RETURN)
-    @Test(valid = AlwaysIncrementalInlineOn, match = {LINKTOSTATIC}, matchCount= {1})
+    @Test(failOn = RETURN)
     public long test61() throws Throwable {
         return (long)nullvccUnboxLoadLongMH.invokeExact();
     }
 
     @DontCompile

@@ -1536,12 +1779,11 @@
 
     /* The compiler is supposed to determine that the allocated
      * ValueCapableClass1 instance is never null (and therefore not
      * generate a null check). Also, the source and target type match
      * (known at compile time), so no type check is needed either.*/
-    @Test(valid = AlwaysIncrementalInlineOff, failOn = NPE)
-    @Test(valid = AlwaysIncrementalInlineOn, match = {LINKTOSTATIC}, matchCount= {1})
+    @Test(failOn = NPE)
     public long test62() throws Throwable {
         return (long)checkedvccUnboxLoadLongMH.invokeExact();
     }
 
     @DontCompile

@@ -1566,12 +1808,11 @@
 
     /* The compiler is supposed to emit a runtime null check because
      * it does not have enough information to determine that the value
      * to be unboxed is not null (and either that it is null). The
      * declared type of the */
-    @Test(valid = AlwaysIncrementalInlineOff, match = {NPE}, matchCount = {1})
-    @Test(valid = AlwaysIncrementalInlineOn, match = {LINKTOSTATIC}, matchCount= {1})
+    @Test(match = {NPE}, matchCount = {1})
     public long test63(ValueCapableClass1 vcc) throws Throwable {
         return (long)vccUnboxLoadLongMH.invokeExact(vcc);
     }
 
     @DontCompile

@@ -1584,12 +1825,11 @@
     }
 
     /* Attempt to unbox an object that is not a subclass of the
      * value-capable class derived from the value type specified in
      * the vunbox bytecode. */
-    @Test(valid = AlwaysIncrementalInlineOff, match = {NPE,CCE}, matchCount = {1,1})
-    @Test(valid = AlwaysIncrementalInlineOn, match = {LINKTOSTATIC}, matchCount= {1})
+    @Test(match = {NPE,CCE}, matchCount = {1,1})
     public long test64(Object vcc) throws Throwable {
         return (long)objectUnboxLoadLongMH.invokeExact(vcc);
     }
 
     @DontCompile

@@ -1624,12 +1864,11 @@
     }
 
     /* Generate an if-then-else construct with one path that contains
      * an invalid boxing operation (boxing of a value-type to a
      * non-matching value-capable class).*/
-    @Test(valid = AlwaysIncrementalInlineOff, match = {NPE,CCE}, matchCount = {2,3})
-    @Test(valid = AlwaysIncrementalInlineOn, match = {LINKTOSTATIC}, matchCount= {1})
+    @Test(match = {NPE,CCE}, matchCount = {2,3})
     public long test65(Object obj, boolean warmup) throws Throwable {
         return (long)objectBoxMH.invokeExact(obj, warmup);
     }
 
     @DontCompile

@@ -1676,23 +1915,267 @@
                     lreturn();
                 }
                 );
     }
 
+    // Test deoptimization at call return with return value in registers
+    @DontCompile
+    public MyValue2 test66_interp(boolean deopt) {
+        if (deopt) {
+            // uncommon trap
+            WHITE_BOX.deoptimizeMethod(tests.get("ValueTypeTestBench::test66"));
+        }
+        return MyValue2.createWithFieldsInline(rI, true);
+    }
+
+    @Test()
+    public MyValue2 test66(boolean flag) {
+        return test66_interp(flag);
+    }
+
+    @DontCompile
+    public void test66_verifier(boolean warmup) {
+        MyValue2 result = test66(!warmup);
+        MyValue2 v = MyValue2.createWithFieldsInline(rI, true);
+        Asserts.assertEQ(result.hash(), v.hash());
+    }
+
+    // Return value types in registers from interpreter -> compiled
+    final MyValue3 test67_vt = MyValue3.create();
+    @DontCompile
+    public MyValue3 test67_interp() {
+        return test67_vt;
+    }
+
+    MyValue3 test67_vt2;
+    @Test(valid = ValueTypeReturnedAsFieldsOn, failOn = ALLOC + LOAD + TRAP)
+    @Test(valid = ValueTypeReturnedAsFieldsOff)
+    public void test67() {
+        test67_vt2 = test67_interp();
+    }
+
+    @DontCompile
+    public void test67_verifier(boolean warmup) {
+        test67();
+        test67_vt.verify(test67_vt2);
+    }
+
+    // Return value types in registers from compiled -> interpreter
+    final MyValue3 test68_vt = MyValue3.create();
+    @Test(valid = ValueTypeReturnedAsFieldsOn, failOn = ALLOC + STORE + TRAP)
+    @Test(valid = ValueTypeReturnedAsFieldsOff)
+    public MyValue3 test68() {
+        return test68_vt;
+    }
+
+    @DontCompile
+    public void test68_verifier(boolean warmup) {
+        MyValue3 vt = test68();
+        test68_vt.verify(vt);
+    }
+
+    // Return value types in registers from compiled -> compiled
+    final MyValue3 test69_vt = MyValue3.create();
+    @DontInline
+    public MyValue3 test69_comp() {
+        return test69_vt;
+    }
+
+    MyValue3 test69_vt2;
+    @Test(valid = ValueTypeReturnedAsFieldsOn, failOn = ALLOC + LOAD + TRAP)
+    @Test(valid = ValueTypeReturnedAsFieldsOff)
+    public void test69() {
+        test69_vt2 = test69_comp();
+    }
+
+    @DontCompile
+    public void test69_verifier(boolean warmup) throws Exception {
+        Method helper_m = getClass().getDeclaredMethod("test69_comp");
+        if (!warmup && USE_COMPILER && !WHITE_BOX.isMethodCompiled(helper_m, false)) {
+            WHITE_BOX.enqueueMethodForCompilation(helper_m, COMP_LEVEL_FULL_OPTIMIZATION);
+            Asserts.assertTrue(WHITE_BOX.isMethodCompiled(helper_m, false), "test69_comp not compiled");
+        }
+        test69();
+        test69_vt.verify(test69_vt2);
+    }
+
+    // Same tests as above but with a value type that cannot be returned in registers
+
+    // Return value types in registers from interpreter -> compiled
+    final MyValue4 test70_vt = MyValue4.create();
+    @DontCompile
+    public MyValue4 test70_interp() {
+        return test70_vt;
+    }
+
+    MyValue4 test70_vt2;
+    @Test
+    public void test70() {
+        test70_vt2 = test70_interp();
+    }
+
+    @DontCompile
+    public void test70_verifier(boolean warmup) {
+        test70();
+        test70_vt.verify(test70_vt2);
+    }
+
+    // Return value types in registers from compiled -> interpreter
+    final MyValue4 test71_vt = MyValue4.create();
+    @Test
+    public MyValue4 test71() {
+        return test71_vt;
+    }
+
+    @DontCompile
+    public void test71_verifier(boolean warmup) {
+        MyValue4 vt = test71();
+        test71_vt.verify(vt);
+    }
+
+    // Return value types in registers from compiled -> compiled
+    final MyValue4 test72_vt = MyValue4.create();
+    @DontInline
+    public MyValue4 test72_comp() {
+        return test72_vt;
+    }
+
+    MyValue4 test72_vt2;
+    @Test
+    public void test72() {
+        test72_vt2 = test72_comp();
+    }
+
+    @DontCompile
+    public void test72_verifier(boolean warmup) throws Exception {
+        Method helper_m = getClass().getDeclaredMethod("test72_comp");
+        if (!warmup && USE_COMPILER && !WHITE_BOX.isMethodCompiled(helper_m, false)) {
+            WHITE_BOX.enqueueMethodForCompilation(helper_m, COMP_LEVEL_FULL_OPTIMIZATION);
+            Asserts.assertTrue(WHITE_BOX.isMethodCompiled(helper_m, false), "test72_comp not compiled");
+        }
+        test72();
+        test72_vt.verify(test72_vt2);
+    }
+
+    // Return values and method handles tests
+
+    // Everything inlined
+    final MyValue3 test73_vt = MyValue3.create();
+    @ForceInline
+    MyValue3 test73_target() {
+        return test73_vt;
+    }
+
+    static final MethodHandle test73_mh;
+
+    @Test(valid = ValueTypeReturnedAsFieldsOn, failOn = ALLOC + STORE + CALL)
+    @Test(valid = ValueTypeReturnedAsFieldsOff, match = { ALLOC, STORE }, matchCount = { 1, 11 })
+    MyValue3 test73() throws Throwable {
+        return (MyValue3)test73_mh.invokeExact(this);
+    }
+
+    @DontCompile
+    public void test73_verifier(boolean warmup) throws Throwable {
+        MyValue3 vt = test73();
+        test73_vt.verify(vt);
+    }
+
+    // Leaf method not inlined but returned type is known
+    final MyValue3 test74_vt = MyValue3.create();
+    @DontInline
+    MyValue3 test74_target() {
+        return test74_vt;
+    }
+
+    static final MethodHandle test74_mh;
+
+    @Test
+    MyValue3 test74() throws Throwable {
+        return (MyValue3)test74_mh.invokeExact(this);
+    }
+
+    @DontCompile
+    public void test74_verifier(boolean warmup) throws Throwable {
+        Method helper_m = getClass().getDeclaredMethod("test74_target");
+        if (!warmup && USE_COMPILER && !WHITE_BOX.isMethodCompiled(helper_m, false)) {
+            WHITE_BOX.enqueueMethodForCompilation(helper_m, COMP_LEVEL_FULL_OPTIMIZATION);
+            Asserts.assertTrue(WHITE_BOX.isMethodCompiled(helper_m, false), "test74_target not compiled");
+        }
+        MyValue3 vt = test74();
+        test74_vt.verify(vt);
+    }
+
+    // Leaf method not inlined and returned type not known
+    final MyValue3 test75_vt = MyValue3.create();
+    @DontInline
+    MyValue3 test75_target() {
+        return test75_vt;
+    }
+
+    static final MethodHandle test75_mh;
+
+    @Test
+    MyValue3 test75() throws Throwable {
+        return (MyValue3)test75_mh.invokeExact(this);
+    }
+
+    @DontCompile
+    public void test75_verifier(boolean warmup) throws Throwable {
+        // hack so C2 doesn't know the target of the invoke call
+        Class c = Class.forName("java.lang.invoke.DirectMethodHandle");
+        Method m = c.getDeclaredMethod("internalMemberName", Object.class);
+        WHITE_BOX.testSetDontInlineMethod(m, warmup);
+        MyValue3 vt = test75();
+        test75_vt.verify(vt);
+    }
+
+    // Test no result from inlined method for incremental inlining
+    final MyValue3 test76_vt = MyValue3.create();
+    public MyValue3 test76_inlined() {
+        throw new RuntimeException();
+    }
+
+    @Test
+    public MyValue3 test76() {
+        try {
+            return test76_inlined();
+        } catch (RuntimeException ex) {
+            return test76_vt;
+        }
+    }
+
+    @DontCompile
+    public void test76_verifier(boolean warmup) throws Exception {
+        MyValue3 vt = test76();
+        test76_vt.verify(vt);
+    }
+
+    static {
+        try {
+            MethodHandles.Lookup lookup = MethodHandles.lookup();
+            MethodType mt = MethodType.fromMethodDescriptorString("()Qcompiler/valhalla/valuetypes/MyValue3;", ValueTypeTestBench.class.getClassLoader());
+            test73_mh = lookup.findVirtual(ValueTypeTestBench.class, "test73_target", mt);
+            test74_mh = lookup.findVirtual(ValueTypeTestBench.class, "test74_target", mt);
+            test75_mh = lookup.findVirtual(ValueTypeTestBench.class, "test75_target", mt);
+        } catch (NoSuchMethodException|IllegalAccessException e) {
+            throw new RuntimeException("method handle lookup fails");
+        }
+    }
+
     // ========== Test infrastructure ==========
 
     private static final WhiteBox WHITE_BOX = WhiteBox.getWhiteBox();
     private static final int ValueTypePassFieldsAsArgsOn = 0x1;
     private static final int ValueTypePassFieldsAsArgsOff = 0x2;
     private static final int ValueTypeArrayFlattenOn = 0x4;
     private static final int ValueTypeArrayFlattenOff = 0x8;
-    private static final int AlwaysIncrementalInlineOff = 0x10;
-    private static final int AlwaysIncrementalInlineOn = 0x20;
-    static final int AllFlags = ValueTypePassFieldsAsArgsOn | ValueTypePassFieldsAsArgsOff | ValueTypeArrayFlattenOn | ValueTypeArrayFlattenOff | AlwaysIncrementalInlineOff | AlwaysIncrementalInlineOn;
+    private static final int ValueTypeReturnedAsFieldsOn = 0x10;
+    private static final int ValueTypeReturnedAsFieldsOff = 0x20;
+    static final int AllFlags = ValueTypePassFieldsAsArgsOn | ValueTypePassFieldsAsArgsOff | ValueTypeArrayFlattenOn | ValueTypeArrayFlattenOff | ValueTypeReturnedAsFieldsOn;
     private static final boolean ValueTypePassFieldsAsArgs = (Boolean)WHITE_BOX.getVMFlag("ValueTypePassFieldsAsArgs");
     private static final boolean ValueTypeArrayFlatten = (Boolean)WHITE_BOX.getVMFlag("ValueArrayFlatten");
-    private static final boolean AlwaysIncrementalInline = (Boolean)WHITE_BOX.getVMFlag("AlwaysIncrementalInline");
+    private static final boolean ValueTypeReturnedAsFields = (Boolean)WHITE_BOX.getVMFlag("ValueTypeReturnedAsFields");
     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 = 251;
     private static boolean USE_COMPILER = WHITE_BOX.getBooleanVMFlag("UseCompiler");

@@ -1713,10 +2196,11 @@
     private static final String TRAP   = START + "CallStaticJava" + MID + "uncommon_trap.*(unstable_if|predicate)" + END;
     private static final String RETURN = START + "Return" + MID + "returns" + END;
     private static final String LINKTOSTATIC = START + "CallStaticJava" + MID + "linkToStatic" + END;
     private static final String NPE = START + "CallStaticJava" + MID + "null_check" + END;
     private static final String CCE = START + "CallStaticJava" + MID + "class_check" + END;
+    private static final String CALL = START + "CallStaticJava" + MID + END;
     private static final String SCOBJ = "(.*# ScObj.*" + END;
 
     static {
         // Gather all test methods and put them in Hashtable
         for (Method m : ValueTypeTestBench.class.getDeclaredMethods()) {

@@ -1749,45 +2233,64 @@
             System.out.println("WARNING: IR verification disabled! Running with -Xint, -Xcomp or release build?");
         }
     }
 
     public static void main(String[] args) throws Throwable {
-        //tests.values().removeIf(p -> !p.getName().equals("test64")); // Run single test
+        //tests.values().removeIf(p -> !p.getName().equals("test74")); // Run single test
         if (args.length == 0) {
             execute_vm("-XX:+IgnoreUnrecognizedVMOptions", "-XX:-BackgroundCompilation",
                     "-XX:+PrintCompilation", "-XX:+PrintInlining", "-XX:+PrintIdeal", "-XX:+PrintOptoAssembly",
+                    "-XX:CICompilerCount=1",
                     "-XX:CompileCommand=quiet", "-XX:CompileCommand=compileonly,compiler.valhalla.valuetypes.ValueTypeTestBench::*",
                     "-XX:CompileCommand=compileonly,compiler.valhalla.valuetypes.MyValue1::*",
                     "-XX:CompileCommand=compileonly,compiler.valhalla.valuetypes.MyValue2::*",
                     "-XX:CompileCommand=compileonly,java.lang.Object::<init>",
-                    "-XX:CompileCommand=inline,java.lang.__Value::hashCode");
+                    "-XX:CompileCommand=inline,java.lang.__Value::hashCode",
+                    "-XX:CompileCommand=compileonly,java.lang.invoke.*::*");
         } else {
             // Execute tests
             ValueTypeTestBench bench = new ValueTypeTestBench();
             bench.run();
         }
     }
 
     public static void parseOutput(String output) throws Exception {
-        String split = "b        compiler.valhalla.valuetypes.";
-        String[] compilations = output.split(split);
+        Pattern comp_re = Pattern.compile("\\n\\s+\\d+\\s+\\d+\\s+(%| )(s| )(!| )b(n| )\\s+\\S+\\.(?<name>[^.]+::\\S+)\\s+(?<osr>@ \\d+\\s+)?[(]\\d+ bytes[)]\\n");
+        Matcher m = comp_re.matcher(output);
+        Map<String,String> compilations = new LinkedHashMap<>();
+        int prev = 0;
+        String methodName = null;
+        while (m.find()) {
+            if (prev == 0) {
         // Print header
-        System.out.println(compilations[0]);
-        // Iterate over compilation output
-        for (String graph : compilations) {
-            String[] lines = graph.split("\\n");
-            if (lines[0].contains("@")) {
-                continue; // Ignore OSR compilations
+                System.out.print(output.substring(0, m.start()+1));
+            } else if (methodName != null) {
+                compilations.put(methodName, output.substring(prev, m.start()+1));
             }
-            String testName = lines[0].split(" ")[0];
+            if (m.group("osr") != null) {
+                methodName = null;
+            } else {
+                methodName = m.group("name");
+            }
+            prev = m.end();
+        }
+        if (prev == 0) {
+            // Print header
+            System.out.print(output);
+        } else if (methodName != null) {
+            compilations.put(methodName, output.substring(prev));
+        }
+        // Iterate over compilation output
+        for (String testName : compilations.keySet()) {
             Method test = tests.get(testName);
             if (test == null) {
                 // Skip helper methods
                 continue;
             }
+            String graph = compilations.get(testName);
             if (PRINT_GRAPH) {
-                System.out.println("\nGraph for " + graph);
+                System.out.println("\nGraph for " + testName + "\n" + graph);
             }
             // Parse graph using regular expressions to determine if it contains forbidden nodes
             Test[] annos = test.getAnnotationsByType(Test.class);
             Test anno = null;
             for (Test a : annos) {

@@ -1801,14 +2304,14 @@
                     assert anno == null;
                     anno = a;
                 } else if ((a.valid() & ValueTypeArrayFlattenOff) != 0 && !ValueTypeArrayFlatten) {
                     assert anno == null;
                     anno = a;
-                } else if ((a.valid() & AlwaysIncrementalInlineOff) != 0 && !AlwaysIncrementalInline) {
+                } else if ((a.valid() & ValueTypeReturnedAsFieldsOn) != 0 && ValueTypeReturnedAsFields) {
                     assert anno == null;
                     anno = a;
-                } else if ((a.valid() & AlwaysIncrementalInlineOn) != 0 && AlwaysIncrementalInline) {
+                } else if ((a.valid() & ValueTypeReturnedAsFieldsOff) != 0 && !ValueTypeReturnedAsFields) {
                     assert anno == null;
                     anno = a;
                 }
             }
             assert anno != null;
< prev index next >