1 /*
   2  * Copyright (c) 2019, 2025, 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.LooselyConsistentValue;
  34 import jdk.internal.vm.annotation.NullRestricted;
  35 import jdk.internal.vm.annotation.Strict;
  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:+UseArrayFlattening",
  59                         "-XX:-UseArrayLoadStoreProfile",
  60                         "-XX:-UseACmpProfile",
  61                         "-XX:TypeProfileLevel=0",
  62                         "-XX:-MonomorphicArrayCheck"),
  63                 new Scenario(1,
  64                         "-XX:+UseArrayFlattening",
  65                         "-XX:+UseArrayLoadStoreProfile",
  66                         "-XX:+UseACmpProfile",
  67                         "-XX:TypeProfileLevel=0",
  68                         "-XX:+UseFieldFlattening"),
  69                 new Scenario(2,
  70                         "-XX:+UseArrayFlattening",
  71                         "-XX:-UseArrayLoadStoreProfile",
  72                         "-XX:-UseACmpProfile",
  73                         "-XX:TypeProfileLevel=222",
  74                         "-XX:-MonomorphicArrayCheck"),
  75                 new Scenario(3,
  76                         "-XX:+UseArrayFlattening",
  77                         "-XX:-UseArrayLoadStoreProfile",
  78                         "-XX:-UseACmpProfile",
  79                         "-XX:TypeProfileLevel=0",
  80                         "-XX:-MonomorphicArrayCheck",
  81                         "-XX:TieredStopAtLevel=4",
  82                         "-XX:-TieredCompilation"),
  83                 new Scenario(4,
  84                         "-XX:+UseArrayFlattening",
  85                         "-XX:+UseArrayLoadStoreProfile",
  86                         "-XX:+UseACmpProfile",
  87                         "-XX:TypeProfileLevel=0",
  88                         "-XX:TieredStopAtLevel=4",
  89                         "-XX:-TieredCompilation",
  90                         "-XX:+UseFieldFlattening"),
  91                 new Scenario(5,
  92                         "-XX:+UseArrayFlattening",
  93                         "-XX:-UseArrayLoadStoreProfile",
  94                         "-XX:-UseACmpProfile",
  95                         "-XX:TypeProfileLevel=222",
  96                         "-XX:-MonomorphicArrayCheck",
  97                         "-XX:TieredStopAtLevel=4",
  98                         "-XX:-TieredCompilation")
  99         };
 100 
 101         InlineTypes.getFramework()
 102                    .addScenarios(scenarios)
 103                    .addFlags("-XX:+IgnoreUnrecognizedVMOptions", "--enable-preview",
 104                              "--add-exports", "java.base/jdk.internal.vm.annotation=ALL-UNNAMED",
 105                              "--add-exports", "java.base/jdk.internal.value=ALL-UNNAMED")
 106                    .addHelperClasses(MyValue1.class,
 107                                      MyValue2.class)
 108                    .start();
 109     }
 110 
 111     @Strict
 112     @NullRestricted
 113     private static final MyValue1 testValue1 = MyValue1.createWithFieldsInline(rI, rL);
 114     @Strict
 115     @NullRestricted
 116     private static final MyValue2 testValue2 = MyValue2.createWithFieldsInline(rI, rD);
 117     private static final MyValue1[] testValue1Array = (MyValue1[])ValueClass.newNullRestrictedNonAtomicArray(MyValue1.class, 1, MyValue1.DEFAULT);
 118     static {
 119         testValue1Array[0] = testValue1;
 120     }
 121     private static final MyValue2[] testValue2Array = (MyValue2[])ValueClass.newNullRestrictedNonAtomicArray(MyValue2.class, 1, MyValue2.DEFAULT);
 122     static {
 123         testValue2Array[0] = testValue2;
 124     }
 125     private static final Integer[] testIntegerArray = new Integer[] { 42 };
 126     private static final Long[] testLongArray = new Long[] { 42L };
 127     private static final Double[] testDoubleArray = new Double[] { 42.0D };
 128     private static final MyValue1[] testValue1NotFlatArray = new MyValue1[] { testValue1 };
 129     private static final MyValue1[][] testValue1ArrayArray = new MyValue1[][] { testValue1Array };
 130 
 131     // Wrap these variables into helper class because
 132     // WhiteBox API needs to be initialized by TestFramework first.
 133     static class WBFlags {
 134         static final boolean UseACmpProfile = (Boolean) WhiteBox.getWhiteBox().getVMFlag("UseACmpProfile");
 135         static final boolean TieredCompilation = (Boolean) WhiteBox.getWhiteBox().getVMFlag("TieredCompilation");
 136         static final boolean ProfileInterpreter = (Boolean) WhiteBox.getWhiteBox().getVMFlag("ProfileInterpreter");
 137         static final boolean UseArrayLoadStoreProfile = (Boolean) WhiteBox.getWhiteBox().getVMFlag("UseArrayLoadStoreProfile");
 138         static final long TypeProfileLevel = (Long) WhiteBox.getWhiteBox().getVMFlag("TypeProfileLevel");
 139     }
 140 
 141     static abstract value class ValueAbstract {
 142 
 143     }
 144 
 145     static class NonValueClass1 extends ValueAbstract {
 146         int x;
 147 
 148         public NonValueClass1(int x) {
 149             this.x = x;
 150         }
 151     }
 152 
 153     static class NonValueClass2 extends ValueAbstract {
 154         int x;
 155 
 156         public NonValueClass2(int x) {
 157             this.x = x;
 158         }
 159     }
 160 
 161     static final NonValueClass1 obj = new NonValueClass1(rI);
 162     static final NonValueClass2 otherObj = new NonValueClass2(rI);
 163 
 164     // aaload
 165 
 166     @Test
 167     @IR(applyIfOr = {"UseArrayLoadStoreProfile", "true", "TypeProfileLevel", "= 222"},
 168         failOn = {LOAD_UNKNOWN_INLINE})
 169     @IR(applyIfAnd={"UseACmpProfile", "false", "TypeProfileLevel", "!= 222"},
 170         counts = {LOAD_UNKNOWN_INLINE, "= 1"})
 171     public Object test1(Object[] array) {
 172         return array[0];
 173     }
 174 
 175     @Run(test = "test1")
 176     @Warmup(10000)
 177     public void test1_verifier(RunInfo info) {
 178         if (info.isWarmUp()) {
 179             Object o = test1(testValue1Array);
 180             Asserts.assertEQ(((MyValue1)o).hash(), testValue1.hash());
 181         } else {
 182             Object o = test1(testValue2Array);
 183             Asserts.assertEQ(((MyValue2)o).hash(), testValue2.hash());
 184         }
 185     }
 186 
 187     @Test
 188     @IR(applyIfOr = {"UseArrayLoadStoreProfile", "true", "TypeProfileLevel", "= 222"},
 189         failOn = {LOAD_UNKNOWN_INLINE})
 190     @IR(applyIfAnd = {"UseArrayLoadStoreProfile", "false", "TypeProfileLevel", "!= 222"},
 191         counts = {LOAD_UNKNOWN_INLINE, "= 1"})
 192     public Object test2(Object[] array) {
 193         return array[0];
 194     }
 195 
 196     @Run(test = "test2")
 197     @Warmup(10000)
 198     public void test2_verifier(RunInfo info) {
 199         if (info.isWarmUp()) {
 200             Object o = test2(testIntegerArray);
 201             Asserts.assertEQ(o, 42);
 202         } else {
 203             Object o = test2(testLongArray);
 204             Asserts.assertEQ(o, 42L);
 205         }
 206     }
 207 
 208     @Test
 209     @IR(counts = {LOAD_UNKNOWN_INLINE, "= 1"})
 210     public Object test3(Object[] array) {
 211         return array[0];
 212     }
 213 
 214     @Run(test = "test3")
 215     @Warmup(10000)
 216     public void test3_verifier() {
 217         Object o = test3(testValue1Array);
 218         Asserts.assertEQ(((MyValue1)o).hash(), testValue1.hash());
 219         o = test3(testValue2Array);
 220         Asserts.assertEQ(((MyValue2)o).hash(), testValue2.hash());
 221     }
 222 
 223     @Test
 224     @IR(applyIf = {"UseArrayLoadStoreProfile", "true"},
 225         failOn = {LOAD_UNKNOWN_INLINE})
 226     @IR(applyIf = {"UseArrayLoadStoreProfile", "false"},
 227         counts = {LOAD_UNKNOWN_INLINE, "= 1"})
 228     public Object test4(Object[] array) {
 229         return array[0];
 230     }
 231 
 232     @Run(test = "test4")
 233     @Warmup(10000)
 234     public void test4_verifier(RunInfo info) {
 235         if (info.isWarmUp()) {
 236             Object o = test4(testIntegerArray);
 237             Asserts.assertEQ(o, 42);
 238             o = test4(testLongArray);
 239             Asserts.assertEQ(o, 42L);
 240         } else {
 241             Object o = test4(testValue2Array);
 242             Asserts.assertEQ(((MyValue2)o).hash(), testValue2.hash());
 243         }
 244     }
 245 
 246     @Test
 247     @IR(counts = {LOAD_UNKNOWN_INLINE, "= 1"})
 248     public Object test5(Object[] array) {
 249         return array[0];
 250     }
 251 
 252     @Run(test = "test5")
 253     @Warmup(10000)
 254     public void test5_verifier() {
 255         Object o = test5(testValue1Array);
 256         Asserts.assertEQ(((MyValue1)o).hash(), testValue1.hash());
 257         o = test5(testValue1NotFlatArray);
 258         Asserts.assertEQ(((MyValue1)o).hash(), testValue1.hash());
 259     }
 260 
 261     // Check that profile data that's useless at the aaload is
 262     // leveraged at a later point
 263     @DontInline
 264     public void test6_no_inline() {
 265     }
 266 
 267     @ForceInline
 268     public void test6_helper(ValueAbstract[] arg) {
 269         if (arg instanceof NonValueClass1[]) {
 270             test6_no_inline();
 271         }
 272     }
 273 
 274     @Test
 275     @IR(applyIfOr = {"UseArrayLoadStoreProfile", "true", "TypeProfileLevel", "= 222"},
 276         counts = {CALL, "= 4", CLASS_CHECK_TRAP, "= 1", NULL_CHECK_TRAP, "= 1", RANGE_CHECK_TRAP, "= 1"})
 277     @IR(applyIfAnd = {"UseArrayLoadStoreProfile", "false", "TypeProfileLevel", "!= 222"},
 278         counts = {CALL, "= 4", RANGE_CHECK_TRAP, "= 1", NULL_CHECK_TRAP, "= 1"})
 279     public Object test6(ValueAbstract[] array) {
 280         ValueAbstract v = array[0];
 281         test6_helper(array);
 282         return v;
 283     }
 284 
 285     @Run(test = "test6")
 286     @Warmup(10000)
 287     public void test6_verifier(RunInfo info) {
 288         if (info.isWarmUp()) {
 289             // pollute profile
 290             test6_helper(new NonValueClass1[1]);
 291             test6_helper(new NonValueClass2[1]);
 292         }
 293         test6(new NonValueClass1[1]);
 294     }
 295 
 296     @DontInline
 297     public void test7_no_inline() {
 298     }
 299 
 300     @ForceInline
 301     public void test7_helper(ValueAbstract arg) {
 302         if (arg instanceof NonValueClass1) {
 303             test7_no_inline();
 304         }
 305     }
 306 
 307     @Test
 308     @IR(applyIfOr = {"UseArrayLoadStoreProfile", "true", "TypeProfileLevel", "= 222"},
 309         counts = {CALL, "= 4", CLASS_CHECK_TRAP, "= 1", NULL_CHECK_TRAP, "= 1", RANGE_CHECK_TRAP, "= 1"})
 310     @IR(applyIfAnd = {"UseArrayLoadStoreProfile", "false", "TypeProfileLevel", "!= 222"},
 311         counts = {CALL, "= 4", RANGE_CHECK_TRAP, "= 1", NULL_CHECK_TRAP, "= 1"})
 312     public Object test7(ValueAbstract[] array) {
 313         ValueAbstract v = array[0];
 314         test7_helper(v);
 315         return v;
 316     }
 317 
 318     @Run(test = "test7")
 319     @Warmup(10000)
 320     public void test7_verifier(RunInfo info) {
 321         if (info.isWarmUp()) {
 322             // pollute profile
 323             test7_helper(new NonValueClass1(rI));
 324             test7_helper(new NonValueClass2(rI));
 325         }
 326         test7(new NonValueClass1[1]);
 327     }
 328 
 329     @DontInline
 330     public void test8_no_inline() {
 331     }
 332 
 333     public void test8_helper(Object arg) {
 334         if (arg instanceof Long) {
 335             test8_no_inline();
 336         }
 337     }
 338 
 339     @Test
 340     @IR(applyIf = {"UseArrayLoadStoreProfile", "true"},
 341         counts = {CALL, "= 5", CLASS_CHECK_TRAP, "= 1", NULL_CHECK_TRAP, "= 2",
 342                   RANGE_CHECK_TRAP, "= 1"})
 343     @IR(applyIf = {"UseArrayLoadStoreProfile", "false"},
 344         counts = {CALL, "= 5", RANGE_CHECK_TRAP, "= 1", NULL_CHECK_TRAP, "= 2"})
 345     public Object test8(Object[] array) {
 346         Object v = array[0];
 347         test8_helper(v);
 348         return v;
 349     }
 350 
 351     @Run(test = "test8")
 352     @Warmup(10000)
 353     public void test8_verifier(RunInfo info) {
 354         if (info.isWarmUp()) {
 355             // pollute profile
 356             test8_helper(42L);
 357             test8_helper(42.0D);
 358         }
 359         test8(testValue1Array);
 360         test8(testValue1NotFlatArray);
 361     }
 362 
 363     // aastore
 364 
 365     @Test
 366     @IR(applyIfOr = {"UseArrayLoadStoreProfile", "true", "TypeProfileLevel", "= 222"},
 367         failOn = {STORE_UNKNOWN_INLINE})
 368     @IR(applyIfAnd = {"UseArrayLoadStoreProfile", "false", "TypeProfileLevel", "!= 222"},
 369         counts = {STORE_UNKNOWN_INLINE, "= 1"})
 370     public void test9(Object[] array, Object v) {
 371         array[0] = v;
 372     }
 373 
 374     @Run(test = "test9")
 375     @Warmup(10000)
 376     public void test9_verifier() {
 377         test9(testValue1Array, testValue1);
 378         Asserts.assertEQ(testValue1Array[0].hash(), testValue1.hash());
 379     }
 380 
 381     @Test
 382     @IR(applyIfOr = {"UseArrayLoadStoreProfile", "true", "TypeProfileLevel", "= 222"},
 383         failOn = {STORE_UNKNOWN_INLINE})
 384     @IR(applyIfAnd = {"UseArrayLoadStoreProfile", "false", "TypeProfileLevel", "!= 222"},
 385         counts = {STORE_UNKNOWN_INLINE, "= 1"})
 386     public void test10(Object[] array, Object v) {
 387         array[0] = v;
 388     }
 389 
 390     @Run(test = "test10")
 391     @Warmup(10000)
 392     public void test10_verifier() {
 393         test10(testIntegerArray, 42);
 394     }
 395 
 396     @Test
 397     @IR(counts = {STORE_UNKNOWN_INLINE, "= 1"})
 398     public void test11(Object[] array, Object v) {
 399         array[0] = v;
 400     }
 401 
 402     @Run(test = "test11")
 403     @Warmup(10000)
 404     public void test11_verifier() {
 405         test11(testValue1Array, testValue1);
 406         test11(testValue2Array, testValue2);
 407     }
 408 
 409     @Test
 410     @IR(applyIf = {"UseArrayLoadStoreProfile", "true"},
 411         failOn = {STORE_UNKNOWN_INLINE})
 412     @IR(applyIf = {"UseArrayLoadStoreProfile", "false"},
 413         counts = {STORE_UNKNOWN_INLINE, "= 1"})
 414     public void test12(Object[] array, Object v) {
 415         array[0] = v;
 416     }
 417 
 418     @Run(test = "test12")
 419     @Warmup(10000)
 420     public void test12_verifier() {
 421         test12(testIntegerArray, 42);
 422         test12(testLongArray, 42L);
 423     }
 424 
 425     @Test
 426     @IR(counts = {STORE_UNKNOWN_INLINE, "= 1"})
 427     public void test13(Object[] array, Object v) {
 428         array[0] = v;
 429     }
 430 
 431     @Run(test = "test13")
 432     @Warmup(10000)
 433     public void test13_verifier() {
 434         test13(testValue1Array, testValue1);
 435         test13(testValue1NotFlatArray, testValue1);
 436     }
 437 
 438     // MonomorphicArrayCheck
 439     @Test
 440     public void test14(Number[] array, Number v) {
 441         array[0] = v;
 442     }
 443 
 444     @Run(test = "test14")
 445     @Warmup(10000)
 446     public void test14_verifier(RunInfo info) {
 447         if (info.isWarmUp()) {
 448             test14(testIntegerArray, 42);
 449         } else {
 450             Method m = info.getTest();
 451             boolean deopt = false;
 452             for (int i = 0; i < 100; i++) {
 453                 test14(testIntegerArray, 42);
 454                 if (!info.isCompilationSkipped() && !TestFramework.isCompiled(m)) {
 455                     deopt = true;
 456                 }
 457             }
 458             if (deopt && TestFramework.isStableDeopt(m, CompLevel.C2) && !WBFlags.TieredCompilation && WBFlags.ProfileInterpreter &&
 459                 (WBFlags.UseArrayLoadStoreProfile || WBFlags.TypeProfileLevel == 222)) {
 460                 throw new RuntimeException("Monomorphic array check should rely on profiling and be accurate");
 461             }
 462         }
 463     }
 464 
 465     // null free array profiling
 466 
 467     @LooselyConsistentValue
 468     static value class NotFlattenable {
 469         private Object o1 = null;
 470         private Object o2 = null;
 471         private Object o3 = null;
 472         private Object o4 = null;
 473         private Object o5 = null;
 474         private Object o6 = null;
 475     }
 476 
 477     @Strict
 478     @NullRestricted
 479     private static final NotFlattenable notFlattenable = new NotFlattenable();
 480     private static final NotFlattenable[] testNotFlattenableArray = (NotFlattenable[])ValueClass.newNullRestrictedNonAtomicArray(NotFlattenable.class, 1, new NotFlattenable());
 481 
 482     @Test
 483     @IR(applyIfOr = {"UseArrayLoadStoreProfile", "true", "TypeProfileLevel", "= 222"},
 484         counts = {NULL_CHECK_TRAP, "= 2"},
 485         failOn = {STORE_UNKNOWN_INLINE})
 486     @IR(applyIfAnd = {"UseArrayLoadStoreProfile", "false", "TypeProfileLevel", "!= 222"},
 487         counts = {NULL_CHECK_TRAP, "= 2", 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, "= 2", 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, "= 2", 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, "= 2", 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     @LooselyConsistentValue
1120     static value class Test40Inline extends Test40Abstract { }
1121 
1122     @ForceInline
1123     public Object test40_access(Object[] array) {
1124         return array[0];
1125     }
1126 
1127     @Test
1128     public Object test40(Test40Abstract[] array) {
1129         return test40_access(array);
1130     }
1131 
1132     @Run(test = "test40")
1133     @Warmup(10000)
1134     public void test40_verifier(RunInfo info) {
1135         // Make sure multiple implementors of Test40Abstract are loaded
1136         Test40Inline tmp1 = new Test40Inline();
1137         Test40Class tmp2 = new Test40Class();
1138         if (info.isWarmUp()) {
1139             // Pollute profile with Object[] (exact)
1140             test40_access(new Object[1]);
1141         } else {
1142             // When inlining test40_access, profiling contradicts actual type of array
1143             test40(new Test40Class[1]);
1144         }
1145     }
1146 
1147     // Same as test40 but with array store
1148     @ForceInline
1149     public void test41_access(Object[] array, Object val) {
1150         array[0] = val;
1151     }
1152 
1153     @Test
1154     public void test41(Test40Inline[] array, Object val) {
1155         test41_access(array, val);
1156     }
1157 
1158     @Run(test = "test41")
1159     @Warmup(10000)
1160     public void test41_verifier(RunInfo info) {
1161         // Make sure multiple implementors of Test40Abstract are loaded
1162         Test40Inline tmp1 = new Test40Inline();
1163         Test40Class tmp2 = new Test40Class();
1164         if (info.isWarmUp()) {
1165             // Pollute profile with exact Object[]
1166             test41_access(new Object[1], new Object());
1167         } else {
1168             // When inlining test41_access, profiling contradicts actual type of array
1169             Test40Inline[] array = (Test40Inline[])ValueClass.newNullRestrictedNonAtomicArray(Test40Inline.class, 1, new Test40Inline());
1170             test41(array, new Test40Inline());
1171         }
1172     }
1173 }