1 /*
   2  * Copyright (c) 2018, Red Hat, Inc. 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 /*
  25  * common code to run and validate tests of code generation for
  26  * volatile ops on AArch64
  27  *
  28  * incoming args are <testclass> <testtype>
  29  *
  30  * where <testclass> in {TestVolatileLoad,
  31  *                       TestVolatileStore,
  32  *                       TestUnsafeVolatileLoad,
  33  *                       TestUnsafeVolatileStore,
  34  *                       TestUnsafeVolatileCAS,
  35  *                       TestUnsafeVolatileWeakCAS,
  36  *                       TestUnsafeVolatileCAE,
  37  *                       TestUnsafeVolatileGAS}
  38  * and <testtype> in {G1,
  39  *                    Serial,
  40  *                    Parallel,
  41  *                    Shenandoah}
  42  */
  43 
  44 
  45 package compiler.c2.aarch64;
  46 
  47 import java.util.List;
  48 import java.util.ListIterator;
  49 import java.util.Iterator;
  50 import java.util.regex.Pattern;
  51 import java.io.*;
  52 
  53 import jdk.test.lib.Asserts;
  54 import jdk.test.lib.compiler.InMemoryJavaCompiler;
  55 import jdk.test.lib.process.OutputAnalyzer;
  56 import jdk.test.lib.process.ProcessTools;
  57 import sun.hotspot.WhiteBox;
  58 
  59 // runner class that spawns a new JVM to exercises a combination of
  60 // volatile MemOp and GC. The ops are compiled with the dmb -->
  61 // ldar/stlr transforms either enabled or disabled. this runner parses
  62 // the PrintOptoAssembly output checking that the generated code is
  63 // correct.
  64 
  65 public class TestVolatiles {
  66     public void runtest(String classname, String testType) throws Throwable {
  67         // n.b. clients omit the package name for the class
  68         String fullclassname = "compiler.c2.aarch64." + classname;
  69         // build up a command line for the spawned JVM
  70         String[] procArgs;
  71         int argcount;
  72         // add one or two extra arguments according to test type
  73         // i.e. GC type plus GC conifg
  74         switch(testType) {
  75         case "G1":
  76             argcount = 9;
  77             procArgs = new String[argcount];
  78             procArgs[argcount - 2] = "-XX:+UseG1GC";
  79             break;
  80         case "Parallel":
  81             argcount = 9;
  82             procArgs = new String[argcount];
  83             procArgs[argcount - 2] = "-XX:+UseParallelGC";
  84             break;
  85         case "Serial":
  86             argcount = 9;
  87             procArgs = new String[argcount];
  88             procArgs[argcount - 2] = "-XX:+UseSerialGC";
  89             break;
  90         case "Shenandoah":
  91             argcount = 10;
  92             procArgs = new String[argcount];
  93             procArgs[argcount - 3] = "-XX:+UnlockExperimentalVMOptions";
  94             procArgs[argcount - 2] = "-XX:+UseShenandoahGC";
  95             break;
  96         default:
  97             throw new RuntimeException("unexpected test type " + testType);
  98         }
  99 
 100         // fill in arguments common to all cases
 101 
 102         // the first round of test enables transform of barriers to
 103         // use acquiring loads and releasing stores by setting arg
 104         // zero appropriately. this arg is reset in the second run to
 105         // disable the transform.
 106 
 107         procArgs[0] = "-XX:-UseBarriersForVolatile";
 108         procArgs[1] = "-XX:+UseCompressedOops";
 109 
 110         procArgs[2] = "-XX:-TieredCompilation";
 111         procArgs[3] = "-XX:+PrintOptoAssembly";
 112         procArgs[4] = "-XX:CompileCommand=compileonly," + fullclassname + "::" + "test*";
 113         procArgs[5] = "--add-exports";
 114         procArgs[6] = "java.base/jdk.internal.misc=ALL-UNNAMED";
 115         procArgs[argcount - 1] = fullclassname;
 116 
 117         runtest(classname, testType, false, true, procArgs);
 118         // rerun the test class without the transform applied and
 119         // check the alternative generation is as expected
 120 
 121         procArgs[0] = "-XX:+UseBarriersForVolatile";
 122         runtest(classname, testType, true, true, procArgs);
 123 
 124         if (!classname.equals("TestUnsafeVolatileGAA")) {
 125             procArgs[0] = "-XX:-UseBarriersForVolatile";
 126             procArgs[1] = "-XX:-UseCompressedOops";
 127             runtest(classname, testType, false, false, procArgs);
 128 
 129             procArgs[0] = "-XX:+UseBarriersForVolatile";
 130             runtest(classname, testType, true, false, procArgs);
 131         }
 132     }
 133 
 134 
 135     public void runtest(String classname, String testType, boolean useBarriersForVolatile, boolean useCompressedOops, String[] procArgs) throws Throwable {
 136         ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(procArgs);
 137         OutputAnalyzer output = new OutputAnalyzer(pb.start());
 138 
 139         output.stderrShouldBeEmptyIgnoreVMWarnings();
 140         output.stdoutShouldNotBeEmpty();
 141         output.shouldHaveExitValue(0);
 142 
 143         // check the output for the correct asm sequence as
 144         // appropriate to test class, test type and whether transform
 145         // was applied
 146 
 147         checkoutput(output, classname, testType, useBarriersForVolatile, useCompressedOops);
 148     }
 149 
 150     // skip through output returning a line containing the desireed
 151     // substring or null
 152     private String skipTo(Iterator<String> iter, String substring)
 153     {
 154         while (iter.hasNext()) {
 155             String nextLine = iter.next();
 156             if (nextLine.matches(".*" + substring + ".*")) {
 157                 return nextLine;
 158             }
 159         }
 160         return null;
 161     }
 162 
 163     // locate the start of compiler output for the desired method and
 164     // then check that each expected instruction occurs in the output
 165     // in the order supplied. throw an excpetion if not found.
 166     // n.b. the spawned JVM's output is included in the exception
 167     // message to make it easeir to identify what is missing.
 168 
 169     private boolean checkCompile(Iterator<String> iter, String methodname, String[] expected, OutputAnalyzer output, boolean do_throw)
 170     {
 171         // trace call to allow eyeball check of what we are checking against
 172         System.out.println("checkCompile(" + methodname + ",");
 173         String sepr = "  { ";
 174         for (String s : expected) {
 175             System.out.print(sepr);
 176             System.out.print(s);
 177             sepr = ",\n    ";
 178         }
 179         System.out.println(" })");
 180 
 181         // look for the start of an opto assembly print block
 182         String match = skipTo(iter, Pattern.quote("{method}"));
 183         if (match == null) {
 184             if (do_throw) {
 185                 throw new RuntimeException("Missing compiler output for " + methodname + "!\n\n" + output.getOutput());
 186             }
 187             return false;
 188         }
 189         // check the compiled method name is right
 190         match = skipTo(iter, Pattern.quote("- name:"));
 191         if (match == null) {
 192             if (do_throw) {
 193                 throw new RuntimeException("Missing compiled method name!\n\n" + output.getOutput());
 194             }
 195             return false;
 196         }
 197         if (!match.contains(methodname)) {
 198             if (do_throw) {
 199                 throw new RuntimeException("Wrong method " + match + "!\n  -- expecting " + methodname + "\n\n" + output.getOutput());
 200             }
 201             return false;
 202         }
 203         // make sure we can match each expected term in order
 204         for (String s : expected) {
 205             match = skipTo(iter, s);
 206             if (match == null) {
 207                 if (do_throw) {
 208                     throw new RuntimeException("Missing expected output " + s + "!\n\n" + output.getOutput());
 209                 }
 210                 return false;
 211             }
 212         }
 213         return true;
 214     }
 215 
 216     // check for expected asm output from a volatile load
 217 
 218     private void checkload(OutputAnalyzer output, String testType, boolean useBarriersForVolatile, boolean useCompressedOops) throws Throwable
 219     {
 220         Iterator<String> iter = output.asLines().listIterator();
 221 
 222         // we shoud see this same sequence for normal or unsafe volatile load
 223         // for both int and Object fields
 224 
 225         String[] matches;
 226 
 227         if (!useBarriersForVolatile) {
 228             matches = new String[] {
 229                 "ldarw",
 230                 "membar_acquire \\(elided\\)",
 231                 "ret"
 232             };
 233         } else {
 234             matches = new String[] {
 235                 "ldrw",
 236                 "membar_acquire",
 237                 "dmb ish",
 238                 "ret"
 239             };
 240         }
 241 
 242         checkCompile(iter, "testInt", matches, output, true);
 243 
 244         if (!useBarriersForVolatile) {
 245             matches = new String[] {
 246                 useCompressedOops ? "ldarw?" : "ldar",
 247                 "membar_acquire \\(elided\\)",
 248                 "ret"
 249             };
 250         } else {
 251             matches = new String[] {
 252                 useCompressedOops ? "ldrw?" : "ldr",
 253                 "membar_acquire",
 254                 "dmb ish",
 255                 "ret"
 256             };
 257         }
 258 
 259         checkCompile(iter, "testObj", matches, output, true);
 260 
 261     }
 262 
 263     // check for expected asm output from a volatile store
 264 
 265     private void checkstore(OutputAnalyzer output, String testType, boolean useBarriersForVolatile, boolean useCompressedOops) throws Throwable
 266     {
 267         Iterator<String> iter = output.asLines().listIterator();
 268 
 269         String[] matches;
 270 
 271         // non object stores are straightforward
 272         if (!useBarriersForVolatile) {
 273             // this is the sequence of instructions for all cases
 274             matches = new String[] {
 275                 "membar_release \\(elided\\)",
 276                 "stlrw",
 277                 "membar_volatile \\(elided\\)",
 278                 "ret"
 279             };
 280         } else {
 281             // this is the alternative sequence of instructions
 282             matches = new String[] {
 283                 "membar_release",
 284                 "dmb ish",
 285                 "strw",
 286                 "membar_volatile",
 287                 "dmb ish",
 288                 "ret"
 289             };
 290         }
 291 
 292         checkCompile(iter, "testInt", matches, output, true);
 293 
 294         // object stores will be as above except for when the GC
 295         // introduces barriers for card marking
 296 
 297         if (!useBarriersForVolatile) {
 298             switch (testType) {
 299             default:
 300                 // this is the basic sequence of instructions
 301                 matches = new String[] {
 302                     "membar_release \\(elided\\)",
 303                     useCompressedOops ? "stlrw?" : "stlr",
 304                     "membar_volatile \\(elided\\)",
 305                     "ret"
 306                 };
 307                 break;
 308             case "G1":
 309                 // a card mark volatile barrier should be generated
 310                 // before the card mark strb
 311                 //
 312                 // following the fix for 8225776 the G1 barrier is now
 313                 // scheduled out of line after the membar volatile and
 314                 // and subsequent return
 315                 matches = new String[] {
 316                     "membar_release \\(elided\\)",
 317                     useCompressedOops ? "stlrw?" : "stlr",
 318                     "membar_volatile \\(elided\\)",
 319                     "ret",
 320                     "membar_volatile",
 321                     "dmb ish",
 322                     "strb"
 323                 };
 324                 break;
 325             case "Shenandoah":
 326                  // Shenandoah generates normal object graphs for
 327                  // volatile stores
 328                 matches = new String[] {
 329                     "membar_release \\(elided\\)",
 330                     useCompressedOops ? "stlrw?" : "stlr",
 331                     "membar_volatile \\(elided\\)",
 332                     "ret"
 333                 };
 334                 break;
 335             }
 336         } else {
 337             switch (testType) {
 338             default:
 339                 // this is the basic sequence of instructions
 340                 matches = new String[] {
 341                     "membar_release",
 342                     "dmb ish",
 343                     useCompressedOops ? "strw?" : "str",
 344                     "membar_volatile",
 345                     "dmb ish",
 346                     "ret"
 347                 };
 348                 break;
 349             case "G1":
 350                 // a card mark volatile barrier should be generated
 351                 // before the card mark strb
 352                 //
 353                 // following the fix for 8225776 the G1 barrier is now
 354                 // scheduled out of line after the membar volatile and
 355                 // and subsequent return
 356                 matches = new String[] {
 357                     "membar_release",
 358                     "dmb ish",
 359                     useCompressedOops ? "strw?" : "str",
 360                     "membar_volatile",
 361                     "dmb ish",
 362                     "ret",
 363                     "membar_volatile",
 364                     "dmb ish",
 365                     "strb"
 366                 };
 367                 break;
 368             case "CMSCondMark":
 369                 // a card mark volatile barrier should be generated
 370                 // before the card mark strb from the StoreCM and the
 371                 // storestore barrier from the StoreCM should be elided
 372                 matches = new String[] {
 373                     "membar_release",
 374                     "dmb ish",
 375                     useCompressedOops ? "strw?" : "str",
 376                     "membar_volatile",
 377                     "dmb ish",
 378                     "storestore \\(elided\\)",
 379                     "strb",
 380                     "membar_volatile",
 381                     "dmb ish",
 382                     "ret"
 383                 };
 384                 break;
 385             case "CMS":
 386                 // a volatile card mark membar should not be generated
 387                 // before the card mark strb from the StoreCM and the
 388                 // storestore barrier from the StoreCM should be generated
 389                 // as "dmb ishst"
 390                 matches = new String[] {
 391                     "membar_release",
 392                     "dmb ish",
 393                     useCompressedOops ? "strw?" : "str",
 394                     "storestore",
 395                     "dmb ishst",
 396                     "strb",
 397                     "membar_volatile",
 398                     "dmb ish",
 399                     "ret"
 400                 };
 401                 break;
 402 
 403             case "Shenandoah":
 404                  // Shenandoah generates normal object graphs for
 405                  // volatile stores
 406                 matches = new String[] {
 407                     "membar_release",
 408                     "dmb ish",
 409                     useCompressedOops ? "strw?" : "str",
 410                     "membar_volatile",
 411                     "dmb ish",
 412                     "ret"
 413                 };
 414                 break;
 415             }
 416         }
 417 
 418         checkCompile(iter, "testObj", matches, output, true);
 419     }
 420 
 421     // check for expected asm output from a volatile cas
 422 
 423     private void checkcas(OutputAnalyzer output, String testType, boolean useBarriersForVolatile, boolean useCompressedOops) throws Throwable
 424     {
 425         Iterator<String> iter = output.asLines().listIterator();
 426 
 427         String[] matches;
 428         String[][] tests = {
 429             { "testInt", "cmpxchgw" },
 430             { "testLong", "cmpxchg" },
 431             { "testByte", "cmpxchgb" },
 432             { "testShort", "cmpxchgs" },
 433         };
 434 
 435         for (String[] test : tests) {
 436             // non object stores are straightforward
 437             if (!useBarriersForVolatile) {
 438                 // this is the sequence of instructions for all cases
 439                 matches = new String[] {
 440                     "membar_release \\(elided\\)",
 441                     test[1] + "_acq",
 442                     "membar_acquire \\(elided\\)",
 443                     "ret"
 444                 };
 445             } else {
 446                 // this is the alternative sequence of instructions
 447                 matches = new String[] {
 448                     "membar_release",
 449                     "dmb ish",
 450                     test[1] + " ",
 451                     "membar_acquire",
 452                     "dmb ish",
 453                     "ret"
 454                 };
 455             }
 456 
 457             checkCompile(iter, test[0], matches, output, true);
 458         }
 459 
 460         // object stores will be as above except for when the GC
 461         // introduces barriers for card marking
 462 
 463         if (!useBarriersForVolatile) {
 464             switch (testType) {
 465             default:
 466                 // this is the basic sequence of instructions
 467                 matches = new String[] {
 468                     "membar_release \\(elided\\)",
 469                     useCompressedOops ? "cmpxchgw?_acq" : "cmpxchg_acq",
 470                     "strb",
 471                     "membar_acquire \\(elided\\)",
 472                     "ret"
 473                 };
 474                 break;
 475             case "G1":
 476                 // a card mark volatile barrier should be generated
 477                 // before the card mark strb
 478                 //
 479                 // following the fix for 8225776 the G1 barrier is now
 480                 // scheduled out of line after the membar acquire and
 481                 // and subsequent return
 482                 matches = new String[] {
 483                     "membar_release \\(elided\\)",
 484                     useCompressedOops ? "cmpxchgw?_acq" : "cmpxchg_acq",
 485                     "membar_acquire \\(elided\\)",
 486                     "ret",
 487                     "membar_volatile",
 488                     "dmb ish",
 489                     "strb"
 490                 };
 491                 break;
 492             case "Shenandoah":
 493                 // For volatile CAS, Shenanodoah generates normal
 494                 // graphs with a shenandoah-specific cmpxchg
 495                 matches = new String[] {
 496                     "membar_release \\(elided\\)",
 497                     useCompressedOops ? "cmpxchgw?_acq_shenandoah" : "cmpxchg_acq_shenandoah",
 498                     "membar_acquire \\(elided\\)",
 499                     "ret"
 500                 };
 501                 break;
 502             }
 503         } else {
 504             switch (testType) {
 505             default:
 506                 // this is the basic sequence of instructions
 507                 matches = new String[] {
 508                     "membar_release",
 509                     "dmb ish",
 510                     useCompressedOops ? "cmpxchgw? " : "cmpxchg ",
 511                     "membar_acquire",
 512                     "dmb ish",
 513                     "ret"
 514                 };
 515                 break;
 516             case "G1":
 517                 // a card mark volatile barrier should be generated
 518                 // before the card mark strb
 519                 //
 520                 // following the fix for 8225776 the G1 barrier is now
 521                 // scheduled out of line after the membar acquire and
 522                 // and subsequent return
 523                 matches = new String[] {
 524                     "membar_release",
 525                     "dmb ish",
 526                     useCompressedOops ? "cmpxchgw? " : "cmpxchg ",
 527                     "membar_acquire",
 528                     "dmb ish",
 529                     "ret",
 530                     "membar_volatile",
 531                     "dmb ish",
 532                     "strb"
 533                 };
 534                 break;
 535             case "CMSCondMark":
 536                 // a card mark volatile barrier should be generated
 537                 // before the card mark strb from the StoreCM and the
 538                 // storestore barrier from the StoreCM should be elided
 539                 matches = new String[] {
 540                     "membar_release",
 541                     "dmb ish",
 542                     useCompressedOops ? "cmpxchgw? " : "cmpxchg ",
 543                     "membar_volatile",
 544                     "dmb ish",
 545                     "storestore \\(elided\\)",
 546                     "strb",
 547                     "membar_acquire",
 548                     "dmb ish",
 549                     "ret"
 550                 };
 551                 break;
 552             case "CMS":
 553                 // a volatile card mark membar should not be generated
 554                 // before the card mark strb from the StoreCM and the
 555                 // storestore barrier from the StoreCM should be generated
 556                 // as "dmb ishst"
 557                 matches = new String[] {
 558                     "membar_release",
 559                     "dmb ish",
 560                     useCompressedOops ? "cmpxchgw? " : "cmpxchg ",
 561                     "storestore",
 562                     "dmb ishst",
 563                     "strb",
 564                     "membar_acquire",
 565                     "dmb ish",
 566                     "ret"
 567                 };
 568                 break;
 569             case "Shenandoah":
 570                 // For volatile CAS, Shenanodoah generates normal
 571                 // graphs with a shenandoah-specific cmpxchg
 572                 matches = new String[] {
 573                     "membar_release",
 574                     "dmb ish",
 575                     useCompressedOops ? "cmpxchgw?_shenandoah" : "cmpxchg_shenandoah",
 576                     "membar_acquire",
 577                     "dmb ish",
 578                     "ret"
 579                 };
 580                 break;
 581             }
 582         }
 583 
 584         checkCompile(iter, "testObj", matches, output, true);
 585     }
 586 
 587     private void checkcae(OutputAnalyzer output, String testType, boolean useBarriersForVolatile, boolean useCompressedOops) throws Throwable
 588     {
 589         ListIterator<String> iter = output.asLines().listIterator();
 590 
 591         String[] matches;
 592         String[][] tests = {
 593             { "testInt", "cmpxchgw" },
 594             { "testLong", "cmpxchg" },
 595             { "testByte", "cmpxchgb" },
 596             { "testShort", "cmpxchgs" },
 597         };
 598 
 599         for (String[] test : tests) {
 600             // non object stores are straightforward
 601             if (!useBarriersForVolatile) {
 602                 // this is the sequence of instructions for all cases
 603                 matches = new String[] {
 604                     "membar_release \\(elided\\)",
 605                     test[1] + "_acq",
 606                     "membar_acquire \\(elided\\)",
 607                     "ret"
 608                 };
 609             } else {
 610                 // this is the alternative sequence of instructions
 611                 matches = new String[] {
 612                     "membar_release",
 613                     "dmb ish",
 614                     test[1] + " ",
 615                     "membar_acquire",
 616                     "dmb ish",
 617                     "ret"
 618                 };
 619             }
 620 
 621             checkCompile(iter, test[0], matches, output, true);
 622         }
 623 
 624         // object stores will be as above except for when the GC
 625         // introduces barriers for card marking
 626 
 627         if (!useBarriersForVolatile) {
 628             switch (testType) {
 629             default:
 630                 // this is the basic sequence of instructions
 631                 matches = new String[] {
 632                     "membar_release \\(elided\\)",
 633                     "strb",
 634                     useCompressedOops ? "cmpxchgw?_acq" : "cmpxchg_acq",
 635                     "membar_acquire \\(elided\\)",
 636                     "ret"
 637                 };
 638 
 639                 // card marking store may be scheduled before or after
 640                 // the cmpxchg so try both sequences.
 641                 int idx = iter.nextIndex();
 642                 if (!checkCompile(iter, "testObj", matches, output, false)) {
 643                     iter = output.asLines().listIterator(idx);
 644 
 645                     matches = new String[] {
 646                         "membar_release \\(elided\\)",
 647                         useCompressedOops ? "cmpxchgw?_acq" : "cmpxchg_acq",
 648                         "strb",
 649                         "membar_acquire \\(elided\\)",
 650                         "ret"
 651                     };
 652 
 653                     checkCompile(iter, "testObj", matches, output, true);
 654                 }
 655                 return;
 656 
 657             case "G1":
 658                 // a card mark volatile barrier should be generated
 659                 // before the card mark strb
 660                 //
 661                 // following the fix for 8225776 the G1 barrier is now
 662                 // scheduled out of line after the membar acquire and
 663                 // and subsequent return
 664                 matches = new String[] {
 665                     "membar_release \\(elided\\)",
 666                     useCompressedOops ? "cmpxchgw?_acq" : "cmpxchg_acq",
 667                     "membar_acquire \\(elided\\)",
 668                     "ret",
 669                     "membar_volatile",
 670                     "dmb ish",
 671                     "strb"
 672                 };
 673                 break;
 674             case "Shenandoah":
 675                 // For volatile CAS, Shenanodoah generates normal
 676                 // graphs with a shenandoah-specific cmpxchg
 677                 matches = new String[] {
 678                     "membar_release \\(elided\\)",
 679                     useCompressedOops ? "cmpxchgw?_acq_shenandoah" : "cmpxchg_acq_shenandoah",
 680                     "membar_acquire \\(elided\\)",
 681                     "ret"
 682                 };
 683                 break;
 684             }
 685         } else {
 686             switch (testType) {
 687             default:
 688                 // this is the basic sequence of instructions
 689                 matches = new String[] {
 690                     "membar_release",
 691                     "dmb ish",
 692                     useCompressedOops ? "cmpxchgw? " : "cmpxchg ",
 693                     "membar_acquire",
 694                     "dmb ish",
 695                     "ret"
 696                 };
 697                 break;
 698             case "G1":
 699                 // a card mark volatile barrier should be generated
 700                 // before the card mark strb
 701                 //
 702                 // following the fix for 8225776 the G1 barrier is now
 703                 // scheduled out of line after the membar acquire and
 704                 // and subsequent return
 705                 matches = new String[] {
 706                     "membar_release",
 707                     "dmb ish",
 708                     useCompressedOops ? "cmpxchgw? " : "cmpxchg ",
 709                     "membar_acquire",
 710                     "dmb ish",
 711                     "ret",
 712                     "membar_volatile",
 713                     "dmb ish",
 714                     "strb"
 715                 };
 716                 break;
 717             case "CMSCondMark":
 718                 // a card mark volatile barrier should be generated
 719                 // before the card mark strb from the StoreCM and the
 720                 // storestore barrier from the StoreCM should be elided
 721                 matches = new String[] {
 722                     "membar_release",
 723                     "dmb ish",
 724                     useCompressedOops ? "cmpxchgw? " : "cmpxchg ",
 725                     "membar_volatile",
 726                     "dmb ish",
 727                     "storestore \\(elided\\)",
 728                     "strb",
 729                     "membar_acquire",
 730                     "dmb ish",
 731                     "ret"
 732                 };
 733                 break;
 734             case "CMS":
 735                 // a volatile card mark membar should not be generated
 736                 // before the card mark strb from the StoreCM and the
 737                 // storestore barrier from the StoreCM should be generated
 738                 // as "dmb ishst"
 739                 matches = new String[] {
 740                     "membar_release",
 741                     "dmb ish",
 742                     useCompressedOops ? "cmpxchgw? " : "cmpxchg ",
 743                     "storestore",
 744                     "dmb ishst",
 745                     "strb",
 746                     "membar_acquire",
 747                     "dmb ish",
 748                     "ret"
 749                 };
 750                 break;
 751             case "Shenandoah":
 752                 // For volatile CAS, Shenanodoah generates normal
 753                 // graphs with a shenandoah-specific cmpxchg
 754                 matches = new String[] {
 755                     "membar_release",
 756                     "dmb ish",
 757                     useCompressedOops ? "cmpxchgw?_shenandoah" : "cmpxchg_shenandoah",
 758                     "membar_acquire",
 759                     "dmb ish",
 760                     "ret"
 761                 };
 762                 break;
 763             }
 764         }
 765 
 766         checkCompile(iter, "testObj", matches, output, true);
 767     }
 768 
 769     private void checkgas(OutputAnalyzer output, String testType, boolean useBarriersForVolatile, boolean useCompressedOops) throws Throwable
 770     {
 771         Iterator<String> iter = output.asLines().listIterator();
 772 
 773         String[] matches;
 774         String[][] tests = {
 775             { "testInt", "atomic_xchgw" },
 776             { "testLong", "atomic_xchg" },
 777         };
 778 
 779         for (String[] test : tests) {
 780             // non object stores are straightforward
 781             if (!useBarriersForVolatile) {
 782                 // this is the sequence of instructions for all cases
 783                 matches = new String[] {
 784                     "membar_release \\(elided\\)",
 785                     test[1] + "_acq",
 786                     "membar_acquire \\(elided\\)",
 787                     "ret"
 788                 };
 789             } else {
 790                 // this is the alternative sequence of instructions
 791                 matches = new String[] {
 792                     "membar_release",
 793                     "dmb ish",
 794                     test[1] + " ",
 795                     "membar_acquire",
 796                     "dmb ish",
 797                     "ret"
 798                 };
 799             }
 800 
 801             checkCompile(iter, test[0], matches, output, true);
 802         }
 803 
 804         // object stores will be as above except for when the GC
 805         // introduces barriers for card marking
 806 
 807         if (!useBarriersForVolatile) {
 808             switch (testType) {
 809             default:
 810                 // this is the basic sequence of instructions
 811                 matches = new String[] {
 812                     "membar_release \\(elided\\)",
 813                     useCompressedOops ? "atomic_xchgw?_acq" : "atomic_xchg_acq",
 814                     "strb",
 815                     "membar_acquire \\(elided\\)",
 816                     "ret"
 817                 };
 818                 break;
 819             case "G1":
 820                 // a card mark volatile barrier should be generated
 821                 // before the card mark strb
 822                 //
 823                 // following the fix for 8225776 the G1 barrier is now
 824                 // scheduled out of line after the membar acquire and
 825                 // and subsequent return
 826                 matches = new String[] {
 827                     "membar_release \\(elided\\)",
 828                     useCompressedOops ? "atomic_xchgw?_acq" : "atomic_xchg_acq",
 829                     "membar_acquire \\(elided\\)",
 830                     "ret",
 831                     "membar_volatile",
 832                     "dmb ish",
 833                     "strb"
 834                 };
 835                 break;
 836             case "Shenandoah":
 837                 matches = new String[] {
 838                     "membar_release \\(elided\\)",
 839                     useCompressedOops ? "atomic_xchgw?_acq" : "atomic_xchg_acq",
 840                     "membar_acquire \\(elided\\)",
 841                     "ret"
 842                 };
 843                 break;
 844             }
 845         } else {
 846             switch (testType) {
 847             default:
 848                 // this is the basic sequence of instructions
 849                 matches = new String[] {
 850                     "membar_release",
 851                     "dmb ish",
 852                     useCompressedOops ? "atomic_xchgw? " : "atomic_xchg ",
 853                     "membar_acquire",
 854                     "dmb ish",
 855                     "ret"
 856                 };
 857                 break;
 858             case "G1":
 859                 // a card mark volatile barrier should be generated
 860                 // before the card mark strb
 861                 //
 862                 // following the fix for 8225776 the G1 barrier is now
 863                 // scheduled out of line after the membar acquire and
 864                 // and subsequent return
 865                 matches = new String[] {
 866                     "membar_release",
 867                     "dmb ish",
 868                     useCompressedOops ? "atomic_xchgw? " : "atomic_xchg ",
 869                     "membar_acquire",
 870                     "dmb ish",
 871                     "ret",
 872                     "membar_volatile",
 873                     "dmb ish",
 874                     "strb"
 875                 };
 876                 break;
 877             case "CMSCondMark":
 878                 // a card mark volatile barrier should be generated
 879                 // before the card mark strb from the StoreCM and the
 880                 // storestore barrier from the StoreCM should be elided
 881                 matches = new String[] {
 882                     "membar_release",
 883                     "dmb ish",
 884                     useCompressedOops ? "atomic_xchgw? " : "atomic_xchg ",
 885                     "membar_volatile",
 886                     "dmb ish",
 887                     "storestore \\(elided\\)",
 888                     "strb",
 889                     "membar_acquire",
 890                     "dmb ish",
 891                     "ret"
 892                 };
 893                 break;
 894             case "CMS":
 895                 // a volatile card mark membar should not be generated
 896                 // before the card mark strb from the StoreCM and the
 897                 // storestore barrier from the StoreCM should be generated
 898                 // as "dmb ishst"
 899                 matches = new String[] {
 900                     "membar_release",
 901                     "dmb ish",
 902                     useCompressedOops ? "atomic_xchgw? " : "atomic_xchg ",
 903                     "storestore",
 904                     "dmb ishst",
 905                     "strb",
 906                     "membar_acquire",
 907                     "dmb ish",
 908                     "ret"
 909                 };
 910                 break;
 911             case "Shenandoah":
 912                 matches = new String[] {
 913                     "membar_release",
 914                     "dmb ish",
 915                     useCompressedOops ? "atomic_xchgw? " : "atomic_xchg ",
 916                     "membar_acquire",
 917                     "dmb ish",
 918                     "ret"
 919                 };
 920                 break;
 921             }
 922         }
 923 
 924         checkCompile(iter, "testObj", matches, output, true);
 925     }
 926 
 927     private void checkgaa(OutputAnalyzer output, String testType, boolean useBarriersForVolatile) throws Throwable
 928     {
 929         Iterator<String> iter = output.asLines().listIterator();
 930 
 931         String[] matches;
 932         String[][] tests = {
 933             { "testInt", "get_and_addI" },
 934             { "testLong", "get_and_addL" },
 935         };
 936 
 937         for (String[] test : tests) {
 938             // non object stores are straightforward
 939             if (!useBarriersForVolatile) {
 940                 // this is the sequence of instructions for all cases
 941                 matches = new String[] {
 942                     "membar_release \\(elided\\)",
 943                     test[1] + "_acq",
 944                     "membar_acquire \\(elided\\)",
 945                     "ret"
 946                 };
 947             } else {
 948                 // this is the alternative sequence of instructions
 949                 matches = new String[] {
 950                     "membar_release",
 951                     "dmb ish",
 952                     test[1] + " ",
 953                     "membar_acquire",
 954                     "dmb ish",
 955                     "ret"
 956                 };
 957             }
 958 
 959             checkCompile(iter, test[0], matches, output, true);
 960         }
 961 
 962     }
 963 
 964     // perform a check appropriate to the classname
 965 
 966     private void checkoutput(OutputAnalyzer output, String classname, String testType, boolean useBarriersForVolatile, boolean useCompressedOops) throws Throwable
 967     {
 968         // trace call to allow eyeball check of what is being checked
 969         System.out.println("checkoutput(" +
 970                            classname + ", " +
 971                            testType + ", " +
 972                            useBarriersForVolatile + ")\n" +
 973                            output.getOutput());
 974 
 975         switch (classname) {
 976         case "TestVolatileLoad":
 977             checkload(output, testType, useBarriersForVolatile, useCompressedOops);
 978             break;
 979         case "TestVolatileStore":
 980             checkstore(output, testType, useBarriersForVolatile, useCompressedOops);
 981             break;
 982         case "TestUnsafeVolatileLoad":
 983             checkload(output, testType, useBarriersForVolatile, useCompressedOops);
 984             break;
 985         case "TestUnsafeVolatileStore":
 986             checkstore(output, testType, useBarriersForVolatile, useCompressedOops);
 987             break;
 988         case "TestUnsafeVolatileCAS":
 989         case "TestUnsafeVolatileWeakCAS":
 990             checkcas(output, testType, useBarriersForVolatile, useCompressedOops);
 991             break;
 992         case "TestUnsafeVolatileCAE":
 993             checkcae(output, testType, useBarriersForVolatile, useCompressedOops);
 994             break;
 995         case "TestUnsafeVolatileGAS":
 996             checkgas(output, testType, useBarriersForVolatile, useCompressedOops);
 997             break;
 998         case "TestUnsafeVolatileGAA":
 999             checkgaa(output, testType, useBarriersForVolatile);
1000             break;
1001         }
1002     }
1003 }