1 /* 2 * Copyright (c) 2019, 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.valuetypes; 25 26 import java.lang.invoke.*; 27 import java.lang.reflect.Method; 28 29 import jdk.test.lib.Asserts; 30 31 /** 32 * @test TestDeoptimizationWhenBuffering 33 * @summary Test correct execution after deoptimizing from inline type specific runtime calls. 34 * @library /testlibrary /test/lib /compiler/whitebox / 35 * @compile -XDallowWithFieldOperator TestDeoptimizationWhenBuffering.java 36 * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:+DeoptimizeALot -XX:-UseTLAB -Xbatch 37 * compiler.valhalla.valuetypes.TestDeoptimizationWhenBuffering 38 * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:+DeoptimizeALot -XX:-UseTLAB -Xbatch -XX:-MonomorphicArrayCheck -XX:-AlwaysIncrementalInline 39 * -XX:-ValueTypePassFieldsAsArgs -XX:-ValueTypeReturnedAsFields -XX:ValueArrayElemMaxFlatSize=1 40 * -XX:CompileCommand=dontinline,compiler.valhalla.valuetypes.*::test* 41 * compiler.valhalla.valuetypes.TestDeoptimizationWhenBuffering 42 * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:+DeoptimizeALot -XX:-UseTLAB -Xbatch -XX:-MonomorphicArrayCheck -XX:+AlwaysIncrementalInline 43 * -XX:-ValueTypePassFieldsAsArgs -XX:-ValueTypeReturnedAsFields -XX:ValueArrayElemMaxFlatSize=1 44 * -XX:CompileCommand=dontinline,compiler.valhalla.valuetypes.*::test* 45 * compiler.valhalla.valuetypes.TestDeoptimizationWhenBuffering 46 * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:+DeoptimizeALot -XX:-UseTLAB -Xbatch -XX:-MonomorphicArrayCheck -XX:-AlwaysIncrementalInline 47 * -XX:+ValueTypePassFieldsAsArgs -XX:+ValueTypeReturnedAsFields -XX:ValueArrayElemMaxFlatSize=-1 48 * -XX:CompileCommand=dontinline,compiler.valhalla.valuetypes.*::test* 49 * compiler.valhalla.valuetypes.TestDeoptimizationWhenBuffering 50 * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:+DeoptimizeALot -XX:-UseTLAB -Xbatch -XX:-MonomorphicArrayCheck -XX:+AlwaysIncrementalInline 51 * -XX:+ValueTypePassFieldsAsArgs -XX:+ValueTypeReturnedAsFields -XX:ValueArrayElemMaxFlatSize=-1 52 * -XX:CompileCommand=dontinline,compiler.valhalla.valuetypes.*::test* 53 * compiler.valhalla.valuetypes.TestDeoptimizationWhenBuffering 54 * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:+DeoptimizeALot -XX:-UseTLAB -Xbatch -XX:-MonomorphicArrayCheck -XX:-AlwaysIncrementalInline 55 * -XX:+ValueTypePassFieldsAsArgs -XX:+ValueTypeReturnedAsFields -XX:ValueArrayElemMaxFlatSize=-1 -XX:ValueFieldMaxFlatSize=0 56 * -XX:CompileCommand=dontinline,compiler.valhalla.valuetypes.*::test* 57 * compiler.valhalla.valuetypes.TestDeoptimizationWhenBuffering 58 * @run main/othervm -XX:+IgnoreUnrecognizedVMOptions -XX:+DeoptimizeALot -XX:-UseTLAB -Xbatch -XX:-MonomorphicArrayCheck -XX:+AlwaysIncrementalInline 59 * -XX:+ValueTypePassFieldsAsArgs -XX:+ValueTypeReturnedAsFields -XX:ValueArrayElemMaxFlatSize=-1 -XX:ValueFieldMaxFlatSize=0 60 * -XX:CompileCommand=dontinline,compiler.valhalla.valuetypes.*::test* 61 * compiler.valhalla.valuetypes.TestDeoptimizationWhenBuffering 62 */ 63 64 final inline class MyValue1 { 65 static int cnt = 0; 66 final int x; 67 final MyValue2 vtField1; 68 final MyValue2? vtField2; 69 70 public MyValue1() { 71 this.x = ++cnt; 72 this.vtField1 = new MyValue2(); 73 this.vtField2 = new MyValue2(); 74 } 75 76 public int hash() { 77 return x + vtField1.x + vtField2.x; 78 } 79 80 public MyValue1 testWithField(int x) { 81 return __WithField(this.x, x); 82 } 83 } 84 85 final inline class MyValue2 { 86 static int cnt = 0; 87 final int x; 88 public MyValue2() { 89 this.x = ++cnt; 90 } 91 } 92 93 public class TestDeoptimizationWhenBuffering { 94 static { 95 try { 96 Class<?> clazz = TestDeoptimizationWhenBuffering.class; 97 MethodHandles.Lookup lookup = MethodHandles.lookup(); 98 99 MethodType mt = MethodType.methodType(MyValue1.class); 100 test9_mh = lookup.findStatic(clazz, "test9Callee", mt); 101 test10_mh = lookup.findStatic(clazz, "test10Callee", mt); 102 } catch (NoSuchMethodException | IllegalAccessException e) { 103 e.printStackTrace(); 104 throw new RuntimeException("Method handle lookup failed"); 105 } 106 } 107 108 MyValue1 test1() { 109 return new MyValue1(); 110 } 111 112 static MyValue1 vtField1; 113 114 MyValue1 test2() { 115 vtField1 = new MyValue1(); 116 return vtField1; 117 } 118 119 int test3Callee(MyValue1 vt) { 120 return vt.hash(); 121 } 122 123 int test3() { 124 MyValue1 vt = new MyValue1(); 125 return test3Callee(vt); 126 } 127 128 static MyValue1[] vtArray = new MyValue1[1]; 129 130 MyValue1 test4() { 131 vtArray[0] = new MyValue1(); 132 return vtArray[0]; 133 } 134 135 Object test5(Object[] array) { 136 array[0] = new MyValue1(); 137 return array[0]; 138 } 139 140 boolean test6(Object obj) { 141 MyValue1 vt = new MyValue1(); 142 return vt == obj; 143 } 144 145 Object test7(Object[] obj) { 146 return obj[0]; 147 } 148 149 MyValue1? test8(MyValue1?[] obj) { 150 return obj[0]; 151 } 152 153 static final MethodHandle test9_mh; 154 155 static MyValue1 test9Callee() { 156 return new MyValue1(); 157 } 158 159 MyValue1 test9() throws Throwable { 160 return (MyValue1)test9_mh.invokeExact(); 161 } 162 163 static final MethodHandle test10_mh; 164 static final MyValue1 test10Field = new MyValue1(); 165 static int test10Counter = 0; 166 167 static MyValue1 test10Callee() { 168 test10Counter++; 169 return test10Field; 170 } 171 172 Object test10() throws Throwable { 173 return test10_mh.invoke(); 174 } 175 176 MyValue1 test11(MyValue1 vt) { 177 return vt.testWithField(42); 178 } 179 180 MyValue1 vtField2; 181 182 MyValue1 test12() { 183 vtField2 = new MyValue1(); 184 return vtField2; 185 } 186 187 public static void main(String[] args) throws Throwable { 188 MyValue1[] va = new MyValue1[3]; 189 va[0] = new MyValue1(); 190 Object[] oa = new Object[3]; 191 oa[0] = va[0]; 192 TestDeoptimizationWhenBuffering t = new TestDeoptimizationWhenBuffering(); 193 for (int i = 0; i < 100_000; ++i) { 194 // Check counters to make sure that we don't accidentially reexecute calls when deoptimizing 195 int expected = MyValue1.cnt + MyValue2.cnt + MyValue2.cnt; 196 Asserts.assertEQ(t.test1().hash(), expected + 4); 197 vtField1 = MyValue1.default; 198 Asserts.assertEQ(t.test2().hash(), expected + 9); 199 Asserts.assertEQ(vtField1.hash(), expected + 9); 200 Asserts.assertEQ(t.test3(), expected + 14); 201 Asserts.assertEQ(t.test4().hash(), expected + 19); 202 Asserts.assertEQ(((MyValue1)t.test5(vtArray)).hash(), expected + 24); 203 Asserts.assertEQ(t.test6(vtField1), false); 204 Asserts.assertEQ(t.test7(((i % 2) == 0) ? va : oa), va[0]); 205 Asserts.assertEQ(t.test8(va), va[0]); 206 Asserts.assertEQ(t.test8(va), va[0]); 207 Asserts.assertEQ(t.test9().hash(), expected + 34); 208 int count = test10Counter; 209 Asserts.assertEQ(((MyValue1)t.test10()).hash(), test10Field.hash()); 210 Asserts.assertEQ(t.test10Counter, count + 1); 211 Asserts.assertEQ(t.test11(va[0]).hash(), va[0].testWithField(42).hash()); 212 t.vtField2 = MyValue1.default; 213 Asserts.assertEQ(t.test12().hash(), expected + 39); 214 Asserts.assertEQ(t.vtField2.hash(), expected + 39); 215 } 216 } 217 }