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 compiler.lib.ir_framework.CompLevel;
 27 import compiler.lib.ir_framework.Run;
 28 import compiler.lib.ir_framework.Scenario;
 29 import compiler.lib.ir_framework.Test;
 30 
 31 import jdk.internal.value.ValueClass;
 32 import jdk.internal.vm.annotation.ImplicitlyConstructible;
 33 import jdk.internal.vm.annotation.LooselyConsistentValue;
 34 import jdk.internal.vm.annotation.NullRestricted;
 35 
 36 import jdk.test.lib.Asserts;
 37 
 38 /*
 39  * @test
 40  * @key randomness
 41  * @summary Verify that chains of getfields on flat fields are correctly optimized.
 42  * @library /test/lib /
 43  * @requires (os.simpleArch == "x64" | os.simpleArch == "aarch64")
 44  * @enablePreview
 45  * @modules java.base/jdk.internal.value
 46  *          java.base/jdk.internal.vm.annotation
 47  * @compile GetfieldChains.jcod
 48  * @run main/othervm/timeout=300 compiler.valhalla.inlinetypes.TestGetfieldChains
 49  */
 50 
 51 @ImplicitlyConstructible
 52 @LooselyConsistentValue
 53 value class Point {
 54     int x = 4;
 55     int y = 7;
 56 }
 57 
 58 @ImplicitlyConstructible
 59 @LooselyConsistentValue
 60 value class Rectangle {
 61     @NullRestricted
 62     Point p0 = new Point();
 63     @NullRestricted
 64     Point p1 = new Point();
 65 }
 66 
 67 class NamedRectangle {
 68     @NullRestricted
 69     Rectangle rect = new Rectangle();
 70     String name = "";
 71 
 72     static int getP1X(NamedRectangle nr) {
 73         return nr.rect
 74             .p1
 75             .x;
 76     }
 77 
 78     static Point getP1(NamedRectangle nr) {
 79         return nr.rect
 80             .p1;
 81     }
 82 }
 83 
 84 public class TestGetfieldChains {
 85 
 86     public static void main(String[] args) {
 87 
 88         final Scenario[] scenarios = {
 89                 new Scenario(0,
 90                         // C1 only
 91                         "-XX:TieredStopAtLevel=1",
 92                         "-XX:+TieredCompilation"),
 93                 new Scenario(1,
 94                         // C2 only. (Make sure the tests are correctly written)
 95                         "-XX:TieredStopAtLevel=4",
 96                         "-XX:-TieredCompilation",
 97                         "-XX:-OmitStackTraceInFastThrow"),
 98                 new Scenario(2,
 99                         // interpreter only
100                         "-Xint"),
101                 new Scenario(3,
102                         // Xcomp Only C1
103                         "-XX:TieredStopAtLevel=1",
104                         "-XX:+TieredCompilation",
105                         "-Xcomp"),
106                 new Scenario(4,
107                         // Xcomp Only C2
108                         "-XX:TieredStopAtLevel=4",
109                         "-XX:-TieredCompilation",
110                         "-XX:-OmitStackTraceInFastThrow",
111                         "-Xcomp")
112         };
113 
114         InlineTypes.getFramework()
115                    .addScenarios(scenarios)
116                    .addFlags("--enable-preview",
117                              "--add-exports", "java.base/jdk.internal.vm.annotation=ALL-UNNAMED",
118                              "--add-exports", "java.base/jdk.internal.value=ALL-UNNAMED")
119                    .start();
120     }
121 
122 
123     // Simple chain of getfields ending with value type field
124     @Test(compLevel = CompLevel.C1_SIMPLE)
125     public int test1() {
126         return NamedRectangle.getP1X(new NamedRectangle());
127     }
128 
129     @Run(test = "test1")
130     public void test1_verifier() {
131         int res = test1();
132         Asserts.assertEQ(res, 4);
133     }
134 
135     // Simple chain of getfields ending with a flat field
136     @Test(compLevel = CompLevel.C1_SIMPLE)
137     public Point test2() {
138         return NamedRectangle.getP1(new NamedRectangle());
139     }
140 
141     @Run(test = "test2")
142     public void test2_verifier() {
143         Point p = test2();
144         Asserts.assertEQ(p.x, 4);
145         Asserts.assertEQ(p.y, 7);
146     }
147 
148     // Chain of getfields but the initial receiver is null
149     @Test(compLevel = CompLevel.C1_SIMPLE)
150     public NullPointerException test3() {
151         NullPointerException npe = null;
152         try {
153             NamedRectangle.getP1X(null);
154             throw new RuntimeException("No NullPointerException thrown");
155         } catch (NullPointerException e) {
156             npe = e;
157         }
158         return npe;
159     }
160 
161     @Run(test = "test3")
162     public void test3_verifier() {
163         NullPointerException npe = test3();
164         Asserts.assertNE(npe, null);
165         StackTraceElement st = npe.getStackTrace()[0];
166         Asserts.assertEQ(st.getMethodName(), "getP1X");
167     }
168 
169     // Chain of getfields but one getfield in the middle of the chain triggers an illegal access
170     @Test(compLevel = CompLevel.C1_SIMPLE)
171     public IllegalAccessError test4() {
172         IllegalAccessError iae = null;
173         try {
174             int i = NamedRectangleP.getP1Y(new NamedRectangleP());
175             throw new RuntimeException("No IllegalAccessError thrown");
176         } catch (IllegalAccessError e) {
177             iae = e;
178         }
179         return iae;
180     }
181 
182     @Run(test = "test4")
183     public void test4_verifier() {
184         IllegalAccessError iae = test4();
185         Asserts.assertNE(iae, null);
186         StackTraceElement st = iae.getStackTrace()[0];
187         Asserts.assertEQ(st.getMethodName(), "getP1Y");
188         Asserts.assertTrue(iae.getMessage().contains("class compiler.valhalla.inlinetypes.NamedRectangleP tried to access private field compiler.valhalla.inlinetypes.RectangleP.p1"));
189     }
190 
191     // Chain of getfields but the last getfield triggers a NoSuchFieldError
192     @Test(compLevel = CompLevel.C1_SIMPLE)
193     public NoSuchFieldError test5() {
194         NoSuchFieldError nsfe = null;
195         try {
196             int i = NamedRectangleN.getP1X(new NamedRectangleN());
197             throw new RuntimeException("No NoSuchFieldError thrown");
198         } catch (NoSuchFieldError e) {
199             nsfe = e;
200         }
201         return nsfe;
202     }
203 
204     @Run(test = "test5")
205     public void test5_verifier() {
206         NoSuchFieldError nsfe = test5();
207         Asserts.assertNE(nsfe, null);
208         StackTraceElement st = nsfe.getStackTrace()[0];
209         Asserts.assertEQ(st.getMethodName(), "getP1X");
210         Asserts.assertEQ(nsfe.getMessage(), "Class compiler.valhalla.inlinetypes.PointN does not have member field 'int x'");
211     }
212 
213     @ImplicitlyConstructible
214     @LooselyConsistentValue
215     static value class EmptyType1 { }
216 
217     @ImplicitlyConstructible
218     @LooselyConsistentValue
219     static value class EmptyContainer1 {
220         int i = 0;
221         @NullRestricted
222         EmptyType1 et = new EmptyType1();
223     }
224 
225     @ImplicitlyConstructible
226     @LooselyConsistentValue
227     static value class Container1 {
228         @NullRestricted
229         EmptyContainer1 container0 = new EmptyContainer1();
230         @NullRestricted
231         EmptyContainer1 container1 = new EmptyContainer1();
232     }
233 
234     @Test(compLevel = CompLevel.C1_SIMPLE)
235     public EmptyType1 test6() {
236         Container1 c = new Container1();
237         return c.container1.et;
238     }
239 
240     @Run(test = "test6")
241     public void test6_verifier() {
242         EmptyType1 et = test6();
243         Asserts.assertEQ(et, new EmptyType1());
244     }
245 
246     @Test(compLevel = CompLevel.C1_SIMPLE)
247     public EmptyType1 test7() {
248         Container1[] ca = (Container1[])ValueClass.newNullRestrictedArray(Container1.class, 10);
249         return ca[3].container0.et;
250     }
251 
252     @Run(test = "test7")
253     public void test7_verifier() {
254         EmptyType1 et = test7();
255         Asserts.assertEQ(et, new EmptyType1());
256     }
257 
258     // Same as test6/test7 but not null-free and EmptyContainer2 with only one field
259 
260     static value class EmptyType2 { }
261 
262     static value class EmptyContainer2 {
263         EmptyType2 et = null;
264     }
265 
266     static value class Container2 {
267         EmptyContainer2 container0 = new EmptyContainer2();
268         EmptyContainer2 container1 = new EmptyContainer2();
269     }
270 
271     @Test(compLevel = CompLevel.C1_SIMPLE)
272     public EmptyType2 test8() {
273         Container2 c = new Container2();
274         return c.container1.et;
275     }
276 
277     @Run(test = "test8")
278     public void test8_verifier() {
279         EmptyType2 et = test8();
280         Asserts.assertEQ(et, null);
281     }
282 
283     @Test(compLevel = CompLevel.C1_SIMPLE)
284     public EmptyType2 test9() {
285         Container2[] ca = new Container2[10];
286         ca[3] = new Container2();
287         return ca[3].container0.et;
288     }
289 
290     @Run(test = "test9")
291     public void test9_verifier() {
292         EmptyType2 et = test9();
293         Asserts.assertEQ(et, null);
294     }
295 }