1 /* 2 * Copyright (c) 2019, 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 java.lang.invoke.*; 27 import java.lang.reflect.Method; 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 jdk.test.lib.Asserts; 35 36 import jdk.test.whitebox.WhiteBox; 37 38 /** 39 * @test TestDeoptimizationWhenBuffering 40 * @summary Test correct execution after deoptimizing from inline type specific runtime calls. 41 * @library /testlibrary /test/lib /compiler/whitebox / 42 * @enablePreview 43 * @modules java.base/jdk.internal.value 44 * java.base/jdk.internal.vm.annotation 45 * @build org.openjdk.asmtools.* org.openjdk.asmtools.jasm.* 46 * @build jdk.test.whitebox.WhiteBox 47 * @enablePreview 48 * @run driver jdk.test.lib.helpers.ClassFileInstaller jdk.test.whitebox.WhiteBox 49 * @run main/othervm -Xbootclasspath/a:. -XX:+IgnoreUnrecognizedVMOptions -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI 50 * -XX:+DeoptimizeALot -XX:CompileCommand=dontinline,compiler.valhalla.inlinetypes.*::test* 51 * compiler.valhalla.inlinetypes.TestDeoptimizationWhenBuffering C1 52 * @run main/othervm -Xbootclasspath/a:. -XX:+IgnoreUnrecognizedVMOptions -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI 53 * -XX:+DeoptimizeALot -XX:-UseTLAB -Xbatch 54 * compiler.valhalla.inlinetypes.TestDeoptimizationWhenBuffering 55 * @run main/othervm -Xbootclasspath/a:. -XX:+IgnoreUnrecognizedVMOptions -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI 56 * -XX:+DeoptimizeALot -XX:-UseTLAB -Xbatch -XX:-MonomorphicArrayCheck -XX:-AlwaysIncrementalInline 57 * -XX:-InlineTypePassFieldsAsArgs -XX:-InlineTypeReturnedAsFields -XX:FlatArrayElementMaxSize=1 58 * -XX:CompileCommand=dontinline,compiler.valhalla.inlinetypes.*::test* 59 * compiler.valhalla.inlinetypes.TestDeoptimizationWhenBuffering 60 * @run main/othervm -Xbootclasspath/a:. -XX:+IgnoreUnrecognizedVMOptions -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI 61 * -XX:+DeoptimizeALot -XX:-UseTLAB -Xbatch -XX:-MonomorphicArrayCheck -XX:+AlwaysIncrementalInline 62 * -XX:-InlineTypePassFieldsAsArgs -XX:-InlineTypeReturnedAsFields -XX:FlatArrayElementMaxSize=1 63 * -XX:CompileCommand=dontinline,compiler.valhalla.inlinetypes.*::test* 64 * compiler.valhalla.inlinetypes.TestDeoptimizationWhenBuffering 65 * @run main/othervm -Xbootclasspath/a:. -XX:+IgnoreUnrecognizedVMOptions -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI 66 * -XX:+DeoptimizeALot -XX:-UseTLAB -Xbatch -XX:-MonomorphicArrayCheck -XX:-AlwaysIncrementalInline 67 * -XX:+InlineTypePassFieldsAsArgs -XX:+InlineTypeReturnedAsFields -XX:FlatArrayElementMaxSize=-1 68 * -XX:CompileCommand=dontinline,compiler.valhalla.inlinetypes.*::test* 69 * compiler.valhalla.inlinetypes.TestDeoptimizationWhenBuffering 70 * @run main/othervm -Xbootclasspath/a:. -XX:+IgnoreUnrecognizedVMOptions -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI 71 * -XX:+DeoptimizeALot -XX:-UseTLAB -Xbatch -XX:-MonomorphicArrayCheck -XX:+AlwaysIncrementalInline 72 * -XX:+InlineTypePassFieldsAsArgs -XX:+InlineTypeReturnedAsFields -XX:FlatArrayElementMaxSize=-1 73 * -XX:CompileCommand=dontinline,compiler.valhalla.inlinetypes.*::test* 74 * compiler.valhalla.inlinetypes.TestDeoptimizationWhenBuffering 75 * @run main/othervm -Xbootclasspath/a:. -XX:+IgnoreUnrecognizedVMOptions -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI 76 * -XX:+DeoptimizeALot -XX:-UseTLAB -Xbatch -XX:-MonomorphicArrayCheck -XX:-AlwaysIncrementalInline 77 * -XX:+InlineTypePassFieldsAsArgs -XX:+InlineTypeReturnedAsFields -XX:FlatArrayElementMaxSize=-1 -XX:InlineFieldMaxFlatSize=0 78 * -XX:CompileCommand=dontinline,compiler.valhalla.inlinetypes.*::test* 79 * compiler.valhalla.inlinetypes.TestDeoptimizationWhenBuffering 80 * @run main/othervm -Xbootclasspath/a:. -XX:+IgnoreUnrecognizedVMOptions -XX:+UnlockDiagnosticVMOptions -XX:+WhiteBoxAPI 81 * -XX:+DeoptimizeALot -XX:-UseTLAB -Xbatch -XX:-MonomorphicArrayCheck -XX:+AlwaysIncrementalInline 82 * -XX:+InlineTypePassFieldsAsArgs -XX:+InlineTypeReturnedAsFields -XX:FlatArrayElementMaxSize=-1 -XX:InlineFieldMaxFlatSize=0 83 * -XX:CompileCommand=dontinline,compiler.valhalla.inlinetypes.*::test* 84 * compiler.valhalla.inlinetypes.TestDeoptimizationWhenBuffering 85 */ 86 87 public class TestDeoptimizationWhenBuffering { 88 static final WhiteBox WHITE_BOX = WhiteBox.getWhiteBox(); 89 static final int COMP_LEVEL_FULL_OPTIMIZATION = 4; // C2 or JVMCI 90 91 @ImplicitlyConstructible 92 @LooselyConsistentValue 93 static value class MyValue1 { 94 static int cnt = 0; 95 int x; 96 @NullRestricted 97 MyValue2 vtField1; 98 MyValue2 vtField2; 99 100 public MyValue1() { 101 cnt++; 102 x = cnt; 103 vtField1 = new MyValue2(); 104 vtField2 = new MyValue2(); 105 } 106 107 public MyValue1(int x, MyValue2 vtField1, MyValue2 vtField2) { 108 this.x = x; 109 this.vtField1 = vtField1; 110 this.vtField2 = vtField2; 111 } 112 113 public int hash() { 114 return x + vtField1.x + vtField2.x; 115 } 116 117 public MyValue1 testWithField(int x) { 118 return new MyValue1(x, vtField1, vtField2); 119 } 120 121 public static MyValue1 makeDefault() { 122 return new MyValue1(0, MyValue2.makeDefault(), null); 123 } 124 } 125 126 @ImplicitlyConstructible 127 @LooselyConsistentValue 128 static value class MyValue2 { 129 static int cnt = 0; 130 int x; 131 132 public MyValue2() { 133 cnt++; 134 x = cnt; 135 } 136 137 public MyValue2(int x) { 138 this.x = x; 139 } 140 141 public static MyValue2 makeDefault() { 142 return new MyValue2(0); 143 } 144 } 145 146 static { 147 try { 148 Class<?> clazz = TestDeoptimizationWhenBuffering.class; 149 MethodHandles.Lookup lookup = MethodHandles.lookup(); 150 151 MethodType mt = MethodType.methodType(MyValue1.class); 152 test9_mh = lookup.findStatic(clazz, "test9Callee", mt); 153 test10_mh = lookup.findStatic(clazz, "test10Callee", mt); 154 } catch (NoSuchMethodException | IllegalAccessException e) { 155 e.printStackTrace(); 156 throw new RuntimeException("Method handle lookup failed"); 157 } 158 } 159 160 MyValue1 test1() { 161 return new MyValue1(); 162 } 163 164 @NullRestricted 165 static MyValue1 vtField1; 166 167 MyValue1 test2() { 168 vtField1 = new MyValue1(); 169 return vtField1; 170 } 171 172 public int test3Callee(MyValue1 vt) { 173 return vt.hash(); 174 } 175 176 int test3() { 177 MyValue1 vt = new MyValue1(); 178 return test3Callee(vt); 179 } 180 181 static MyValue1[] vtArray = (MyValue1[])ValueClass.newNullRestrictedArray(MyValue1.class, 1); 182 183 MyValue1 test4() { 184 vtArray[0] = new MyValue1(); 185 return vtArray[0]; 186 } 187 188 Object test5(Object[] array) { 189 array[0] = new MyValue1(); 190 return array[0]; 191 } 192 193 boolean test6(Object obj) { 194 MyValue1 vt = new MyValue1(); 195 return vt == obj; 196 } 197 198 Object test7(Object[] obj) { 199 return obj[0]; 200 } 201 202 MyValue1 test8(MyValue1[] obj) { 203 return obj[0]; 204 } 205 206 static final MethodHandle test9_mh; 207 208 public static MyValue1 test9Callee() { 209 return new MyValue1(); 210 } 211 212 MyValue1 test9() throws Throwable { 213 return (MyValue1)test9_mh.invokeExact(); 214 } 215 216 static final MethodHandle test10_mh; 217 @NullRestricted 218 static final MyValue1 test10Field = new MyValue1(); 219 static int test10Counter = 0; 220 221 public static MyValue1 test10Callee() { 222 test10Counter++; 223 return test10Field; 224 } 225 226 Object test10() throws Throwable { 227 return test10_mh.invoke(); 228 } 229 230 MyValue1 test11(MyValue1 vt) { 231 return vt.testWithField(42); 232 } 233 234 MyValue1 vtField2; 235 236 MyValue1 test12() { 237 vtField2 = new MyValue1(); 238 return vtField2; 239 } 240 241 public static void main(String[] args) throws Throwable { 242 // TODO 8325106 Fix and re-enable 243 /* 244 if (args.length > 0) { 245 // Compile callees with C1 only, to exercise deoptimization while buffering at method entry 246 Asserts.assertEQ(args[0], "C1", "unsupported mode"); 247 Method m = MyValue1.class.getMethod("testWithField", int.class); 248 WHITE_BOX.makeMethodNotCompilable(m, COMP_LEVEL_FULL_OPTIMIZATION, false); 249 m = TestDeoptimizationWhenBuffering.class.getMethod("test3Callee", MyValue1.class); 250 WHITE_BOX.makeMethodNotCompilable(m, COMP_LEVEL_FULL_OPTIMIZATION, false); 251 m = TestDeoptimizationWhenBuffering.class.getMethod("test9Callee"); 252 WHITE_BOX.makeMethodNotCompilable(m, COMP_LEVEL_FULL_OPTIMIZATION, false); 253 m = TestDeoptimizationWhenBuffering.class.getMethod("test10Callee"); 254 WHITE_BOX.makeMethodNotCompilable(m, COMP_LEVEL_FULL_OPTIMIZATION, false); 255 } 256 257 MyValue1[] va = (MyValue1[])ValueClass.newNullRestrictedArray(MyValue1.class, 3); 258 va[0] = new MyValue1(); 259 Object[] oa = new Object[3]; 260 oa[0] = va[0]; 261 TestDeoptimizationWhenBuffering t = new TestDeoptimizationWhenBuffering(); 262 for (int i = 0; i < 100_000; ++i) { 263 // Check counters to make sure that we don't accidentially reexecute calls when deoptimizing 264 int expected = MyValue1.cnt + MyValue2.cnt + MyValue2.cnt; 265 Asserts.assertEQ(t.test1().hash(), expected + 4); 266 vtField1 = MyValue1.makeDefault(); 267 Asserts.assertEQ(t.test2().hash(), expected + 9); 268 Asserts.assertEQ(vtField1.hash(), expected + 9); 269 Asserts.assertEQ(t.test3(), expected + 14); 270 Asserts.assertEQ(t.test4().hash(), expected + 19); 271 Asserts.assertEQ(((MyValue1)t.test5(vtArray)).hash(), expected + 24); 272 Asserts.assertEQ(t.test6(vtField1), false); 273 Asserts.assertEQ(t.test7(((i % 2) == 0) ? va : oa), va[0]); 274 Asserts.assertEQ(t.test8(va), va[0]); 275 Asserts.assertEQ(t.test8(va), va[0]); 276 Asserts.assertEQ(t.test9().hash(), expected + 34); 277 int count = test10Counter; 278 Asserts.assertEQ(((MyValue1)t.test10()).hash(), test10Field.hash()); 279 Asserts.assertEQ(t.test10Counter, count + 1); 280 Asserts.assertEQ(t.test11(va[0]).hash(), va[0].testWithField(42).hash()); 281 t.vtField2 = MyValue1.makeDefault(); 282 Asserts.assertEQ(t.test12().hash(), expected + 39); 283 Asserts.assertEQ(t.vtField2.hash(), expected + 39); 284 } 285 */ 286 } 287 }