1 /* 2 * Copyright (c) 2019, 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 import jdk.test.lib.Asserts; 31 32 import jdk.internal.value.ValueClass; 33 import jdk.internal.vm.annotation.LooselyConsistentValue; 34 import jdk.internal.vm.annotation.NullRestricted; 35 import jdk.internal.vm.annotation.Strict; 36 37 import static compiler.valhalla.inlinetypes.InlineTypes.rI; 38 import static compiler.valhalla.inlinetypes.InlineTypes.rL; 39 40 /* 41 * @test 42 * @key randomness 43 * @summary Various tests that are specific to C1. 44 * @library /test/lib / 45 * @requires (os.simpleArch == "x64" | os.simpleArch == "aarch64") 46 * @enablePreview 47 * @modules java.base/jdk.internal.value 48 * java.base/jdk.internal.vm.annotation 49 * @run main/othervm/timeout=300 compiler.valhalla.inlinetypes.TestC1 50 */ 51 52 public class TestC1 { 53 public static void main(String[] args) { 54 final Scenario[] scenarios = { 55 // C1 only 56 new Scenario(0, "-XX:TieredStopAtLevel=1", "-XX:+TieredCompilation"), 57 // C2 only. (Make sure the tests are correctly written) 58 new Scenario(1, "-XX:TieredStopAtLevel=4", "-XX:-TieredCompilation"), 59 // interpreter only 60 new Scenario(2, "-Xint"), 61 // Xcomp Only C1. 62 new Scenario(3, "-XX:TieredStopAtLevel=1", "-XX:+TieredCompilation", "-Xcomp"), 63 // Xcomp Only C2. 64 new Scenario(4, "-XX:TieredStopAtLevel=4", "-XX:-TieredCompilation", "-Xcomp") 65 }; 66 67 InlineTypes.getFramework() 68 .addScenarios(scenarios) 69 .addFlags("--enable-preview", 70 "--add-exports", "java.base/jdk.internal.vm.annotation=ALL-UNNAMED", 71 "--add-exports", "java.base/jdk.internal.value=ALL-UNNAMED") 72 .addHelperClasses(MyValue1.class, 73 MyValue2.class, 74 MyValue2Inline.class, 75 MyValue3.class, 76 MyValue3Inline.class) 77 .start(); 78 } 79 80 // JDK-8229799 81 @Test(compLevel = CompLevel.C1_SIMPLE) 82 public long test1(Object a, Object b, long n) { 83 long r; 84 n += (a == b) ? 0x5678123456781234L : 0x1234567812345678L; 85 n -= 1; 86 return n; 87 } 88 89 @Run(test = "test1") 90 public void test1_verifier() { 91 MyValue1 v1 = MyValue1.createWithFieldsInline(rI, rL); 92 MyValue1 v2 = MyValue1.createWithFieldsInline(rI, rL+1); 93 long r1 = test1(v1, v1, 1); 94 long r2 = test1(v1, v2, 1); 95 Asserts.assertEQ(r1, 0x5678123456781234L); 96 Asserts.assertEQ(r2, 0x1234567812345678L); 97 } 98 99 @LooselyConsistentValue 100 static value class SimpleValue2 { 101 int value; 102 103 SimpleValue2(int value) { 104 this.value = value; 105 } 106 } 107 108 // JDK-8231961 109 // Test that the value numbering optimization does not remove 110 // the second load from the buffered array element. 111 @Test(compLevel = CompLevel.C1_SIMPLE) 112 public int test2(SimpleValue2[] array) { 113 return array[0].value + array[0].value; 114 } 115 116 @Run(test = "test2") 117 public void test2_verifier() { 118 SimpleValue2[] array = (SimpleValue2[])ValueClass.newNullRestrictedNonAtomicArray(SimpleValue2.class, 1, new SimpleValue2(0)); 119 array[0] = new SimpleValue2(rI); 120 int result = test2(array); 121 Asserts.assertEQ(result, 2*rI); 122 } 123 124 125 // Tests below (3 to 8) check the behavior of the C1 optimization to access 126 // sub-elements of a flattened array without copying the element first 127 128 // Test access to a null array 129 @Test(compLevel = CompLevel.C1_SIMPLE) 130 public int test3(MyValue2[] array, int index) { 131 return array[index].x; 132 } 133 134 @Run(test = "test3") 135 public void test3_verifier() { 136 NullPointerException npe = null; 137 try { 138 test3(null, 0); 139 } catch(NullPointerException e) { 140 npe = e; 141 } 142 Asserts.assertNE(npe, null); 143 } 144 145 // Test out of bound accesses 146 @Test(compLevel = CompLevel.C1_SIMPLE) 147 public int test4(MyValue2[] array, int index) { 148 return array[index].x; 149 } 150 151 @Run(test = "test4") 152 public void test4_verifier() { 153 MyValue2[] array = new MyValue2[2]; 154 ArrayIndexOutOfBoundsException aioob = null; 155 try { 156 test3(array, -1); 157 } catch(ArrayIndexOutOfBoundsException e) { 158 aioob = e; 159 } 160 Asserts.assertNE(aioob, null); 161 aioob = null; 162 try { 163 test3(array, 2); 164 } catch(ArrayIndexOutOfBoundsException e) { 165 aioob = e; 166 } 167 Asserts.assertNE(aioob, null); 168 } 169 170 // Test 1st level sub-element access to primitive field 171 @Test(compLevel = CompLevel.C1_SIMPLE) 172 public int test5(MyValue2[] array, int index) { 173 return array[index].x; 174 } 175 176 @Run(test = "test5") 177 public void test5_verifier() { 178 MyValue2[] array = new MyValue2[2]; 179 MyValue2 v = new MyValue2(1,(byte)2, new MyValue2Inline(5.0d, 345L)); 180 array[1] = v; 181 int x = test5(array, 1); 182 Asserts.assertEQ(x, 1); 183 } 184 185 // Test 1st level sub-element access to flattened field 186 @Test(compLevel = CompLevel.C1_SIMPLE) 187 public MyValue2Inline test6(MyValue2[] array, int index) { 188 return array[index].v; 189 } 190 191 @Run(test = "test6") 192 public void test6_verifier() { 193 MyValue2[] array = new MyValue2[2]; 194 MyValue2Inline vi = new MyValue2Inline(3.5d, 678L); 195 MyValue2 v = new MyValue2(1,(byte)2, vi); 196 array[0] = v; 197 MyValue2Inline vi2 = test6(array, 0); 198 Asserts.assertEQ(vi, vi2); 199 } 200 201 // Test 1st level sub-element access to non-flattened field 202 @LooselyConsistentValue 203 static value class Big { 204 long l0,l1,l2,l3,l4,l5,l6,l7,l8,l9,l10,l11,l12,l13,l14,l15,l16,l17,l18,l19; 205 206 Big(long n) { 207 l0 = n++; l1 = n++; l2 = n++; l3 = n++; l4 = n++; l5 = n++; l6 = n++; l7 = n++; l8 = n++; 208 l9 = n++; l10 = n++; l11 = n++; l12 = n++; l13 = n++; l14 = n++; l15 = n++; l16= n++; 209 l17 = n++; l18 = n++; l19 = n++; 210 } 211 212 Big() { 213 l0 = l1 = l2 = l3 = l4 = l5 = l6 = l7 = l8 = l9 = l10 = 214 l11 = l12 = l13 = l14 = l15 = l16 = l17 = l18 = l19 = 0; 215 } 216 217 void check(long n, int i) { 218 Asserts.assertEQ(l0, n); n += i; 219 Asserts.assertEQ(l1, n); n += i; 220 Asserts.assertEQ(l2, n); n += i; 221 Asserts.assertEQ(l3, n); n += i; 222 Asserts.assertEQ(l4, n); n += i; 223 Asserts.assertEQ(l5, n); n += i; 224 Asserts.assertEQ(l6, n); n += i; 225 Asserts.assertEQ(l7, n); n += i; 226 Asserts.assertEQ(l8, n); n += i; 227 Asserts.assertEQ(l9, n); n += i; 228 Asserts.assertEQ(l10, n); n += i; 229 Asserts.assertEQ(l11, n); n += i; 230 Asserts.assertEQ(l12, n); n += i; 231 Asserts.assertEQ(l13, n); n += i; 232 Asserts.assertEQ(l14, n); n += i; 233 Asserts.assertEQ(l15, n); n += i; 234 Asserts.assertEQ(l16, n); n += i; 235 Asserts.assertEQ(l17, n); n += i; 236 Asserts.assertEQ(l18, n); n += i; 237 Asserts.assertEQ(l19, n); 238 } 239 } 240 241 @LooselyConsistentValue 242 static value class TestValue { 243 int i; 244 @Strict 245 @NullRestricted 246 Big big; 247 248 TestValue(int i, Big big) { 249 this.i = i; 250 this.big = big; 251 } 252 } 253 254 @Test(compLevel = CompLevel.C1_SIMPLE) 255 public Big test7(TestValue[] array, int index) { 256 return array[index].big; 257 } 258 259 @Run(test = "test7") 260 public void test7_verifier() { 261 TestValue[] array = (TestValue[])ValueClass.newNullRestrictedNonAtomicArray(TestValue.class, 7, new TestValue(0, new Big())); 262 Big b0 = test7(array, 3); 263 b0.check(0, 0); 264 TestValue tv = new TestValue(9, new Big(9)); 265 array[5] = tv; 266 Big b1 = test7(array, 5); 267 b1.check(9, 1); 268 } 269 270 // Test 2nd level sub-element access to primitive field 271 @Test(compLevel = CompLevel.C1_SIMPLE) 272 public byte test8(MyValue1[] array, int index) { 273 return array[index].v2.y; 274 } 275 276 @Run(test = "test8") 277 public void test8_verifier() { 278 MyValue1[] array = new MyValue1[23]; 279 MyValue2 mv2a = MyValue2.createWithFieldsInline(7, 63L, 8.9d); 280 MyValue2 mv2b = MyValue2.createWithFieldsInline(11, 69L, 17.3d); 281 MyValue1 mv1 = new MyValue1(1, 2L, (short)3, 4, null, mv2a, mv2b, mv2a, mv2b, 'z'); 282 array[19] = mv1; 283 byte b = test8(array, 19); 284 Asserts.assertEQ(b, (byte)11); 285 } 286 287 288 // Test optimizations for arrays of empty types 289 // (read/write are not performed, pre-allocated instance is used for reads) 290 // Most tests check that error conditions are still correctly handled 291 // (OOB, null pointer) 292 @LooselyConsistentValue 293 static value class EmptyType {} 294 295 @Test(compLevel = CompLevel.C1_SIMPLE) 296 public EmptyType test9() { 297 EmptyType[] array = (EmptyType[])ValueClass.newNullRestrictedNonAtomicArray(EmptyType.class, 10, new EmptyType()); 298 return array[4]; 299 } 300 301 @Run(test = "test9") 302 public void test9_verifier() { 303 EmptyType et = test9(); 304 Asserts.assertEQ(et, new EmptyType()); 305 } 306 307 @Test(compLevel = CompLevel.C1_SIMPLE) 308 public EmptyType test10(EmptyType[] array) { 309 return array[0]; 310 } 311 312 @Run(test = "test10") 313 public void test10_verifier() { 314 EmptyType[] array = (EmptyType[])ValueClass.newNullRestrictedNonAtomicArray(EmptyType.class, 16, new EmptyType()); 315 EmptyType et = test10(array); 316 Asserts.assertEQ(et, new EmptyType()); 317 } 318 319 @Test(compLevel = CompLevel.C1_SIMPLE) 320 public EmptyType test11(EmptyType[] array, int index) { 321 return array[index]; 322 } 323 324 @Run(test = "test11") 325 public void test11_verifier() { 326 Exception e = null; 327 EmptyType[] array = (EmptyType[])ValueClass.newNullRestrictedNonAtomicArray(EmptyType.class, 10, new EmptyType()); 328 try { 329 EmptyType et = test11(array, 11); 330 } catch (ArrayIndexOutOfBoundsException ex) { 331 e = ex; 332 } 333 Asserts.assertNotNull(e); 334 e = null; 335 try { 336 EmptyType et = test11(array, -1); 337 } catch (ArrayIndexOutOfBoundsException ex) { 338 e = ex; 339 } 340 Asserts.assertNotNull(e); 341 e = null; 342 try { 343 EmptyType et = test11(null, 1); 344 } catch (NullPointerException ex) { 345 e = ex; 346 } 347 Asserts.assertNotNull(e); 348 } 349 350 @Test(compLevel = CompLevel.C1_SIMPLE) 351 public void test12(EmptyType[] array, int index, EmptyType value) { 352 array[index] = value; 353 } 354 355 @Run(test = "test12") 356 public void test12_verifier() { 357 EmptyType empty = new EmptyType(); 358 EmptyType[] array = (EmptyType[])ValueClass.newNullRestrictedNonAtomicArray(EmptyType.class, 16, new EmptyType()); 359 test12(array, 2, empty); 360 Exception e = null; 361 try { 362 test12(null, 2, empty); 363 } catch(NullPointerException ex) { 364 e = ex; 365 } 366 Asserts.assertNotNull(e); 367 e = null; 368 try { 369 test12(array, 17, empty); 370 } catch(ArrayIndexOutOfBoundsException ex) { 371 e = ex; 372 } 373 Asserts.assertNotNull(e); 374 e = null; 375 try { 376 test12(array, -8, empty); 377 } catch(ArrayIndexOutOfBoundsException ex) { 378 e = ex; 379 } 380 Asserts.assertNotNull(e); 381 } 382 }