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 compiler.lib.ir_framework.*;
  27 import jdk.test.lib.Asserts;
  28 import jdk.test.whitebox.WhiteBox;
  29 
  30 import java.lang.reflect.Method;
  31 
  32 import jdk.internal.value.ValueClass;
  33 import jdk.internal.vm.annotation.ImplicitlyConstructible;
  34 import jdk.internal.vm.annotation.LooselyConsistentValue;
  35 import jdk.internal.vm.annotation.NullRestricted;
  36 
  37 import static compiler.valhalla.inlinetypes.InlineTypeIRNode.*;
  38 import static compiler.valhalla.inlinetypes.InlineTypes.*;
  39 
  40 /*
  41  * @test
  42  * @key randomness
  43  * @summary Test value class specific type profiling.
  44  * @library /test/lib /
  45  * @requires (os.simpleArch == "x64" | os.simpleArch == "aarch64")
  46  * @enablePreview
  47  * @modules java.base/jdk.internal.value
  48  *          java.base/jdk.internal.vm.annotation
  49  * @run main/othervm/timeout=300 compiler.valhalla.inlinetypes.TestLWorldProfiling
  50  */
  51 
  52 @ForceCompileClassInitializer
  53 public class TestLWorldProfiling {
  54 
  55     public static void main(String[] args) {
  56         final Scenario[] scenarios = {
  57                 new Scenario(0,
  58                         "-XX:FlatArrayElementMaxSize=-1",
  59                         "-XX:-UseArrayLoadStoreProfile",
  60                         "-XX:-UseACmpProfile",
  61                         "-XX:TypeProfileLevel=0",
  62                         "-XX:-MonomorphicArrayCheck"),
  63                 new Scenario(1,
  64                         "-XX:FlatArrayElementMaxSize=-1",
  65                         "-XX:+UseArrayLoadStoreProfile",
  66                         "-XX:+UseACmpProfile",
  67                         "-XX:TypeProfileLevel=0"),
  68                 new Scenario(2,
  69                         "-XX:FlatArrayElementMaxSize=-1",
  70                         "-XX:-UseArrayLoadStoreProfile",
  71                         "-XX:-UseACmpProfile",
  72                         "-XX:TypeProfileLevel=222",
  73                         "-XX:-MonomorphicArrayCheck"),
  74                 new Scenario(3,
  75                         "-XX:FlatArrayElementMaxSize=-1",
  76                         "-XX:-UseArrayLoadStoreProfile",
  77                         "-XX:-UseACmpProfile",
  78                         "-XX:TypeProfileLevel=0",
  79                         "-XX:-MonomorphicArrayCheck",
  80                         "-XX:TieredStopAtLevel=4",
  81                         "-XX:-TieredCompilation"),
  82                 new Scenario(4,
  83                         "-XX:FlatArrayElementMaxSize=-1",
  84                         "-XX:+UseArrayLoadStoreProfile",
  85                         "-XX:+UseACmpProfile",
  86                         "-XX:TypeProfileLevel=0",
  87                         "-XX:TieredStopAtLevel=4",
  88                         "-XX:-TieredCompilation"),
  89                 new Scenario(5,
  90                         "-XX:FlatArrayElementMaxSize=-1",
  91                         "-XX:-UseArrayLoadStoreProfile",
  92                         "-XX:-UseACmpProfile",
  93                         "-XX:TypeProfileLevel=222",
  94                         "-XX:-MonomorphicArrayCheck",
  95                         "-XX:TieredStopAtLevel=4",
  96                         "-XX:-TieredCompilation")
  97         };
  98 
  99         InlineTypes.getFramework()
 100                    .addScenarios(scenarios)
 101                    .addFlags("-XX:+IgnoreUnrecognizedVMOptions", "--enable-preview",
 102                              "--add-exports", "java.base/jdk.internal.vm.annotation=ALL-UNNAMED",
 103                              "--add-exports", "java.base/jdk.internal.value=ALL-UNNAMED")
 104                    .addHelperClasses(MyValue1.class,
 105                                      MyValue2.class)
 106                    .start();
 107     }
 108 
 109     @NullRestricted
 110     private static final MyValue1 testValue1 = MyValue1.createWithFieldsInline(rI, rL);
 111     @NullRestricted
 112     private static final MyValue2 testValue2 = MyValue2.createWithFieldsInline(rI, rD);
 113     private static final MyValue1[] testValue1Array = (MyValue1[])ValueClass.newNullRestrictedArray(MyValue1.class, 1);
 114     static {
 115         testValue1Array[0] = testValue1;
 116     }
 117     private static final MyValue2[] testValue2Array = (MyValue2[])ValueClass.newNullRestrictedArray(MyValue2.class, 1);
 118     static {
 119         testValue2Array[0] = testValue2;
 120     }
 121     private static final Integer[] testIntegerArray = new Integer[] { 42 };
 122     private static final Long[] testLongArray = new Long[] { 42L };
 123     private static final Double[] testDoubleArray = new Double[] { 42.0D };
 124     private static final MyValue1[] testValue1NotFlatArray = new MyValue1[] { testValue1 };
 125     private static final MyValue1[][] testValue1ArrayArray = new MyValue1[][] { testValue1Array };
 126 
 127     // Wrap these variables into helper class because
 128     // WhiteBox API needs to be initialized by TestFramework first.
 129     static class WBFlags {
 130         static final boolean UseACmpProfile = (Boolean) WhiteBox.getWhiteBox().getVMFlag("UseACmpProfile");
 131         static final boolean TieredCompilation = (Boolean) WhiteBox.getWhiteBox().getVMFlag("TieredCompilation");
 132         static final boolean ProfileInterpreter = (Boolean) WhiteBox.getWhiteBox().getVMFlag("ProfileInterpreter");
 133         static final boolean UseArrayLoadStoreProfile = (Boolean) WhiteBox.getWhiteBox().getVMFlag("UseArrayLoadStoreProfile");
 134         static final long TypeProfileLevel = (Long) WhiteBox.getWhiteBox().getVMFlag("TypeProfileLevel");
 135     }
 136 
 137     static abstract class NonValueAbstract {
 138 
 139     }
 140 
 141     static class NonValueClass1 extends NonValueAbstract {
 142         int x;
 143 
 144         public NonValueClass1(int x) {
 145             this.x = x;
 146         }
 147     }
 148 
 149     static class NonValueClass2 extends NonValueAbstract {
 150         int x;
 151 
 152         public NonValueClass2(int x) {
 153             this.x = x;
 154         }
 155     }
 156 
 157     static final NonValueClass1 obj = new NonValueClass1(rI);
 158     static final NonValueClass2 otherObj = new NonValueClass2(rI);
 159 
 160     // aaload
 161 
 162     @Test
 163     @IR(applyIfOr = {"UseArrayLoadStoreProfile", "true", "TypeProfileLevel", "= 222"},
 164         failOn = {LOAD_UNKNOWN_INLINE})
 165     @IR(applyIfAnd={"UseACmpProfile", "false", "TypeProfileLevel", "!= 222"},
 166         counts = {LOAD_UNKNOWN_INLINE, "= 1"})
 167     public Object test1(Object[] array) {
 168         return array[0];
 169     }
 170 
 171     @Run(test = "test1")
 172     @Warmup(10000)
 173     public void test1_verifier(RunInfo info) {
 174         if (info.isWarmUp()) {
 175             Object o = test1(testValue1Array);
 176             Asserts.assertEQ(((MyValue1)o).hash(), testValue1.hash());
 177         } else {
 178             Object o = test1(testValue2Array);
 179             Asserts.assertEQ(((MyValue2)o).hash(), testValue2.hash());
 180         }
 181     }
 182 
 183     @Test
 184     @IR(applyIfOr = {"UseArrayLoadStoreProfile", "true", "TypeProfileLevel", "= 222"},
 185         failOn = {LOAD_UNKNOWN_INLINE})
 186     @IR(applyIfAnd = {"UseArrayLoadStoreProfile", "false", "TypeProfileLevel", "!= 222"},
 187         counts = {LOAD_UNKNOWN_INLINE, "= 1"})
 188     public Object test2(Object[] array) {
 189         return array[0];
 190     }
 191 
 192     @Run(test = "test2")
 193     @Warmup(10000)
 194     public void test2_verifier(RunInfo info) {
 195         if (info.isWarmUp()) {
 196             Object o = test2(testIntegerArray);
 197             Asserts.assertEQ(o, 42);
 198         } else {
 199             Object o = test2(testLongArray);
 200             Asserts.assertEQ(o, 42L);
 201         }
 202     }
 203 
 204     @Test
 205     @IR(counts = {LOAD_UNKNOWN_INLINE, "= 1"})
 206     public Object test3(Object[] array) {
 207         return array[0];
 208     }
 209 
 210     @Run(test = "test3")
 211     @Warmup(10000)
 212     public void test3_verifier() {
 213         Object o = test3(testValue1Array);
 214         Asserts.assertEQ(((MyValue1)o).hash(), testValue1.hash());
 215         o = test3(testValue2Array);
 216         Asserts.assertEQ(((MyValue2)o).hash(), testValue2.hash());
 217     }
 218 
 219     @Test
 220     @IR(applyIf = {"UseArrayLoadStoreProfile", "true"},
 221         failOn = {LOAD_UNKNOWN_INLINE})
 222     @IR(applyIf = {"UseArrayLoadStoreProfile", "false"},
 223         counts = {LOAD_UNKNOWN_INLINE, "= 1"})
 224     public Object test4(Object[] array) {
 225         return array[0];
 226     }
 227 
 228     @Run(test = "test4")
 229     @Warmup(10000)
 230     public void test4_verifier(RunInfo info) {
 231         if (info.isWarmUp()) {
 232             Object o = test4(testIntegerArray);
 233             Asserts.assertEQ(o, 42);
 234             o = test4(testLongArray);
 235             Asserts.assertEQ(o, 42L);
 236         } else {
 237             Object o = test4(testValue2Array);
 238             Asserts.assertEQ(((MyValue2)o).hash(), testValue2.hash());
 239         }
 240     }
 241 
 242     @Test
 243     @IR(counts = {LOAD_UNKNOWN_INLINE, "= 1"})
 244     public Object test5(Object[] array) {
 245         return array[0];
 246     }
 247 
 248     @Run(test = "test5")
 249     @Warmup(10000)
 250     public void test5_verifier() {
 251         Object o = test5(testValue1Array);
 252         Asserts.assertEQ(((MyValue1)o).hash(), testValue1.hash());
 253         o = test5(testValue1NotFlatArray);
 254         Asserts.assertEQ(((MyValue1)o).hash(), testValue1.hash());
 255     }
 256 
 257     // Check that profile data that's useless at the aaload is
 258     // leveraged at a later point
 259     @DontInline
 260     public void test6_no_inline() {
 261     }
 262 
 263     @ForceInline
 264     public void test6_helper(NonValueAbstract[] arg) {
 265         if (arg instanceof NonValueClass1[]) {
 266             test6_no_inline();
 267         }
 268     }
 269 
 270     @Test
 271     // TODO 8325106 double-check rule modifications done by 8325660
 272     @IR(applyIfOr = {"UseArrayLoadStoreProfile", "true", "TypeProfileLevel", "= 222"},
 273         counts = {CALL, "= 4", CLASS_CHECK_TRAP, "= 1", NULL_CHECK_TRAP, "= 1", RANGE_CHECK_TRAP, "= 1"})
 274     @IR(applyIfAnd = {"UseArrayLoadStoreProfile", "false", "TypeProfileLevel", "!= 222"},
 275         counts = {CALL, "= 3", RANGE_CHECK_TRAP, "= 1", NULL_CHECK_TRAP, "= 1"})
 276     public Object test6(NonValueAbstract[] array) {
 277         NonValueAbstract v = array[0];
 278         test6_helper(array);
 279         return v;
 280     }
 281 
 282     @Run(test = "test6")
 283     @Warmup(10000)
 284     public void test6_verifier(RunInfo info) {
 285         if (info.isWarmUp()) {
 286             // pollute profile
 287             test6_helper(new NonValueClass1[1]);
 288             test6_helper(new NonValueClass2[1]);
 289         }
 290         test6(new NonValueClass1[1]);
 291     }
 292 
 293     @DontInline
 294     public void test7_no_inline() {
 295     }
 296 
 297     @ForceInline
 298     public void test7_helper(Object arg) {
 299         if (arg instanceof NonValueClass1) {
 300             test7_no_inline();
 301         }
 302     }
 303 
 304     @Test
 305     // TODO 8325106 double-check rule modifications done by 8325660
 306     @IR(applyIfOr = {"UseArrayLoadStoreProfile", "true", "TypeProfileLevel", "= 222"},
 307         counts = {CALL, "= 3", CLASS_CHECK_TRAP, "= 0", NULL_CHECK_TRAP, "= 1", RANGE_CHECK_TRAP, "= 1"})
 308     @IR(applyIfAnd = {"UseArrayLoadStoreProfile", "false", "TypeProfileLevel", "!= 222"},
 309         counts = {CALL, "= 3", RANGE_CHECK_TRAP, "= 1", NULL_CHECK_TRAP, "= 1"})
 310     public Object test7(NonValueAbstract[] array) {
 311         NonValueAbstract v = array[0];
 312         test7_helper(v);
 313         return v;
 314     }
 315 
 316     @Run(test = "test7")
 317     @Warmup(10000)
 318     public void test7_verifier(RunInfo info) {
 319         if (info.isWarmUp()) {
 320             // pollute profile
 321             test7_helper(new NonValueClass1(rI));
 322             test7_helper(new NonValueClass2(rI));
 323         }
 324         test7(new NonValueClass1[1]);
 325     }
 326 
 327     @DontInline
 328     public void test8_no_inline() {
 329     }
 330 
 331     public void test8_helper(Object arg) {
 332         if (arg instanceof Long) {
 333             test8_no_inline();
 334         }
 335     }
 336 
 337     @Test
 338     @IR(applyIf = {"UseArrayLoadStoreProfile", "true"},
 339         counts = {CALL, "= 5", CLASS_CHECK_TRAP, "= 1", NULL_CHECK_TRAP, "= 2",
 340                   RANGE_CHECK_TRAP, "= 1"})
 341     @IR(applyIf = {"UseArrayLoadStoreProfile", "false"},
 342         counts = {CALL, "= 5", RANGE_CHECK_TRAP, "= 1", NULL_CHECK_TRAP, "= 2"})
 343     public Object test8(Object[] array) {
 344         Object v = array[0];
 345         test8_helper(v);
 346         return v;
 347     }
 348 
 349     @Run(test = "test8")
 350     @Warmup(10000)
 351     public void test8_verifier(RunInfo info) {
 352         if (info.isWarmUp()) {
 353             // pollute profile
 354             test8_helper(42L);
 355             test8_helper(42.0D);
 356         }
 357         test8(testValue1Array);
 358         test8(testValue1NotFlatArray);
 359     }
 360 
 361     // aastore
 362 
 363     @Test
 364     @IR(applyIfOr = {"UseArrayLoadStoreProfile", "true", "TypeProfileLevel", "= 222"},
 365         failOn = {STORE_UNKNOWN_INLINE})
 366     @IR(applyIfAnd = {"UseArrayLoadStoreProfile", "false", "TypeProfileLevel", "!= 222"},
 367         counts = {STORE_UNKNOWN_INLINE, "= 1"})
 368     public void test9(Object[] array, Object v) {
 369         array[0] = v;
 370     }
 371 
 372     @Run(test = "test9")
 373     @Warmup(10000)
 374     public void test9_verifier() {
 375         test9(testValue1Array, testValue1);
 376         Asserts.assertEQ(testValue1Array[0].hash(), testValue1.hash());
 377     }
 378 
 379     @Test
 380     @IR(applyIfOr = {"UseArrayLoadStoreProfile", "true", "TypeProfileLevel", "= 222"},
 381         failOn = {STORE_UNKNOWN_INLINE})
 382     @IR(applyIfAnd = {"UseArrayLoadStoreProfile", "false", "TypeProfileLevel", "!= 222"},
 383         counts = {STORE_UNKNOWN_INLINE, "= 1"})
 384     public void test10(Object[] array, Object v) {
 385         array[0] = v;
 386     }
 387 
 388     @Run(test = "test10")
 389     @Warmup(10000)
 390     public void test10_verifier() {
 391         test10(testIntegerArray, 42);
 392     }
 393 
 394     @Test
 395     @IR(counts = {STORE_UNKNOWN_INLINE, "= 1"})
 396     public void test11(Object[] array, Object v) {
 397         array[0] = v;
 398     }
 399 
 400     @Run(test = "test11")
 401     @Warmup(10000)
 402     public void test11_verifier() {
 403         test11(testValue1Array, testValue1);
 404         test11(testValue2Array, testValue2);
 405     }
 406 
 407     @Test
 408     @IR(applyIf = {"UseArrayLoadStoreProfile", "true"},
 409         failOn = {STORE_UNKNOWN_INLINE})
 410     @IR(applyIf = {"UseArrayLoadStoreProfile", "false"},
 411         counts = {STORE_UNKNOWN_INLINE, "= 1"})
 412     public void test12(Object[] array, Object v) {
 413         array[0] = v;
 414     }
 415 
 416     @Run(test = "test12")
 417     @Warmup(10000)
 418     public void test12_verifier() {
 419         test12(testIntegerArray, 42);
 420         test12(testLongArray, 42L);
 421     }
 422 
 423     @Test
 424     @IR(counts = {STORE_UNKNOWN_INLINE, "= 1"})
 425     public void test13(Object[] array, Object v) {
 426         array[0] = v;
 427     }
 428 
 429     @Run(test = "test13")
 430     @Warmup(10000)
 431     public void test13_verifier() {
 432         test13(testValue1Array, testValue1);
 433         test13(testValue1NotFlatArray, testValue1);
 434     }
 435 
 436     // MonomorphicArrayCheck
 437     @Test
 438     public void test14(Number[] array, Number v) {
 439         array[0] = v;
 440     }
 441 
 442     @Run(test = "test14")
 443     @Warmup(10000)
 444     public void test14_verifier(RunInfo info) {
 445         if (info.isWarmUp()) {
 446             test14(testIntegerArray, 42);
 447         } else {
 448             Method m = info.getTest();
 449             boolean deopt = false;
 450             for (int i = 0; i < 100; i++) {
 451                 test14(testIntegerArray, 42);
 452                 if (!info.isCompilationSkipped() && !TestFramework.isCompiled(m)) {
 453                     deopt = true;
 454                 }
 455             }
 456             if (deopt && TestFramework.isStableDeopt(m, CompLevel.C2) && !WBFlags.TieredCompilation && WBFlags.ProfileInterpreter &&
 457                 (WBFlags.UseArrayLoadStoreProfile || WBFlags.TypeProfileLevel == 222)) {
 458                 throw new RuntimeException("Monomorphic array check should rely on profiling and be accurate");
 459             }
 460         }
 461     }
 462 
 463     // null free array profiling
 464 
 465     @ImplicitlyConstructible
 466     @LooselyConsistentValue
 467     static value class NotFlattenable {
 468         private Object o1 = null;
 469         private Object o2 = null;
 470         private Object o3 = null;
 471         private Object o4 = null;
 472         private Object o5 = null;
 473         private Object o6 = null;
 474     }
 475 
 476     @NullRestricted
 477     private static final NotFlattenable notFlattenable = new NotFlattenable();
 478     private static final NotFlattenable[] testNotFlattenableArray = (NotFlattenable[])ValueClass.newNullRestrictedArray(NotFlattenable.class, 1);
 479 
 480     @Test
 481 // TODO 8325106
 482 //    @IR(applyIfOr = {"UseArrayLoadStoreProfile", "true", "TypeProfileLevel", "= 222"},
 483     @IR(applyIf = {"UseArrayLoadStoreProfile", "true"},
 484         counts = {NULL_CHECK_TRAP, "= 2"},
 485         failOn = {STORE_UNKNOWN_INLINE})
 486     @IR(applyIfAnd = {"UseArrayLoadStoreProfile", "false", "TypeProfileLevel", "!= 222"},
 487         counts = {NULL_CHECK_TRAP, "= 3", STORE_UNKNOWN_INLINE, "= 1"})
 488     public void test15(Object[] array, Object v) {
 489         array[0] = v;
 490     }
 491 
 492     @Run(test = "test15")
 493     @Warmup(10000)
 494     public void test15_verifier() {
 495         test15(testNotFlattenableArray, notFlattenable);
 496         try {
 497             test15(testNotFlattenableArray, null);
 498             throw new RuntimeException("NullPointerException expected");
 499         } catch (NullPointerException npe) {
 500             // Expected
 501         }
 502     }
 503 
 504     @Test
 505     @IR(applyIf = {"UseArrayLoadStoreProfile", "true"},
 506         counts = {NULL_CHECK_TRAP, "= 2"},
 507         failOn = {STORE_UNKNOWN_INLINE})
 508     @IR(applyIf = {"UseArrayLoadStoreProfile", "false"},
 509         counts = {NULL_CHECK_TRAP, "= 3", STORE_UNKNOWN_INLINE, "= 1"})
 510     public void test16(Object[] array, Object v) {
 511         array[0] = v;
 512     }
 513 
 514     @Run(test = "test16")
 515     @Warmup(10000)
 516     public void test16_verifier() {
 517         test16(testNotFlattenableArray, notFlattenable);
 518         try {
 519             test16(testNotFlattenableArray, null);
 520             throw new RuntimeException("NullPointerException expected");
 521         } catch (NullPointerException npe) {
 522             // Expected
 523         }
 524         test16(testIntegerArray, 42);
 525     }
 526 
 527     @Test
 528     @IR(applyIf = {"UseArrayLoadStoreProfile", "true"},
 529         counts = {NULL_CHECK_TRAP, "= 1"},
 530         failOn = {STORE_UNKNOWN_INLINE})
 531     @IR(applyIf = {"UseArrayLoadStoreProfile", "false"},
 532         counts = {NULL_CHECK_TRAP, "= 3", STORE_UNKNOWN_INLINE, "= 1"})
 533     public void test17(Object[] array, Object v) {
 534         array[0] = v;
 535     }
 536 
 537     @Run(test = "test17")
 538     @Warmup(10000)
 539     public void test17_verifier() {
 540         test17(testIntegerArray, 42);
 541         test17(testIntegerArray, null);
 542         testIntegerArray[0] = 42;
 543         test17(testLongArray, 42L);
 544     }
 545 
 546     public void test18_helper(Object[] array, Object v) {
 547         array[0] = v;
 548     }
 549 
 550     @Test
 551     @IR(applyIf = {"UseArrayLoadStoreProfile", "true"},
 552         counts = {NULL_CHECK_TRAP, "= 1"},
 553         failOn = {STORE_UNKNOWN_INLINE})
 554     @IR(applyIf = {"UseArrayLoadStoreProfile", "false"},
 555         counts = {NULL_CHECK_TRAP, "= 3", STORE_UNKNOWN_INLINE, "= 1"})
 556     public Object test18(Object[] array, Object v1) {
 557         Object v2 = array[0];
 558         test18_helper(array, v1);
 559         return v2;
 560     }
 561 
 562     @Run(test = "test18")
 563     @Warmup(10000)
 564     public void test18_verifier() {
 565         test18_helper(testValue1Array, testValue1); // pollute profile
 566         test18(testIntegerArray, 42);
 567         test18(testIntegerArray, null);
 568         testIntegerArray[0] = 42;
 569         test18(testLongArray, 42L);
 570     }
 571 
 572     // maybe null free, not flat
 573 
 574     @Test
 575     @IR(applyIf = {"UseArrayLoadStoreProfile", "true"},
 576         failOn = {LOAD_UNKNOWN_INLINE})
 577     @IR(applyIf = {"UseArrayLoadStoreProfile", "false"},
 578         counts = {LOAD_UNKNOWN_INLINE, "= 1"})
 579     public Object test19(Object[] array) {
 580         return array[0];
 581     }
 582 
 583     @Run(test = "test19")
 584     @Warmup(10000)
 585     public void test19_verifier() {
 586         Object o = test19(testIntegerArray);
 587         Asserts.assertEQ(o, 42);
 588         o = test19(testNotFlattenableArray);
 589         Asserts.assertEQ(o, notFlattenable);
 590     }
 591 
 592     @Test
 593     @IR(applyIf = {"UseArrayLoadStoreProfile", "true"},
 594         failOn = {STORE_UNKNOWN_INLINE})
 595     @IR(applyIf = {"UseArrayLoadStoreProfile", "false"},
 596         counts = {STORE_UNKNOWN_INLINE, "= 1"})
 597     public void test20(Object[] array, Object o) {
 598         array[0] = o;
 599     }
 600 
 601     @Run(test = "test20")
 602     @Warmup(10000)
 603     public void test20_verifier() {
 604         test20(testIntegerArray, 42);
 605         test20(testNotFlattenableArray, notFlattenable);
 606     }
 607 
 608     // acmp tests
 609 
 610     // branch frequency profiling causes not equal branch to be optimized out
 611     @Test
 612     @IR(counts = {IRNode.UNSTABLE_IF_TRAP, " = 1"})
 613     public boolean test21(Object o1, Object o2) {
 614         return o1 == o2;
 615     }
 616 
 617     @Run(test = "test21")
 618     @Warmup(10000)
 619     public void test21_verifier() {
 620         test21(obj, obj);
 621         test21(testValue1, testValue1);
 622     }
 623 
 624     // Input profiled non null
 625     @Test
 626     @IR(applyIf = {"UseACmpProfile", "true"},
 627         failOn = {SUBSTITUTABILITY_TEST},
 628         counts = {NULL_ASSERT_TRAP, "= 1"})
 629     @IR(applyIf = {"UseACmpProfile", "false"},
 630         counts = {SUBSTITUTABILITY_TEST, "= 1"})
 631     public boolean test22(Object o1, Object o2) {
 632         return o1 == o2;
 633     }
 634 
 635     @Run(test = "test22")
 636     @Warmup(10000)
 637     public void test22_verifier(RunInfo info) {
 638         test22(obj, null);
 639         test22(otherObj, null);
 640         if (!info.isWarmUp()) {
 641             Method m = info.getTest();
 642             TestFramework.assertCompiledByC2(m);
 643             test22(obj, otherObj);
 644             if (WBFlags.UseACmpProfile) {
 645                 TestFramework.assertDeoptimizedByC2(m);
 646             }
 647         }
 648     }
 649 
 650     @Test
 651     @IR(applyIfOr = {"UseACmpProfile", "true", "TypeProfileLevel", "= 222"},
 652         failOn = {SUBSTITUTABILITY_TEST},
 653         counts = {NULL_ASSERT_TRAP, "= 1"})
 654     @IR(applyIfAnd = {"UseACmpProfile", "false", "TypeProfileLevel", "!= 222"},
 655         counts = {SUBSTITUTABILITY_TEST, "= 1"})
 656     public boolean test23(Object o1, Object o2) {
 657         return o1 == o2;
 658     }
 659 
 660     @Run(test = "test23")
 661     @Warmup(10000)
 662     public void test23_verifier(RunInfo info) {
 663         test23(null, obj);
 664         test23(null, otherObj);
 665         if (!info.isWarmUp()) {
 666             Method m = info.getTest();
 667             TestFramework.assertCompiledByC2(m);
 668             test23(obj, otherObj);
 669             if (WBFlags.UseACmpProfile || WBFlags.TypeProfileLevel != 0) {
 670                 TestFramework.assertDeoptimizedByC2(m);
 671             }
 672         }
 673     }
 674 
 675     @Test
 676     @IR(applyIf = {"UseACmpProfile", "true"},
 677         failOn = {SUBSTITUTABILITY_TEST},
 678         counts = {NULL_ASSERT_TRAP, "= 1"})
 679     @IR(applyIf = {"UseACmpProfile", "false"},
 680         counts = {SUBSTITUTABILITY_TEST, "= 1"})
 681     public boolean test24(Object o1, Object o2) {
 682         return o1 != o2;
 683     }
 684 
 685     @Run(test = "test24")
 686     @Warmup(10000)
 687     public void test24_verifier(RunInfo info) {
 688         test24(obj, null);
 689         test24(otherObj, null);
 690         if (!info.isWarmUp()) {
 691             Method m = info.getTest();
 692             TestFramework.assertCompiledByC2(m);
 693             test24(obj, otherObj);
 694              if (WBFlags.UseACmpProfile) {
 695                  TestFramework.assertDeoptimizedByC2(m);
 696             }
 697         }
 698     }
 699 
 700     @Test
 701     @IR(applyIfOr = {"UseACmpProfile", "true", "TypeProfileLevel", "= 222"},
 702         failOn = {SUBSTITUTABILITY_TEST},
 703         counts = {NULL_ASSERT_TRAP, "= 1"})
 704     @IR(applyIfAnd = {"UseACmpProfile", "false", "TypeProfileLevel", "!= 222"},
 705         counts = {SUBSTITUTABILITY_TEST, "= 1"})
 706     public boolean test25(Object o1, Object o2) {
 707         return o1 != o2;
 708     }
 709 
 710     @Run(test = "test25")
 711     @Warmup(10000)
 712     public void test25_verifier(RunInfo info) {
 713         test25(null, obj);
 714         test25(null, otherObj);
 715         if (!info.isWarmUp()) {
 716             Method m = info.getTest();
 717             TestFramework.assertCompiledByC2(m);
 718             test25(obj, otherObj);
 719             if (WBFlags.UseACmpProfile || WBFlags.TypeProfileLevel != 0) {
 720                 TestFramework.assertDeoptimizedByC2(m);
 721             }
 722         }
 723     }
 724 
 725     // Input profiled not value class with known type
 726     @Test
 727     @IR(applyIfOr = {"UseACmpProfile", "true", "TypeProfileLevel", "= 222"},
 728         failOn = {SUBSTITUTABILITY_TEST},
 729         counts = {NULL_CHECK_TRAP, "= 1", CLASS_CHECK_TRAP, "= 1"})
 730     @IR(applyIfAnd = {"UseACmpProfile", "false", "TypeProfileLevel", "!= 222"},
 731         counts = {SUBSTITUTABILITY_TEST, "= 1"})
 732     public boolean test26(Object o1, Object o2) {
 733         return o1 == o2;
 734     }
 735 
 736     @Run(test = "test26")
 737     @Warmup(10000)
 738     public void test26_verifier(RunInfo info) {
 739         test26(obj, obj);
 740         test26(obj, otherObj);
 741         if (!info.isWarmUp()) {
 742             Method m = info.getTest();
 743             TestFramework.assertCompiledByC2(m);
 744             for (int i = 0; i < 10; i++) {
 745                 test26(otherObj, obj);
 746             }
 747             if (WBFlags.UseACmpProfile || WBFlags.TypeProfileLevel != 0) {
 748                 TestFramework.assertDeoptimizedByC2(m);
 749             }
 750         }
 751     }
 752 
 753     @Test
 754     @IR(applyIf = {"UseACmpProfile", "true"},
 755         failOn = {SUBSTITUTABILITY_TEST},
 756         counts = { NULL_CHECK_TRAP, "= 1", CLASS_CHECK_TRAP, "= 1"})
 757     @IR(applyIf = {"UseACmpProfile", "false"},
 758         counts = {SUBSTITUTABILITY_TEST, "= 1"})
 759     public boolean test27(Object o1, Object o2) {
 760         return o1 == o2;
 761     }
 762 
 763     @Run(test = "test27")
 764     @Warmup(10000)
 765     public void test27_verifier(RunInfo info) {
 766         test27(obj, obj);
 767         test27(otherObj, obj);
 768         if (!info.isWarmUp()) {
 769             Method m = info.getTest();
 770             TestFramework.assertCompiledByC2(m);
 771             for (int i = 0; i < 10; i++) {
 772                 test27(obj, otherObj);
 773             }
 774             if (WBFlags.UseACmpProfile) {
 775                 TestFramework.assertDeoptimizedByC2(m);
 776             }
 777         }
 778     }
 779 
 780     @Test
 781     @IR(applyIfOr = {"UseACmpProfile", "true", "TypeProfileLevel", "= 222"},
 782         failOn = {SUBSTITUTABILITY_TEST},
 783         counts = {NULL_CHECK_TRAP, "= 1", CLASS_CHECK_TRAP, "= 1"})
 784     @IR(applyIfAnd = {"UseACmpProfile", "false", "TypeProfileLevel", "!= 222"},
 785         counts = {SUBSTITUTABILITY_TEST, "= 1"})
 786     public boolean test28(Object o1, Object o2) {
 787         return o1 != o2;
 788     }
 789 
 790     @Run(test = "test28")
 791     @Warmup(10000)
 792     public void test28_verifier(RunInfo info) {
 793         test28(obj, obj);
 794         test28(obj, otherObj);
 795         if (!info.isWarmUp()) {
 796             Method m = info.getTest();
 797             TestFramework.assertCompiledByC2(m);
 798             for (int i = 0; i < 10; i++) {
 799                 test28(otherObj, obj);
 800             }
 801             if (WBFlags.UseACmpProfile || WBFlags.TypeProfileLevel != 0) {
 802                 TestFramework.assertDeoptimizedByC2(m);
 803             }
 804         }
 805     }
 806 
 807     @Test
 808     @IR(applyIf = {"UseACmpProfile", "true"},
 809         failOn = {SUBSTITUTABILITY_TEST},
 810         counts = {NULL_CHECK_TRAP, "= 1", CLASS_CHECK_TRAP, "= 1"})
 811     @IR(applyIf = {"UseACmpProfile", "false"},
 812         counts = {SUBSTITUTABILITY_TEST, "= 1"})
 813     public boolean test29(Object o1, Object o2) {
 814         return o1 != o2;
 815     }
 816 
 817     @Run(test = "test29")
 818     @Warmup(10000)
 819     public void test29_verifier(RunInfo info) {
 820         test29(obj, obj);
 821         test29(otherObj, obj);
 822         if (!info.isWarmUp()) {
 823             Method m = info.getTest();
 824             TestFramework.assertCompiledByC2(m);
 825             for (int i = 0; i < 10; i++) {
 826                 test29(obj, otherObj);
 827             }
 828             if (WBFlags.UseACmpProfile) {
 829                 TestFramework.assertDeoptimizedByC2(m);
 830             }
 831         }
 832     }
 833 
 834     @Test
 835     @IR(applyIfOr = {"UseACmpProfile", "true", "TypeProfileLevel", "= 222"},
 836         failOn = {SUBSTITUTABILITY_TEST, NULL_CHECK_TRAP},
 837         counts = {CLASS_CHECK_TRAP, "= 1"})
 838     @IR(applyIfAnd = {"UseACmpProfile", "false", "TypeProfileLevel", "!= 222"},
 839         counts = {SUBSTITUTABILITY_TEST, "= 1"})
 840     public boolean test30(Object o1, Object o2) {
 841         return o1 == o2;
 842     }
 843 
 844     @Run(test = "test30")
 845     @Warmup(10000)
 846     public void test30_verifier(RunInfo info) {
 847         test30(obj, obj);
 848         test30(obj, otherObj);
 849         test30(null, 42);
 850         if (!info.isWarmUp()) {
 851             Method m = info.getTest();
 852             TestFramework.assertCompiledByC2(m);
 853             for (int i = 0; i < 10; i++) {
 854                 test30(otherObj, obj);
 855             }
 856             if (WBFlags.UseACmpProfile || WBFlags.TypeProfileLevel != 0) {
 857                 TestFramework.assertDeoptimizedByC2(m);
 858             }
 859         }
 860     }
 861 
 862     @Test
 863     @IR(applyIf = {"UseACmpProfile", "true"},
 864         failOn = {SUBSTITUTABILITY_TEST, NULL_CHECK_TRAP})
 865     @IR(applyIf = {"UseACmpProfile", "false"},
 866         counts = {SUBSTITUTABILITY_TEST, "= 1"})
 867     public boolean test31(Object o1, Object o2) {
 868         return o1 == o2;
 869     }
 870 
 871     @Run(test = "test31")
 872     @Warmup(10000)
 873     public void test31_verifier(RunInfo info) {
 874         test31(obj, obj);
 875         test31(otherObj, obj);
 876         test31(obj, null);
 877         if (!info.isWarmUp()) {
 878             Method m = info.getTest();
 879             TestFramework.assertCompiledByC2(m);
 880             for (int i = 0; i < 10; i++) {
 881                 test31(obj, otherObj);
 882             }
 883             if (WBFlags.UseACmpProfile) {
 884                 TestFramework.assertDeoptimizedByC2(m);
 885             }
 886         }
 887     }
 888 
 889     // Input profiled not value class with unknown type
 890     @Test
 891     @IR(applyIf = {"UseACmpProfile", "true"},
 892         failOn = {SUBSTITUTABILITY_TEST},
 893         counts = {NULL_CHECK_TRAP, "= 1", CLASS_CHECK_TRAP, "= 1"})
 894     @IR(applyIf = {"UseACmpProfile", "false"},
 895         counts = {SUBSTITUTABILITY_TEST, "= 1"})
 896     public boolean test32(Object o1, Object o2) {
 897         return o1 == o2;
 898     }
 899 
 900     @Run(test = "test32")
 901     @Warmup(10000)
 902     public void test32_verifier(RunInfo info) {
 903         test32(obj, obj);
 904         test32(obj, testValue1);
 905         test32(otherObj, obj);
 906         if (!info.isWarmUp()) {
 907             Method m = info.getTest();
 908             TestFramework.assertCompiledByC2(m);
 909             for (int i = 0; i < 10; i++) {
 910                 test32(testValue1, 42);
 911             }
 912             if (WBFlags.UseACmpProfile) {
 913                 TestFramework.assertDeoptimizedByC2(m);
 914             }
 915         }
 916     }
 917 
 918     @Test
 919     @IR(applyIf = {"UseACmpProfile", "true"},
 920         failOn = {SUBSTITUTABILITY_TEST},
 921         counts = {NULL_CHECK_TRAP, "= 1", CLASS_CHECK_TRAP, "= 1"})
 922     @IR(applyIf = {"UseACmpProfile", "false"},
 923         counts = {SUBSTITUTABILITY_TEST, "= 1"})
 924     public boolean test33(Object o1, Object o2) {
 925         return o1 == o2;
 926     }
 927 
 928     @Run(test = "test33")
 929     @Warmup(10000)
 930     public void test33_verifier(RunInfo info) {
 931         test33(obj, obj);
 932         test33(testValue1, obj);
 933         test33(obj, otherObj);
 934         if (!info.isWarmUp()) {
 935             Method m = info.getTest();
 936             TestFramework.assertCompiledByC2(m);
 937             for (int i = 0; i < 10; i++) {
 938                 test33(obj, testValue1);
 939             }
 940             if (WBFlags.UseACmpProfile) {
 941                 TestFramework.assertDeoptimizedByC2(m);
 942             }
 943         }
 944     }
 945 
 946     @Test
 947     @IR(applyIf = {"UseACmpProfile", "true"},
 948         failOn = {SUBSTITUTABILITY_TEST},
 949         counts = {NULL_CHECK_TRAP, "= 1", CLASS_CHECK_TRAP, "= 1"})
 950     @IR(applyIf = {"UseACmpProfile", "false"},
 951         counts = {SUBSTITUTABILITY_TEST, "= 1"})
 952     public boolean test34(Object o1, Object o2) {
 953         return o1 != o2;
 954     }
 955 
 956     @Run(test = "test34")
 957     @Warmup(10000)
 958     public void test34_verifier(RunInfo info) {
 959         test34(obj, obj);
 960         test34(obj, testValue1);
 961         test34(otherObj, obj);
 962         if (!info.isWarmUp()) {
 963             Method m = info.getTest();
 964             TestFramework.assertCompiledByC2(m);
 965             for (int i = 0; i < 10; i++) {
 966                 test34(testValue1, 42);
 967             }
 968             if (WBFlags.UseACmpProfile) {
 969                 TestFramework.assertDeoptimizedByC2(m);
 970             }
 971         }
 972     }
 973 
 974     @Test
 975     @IR(applyIf = {"UseACmpProfile", "true"},
 976         failOn = {SUBSTITUTABILITY_TEST},
 977         counts = {NULL_CHECK_TRAP, "= 1", CLASS_CHECK_TRAP, "= 1"})
 978     @IR(applyIf = {"UseACmpProfile", "false"},
 979         counts = {SUBSTITUTABILITY_TEST, "= 1"})
 980     public boolean test35(Object o1, Object o2) {
 981         return o1 != o2;
 982     }
 983 
 984     @Run(test = "test35")
 985     @Warmup(10000)
 986     public void test35_verifier(RunInfo info) {
 987         test35(obj, obj);
 988         test35(testValue1, obj);
 989         test35(obj, otherObj);
 990         if (!info.isWarmUp()) {
 991             Method m = info.getTest();
 992             TestFramework.assertCompiledByC2(m);
 993             for (int i = 0; i < 10; i++) {
 994                 test35(obj, testValue1);
 995             }
 996             if (WBFlags.UseACmpProfile) {
 997                 TestFramework.assertDeoptimizedByC2(m);
 998             }
 999         }
1000     }
1001 
1002     @Test
1003     @IR(applyIf = {"UseACmpProfile", "true"},
1004         failOn = {SUBSTITUTABILITY_TEST, NULL_CHECK_TRAP},
1005         counts = {CLASS_CHECK_TRAP, "= 1"})
1006     @IR(applyIf = {"UseACmpProfile", "false"},
1007         counts = {SUBSTITUTABILITY_TEST, "= 1"})
1008     public boolean test36(Object o1, Object o2) {
1009         return o1 == o2;
1010     }
1011 
1012     @Run(test = "test36")
1013     @Warmup(10000)
1014     public void test36_verifier(RunInfo info) {
1015         test36(obj, otherObj);
1016         test36(otherObj, testValue1);
1017         test36(null, obj);
1018         if (!info.isWarmUp()) {
1019             Method m = info.getTest();
1020             TestFramework.assertCompiledByC2(m);
1021             for (int i = 0; i < 10; i++) {
1022                 test36(testValue1, obj);
1023             }
1024             if (WBFlags.UseACmpProfile) {
1025                 TestFramework.assertDeoptimizedByC2(m);
1026             }
1027         }
1028     }
1029 
1030     @Test
1031     @IR(applyIf = {"UseACmpProfile", "true"},
1032         failOn = {SUBSTITUTABILITY_TEST, NULL_CHECK_TRAP})
1033     @IR(applyIf = {"UseACmpProfile", "false"},
1034         counts = {SUBSTITUTABILITY_TEST, "= 1"})
1035     public boolean test37(Object o1, Object o2) {
1036         return o1 == o2;
1037     }
1038 
1039     @Run(test = "test37")
1040     @Warmup(10000)
1041     public void test37_verifier(RunInfo info) {
1042         test37(otherObj, obj);
1043         test37(testValue1, otherObj);
1044         test37(obj, null);
1045         if (!info.isWarmUp()) {
1046             Method m = info.getTest();
1047             TestFramework.assertCompiledByC2(m);
1048             for (int i = 0; i < 10; i++) {
1049                 test37(obj, testValue1);
1050             }
1051             if (WBFlags.UseACmpProfile) {
1052                 TestFramework.assertDeoptimizedByC2(m);
1053             }
1054         }
1055     }
1056 
1057     // Test that acmp profile data that's unused at the acmp is fed to
1058     // speculation and leverage later
1059     @Test
1060     @IR(applyIfOr = {"UseACmpProfile", "true", "TypeProfileLevel", "= 222"},
1061         failOn = {SUBSTITUTABILITY_TEST},
1062         counts = {CLASS_CHECK_TRAP, "= 2"})
1063     @IR(applyIfAnd = {"UseACmpProfile", "false", "TypeProfileLevel", "!= 222"},
1064         counts = {SUBSTITUTABILITY_TEST, "= 2"})
1065     public void test38(Object o1, Object o2, Object o3) {
1066         if (o1 == o2) {
1067             test38_helper2();
1068         }
1069         test38_helper(o1, o3);
1070     }
1071 
1072     public void test38_helper(Object o1, Object o2) {
1073         if (o1 == o2) {
1074         }
1075     }
1076 
1077     public void test38_helper2() {
1078     }
1079 
1080     @Run(test = "test38")
1081     @Warmup(10000)
1082     public void test38_verifier() {
1083         test38(obj, obj, obj);
1084         test38_helper(testValue1, testValue2);
1085     }
1086 
1087     @Test
1088     @IR(applyIfOr = {"UseACmpProfile", "true", "TypeProfileLevel", "= 222"},
1089         failOn = {SUBSTITUTABILITY_TEST},
1090         counts = {CLASS_CHECK_TRAP, "= 2"})
1091     @IR(applyIfAnd = {"UseACmpProfile", "false", "TypeProfileLevel", "!= 222"},
1092         counts = {SUBSTITUTABILITY_TEST, "= 2"})
1093     public void test39(Object o1, Object o2, Object o3) {
1094         if (o1 == o2) {
1095             test39_helper2();
1096         }
1097         test39_helper(o2, o3);
1098     }
1099 
1100     public void test39_helper(Object o1, Object o2) {
1101         if (o1 == o2) {
1102         }
1103     }
1104 
1105     public void test39_helper2() {
1106     }
1107 
1108     @Run(test = "test39")
1109     @Warmup(10000)
1110     public void test39_verifier() {
1111         test39(obj, obj, obj);
1112         test39_helper(testValue1, testValue2);
1113     }
1114 
1115     // Test array access with polluted array type profile
1116     static abstract value class Test40Abstract { }
1117     static value class Test40Class extends Test40Abstract { }
1118 
1119     @ImplicitlyConstructible
1120     @LooselyConsistentValue
1121     static value class Test40Inline extends Test40Abstract { }
1122 
1123     @ForceInline
1124     public Object test40_access(Object[] array) {
1125         return array[0];
1126     }
1127 
1128     @Test
1129     public Object test40(Test40Abstract[] array) {
1130         return test40_access(array);
1131     }
1132 
1133     @Run(test = "test40")
1134     @Warmup(10000)
1135     public void test40_verifier(RunInfo info) {
1136         // Make sure multiple implementors of Test40Abstract are loaded
1137         Test40Inline tmp1 = new Test40Inline();
1138         Test40Class tmp2 = new Test40Class();
1139         if (info.isWarmUp()) {
1140             // Pollute profile with Object[] (exact)
1141             test40_access(new Object[1]);
1142         } else {
1143             // When inlining test40_access, profiling contradicts actual type of array
1144             test40(new Test40Class[1]);
1145         }
1146     }
1147 
1148     // Same as test40 but with array store
1149     @ForceInline
1150     public void test41_access(Object[] array, Object val) {
1151         array[0] = val;
1152     }
1153 
1154     @Test
1155     public void test41(Test40Inline[] array, Object val) {
1156         test41_access(array, val);
1157     }
1158 
1159     @Run(test = "test41")
1160     @Warmup(10000)
1161     public void test41_verifier(RunInfo info) {
1162         // Make sure multiple implementors of Test40Abstract are loaded
1163         Test40Inline tmp1 = new Test40Inline();
1164         Test40Class tmp2 = new Test40Class();
1165         if (info.isWarmUp()) {
1166             // Pollute profile with exact Object[]
1167             test41_access(new Object[1], new Object());
1168         } else {
1169             // When inlining test41_access, profiling contradicts actual type of array
1170             Test40Inline[] array = (Test40Inline[])ValueClass.newNullRestrictedArray(Test40Inline.class, 1);
1171             test41(array, new Test40Inline());
1172         }
1173     }
1174 }