< prev index next >

test/compiler/valhalla/valuetypes/ValueTypeTestBench.java

Print this page

        

@@ -86,22 +86,10 @@
     final MyValue2 v1;
     final MyValue2 v2;
     static final MyValue2 v3 = MyValue2.createWithFieldsInline(ValueTypeTestBench.rI, true);
     final int c;
 
-    private MyValue1(int x, long y, short z, Integer o, int[] oa, MyValue2 v1, MyValue2 v2, int c) {
-        s = x;
-        this.x = x;
-        this.y = y;
-        this.z = z;
-        this.o = o;
-        this.oa = oa;
-        this.v1 = v1;
-        this.v2 = v2;
-        this.c = c;
-    }
-
     private MyValue1() {
         s = 0;
         this.x = 0;
         this.y = 0;
         this.z = 0;

@@ -112,31 +100,21 @@
         this.c = 0;
     }
 
     @DontInline
     __ValueFactory static MyValue1 createDefaultDontInline() {
-        return __MakeDefault MyValue1();
+        return createDefaultInline();
     }
 
     @ForceInline
     __ValueFactory static MyValue1 createDefaultInline() {
         return __MakeDefault MyValue1();
     }
 
     @DontInline
     static MyValue1 createWithFieldsDontInline(int x, long y) {
-        MyValue1 v = createDefaultInline();
-        v = setX(v, x);
-        v = setY(v, y);
-        v = setZ(v, (short)x);
-        v = setO(v, new Integer(x));
-        int[] oa = {x};
-        v = setOA(v, oa);
-        v = setV1(v, MyValue2.createWithFieldsInline(x, x < y));
-        v = setV2(v, MyValue2.createWithFieldsInline(x, x > y));
-        v = setC(v, ValueTypeTestBench.rI);
-        return v;
+        return createWithFieldsInline(x, y);
     }
 
     @ForceInline
     static MyValue1 createWithFieldsInline(int x, long y) {
         MyValue1 v = createDefaultInline();

@@ -232,17 +210,10 @@
     final int x;
     final byte y;
     final boolean b;
     final long c;
 
-    private MyValue2(int x, byte y, boolean b, long c) {
-        this.x = x;
-        this.y = y;
-        this.b = b;
-        this.c = c;
-    }
-
     private MyValue2() {
         this.x = 0;
         this.y = 0;
         this.b = false;
         this.c = 0;

@@ -476,10 +447,36 @@
         v = setF7(v, r.nextFloat());
         v = setF8(v, r.nextDouble());
         return v;
     }
 
+    @DontInline
+    public static MyValue3 createDontInline() {
+        return create();
+    }
+
+    @ForceInline
+    public static MyValue3 copy(MyValue3 other) {
+        MyValue3 v = createDefault();
+        v = setC(v, other.c);
+        v = setBB(v, other.bb);
+        v = setS(v, other.s);
+        v = setI(v, other.i);
+        v = setL(v, other.l);
+        v = setO(v, other.o);
+        v = setF1(v, other.f1);
+        v = setF2(v, other.f2);
+        v = setF3(v, other.f3);
+        v = setF4(v, other.f4);
+        v = setF5(v, other.f5);
+        v = setF6(v, other.f6);
+        v = setF7(v, other.f7);
+        v = setF8(v, other.f8);
+        return v;
+    }
+
+    @DontInline
     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);

@@ -2424,10 +2421,150 @@
             test86_mh = lookup.findVirtual(ValueTypeTestBench.class, "test86_target", test86_mt);
         } catch (NoSuchMethodException|IllegalAccessException e) {
             throw new RuntimeException("method handle lookup fails");
         }
     }
+
+    static MyValue3 staticVal3;
+    static MyValue3 staticVal3_copy;
+
+    // Check elimination of redundant value type allocations
+    @Test(match = {ALLOC}, matchCount = {1})
+    public MyValue3 test87(MyValue3[] va) {
+        // Create value type and force allocation
+        MyValue3 vt = MyValue3.create();
+        va[0] = vt;
+        staticVal3 = vt;
+        vt.verify(staticVal3);
+
+        // Value type is now allocated, make a copy and force allocation.
+        // Because copy is equal to vt, C2 should remove this redundant allocation.
+        MyValue3 copy = MyValue3.setC(vt, vt.c);
+        va[0] = copy;
+        staticVal3_copy = copy;
+        copy.verify(staticVal3_copy);
+        return copy;
+    }
+
+    @DontCompile
+    public void test87_verifier(boolean warmup) {
+        MyValue3[] va = new MyValue3[1];
+        MyValue3 vt = test87(va);
+        staticVal3.verify(vt);
+        staticVal3.verify(va[0]);
+        staticVal3_copy.verify(vt);
+        staticVal3_copy.verify(va[0]);
+    }
+
+    // Verify that only dominating allocations are re-used
+    @Test()
+    public MyValue3 test88(boolean warmup) {
+        MyValue3 vt = MyValue3.create();
+        if (warmup) {
+            staticVal3 = vt; // Force allocation
+        }
+        // Force allocation to verify that above
+        // non-dominating allocation is not re-used
+        MyValue3 copy = MyValue3.setC(vt, vt.c);
+        staticVal3_copy = copy;
+        copy.verify(vt);
+        return copy;
+    }
+
+    @DontCompile
+    public void test88_verifier(boolean warmup) {
+        MyValue3 vt = test88(warmup);
+        if (warmup) {
+            staticVal3.verify(vt);
+        }
+    }
+
+    // Verify that C2 recognizes value type loads and re-uses the oop to avoid allocations
+    @Test(failOn = ALLOC + ALLOCA + STORE)
+    public MyValue3 test89(MyValue3[] va) {
+        // C2 can re-use the oop of staticVal3 because staticVal3 is equal to copy
+        MyValue3 copy = MyValue3.copy(staticVal3);
+        va[0] = copy;
+        staticVal3 = copy;
+        copy.verify(staticVal3);
+        return copy;
+    }
+
+    @DontCompile
+    public void test89_verifier(boolean warmup) {
+        staticVal3 = MyValue3.create();
+        MyValue3[] va = new MyValue3[1];
+        MyValue3 vt = test89(va);
+        staticVal3.verify(vt);
+        staticVal3.verify(va[0]);
+    }
+
+    // Verify that C2 recognizes value type loads and re-uses the oop to avoid allocations
+    @Test(valid = ValueTypeReturnedAsFieldsOff, failOn = ALLOC + ALLOCA + STORE)
+    @Test(valid = ValueTypeReturnedAsFieldsOn)
+    public MyValue3 test90(MyValue3[] va) {
+        // C2 can re-use the oop returned by createDontInline()
+        // because the corresponding value type is equal to 'copy'.
+        MyValue3 copy = MyValue3.copy(MyValue3.createDontInline());
+        va[0] = copy;
+        staticVal3 = copy;
+        copy.verify(staticVal3);
+        return copy;
+    }
+
+    @DontCompile
+    public void test90_verifier(boolean warmup) {
+        MyValue3[] va = new MyValue3[1];
+        MyValue3 vt = test90(va);
+        staticVal3.verify(vt);
+        staticVal3.verify(va[0]);
+    }
+
+    // Verify that C2 recognizes value type loads and re-uses the oop to avoid allocations
+    @Test(valid = ValueTypePassFieldsAsArgsOff, failOn = ALLOC + ALLOCA + STORE)
+    @Test(valid = ValueTypePassFieldsAsArgsOn)
+    public MyValue3 test91(MyValue3 vt, MyValue3[] va) {
+        // C2 can re-use the oop of vt because vt is equal to 'copy'.
+        MyValue3 copy = MyValue3.copy(vt);
+        va[0] = copy;
+        staticVal3 = copy;
+        copy.verify(staticVal3);
+        return copy;
+    }
+
+    @DontCompile
+    public void test91_verifier(boolean warmup) {
+        MyValue3 vt = MyValue3.create();
+        MyValue3[] va = new MyValue3[1];
+        MyValue3 result = test91(vt, va);
+        staticVal3.verify(vt);
+        va[0].verify(vt);
+        result.verify(vt);
+    }
+
+    // Test correct identification of value type copies
+    @Test()
+    public MyValue3 test92(MyValue3[] va) {
+        MyValue3 vt = MyValue3.copy(staticVal3);
+        vt = MyValue3.setI(vt, (int)vt.c);
+        // vt is not equal to staticVal3, so C2 should not re-use the oop
+        va[0] = vt;
+        staticVal3 = vt;
+        vt.verify(staticVal3);
+        return vt;
+    }
+
+    @DontCompile
+    public void test92_verifier(boolean warmup) {
+        staticVal3 = MyValue3.create();
+        MyValue3[] va = new MyValue3[1];
+        MyValue3 vt = test92(va);
+        Asserts.assertEQ(staticVal3.i, (int)staticVal3.c);
+        Asserts.assertEQ(va[0].i, (int)staticVal3.c);
+        Asserts.assertEQ(vt.i, (int)staticVal3.c);
+    }
+
     // ========== Test infrastructure ==========
 
     private static final WhiteBox WHITE_BOX = WhiteBox.getWhiteBox();
     private static final int ValueTypePassFieldsAsArgsOn = 0x1;
     private static final int ValueTypePassFieldsAsArgsOff = 0x2;

@@ -2647,15 +2784,19 @@
         }
         System.out.format("rI = %d, rL = %d\n", rI, rL);
         setup(this.getClass().getDeclaredMethods());
         setup(MyValue1.class.getDeclaredMethods());
         setup(MyValue2.class.getDeclaredMethods());
+        setup(MyValue3.class.getDeclaredMethods());
+        setup(MyValue4.class.getDeclaredMethods());
 
         // Compile class initializers
         WHITE_BOX.enqueueInitializerForCompilation(this.getClass(), COMP_LEVEL_FULL_OPTIMIZATION);
         WHITE_BOX.enqueueInitializerForCompilation(MyValue1.class, COMP_LEVEL_FULL_OPTIMIZATION);
         WHITE_BOX.enqueueInitializerForCompilation(MyValue2.class, COMP_LEVEL_FULL_OPTIMIZATION);
+        WHITE_BOX.enqueueInitializerForCompilation(MyValue3.class, COMP_LEVEL_FULL_OPTIMIZATION);
+        WHITE_BOX.enqueueInitializerForCompilation(MyValue4.class, COMP_LEVEL_FULL_OPTIMIZATION);
 
         // Execute tests
         for (Method test : tests.values()) {
             Method verifier = getClass().getDeclaredMethod(test.getName() + "_verifier", boolean.class);
             // Warmup using verifier method
< prev index next >