1 /*
  2  * Copyright (c) 2020, 2024, Oracle and/or its affiliates. All rights reserved.
  3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  4  *
  5  * This code is free software; you can redistribute it and/or modify it
  6  * under the terms of the GNU General Public License version 2 only, as
  7  * published by the Free Software Foundation.
  8  *
  9  * This code is distributed in the hope that it will be useful, but WITHOUT
 10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 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 package compiler.valhalla.inlinetypes;
 25 
 26 import jdk.test.lib.Asserts;
 27 
 28 import jdk.internal.value.ValueClass;
 29 import jdk.internal.vm.annotation.ImplicitlyConstructible;
 30 import jdk.internal.vm.annotation.LooselyConsistentValue;
 31 import jdk.internal.vm.annotation.NullRestricted;
 32 
 33 
 34 /**
 35  * @test
 36  * @bug 8253416
 37  * @summary Test nestmate access to flattened field if nest-host is not loaded.
 38  * @library /test/lib
 39  * @enablePreview
 40  * @modules java.base/jdk.internal.value
 41  *          java.base/jdk.internal.vm.annotation
 42  * @run main/othervm -Xcomp
 43  *                   -XX:CompileCommand=compileonly,compiler.valhalla.inlinetypes.Test*::<init>
 44  *                   compiler.valhalla.inlinetypes.TestNestmateAccess
 45  * @run main/othervm -Xcomp -XX:TieredStopAtLevel=1
 46  *                   -XX:CompileCommand=compileonly,compiler.valhalla.inlinetypes.Test*::<init>
 47  *                   compiler.valhalla.inlinetypes.TestNestmateAccess
 48  * @run main/othervm compiler.valhalla.inlinetypes.TestNestmateAccess
 49  */
 50 
 51 interface MyInterface {
 52     int hash();
 53 }
 54 
 55 @ImplicitlyConstructible
 56 @LooselyConsistentValue
 57 value class MyValue implements MyInterface {
 58     int x = 42;
 59     int y = 43;
 60 
 61     @Override
 62     public int hash() { return x + y; }
 63 }
 64 
 65 // Test load from flattened field in nestmate when nest-host is not loaded.
 66 class Test1 {
 67     @NullRestricted
 68     private MyValue vt;
 69 
 70     public Test1(final MyValue vt) {
 71         this.vt = vt;
 72     }
 73 
 74     public MyInterface test() {
 75         return new MyInterface() {
 76             // The vt field load does not link.
 77             private int x = (Test1.this).vt.hash();
 78 
 79             @Override
 80             public int hash() { return x; }
 81         };
 82     }
 83 }
 84 
 85 // Same as Test1 but outer class is a value class
 86 @ImplicitlyConstructible
 87 @LooselyConsistentValue
 88 value class Test2 {
 89     @NullRestricted
 90     private MyValue vt;
 91 
 92     public Test2(final MyValue vt) {
 93         this.vt = vt;
 94     }
 95 
 96     public MyInterface test() {
 97         return new MyInterface() {
 98             // Delayed flattened load of Test2.this.
 99             // The vt field load does not link.
100             private int x = (Test2.this).vt.hash();
101 
102             @Override
103             public int hash() { return x; }
104         };
105     }
106 }
107 
108 // Test store to flattened field in nestmate when nest-host is not loaded.
109 class Test3 {
110     @NullRestricted
111     private MyValue vt;
112 
113     public MyInterface test(MyValue init) {
114         return new MyInterface() {
115             // Store to the vt field does not link.
116             private MyValue tmp = (vt = init);
117 
118             @Override
119             public int hash() { return tmp.hash() + vt.hash(); }
120         };
121     }
122 }
123 
124 // Same as Test1 but with static field
125 class Test4 {
126     @NullRestricted
127     private static MyValue vt;
128 
129     public Test4(final MyValue vt) {
130         this.vt = vt;
131     }
132 
133     public MyInterface test() {
134         return new MyInterface() {
135             // The vt field load does not link.
136             private int x = (Test4.this).vt.hash();
137 
138             @Override
139             public int hash() { return x; }
140         };
141     }
142 }
143 
144 // Same as Test2 but with static field
145 @ImplicitlyConstructible
146 @LooselyConsistentValue
147 value class Test5 {
148     @NullRestricted
149     private static MyValue vt;
150 
151     public Test5(final MyValue vt) {
152         this.vt = vt;
153     }
154 
155     public MyInterface test() {
156         return new MyInterface() {
157             // Delayed flattened load of Test5.this.
158             // The vt field load does not link.
159             private int x = (Test5.this).vt.hash();
160 
161             @Override
162             public int hash() { return x; }
163         };
164     }
165 }
166 
167 // Same as Test3 but with static field
168 class Test6 {
169     @NullRestricted
170     private static MyValue vt;
171 
172     public MyInterface test(MyValue init) {
173         return new MyInterface() {
174             // Store to the vt field does not link.
175             private MyValue tmp = (vt = init);
176 
177             @Override
178             public int hash() { return tmp.hash() + vt.hash(); }
179         };
180     }
181 }
182 
183 // Same as Test6 but outer class is a value class
184 @ImplicitlyConstructible
185 @LooselyConsistentValue
186 value class Test7 {
187     @NullRestricted
188     private static MyValue vt;
189 
190     public MyInterface test(MyValue init) {
191         return new MyInterface() {
192             // Store to the vt field does not link.
193             private MyValue tmp = (vt = init);
194 
195             @Override
196             public int hash() { return tmp.hash() + vt.hash(); }
197         };
198     }
199 }
200 
201 public class TestNestmateAccess {
202 
203     public static void main(String[] args) {
204         Test1 t1 = new Test1(new MyValue());
205         int res = t1.test().hash();
206         Asserts.assertEQ(res, 85);
207 
208         Test2 t2 = new Test2(new MyValue());
209         res = t2.test().hash();
210         Asserts.assertEQ(res, 85);
211 
212         Test3 t3 = new Test3();
213         res = t3.test(new MyValue()).hash();
214         Asserts.assertEQ(res, 170);
215 
216         Test4 t4 = new Test4(new MyValue());
217         res = t4.test().hash();
218         Asserts.assertEQ(res, 85);
219 
220         Test5 t5 = new Test5(new MyValue());
221         res = t5.test().hash();
222         Asserts.assertEQ(res, 85);
223 
224         Test6 t6 = new Test6();
225         res = t6.test(new MyValue()).hash();
226         Asserts.assertEQ(res, 170);
227 
228         Test7 t7 = new Test7();
229         res = t7.test(new MyValue()).hash();
230         Asserts.assertEQ(res, 170);
231     }
232 }