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             ClassLoader loader = clazz.getClassLoader();
  98             MethodHandles.Lookup lookup = MethodHandles.lookup();
  99 
 100             MethodType mt = MethodType.methodType(MyValue1.class);
 101             test9_mh = lookup.findStatic(clazz, "test9Callee", mt);
 102             test10_mh = lookup.findStatic(clazz, "test10Callee", mt);
 103         } catch (NoSuchMethodException | IllegalAccessException e) {
 104             e.printStackTrace();
 105             throw new RuntimeException("Method handle lookup failed");
 106         }
 107     }
 108 
 109     MyValue1 test1() {
 110         return new MyValue1();
 111     }
 112 
 113     static MyValue1 vtField1;
 114 
 115     MyValue1 test2() {
 116         vtField1 = new MyValue1();
 117         return vtField1;
 118     }
 119 
 120     int test3Callee(MyValue1 vt) {
 121         return vt.hash();
 122     }
 123 
 124     int test3() {
 125         MyValue1 vt = new MyValue1();
 126         return test3Callee(vt);
 127     }
 128 
 129     static MyValue1[] vtArray = new MyValue1[1];
 130 
 131     MyValue1 test4() {
 132         vtArray[0] = new MyValue1();
 133         return vtArray[0];
 134     }
 135 
 136     Object test5(Object[] array) {
 137         array[0] = new MyValue1();
 138         return array[0];
 139     }
 140 
 141     boolean test6(Object obj) {
 142         MyValue1 vt = new MyValue1();
 143         return vt == obj;
 144     }
 145 
 146     Object test7(Object[] obj) {
 147         return obj[0];
 148     }
 149 
 150     MyValue1? test8(MyValue1?[] obj) {
 151         return obj[0];
 152     }
 153 
 154     static final MethodHandle test9_mh;
 155 
 156     static MyValue1 test9Callee() {
 157         return new MyValue1();
 158     }
 159 
 160     MyValue1 test9() throws Throwable {
 161         return (MyValue1)test9_mh.invokeExact();
 162     }
 163 
 164     static final MethodHandle test10_mh;
 165     static final MyValue1 test10Field = new MyValue1();
 166     static int test10Counter = 0;
 167 
 168     static MyValue1 test10Callee() {
 169         test10Counter++;
 170         return test10Field;
 171     }
 172 
 173     Object test10() throws Throwable {
 174         return test10_mh.invoke();
 175     }
 176 
 177     MyValue1 test11(MyValue1 vt) {
 178         return vt.testWithField(42);
 179     }
 180 
 181     MyValue1 vtField2;
 182 
 183     MyValue1 test12() {
 184         vtField2 = new MyValue1();
 185         return vtField2;
 186     }
 187 
 188     public static void main(String[] args) throws Throwable {
 189         MyValue1[] va = new MyValue1[3];
 190         va[0] = new MyValue1();
 191         Object[] oa = new Object[3];
 192         oa[0] = va[0];
 193         TestDeoptimizationWhenBuffering t = new TestDeoptimizationWhenBuffering();
 194         for (int i = 0; i < 100_000; ++i) {
 195             // Check counters to make sure that we don't accidentially reexecute calls when deoptimizing
 196             int expected = MyValue1.cnt + MyValue2.cnt + MyValue2.cnt;
 197             Asserts.assertEQ(t.test1().hash(), expected + 4);
 198             vtField1 = MyValue1.default;
 199             Asserts.assertEQ(t.test2().hash(), expected + 9);
 200             Asserts.assertEQ(vtField1.hash(), expected + 9);
 201             Asserts.assertEQ(t.test3(), expected + 14);
 202             Asserts.assertEQ(t.test4().hash(), expected + 19);
 203             Asserts.assertEQ(((MyValue1)t.test5(vtArray)).hash(), expected + 24);
 204             Asserts.assertEQ(t.test6(vtField1), false);
 205             Asserts.assertEQ(t.test7(((i % 2) == 0) ? va : oa), va[0]);
 206             Asserts.assertEQ(t.test8(va), va[0]);
 207             Asserts.assertEQ(t.test8(va), va[0]);
 208             Asserts.assertEQ(t.test9().hash(), expected + 34);
 209             int count = test10Counter;
 210             Asserts.assertEQ(((MyValue1)t.test10()).hash(), test10Field.hash());
 211             Asserts.assertEQ(t.test10Counter, count + 1);
 212             Asserts.assertEQ(t.test11(va[0]).hash(), va[0].testWithField(42).hash());
 213             t.vtField2 = MyValue1.default;
 214             Asserts.assertEQ(t.test12().hash(), expected + 39);
 215             Asserts.assertEQ(t.vtField2.hash(), expected + 39);
 216         }
 217     }
 218 }