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