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 }