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 }