1 /*
   2  * Copyright (c) 2017, 2018, 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 jdk.test.lib.Asserts;
  27 
  28 import java.lang.reflect.Method;
  29 
  30 /*
  31  * @test
  32  * @summary Test value type calling convention optimizations
  33  * @library /testlibrary /test/lib /compiler/whitebox /
  34  * @requires os.simpleArch == "x64"
  35  * @compile -XDenableValueTypes -XDallowWithFieldOperator -XDallowFlattenabilityModifiers TestCallingConvention.java
  36  * @run driver ClassFileInstaller sun.hotspot.WhiteBox jdk.test.lib.Platform
  37  * @run main/othervm/timeout=120 -Xbootclasspath/a:. -ea -XX:+IgnoreUnrecognizedVMOptions -XX:+UnlockDiagnosticVMOptions
  38  *                               -XX:+UnlockExperimentalVMOptions -XX:+WhiteBoxAPI -XX:+EnableValhalla
  39  *                               compiler.valhalla.valuetypes.ValueTypeTest
  40  *                               compiler.valhalla.valuetypes.TestCallingConvention
  41  */
  42 public class TestCallingConvention extends ValueTypeTest {
  43     // Extra VM parameters for some test scenarios. See ValueTypeTest.getVMParameters()
  44     @Override
  45     public String[] getExtraVMParameters(int scenario) {
  46         switch (scenario) {
  47         case 3: return new String[] {"-XX:-ValueArrayFlatten"};
  48         }
  49         return null;
  50     }
  51 
  52    public static void main(String[] args) throws Throwable {
  53        TestCallingConvention test = new TestCallingConvention();
  54        test.run(args, MyValue1.class, MyValue2.class, MyValue2Inline.class, MyValue4.class);
  55    }
  56 
  57    // Test interpreter to compiled code with various signatures
  58    @Test(failOn = ALLOC + STORE + TRAP)
  59    public long test1(MyValue2 v) {
  60        return v.hash();
  61    }
  62 
  63    @DontCompile
  64    public void test1_verifier(boolean warmup) {
  65        MyValue2 v = MyValue2.createWithFieldsInline(rI, true);
  66        long result = test1(v);
  67        Asserts.assertEQ(result, v.hashInterpreted());
  68    }
  69 
  70    @Test(failOn = ALLOC + STORE + TRAP)
  71    public long test2(int i1, MyValue2 v, int i2) {
  72        return v.hash() + i1 - i2;
  73    }
  74 
  75    @DontCompile
  76    public void test2_verifier(boolean warmup) {
  77        MyValue2 v = MyValue2.createWithFieldsInline(rI, true);
  78        long result = test2(rI, v, 2*rI);
  79        Asserts.assertEQ(result, v.hashInterpreted() - rI);
  80    }
  81 
  82    @Test(failOn = ALLOC + STORE + TRAP)
  83    public long test3(long l1, MyValue2 v, long l2) {
  84        return v.hash() + l1 - l2;
  85    }
  86 
  87    @DontCompile
  88    public void test3_verifier(boolean warmup) {
  89        MyValue2 v = MyValue2.createWithFieldsInline(rI, true);
  90        long result = test3(rL, v, 2*rL);
  91        Asserts.assertEQ(result, v.hashInterpreted() - rL);
  92    }
  93 
  94    @Test(failOn = ALLOC + STORE + TRAP)
  95    public long test4(int i, MyValue2 v, long l) {
  96        return v.hash() + i + l;
  97    }
  98 
  99    @DontCompile
 100    public void test4_verifier(boolean warmup) {
 101        MyValue2 v = MyValue2.createWithFieldsInline(rI, true);
 102        long result = test4(rI, v, rL);
 103        Asserts.assertEQ(result, v.hashInterpreted() + rL + rI);
 104    }
 105 
 106    @Test(failOn = ALLOC + STORE + TRAP)
 107    public long test5(long l, MyValue2 v, int i) {
 108        return v.hash() + i + l;
 109    }
 110 
 111    @DontCompile
 112    public void test5_verifier(boolean warmup) {
 113        MyValue2 v = MyValue2.createWithFieldsInline(rI, true);
 114        long result = test5(rL, v, rI);
 115        Asserts.assertEQ(result, v.hashInterpreted() + rL + rI);
 116    }
 117 
 118    @Test(failOn = ALLOC + STORE + TRAP)
 119    public long test6(long l, MyValue1 v1, int i, MyValue2 v2) {
 120        return v1.hash() + i + l + v2.hash();
 121    }
 122 
 123    @DontCompile
 124    public void test6_verifier(boolean warmup) {
 125        MyValue1 v1 = MyValue1.createWithFieldsDontInline(rI, rL);
 126        MyValue2 v2 = MyValue2.createWithFieldsInline(rI, true);
 127        long result = test6(rL, v1, rI, v2);
 128        Asserts.assertEQ(result, v1.hashInterpreted() + rL + rI + v2.hashInterpreted());
 129    }
 130 
 131    // Test compiled code to interpreter with various signatures
 132    @DontCompile
 133    public long test7_interp(MyValue2 v) {
 134        return v.hash();
 135    }
 136 
 137    @Test(failOn = ALLOC + STORE + TRAP)
 138    public long test7(MyValue2 v) {
 139        return test7_interp(v);
 140    }
 141 
 142    @DontCompile
 143    public void test7_verifier(boolean warmup) {
 144        MyValue2 v = MyValue2.createWithFieldsInline(rI, true);
 145        long result = test7(v);
 146        Asserts.assertEQ(result, v.hashInterpreted());
 147    }
 148 
 149    @DontCompile
 150    public long test8_interp(int i1, MyValue2 v, int i2) {
 151        return v.hash() + i1 - i2;
 152    }
 153 
 154    @Test(failOn = ALLOC + STORE + TRAP)
 155    public long test8(int i1, MyValue2 v, int i2) {
 156        return test8_interp(i1, v, i2);
 157    }
 158 
 159    @DontCompile
 160    public void test8_verifier(boolean warmup) {
 161        MyValue2 v = MyValue2.createWithFieldsInline(rI, true);
 162        long result = test8(rI, v, 2*rI);
 163        Asserts.assertEQ(result, v.hashInterpreted() - rI);
 164    }
 165 
 166    @DontCompile
 167    public long test9_interp(long l1, MyValue2 v, long l2) {
 168        return v.hash() + l1 - l2;
 169    }
 170 
 171    @Test(failOn = ALLOC + STORE + TRAP)
 172    public long test9(long l1, MyValue2 v, long l2) {
 173        return test9_interp(l1, v, l2);
 174    }
 175 
 176    @DontCompile
 177    public void test9_verifier(boolean warmup) {
 178        MyValue2 v = MyValue2.createWithFieldsInline(rI, true);
 179        long result = test9(rL, v, 2*rL);
 180        Asserts.assertEQ(result, v.hashInterpreted() - rL);
 181    }
 182 
 183    @DontCompile
 184    public long test10_interp(int i, MyValue2 v, long l) {
 185        return v.hash() + i + l;
 186    }
 187 
 188    @Test(failOn = ALLOC + STORE + TRAP)
 189    public long test10(int i, MyValue2 v, long l) {
 190        return test10_interp(i, v, l);
 191    }
 192 
 193    @DontCompile
 194    public void test10_verifier(boolean warmup) {
 195        MyValue2 v = MyValue2.createWithFieldsInline(rI, true);
 196        long result = test10(rI, v, rL);
 197        Asserts.assertEQ(result, v.hashInterpreted() + rL + rI);
 198    }
 199 
 200    @DontCompile
 201    public long test11_interp(long l, MyValue2 v, int i) {
 202        return v.hash() + i + l;
 203    }
 204 
 205    @Test(failOn = ALLOC + STORE + TRAP)
 206    public long test11(long l, MyValue2 v, int i) {
 207        return test11_interp(l, v, i);
 208    }
 209 
 210    @DontCompile
 211    public void test11_verifier(boolean warmup) {
 212        MyValue2 v = MyValue2.createWithFieldsInline(rI, true);
 213        long result = test11(rL, v, rI);
 214        Asserts.assertEQ(result, v.hashInterpreted() + rL + rI);
 215    }
 216 
 217    @DontCompile
 218    public long test12_interp(long l, MyValue1 v1, int i, MyValue2 v2) {
 219        return v1.hash() + i + l + v2.hash();
 220    }
 221 
 222    @Test(failOn = ALLOC + STORE + TRAP)
 223    public long test12(long l, MyValue1 v1, int i, MyValue2 v2) {
 224        return test12_interp(l, v1, i, v2);
 225    }
 226 
 227    @DontCompile
 228    public void test12_verifier(boolean warmup) {
 229        MyValue1 v1 = MyValue1.createWithFieldsDontInline(rI, rL);
 230        MyValue2 v2 = MyValue2.createWithFieldsInline(rI, true);
 231        long result = test12(rL, v1, rI, v2);
 232        Asserts.assertEQ(result, v1.hashInterpreted() + rL + rI + v2.hashInterpreted());
 233    }
 234 
 235    // Test that debug info at a call is correct
 236    @DontCompile
 237    public long test13_interp(MyValue2 v, MyValue1[] va, boolean deopt) {
 238        if (deopt) {
 239            // uncommon trap
 240            WHITE_BOX.deoptimizeMethod(tests.get(getClass().getSimpleName() + "::test13"));
 241        }
 242        return v.hash() + va[0].hash() + va[1].hash();
 243    }
 244 
 245    @Test(failOn = ALLOC + STORE + TRAP)
 246    public long test13(MyValue2 v, MyValue1[] va, boolean flag, long l) {
 247        return test13_interp(v, va, flag) + l;
 248    }
 249 
 250    @DontCompile
 251    public void test13_verifier(boolean warmup) {
 252        MyValue2 v = MyValue2.createWithFieldsInline(rI, true);
 253        MyValue1[] va = new MyValue1[2];
 254        va[0] = MyValue1.createWithFieldsDontInline(rI, rL);
 255        va[1] = MyValue1.createWithFieldsDontInline(rI, rL);
 256        long result = test13(v, va, !warmup, rL);
 257        Asserts.assertEQ(result, v.hashInterpreted() + va[0].hash() + va[1].hash() + rL);
 258    }
 259 
 260    // Test deoptimization at call return with return value in registers
 261    @DontCompile
 262    public MyValue2 test14_interp(boolean deopt) {
 263        if (deopt) {
 264            // uncommon trap
 265            WHITE_BOX.deoptimizeMethod(tests.get(getClass().getSimpleName() + "::test14"));
 266        }
 267        return MyValue2.createWithFieldsInline(rI, true);
 268    }
 269 
 270    @Test()
 271    public MyValue2 test14(boolean flag) {
 272        return test14_interp(flag);
 273    }
 274 
 275    @DontCompile
 276    public void test14_verifier(boolean warmup) {
 277        MyValue2 result = test14(!warmup);
 278        MyValue2 v = MyValue2.createWithFieldsInline(rI, true);
 279        Asserts.assertEQ(result.hash(), v.hash());
 280    }
 281 
 282    // Return value types in registers from interpreter -> compiled
 283    final MyValue3 test15_vt = MyValue3.create();
 284    @DontCompile
 285    public MyValue3 test15_interp() {
 286        return test15_vt;
 287    }
 288 
 289    MyValue3 test15_vt2;
 290    @Test(valid = ValueTypeReturnedAsFieldsOn, failOn = ALLOC + LOAD + TRAP)
 291    @Test(valid = ValueTypeReturnedAsFieldsOff)
 292    public void test15() {
 293        test15_vt2 = test15_interp();
 294    }
 295 
 296    @DontCompile
 297    public void test15_verifier(boolean warmup) {
 298        test15();
 299        test15_vt.verify(test15_vt2);
 300    }
 301 
 302    // Return value types in registers from compiled -> interpreter
 303    final MyValue3 test16_vt = MyValue3.create();
 304    @Test(valid = ValueTypeReturnedAsFieldsOn, failOn = ALLOC + STORE + TRAP)
 305    @Test(valid = ValueTypeReturnedAsFieldsOff)
 306    public MyValue3 test16() {
 307        return test16_vt;
 308    }
 309 
 310    @DontCompile
 311    public void test16_verifier(boolean warmup) {
 312        MyValue3 vt = test16();
 313        test16_vt.verify(vt);
 314    }
 315 
 316    // Return value types in registers from compiled -> compiled
 317    final MyValue3 test17_vt = MyValue3.create();
 318    @DontInline
 319    public MyValue3 test17_comp() {
 320        return test17_vt;
 321    }
 322 
 323    MyValue3 test17_vt2;
 324    @Test(valid = ValueTypeReturnedAsFieldsOn, failOn = ALLOC + LOAD + TRAP)
 325    @Test(valid = ValueTypeReturnedAsFieldsOff)
 326    public void test17() {
 327        test17_vt2 = test17_comp();
 328    }
 329 
 330    @DontCompile
 331    public void test17_verifier(boolean warmup) throws Exception {
 332        Method helper_m = getClass().getDeclaredMethod("test17_comp");
 333        if (!warmup && USE_COMPILER && !WHITE_BOX.isMethodCompiled(helper_m, false)) {
 334            WHITE_BOX.enqueueMethodForCompilation(helper_m, COMP_LEVEL_FULL_OPTIMIZATION);
 335            Asserts.assertTrue(WHITE_BOX.isMethodCompiled(helper_m, false), "test17_comp not compiled");
 336        }
 337        test17();
 338        test17_vt.verify(test17_vt2);
 339    }
 340 
 341    // Same tests as above but with a value type that cannot be returned in registers
 342 
 343    // Return value types in registers from interpreter -> compiled
 344    final MyValue4 test18_vt = MyValue4.create();
 345    @DontCompile
 346    public MyValue4 test18_interp() {
 347        return test18_vt;
 348    }
 349 
 350    MyValue4 test18_vt2;
 351    @Test
 352    public void test18() {
 353        test18_vt2 = test18_interp();
 354    }
 355 
 356    @DontCompile
 357    public void test18_verifier(boolean warmup) {
 358        test18();
 359        test18_vt.verify(test18_vt2);
 360    }
 361 
 362    // Return value types in registers from compiled -> interpreter
 363    final MyValue4 test19_vt = MyValue4.create();
 364    @Test
 365    public MyValue4 test19() {
 366        return test19_vt;
 367    }
 368 
 369    @DontCompile
 370    public void test19_verifier(boolean warmup) {
 371        MyValue4 vt = test19();
 372        test19_vt.verify(vt);
 373    }
 374 
 375    // Return value types in registers from compiled -> compiled
 376    final MyValue4 test20_vt = MyValue4.create();
 377    @DontInline
 378    public MyValue4 test20_comp() {
 379        return test20_vt;
 380    }
 381 
 382    MyValue4 test20_vt2;
 383    @Test
 384    public void test20() {
 385        test20_vt2 = test20_comp();
 386    }
 387 
 388    @DontCompile
 389    public void test20_verifier(boolean warmup) throws Exception {
 390        Method helper_m = getClass().getDeclaredMethod("test20_comp");
 391        if (!warmup && USE_COMPILER && !WHITE_BOX.isMethodCompiled(helper_m, false)) {
 392            WHITE_BOX.enqueueMethodForCompilation(helper_m, COMP_LEVEL_FULL_OPTIMIZATION);
 393            Asserts.assertTrue(WHITE_BOX.isMethodCompiled(helper_m, false), "test20_comp not compiled");
 394        }
 395        test20();
 396        test20_vt.verify(test20_vt2);
 397    }
 398 
 399    // Test no result from inlined method for incremental inlining
 400    final MyValue3 test21_vt = MyValue3.create();
 401    public MyValue3 test21_inlined() {
 402        throw new RuntimeException();
 403    }
 404 
 405    @Test
 406    public MyValue3 test21() {
 407        try {
 408            return test21_inlined();
 409        } catch (RuntimeException ex) {
 410            return test21_vt;
 411        }
 412    }
 413 
 414    @DontCompile
 415    public void test21_verifier(boolean warmup) {
 416        MyValue3 vt = test21();
 417        test21_vt.verify(vt);
 418    }
 419 }