--- /dev/null 2019-03-11 09:22:42.048915961 +0100 +++ new/test/hotspot/jtreg/compiler/valhalla/valuetypes/TestUnloadedValueTypeField.java 2019-03-11 14:27:40.582353849 +0100 @@ -0,0 +1,272 @@ +/* + * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. + * + * This code is free software; you can redistribute it and/or modify it + * under the terms of the GNU General Public License version 2 only, as + * published by the Free Software Foundation. + * + * This code is distributed in the hope that it will be useful, but WITHOUT + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License + * version 2 for more details (a copy is included in the LICENSE file that + * accompanied this code). + * + * You should have received a copy of the GNU General Public License version + * 2 along with this work; if not, write to the Free Software Foundation, + * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA + * or visit www.oracle.com if you need additional information or have any + * questions. + */ + +/** + * @test + * @library /test/lib + * @summary Test the handling of fields of unloaded value classes. + * @compile -XDallowWithFieldOperator hack/GetUnresolvedValueFieldWrongSignature.java + * @compile -XDallowWithFieldOperator TestUnloadedValueTypeField.java + * @run main/othervm -XX:+EnableValhalla -Xcomp + * -XX:CompileCommand=compileonly,TestUnloadedValueTypeField::test1 + * -XX:CompileCommand=compileonly,TestUnloadedValueTypeField::test2 + * -XX:CompileCommand=compileonly,GetUnresolvedValueFieldWrongSignature::test3 + * -XX:CompileCommand=compileonly,TestUnloadedValueTypeField::test4 + * -XX:CompileCommand=compileonly,TestUnloadedValueTypeField::test5 + * TestUnloadedValueTypeField + */ + +import jdk.test.lib.Asserts; + +public class TestUnloadedValueTypeField { + static public void main(String[] args) { + test1_verifier(); + test2_verifier(); + test3_verifier(); + test4_verifier(); + test5_verifier(); + } + + // Test case 1: + // The value type field class has been loaded, but the holder class has not been loaded. + // + // aload_0 + // getfield MyValue1Holder.v:QMyValue1; + // ^ not loaded ^ already loaded + // + // MyValue1 has already been loaded, because it's in the ValueType attribute of + // TestUnloadedValueTypeField, due to TestUnloadedValueTypeField.test1_precondition(). + static value final class MyValue1 { + final int foo = 0; + + static MyValue1 make() { + return __WithField(MyValue1.default.foo, 1234); + } + } + + static class MyValue1Holder { + MyValue1 v; + + public MyValue1Holder() { + v = MyValue1.make(); + } + } + + static MyValue1 test1_precondition() { + return MyValue1.make(); + } + + static int test1(MyValue1Holder holder) { + if (holder != null) { + return holder.v.foo + 1; + } else { + return 0; + } + } + + static void test1_verifier() { + for (int i=0; i<10000; i++) { + // Make sure test1() is compiled for the first iteration of this loop, + // while MyValue1Holder is yet to be loaded. + test1(null); + MyValue1Holder holder = new MyValue1Holder(); + Asserts.assertEQ(test1(holder), 1235); + } + } + + // Test case 2: + // Both the value type field class, and the holder class have not been loaded. + // + // aload_0 + // getfield MyValueHolder2.v:QMyValue2; + // ^ not loaded ^ not loaded + // + // MyValue2 has already been loaded, because it is not explicitly referenced by + // TestUnloadedValueTypeField. + static value final class MyValue2 { + final int foo = 0; + + static MyValue2 make(int n) { + return __WithField(MyValue2.default.foo, n); + } + } + + static class MyValue2Holder { + MyValue2 v; + + public MyValue2Holder() { + v = MyValue2.make(1234); + } + } + + + static int test2(MyValue2Holder holder) { + if (holder != null) { + return holder.v.foo + 2; + } else { + return 0; + } + } + + static void test2_verifier() { + for (int i=0; i<10000; i++) { + // Make sure test2() is compiled for the first iteration of this loop, + // while MyValue2Holder2 and MyValue2 is yet to be loaded. + test2(null); + MyValue2Holder holder2 = new MyValue2Holder(); + Asserts.assertEQ(test2(holder2), 1236); + } + } + + // Test case 3: same as test1, except we are using an incorrect signature to + // refer to the value class. + // The value type field class has been loaded, but the holder class has not been loaded. + // + // GetUnresolvedValueFieldWrongSignature::test3() { + // aload_0 + // getfield MyValueHolder3.v:LMyValue3; + // ^ not loaded ^ already loaded (but should have been "Q") + // ... + // } + // + // MyValue3 has already been loaded, because it's in the ValueType attribute of + // TestUnloadedValueTypeField, due to TestUnloadedValueTypeField.test3_precondition(). + static value final class MyValue3 { + final int foo = 0; + + static MyValue3 make() { + return __WithField(MyValue3.default.foo, 1234); + } + } + + static class MyValue3Holder { + MyValue3 v; + + public MyValue3Holder() { + v = MyValue3.make(); + } + } + + static MyValue3 test3_precondition() { + return MyValue3.make(); + } + + static int test3(MyValue3Holder holder) { + return GetUnresolvedValueFieldWrongSignature.test3(holder); + } + + static void test3_verifier() { + for (int i=0; i<10000; i++) { + // Make sure test3() is compiled for the first iteration of this loop, + // while MyValue3Holder is yet to be loaded. + test3(null); + MyValue3Holder holder = new MyValue3Holder(); + try { + test3(holder); + Asserts.fail("Should have thrown NoSuchFieldError"); + } catch (NoSuchFieldError e) { + // OK + } + } + } + + // Test case 4: + // Same as case 1, except we use putfield instead of getfield. + static value final class MyValue4 { + final int foo = 0; + + static MyValue4 make(int n) { + return __WithField(MyValue4.default.foo, n); + } + } + + static class MyValue4Holder { + MyValue4 v; + + public MyValue4Holder() { + v = MyValue4.make(0); + } + } + + static MyValue4 test4_precondition() { + return MyValue4.make(0); + } + + static void test4(MyValue4Holder holder, MyValue4 v) { + if (holder != null) { + holder.v = v; + } + } + + static void test4_verifier() { + MyValue4 v = MyValue4.make(5678); + for (int i=0; i<10000; i++) { + // Make sure test4() is compiled for the first iteration of this loop, + // while MyValue4Holder is yet to be loaded. + test4(null, v); + MyValue4Holder holder = new MyValue4Holder(); + test4(holder, v); + Asserts.assertEQ(holder.v.foo, 5678); + } + } + + // Test case 5: + // Same as case 2, except we use putfield instead of getfield. + static value final class MyValue5 { + final int foo = 0; + + static MyValue5 make(int n) { + return __WithField(MyValue5.default.foo, n); + } + } + + static class MyValue5Holder { + MyValue5 v; + + public MyValue5Holder() { + v = MyValue5.make(0); + } + public Object make(int n) { + return MyValue5.make(n); + } + } + + static void test5(MyValue5Holder holder, Object o) { + if (holder != null) { + MyValue5 v = (MyValue5)o; + holder.v = v; + } + } + + static void test5_verifier() { + for (int i=0; i<10000; i++) { + // Make sure test5() is compiled for the first iteration of this loop, + // while both MyValue5Holder and MyValye5 are yet to be loaded. + test5(null, null); + MyValue5Holder holder = new MyValue5Holder(); + Object v = holder.make(5679); + test5(holder, v); + Asserts.assertEQ(holder.v.foo, 5679); + } + } +}