1 /* 2 * Copyright (c) 2017, 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.*; 27 import jdk.test.lib.Asserts; 28 29 import jdk.internal.value.ValueClass; 30 import jdk.internal.vm.annotation.ImplicitlyConstructible; 31 import jdk.internal.vm.annotation.LooselyConsistentValue; 32 import jdk.internal.vm.annotation.NullRestricted; 33 34 import static compiler.valhalla.inlinetypes.InlineTypeIRNode.*; 35 import static compiler.valhalla.inlinetypes.InlineTypes.rI; 36 import static compiler.valhalla.inlinetypes.InlineTypes.rL; 37 38 /* 39 * @test 40 * @key randomness 41 * @summary Test on stack replacement (OSR) with value classes. 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 * @run main/othervm/timeout=300 compiler.valhalla.inlinetypes.TestOnStackReplacement 48 */ 49 50 public class TestOnStackReplacement { 51 52 public static void main(String[] args) throws Throwable { 53 Scenario[] scenarios = InlineTypes.DEFAULT_SCENARIOS; 54 scenarios[3].addFlags("-XX:FlatArrayElementMaxSize=0"); 55 56 InlineTypes.getFramework() 57 .addScenarios(scenarios) 58 .addHelperClasses(MyValue1.class, 59 MyValue2.class, 60 MyValue2Inline.class, 61 MyValue3.class, 62 MyValue3Inline.class) 63 .start(); 64 } 65 66 // Helper methods 67 68 protected long hash() { 69 return hash(rI, rL); 70 } 71 72 protected long hash(int x, long y) { 73 return MyValue1.createWithFieldsInline(x, y).hash(); 74 } 75 76 // Test OSR compilation 77 @Test(compLevel = CompLevel.WAIT_FOR_COMPILATION) 78 public long test1() { 79 MyValue1 v = MyValue1.createWithFieldsInline(rI, rL); 80 MyValue1[] va = (MyValue1[])ValueClass.newNullRestrictedArray(MyValue1.class, Math.abs(rI) % 3); 81 for (int i = 0; i < va.length; ++i) { 82 va[i] = MyValue1.createWithFieldsInline(rI, rL); 83 } 84 long result = 0; 85 // Long loop to trigger OSR compilation 86 for (int i = 0; i < 50_000; ++i) { 87 // Reference local value object in interpreter state 88 result = v.hash(); 89 for (int j = 0; j < va.length; ++j) { 90 result += va[j].hash(); 91 } 92 } 93 return result; 94 } 95 96 @Run(test = "test1") 97 @Warmup(0) 98 public void test1_verifier() { 99 long result = test1(); 100 Asserts.assertEQ(result, ((Math.abs(rI) % 3) + 1) * hash()); 101 } 102 103 // Test loop peeling 104 @Test(compLevel = CompLevel.WAIT_FOR_COMPILATION) 105 @IR(failOn = {ALLOC, LOAD, STORE}) 106 public void test2() { 107 MyValue1 v = MyValue1.createWithFieldsInline(0, 1); 108 // Trigger OSR compilation and loop peeling 109 for (int i = 0; i < 50_000; ++i) { 110 if (v.x != i || v.y != i + 1) { 111 // Uncommon trap 112 throw new RuntimeException("test2 failed"); 113 } 114 v = MyValue1.createWithFieldsInline(i + 1, i + 2); 115 } 116 } 117 118 @Run(test = "test2") 119 @Warmup(0) 120 public void test2_verifier() { 121 test2(); 122 } 123 124 // TODO: Should be fixed with JDK-8327465. 125 // Test loop peeling and unrolling 126 //@Test(compLevel = CompLevel.WAIT_FOR_COMPILATION) 127 public void test3() { 128 MyValue1 v1 = MyValue1.createWithFieldsInline(0, 0); 129 MyValue1 v2 = MyValue1.createWithFieldsInline(1, 1); 130 // Trigger OSR compilation and loop peeling 131 for (int i = 0; i < 50_000; ++i) { 132 if (v1.x != 2*i || v2.x != i+1 || v2.y != i+1) { 133 // Uncommon trap 134 throw new RuntimeException("test3 failed"); 135 } 136 v1 = MyValue1.createWithFieldsInline(2*(i+1), 0); 137 v2 = MyValue1.createWithFieldsInline(i+2, i+2); 138 } 139 } 140 141 //@Run(test = "test3") 142 //@Warmup(0) 143 public void test3_verifier() { 144 test3(); 145 } 146 147 // OSR compilation with Object local 148 @DontCompile 149 public Object test4_init() { 150 return MyValue1.createWithFieldsInline(rI, rL); 151 } 152 153 @DontCompile 154 public Object test4_body() { 155 return MyValue1.createWithFieldsInline(rI, rL); 156 } 157 158 @Test(compLevel = CompLevel.WAIT_FOR_COMPILATION) 159 public Object test4() { 160 Object vt = test4_init(); 161 for (int i = 0; i < 50_000; i++) { 162 if (i % 2 == 1) { 163 vt = test4_body(); 164 } 165 } 166 return vt; 167 } 168 169 @Run(test = "test4") 170 @Warmup(0) 171 public void test4_verifier() { 172 test4(); 173 } 174 175 // OSR compilation with null value class local 176 177 MyValue1 nullField; 178 179 @Test(compLevel = CompLevel.WAIT_FOR_COMPILATION) 180 public void test5() { 181 MyValue1 vt = nullField; 182 for (int i = 0; i < 50_000; i++) { 183 if (vt != null) { 184 throw new RuntimeException("test5 failed: vt should be null"); 185 } 186 } 187 } 188 189 @Run(test = "test5") 190 @Warmup(0) 191 public void test5_verifier() { 192 test5(); 193 } 194 195 // Test OSR in method with value class receiver 196 @ImplicitlyConstructible 197 @LooselyConsistentValue 198 value class Test6Value { 199 public int f = 0; 200 201 public int test() { 202 int res = 0; 203 for (int i = 1; i < 20_000; ++i) { 204 res -= i; 205 } 206 return res; 207 } 208 } 209 210 @Test(compLevel = CompLevel.WAIT_FOR_COMPILATION) 211 public void test6() { 212 Test6Value tmp = new Test6Value(); 213 for (int i = 0; i < 100; ++i) { 214 tmp.test(); 215 } 216 } 217 218 @Run(test = "test6") 219 @Warmup(0) 220 public void test6_verifier() { 221 test6(); 222 } 223 224 // Similar to test6 but with more fields and reserved stack entry 225 @ImplicitlyConstructible 226 @LooselyConsistentValue 227 static value class Test7Value1 { 228 public int i1 = rI; 229 public int i2 = rI; 230 public int i3 = rI; 231 public int i4 = rI; 232 public int i5 = rI; 233 public int i6 = rI; 234 } 235 236 @ImplicitlyConstructible 237 @LooselyConsistentValue 238 static value class Test7Value2 { 239 public int i1 = rI; 240 public int i2 = rI; 241 public int i3 = rI; 242 public int i4 = rI; 243 public int i5 = rI; 244 public int i6 = rI; 245 public int i7 = rI; 246 public int i8 = rI; 247 public int i9 = rI; 248 public int i10 = rI; 249 public int i11 = rI; 250 public int i12 = rI; 251 public int i13 = rI; 252 public int i14 = rI; 253 public int i15 = rI; 254 public int i16 = rI; 255 public int i17 = rI; 256 public int i18 = rI; 257 public int i19 = rI; 258 public int i20 = rI; 259 public int i21 = rI; 260 261 @NullRestricted 262 public Test7Value1 vt = new Test7Value1(); 263 264 public int test(String[] args) { 265 int res = 0; 266 for (int i = 1; i < 20_000; ++i) { 267 res -= i; 268 } 269 return res; 270 } 271 } 272 273 @Test(compLevel = CompLevel.WAIT_FOR_COMPILATION) 274 public void test7() { 275 Test7Value2 tmp = new Test7Value2(); 276 for (int i = 0; i < 10; ++i) { 277 tmp.test(null); 278 } 279 } 280 281 @Run(test = "test7") 282 @Warmup(0) 283 public void test7_verifier() { 284 test7(); 285 } 286 287 // Test OSR with scalarized value class return 288 @NullRestricted 289 MyValue3 test8_vt; 290 291 @DontInline 292 public MyValue3 test8_callee(int len) { 293 test8_vt = MyValue3.create(); 294 int val = 0; 295 for (int i = 0; i < len; ++i) { 296 val = i; 297 } 298 test8_vt = test8_vt.setI(test8_vt, val); 299 return test8_vt; 300 } 301 302 @Test 303 public int test8(int start) { 304 MyValue3 vt = test8_callee(start); 305 test8_vt.verify(vt); 306 int result = 0; 307 for (int i = 0; i < 50_000; ++i) { 308 result += i; 309 } 310 return result; 311 } 312 313 @Run(test = "test8") 314 @Warmup(2) 315 public void test8_verifier() { 316 test8(1); 317 test8(50_000); 318 } 319 }