| /* |
| * Copyright (c) 2018, Red Hat, Inc. All rights reserved. |
| * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
| * |
| * This code is free software; you can redistribute it and/or modify it |
| * under the terms of the GNU General Public License version 2 only, as |
| * published by the Free Software Foundation. |
| * |
| * This code is distributed in the hope that it will be useful, but WITHOUT |
| * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or |
| * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
| * version 2 for more details (a copy is included in the LICENSE file that |
| * accompanied this code). |
| * |
| * You should have received a copy of the GNU General Public License version |
| * 2 along with this work; if not, write to the Free Software Foundation, |
| * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. |
| * |
| * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA |
| * or visit www.oracle.com if you need additional information or have any |
| * questions. |
| */ |
| |
| /* |
| * common code to run and validate tests of code generation for |
| * volatile ops on AArch64 |
| * |
| * incoming args are <testclass> <testtype> |
| * |
| * where <testclass> in {TestVolatileLoad, |
| * TestVolatileStore, |
| * TestUnsafeVolatileLoad, |
| * TestUnsafeVolatileStore, |
| * TestUnsafeVolatileCAS, |
| * TestUnsafeVolatileWeakCAS, |
| * TestUnsafeVolatileCAE, |
| * TestUnsafeVolatileGAS} |
| * and <testtype> in {G1, |
| * CMS, |
| * CMSCondMark, |
| * Serial, |
| * Parallel, |
| * Shenandoah, |
| * ShenandoahIU} |
| */ |
| |
| |
| package compiler.c2.aarch64; |
| |
| import java.util.List; |
| import java.util.ListIterator; |
| import java.util.Iterator; |
| import java.util.regex.Pattern; |
| import java.io.*; |
| |
| import jdk.test.lib.Asserts; |
| import jdk.test.lib.compiler.InMemoryJavaCompiler; |
| import jdk.test.lib.process.OutputAnalyzer; |
| import jdk.test.lib.process.ProcessTools; |
| import sun.hotspot.WhiteBox; |
| |
| // runner class that spawns a new JVM to exercises a combination of |
| // volatile MemOp and GC. The ops are compiled with the dmb --> |
| // ldar/stlr transforms either enabled or disabled. this runner parses |
| // the PrintOptoAssembly output checking that the generated code is |
| // correct. |
| |
| public class TestVolatiles { |
| public void runtest(String classname, String testType) throws Throwable { |
| // n.b. clients omit the package name for the class |
| String fullclassname = "compiler.c2.aarch64." + classname; |
| // build up a command line for the spawned JVM |
| String[] procArgs; |
| int argcount; |
| // add one or two extra arguments according to test type |
| // i.e. GC type plus GC conifg |
| switch(testType) { |
| case "G1": |
| argcount = 9; |
| procArgs = new String[argcount]; |
| procArgs[argcount - 2] = "-XX:+UseG1GC"; |
| break; |
| case "Parallel": |
| argcount = 9; |
| procArgs = new String[argcount]; |
| procArgs[argcount - 2] = "-XX:+UseParallelGC"; |
| break; |
| case "Serial": |
| argcount = 9; |
| procArgs = new String[argcount]; |
| procArgs[argcount - 2] = "-XX:+UseSerialGC"; |
| break; |
| case "CMS": |
| argcount = 10; |
| procArgs = new String[argcount]; |
| procArgs[argcount - 3] = "-XX:+UseConcMarkSweepGC"; |
| procArgs[argcount - 2] = "-XX:-UseCondCardMark"; |
| break; |
| case "CMSCondMark": |
| argcount = 10; |
| procArgs = new String[argcount]; |
| procArgs[argcount - 3] = "-XX:+UseConcMarkSweepGC"; |
| procArgs[argcount - 2] = "-XX:+UseCondCardMark"; |
| break; |
| case "Shenandoah": |
| argcount = 9; |
| procArgs = new String[argcount]; |
| procArgs[argcount - 2] = "-XX:+UseShenandoahGC"; |
| break; |
| case "ShenandoahIU": |
| argcount = 11; |
| procArgs = new String[argcount]; |
| procArgs[argcount - 4] = "-XX:+UnlockExperimentalVMOptions"; |
| procArgs[argcount - 3] = "-XX:+UseShenandoahGC"; |
| procArgs[argcount - 2] = "-XX:ShenandoahGCMode=iu"; |
| break; |
| default: |
| throw new RuntimeException("unexpected test type " + testType); |
| } |
| |
| // fill in arguments common to all cases |
| |
| // the first round of test enables transform of barriers to |
| // use acquiring loads and releasing stores by setting arg |
| // zero appropriately. this arg is reset in the second run to |
| // disable the transform. |
| |
| procArgs[0] = "-XX:-UseBarriersForVolatile"; |
| procArgs[1] = "-XX:+UseCompressedOops"; |
| |
| procArgs[2] = "-XX:-TieredCompilation"; |
| procArgs[3] = "-XX:+PrintOptoAssembly"; |
| procArgs[4] = "-XX:CompileCommand=compileonly," + fullclassname + "::" + "test*"; |
| procArgs[5] = "--add-exports"; |
| procArgs[6] = "java.base/jdk.internal.misc=ALL-UNNAMED"; |
| procArgs[argcount - 1] = fullclassname; |
| |
| runtest(classname, testType, false, true, procArgs); |
| // rerun the test class without the transform applied and |
| // check the alternative generation is as expected |
| |
| procArgs[0] = "-XX:+UseBarriersForVolatile"; |
| runtest(classname, testType, true, true, procArgs); |
| |
| if (!classname.equals("TestUnsafeVolatileGAA")) { |
| procArgs[0] = "-XX:-UseBarriersForVolatile"; |
| procArgs[1] = "-XX:-UseCompressedOops"; |
| runtest(classname, testType, false, false, procArgs); |
| |
| procArgs[0] = "-XX:+UseBarriersForVolatile"; |
| runtest(classname, testType, true, false, procArgs); |
| } |
| } |
| |
| |
| public void runtest(String classname, String testType, boolean useBarriersForVolatile, boolean useCompressedOops, String[] procArgs) throws Throwable { |
| ProcessBuilder pb = ProcessTools.createJavaProcessBuilder(procArgs); |
| OutputAnalyzer output = new OutputAnalyzer(pb.start()); |
| |
| output.stderrShouldBeEmptyIgnoreVMWarnings(); |
| output.stdoutShouldNotBeEmpty(); |
| output.shouldHaveExitValue(0); |
| |
| // check the output for the correct asm sequence as |
| // appropriate to test class, test type and whether transform |
| // was applied |
| |
| checkoutput(output, classname, testType, useBarriersForVolatile, useCompressedOops); |
| } |
| |
| // skip through output returning a line containing the desireed |
| // substring or null |
| private String skipTo(Iterator<String> iter, String substring) |
| { |
| while (iter.hasNext()) { |
| String nextLine = iter.next(); |
| if (nextLine.matches(".*" + substring + ".*")) { |
| return nextLine; |
| } |
| } |
| return null; |
| } |
| |
| // locate the start of compiler output for the desired method and |
| // then check that each expected instruction occurs in the output |
| // in the order supplied. throw an excpetion if not found. |
| // n.b. the spawned JVM's output is included in the exception |
| // message to make it easeir to identify what is missing. |
| |
| private boolean checkCompile(Iterator<String> iter, String methodname, String[] expected, OutputAnalyzer output, boolean do_throw) |
| { |
| // trace call to allow eyeball check of what we are checking against |
| System.out.println("checkCompile(" + methodname + ","); |
| String sepr = " { "; |
| for (String s : expected) { |
| System.out.print(sepr); |
| System.out.print(s); |
| sepr = ",\n "; |
| } |
| System.out.println(" })"); |
| |
| // look for the start of an opto assembly print block |
| String match = skipTo(iter, Pattern.quote("{method}")); |
| if (match == null) { |
| if (do_throw) { |
| throw new RuntimeException("Missing compiler output for " + methodname + "!\n\n" + output.getOutput()); |
| } |
| return false; |
| } |
| // check the compiled method name is right |
| match = skipTo(iter, Pattern.quote("- name:")); |
| if (match == null) { |
| if (do_throw) { |
| throw new RuntimeException("Missing compiled method name!\n\n" + output.getOutput()); |
| } |
| return false; |
| } |
| if (!match.contains(methodname)) { |
| if (do_throw) { |
| throw new RuntimeException("Wrong method " + match + "!\n -- expecting " + methodname + "\n\n" + output.getOutput()); |
| } |
| return false; |
| } |
| // make sure we can match each expected term in order |
| for (String s : expected) { |
| match = skipTo(iter, s); |
| if (match == null) { |
| if (do_throw) { |
| throw new RuntimeException("Missing expected output " + s + "!\n\n" + output.getOutput()); |
| } |
| return false; |
| } |
| } |
| return true; |
| } |
| |
| // check for expected asm output from a volatile load |
| |
| private void checkload(OutputAnalyzer output, String testType, boolean useBarriersForVolatile, boolean useCompressedOops) throws Throwable |
| { |
| Iterator<String> iter = output.asLines().listIterator(); |
| |
| // we shoud see this same sequence for normal or unsafe volatile load |
| // for both int and Object fields |
| |
| String[] matches; |
| |
| if (!useBarriersForVolatile) { |
| matches = new String[] { |
| "ldarw", |
| "membar_acquire \\(elided\\)", |
| "ret" |
| }; |
| } else { |
| matches = new String[] { |
| "ldrw", |
| "membar_acquire", |
| "dmb ish", |
| "ret" |
| }; |
| } |
| |
| checkCompile(iter, "testInt", matches, output, true); |
| |
| if (!useBarriersForVolatile) { |
| matches = new String[] { |
| useCompressedOops ? "ldarw?" : "ldar", |
| "membar_acquire \\(elided\\)", |
| "ret" |
| }; |
| } else { |
| matches = new String[] { |
| useCompressedOops ? "ldrw?" : "ldr", |
| "membar_acquire", |
| "dmb ish", |
| "ret" |
| }; |
| } |
| |
| checkCompile(iter, "testObj", matches, output, true); |
| |
| } |
| |
| // check for expected asm output from a volatile store |
| |
| private void checkstore(OutputAnalyzer output, String testType, boolean useBarriersForVolatile, boolean useCompressedOops) throws Throwable |
| { |
| Iterator<String> iter = output.asLines().listIterator(); |
| |
| String[] matches; |
| |
| // non object stores are straightforward |
| if (!useBarriersForVolatile) { |
| // this is the sequence of instructions for all cases |
| matches = new String[] { |
| "membar_release \\(elided\\)", |
| "stlrw", |
| "membar_volatile \\(elided\\)", |
| "ret" |
| }; |
| } else { |
| // this is the alternative sequence of instructions |
| matches = new String[] { |
| "membar_release", |
| "dmb ish", |
| "strw", |
| "membar_volatile", |
| "dmb ish", |
| "ret" |
| }; |
| } |
| |
| checkCompile(iter, "testInt", matches, output, true); |
| |
| // object stores will be as above except for when the GC |
| // introduces barriers for card marking |
| |
| if (!useBarriersForVolatile) { |
| switch (testType) { |
| default: |
| // this is the basic sequence of instructions |
| matches = new String[] { |
| "membar_release \\(elided\\)", |
| useCompressedOops ? "stlrw?" : "stlr", |
| "membar_volatile \\(elided\\)", |
| "ret" |
| }; |
| break; |
| case "G1": |
| // a card mark volatile barrier should be generated |
| // before the card mark strb |
| matches = new String[] { |
| "membar_release \\(elided\\)", |
| useCompressedOops ? "stlrw?" : "stlr", |
| "membar_volatile", |
| "dmb ish", |
| "strb", |
| "membar_volatile \\(elided\\)", |
| "ret" |
| }; |
| break; |
| case "CMSCondMark": |
| // a card mark volatile barrier should be generated |
| // before the card mark strb from the StoreCM and the |
| // storestore barrier from the StoreCM should be elided |
| matches = new String[] { |
| "membar_release \\(elided\\)", |
| useCompressedOops ? "stlrw?" : "stlr", |
| "membar_volatile", |
| "dmb ish", |
| "storestore \\(elided\\)", |
| "strb", |
| "membar_volatile \\(elided\\)", |
| "ret" |
| }; |
| break; |
| case "CMS": |
| // a volatile card mark membar should not be generated |
| // before the card mark strb from the StoreCM and the |
| // storestore barrier from the StoreCM should be |
| // generated as "dmb ishst" |
| matches = new String[] { |
| "membar_release \\(elided\\)", |
| useCompressedOops ? "stlrw?" : "stlr", |
| "storestore", |
| "dmb ishst", |
| "strb", |
| "membar_volatile \\(elided\\)", |
| "ret" |
| }; |
| break; |
| case "Shenandoah": |
| case "ShenandoahIU": |
| // Shenandoah generates normal object graphs for |
| // volatile stores |
| matches = new String[] { |
| "membar_release \\(elided\\)", |
| useCompressedOops ? "stlrw?" : "stlr", |
| "membar_volatile \\(elided\\)", |
| "ret" |
| }; |
| break; |
| } |
| } else { |
| switch (testType) { |
| default: |
| // this is the basic sequence of instructions |
| matches = new String[] { |
| "membar_release", |
| "dmb ish", |
| useCompressedOops ? "strw?" : "str", |
| "membar_volatile", |
| "dmb ish", |
| "ret" |
| }; |
| break; |
| case "G1": |
| // a card mark volatile barrier should be generated |
| // before the card mark strb |
| matches = new String[] { |
| "membar_release", |
| "dmb ish", |
| useCompressedOops ? "strw?" : "str", |
| "membar_volatile", |
| "dmb ish", |
| "strb", |
| "membar_volatile", |
| "dmb ish", |
| "ret" |
| }; |
| break; |
| case "CMSCondMark": |
| // a card mark volatile barrier should be generated |
| // before the card mark strb from the StoreCM and the |
| // storestore barrier from the StoreCM should be elided |
| matches = new String[] { |
| "membar_release", |
| "dmb ish", |
| useCompressedOops ? "strw?" : "str", |
| "membar_volatile", |
| "dmb ish", |
| "storestore \\(elided\\)", |
| "strb", |
| "membar_volatile", |
| "dmb ish", |
| "ret" |
| }; |
| break; |
| case "CMS": |
| // a volatile card mark membar should not be generated |
| // before the card mark strb from the StoreCM and the |
| // storestore barrier from the StoreCM should be generated |
| // as "dmb ishst" |
| matches = new String[] { |
| "membar_release", |
| "dmb ish", |
| useCompressedOops ? "strw?" : "str", |
| "storestore", |
| "dmb ishst", |
| "strb", |
| "membar_volatile", |
| "dmb ish", |
| "ret" |
| }; |
| break; |
| |
| case "Shenandoah": |
| case "ShenandoahIU": |
| // Shenandoah generates normal object graphs for |
| // volatile stores |
| matches = new String[] { |
| "membar_release", |
| "dmb ish", |
| useCompressedOops ? "strw?" : "str", |
| "membar_volatile", |
| "dmb ish", |
| "ret" |
| }; |
| break; |
| } |
| } |
| |
| checkCompile(iter, "testObj", matches, output, true); |
| } |
| |
| // check for expected asm output from a volatile cas |
| |
| private void checkcas(OutputAnalyzer output, String testType, boolean useBarriersForVolatile, boolean useCompressedOops) throws Throwable |
| { |
| Iterator<String> iter = output.asLines().listIterator(); |
| |
| String[] matches; |
| String[][] tests = { |
| { "testInt", "cmpxchgw" }, |
| { "testLong", "cmpxchg" }, |
| { "testByte", "cmpxchgb" }, |
| { "testShort", "cmpxchgs" }, |
| }; |
| |
| for (String[] test : tests) { |
| // non object stores are straightforward |
| if (!useBarriersForVolatile) { |
| // this is the sequence of instructions for all cases |
| matches = new String[] { |
| "membar_release \\(elided\\)", |
| test[1] + "_acq", |
| "membar_acquire \\(elided\\)", |
| "ret" |
| }; |
| } else { |
| // this is the alternative sequence of instructions |
| matches = new String[] { |
| "membar_release", |
| "dmb ish", |
| test[1] + " ", |
| "membar_acquire", |
| "dmb ish", |
| "ret" |
| }; |
| } |
| |
| checkCompile(iter, test[0], matches, output, true); |
| } |
| |
| // object stores will be as above except for when the GC |
| // introduces barriers for card marking |
| |
| if (!useBarriersForVolatile) { |
| switch (testType) { |
| default: |
| // this is the basic sequence of instructions |
| matches = new String[] { |
| "membar_release \\(elided\\)", |
| useCompressedOops ? "cmpxchgw?_acq" : "cmpxchg_acq", |
| "strb", |
| "membar_acquire \\(elided\\)", |
| "ret" |
| }; |
| break; |
| case "G1": |
| // a card mark volatile barrier should be generated |
| // before the card mark strb |
| matches = new String[] { |
| "membar_release \\(elided\\)", |
| useCompressedOops ? "cmpxchgw?_acq" : "cmpxchg_acq", |
| "membar_volatile", |
| "dmb ish", |
| "strb", |
| "membar_acquire \\(elided\\)", |
| "ret" |
| }; |
| break; |
| case "CMSCondMark": |
| // a card mark volatile barrier should be generated |
| // before the card mark strb from the StoreCM and the |
| // storestore barrier from the StoreCM should be elided |
| matches = new String[] { |
| "membar_release \\(elided\\)", |
| useCompressedOops ? "cmpxchgw?_acq" : "cmpxchg_acq", |
| "membar_volatile", |
| "dmb ish", |
| "storestore \\(elided\\)", |
| "strb", |
| "membar_acquire \\(elided\\)", |
| "ret" |
| }; |
| break; |
| case "CMS": |
| // a volatile card mark membar should not be generated |
| // before the card mark strb from the StoreCM and the |
| // storestore barrier from the StoreCM should be elided |
| matches = new String[] { |
| "membar_release \\(elided\\)", |
| useCompressedOops ? "cmpxchgw?_acq" : "cmpxchg_acq", |
| "storestore", |
| "dmb ishst", |
| "strb", |
| "membar_acquire \\(elided\\)", |
| "ret" |
| }; |
| break; |
| case "Shenandoah": |
| case "ShenandoahIU": |
| // For volatile CAS, Shenanodoah generates normal |
| // graphs with a shenandoah-specific cmpxchg |
| matches = new String[] { |
| "membar_release \\(elided\\)", |
| useCompressedOops ? "cmpxchgw?_acq_shenandoah" : "cmpxchg_acq_shenandoah", |
| "membar_acquire \\(elided\\)", |
| "ret" |
| }; |
| break; |
| } |
| } else { |
| switch (testType) { |
| default: |
| // this is the basic sequence of instructions |
| matches = new String[] { |
| "membar_release", |
| "dmb ish", |
| useCompressedOops ? "cmpxchgw? " : "cmpxchg ", |
| "membar_acquire", |
| "dmb ish", |
| "ret" |
| }; |
| break; |
| case "G1": |
| // a card mark volatile barrier should be generated |
| // before the card mark strb |
| matches = new String[] { |
| "membar_release", |
| "dmb ish", |
| useCompressedOops ? "cmpxchgw? " : "cmpxchg ", |
| "membar_volatile", |
| "dmb ish", |
| "strb", |
| "membar_acquire", |
| "dmb ish", |
| "ret" |
| }; |
| break; |
| case "CMSCondMark": |
| // a card mark volatile barrier should be generated |
| // before the card mark strb from the StoreCM and the |
| // storestore barrier from the StoreCM should be elided |
| matches = new String[] { |
| "membar_release", |
| "dmb ish", |
| useCompressedOops ? "cmpxchgw? " : "cmpxchg ", |
| "membar_volatile", |
| "dmb ish", |
| "storestore \\(elided\\)", |
| "strb", |
| "membar_acquire", |
| "dmb ish", |
| "ret" |
| }; |
| break; |
| case "CMS": |
| // a volatile card mark membar should not be generated |
| // before the card mark strb from the StoreCM and the |
| // storestore barrier from the StoreCM should be generated |
| // as "dmb ishst" |
| matches = new String[] { |
| "membar_release", |
| "dmb ish", |
| useCompressedOops ? "cmpxchgw? " : "cmpxchg ", |
| "storestore", |
| "dmb ishst", |
| "strb", |
| "membar_acquire", |
| "dmb ish", |
| "ret" |
| }; |
| break; |
| case "Shenandoah": |
| case "ShenandoahIU": |
| // For volatile CAS, Shenanodoah generates normal |
| // graphs with a shenandoah-specific cmpxchg |
| matches = new String[] { |
| "membar_release", |
| useCompressedOops ? "cmpxchgw?_shenandoah" : "cmpxchg_shenandoah", |
| "membar_acquire", |
| "ret" |
| }; |
| break; |
| } |
| } |
| |
| checkCompile(iter, "testObj", matches, output, true); |
| } |
| |
| private void checkcae(OutputAnalyzer output, String testType, boolean useBarriersForVolatile, boolean useCompressedOops) throws Throwable |
| { |
| ListIterator<String> iter = output.asLines().listIterator(); |
| |
| String[] matches; |
| String[][] tests = { |
| { "testInt", "cmpxchgw" }, |
| { "testLong", "cmpxchg" }, |
| { "testByte", "cmpxchgb" }, |
| { "testShort", "cmpxchgs" }, |
| }; |
| |
| for (String[] test : tests) { |
| // non object stores are straightforward |
| if (!useBarriersForVolatile) { |
| // this is the sequence of instructions for all cases |
| matches = new String[] { |
| "membar_release \\(elided\\)", |
| test[1] + "_acq", |
| "membar_acquire \\(elided\\)", |
| "ret" |
| }; |
| } else { |
| // this is the alternative sequence of instructions |
| matches = new String[] { |
| "membar_release", |
| "dmb ish", |
| test[1] + " ", |
| "membar_acquire", |
| "dmb ish", |
| "ret" |
| }; |
| } |
| |
| checkCompile(iter, test[0], matches, output, true); |
| } |
| |
| // object stores will be as above except for when the GC |
| // introduces barriers for card marking |
| |
| if (!useBarriersForVolatile) { |
| switch (testType) { |
| default: |
| // this is the basic sequence of instructions |
| matches = new String[] { |
| "membar_release \\(elided\\)", |
| "strb", |
| useCompressedOops ? "cmpxchgw?_acq" : "cmpxchg_acq", |
| "membar_acquire \\(elided\\)", |
| "ret" |
| }; |
| |
| // card marking store may be scheduled before or after |
| // the cmpxchg so try both sequences. |
| int idx = iter.nextIndex(); |
| if (!checkCompile(iter, "testObj", matches, output, false)) { |
| iter = output.asLines().listIterator(idx); |
| |
| matches = new String[] { |
| "membar_release \\(elided\\)", |
| useCompressedOops ? "cmpxchgw?_acq" : "cmpxchg_acq", |
| "strb", |
| "membar_acquire \\(elided\\)", |
| "ret" |
| }; |
| |
| checkCompile(iter, "testObj", matches, output, true); |
| } |
| return; |
| |
| case "G1": |
| // a card mark volatile barrier should be generated |
| // before the card mark strb |
| matches = new String[] { |
| "membar_release \\(elided\\)", |
| useCompressedOops ? "cmpxchgw?_acq" : "cmpxchg_acq", |
| "membar_volatile", |
| "dmb ish", |
| "strb", |
| "membar_acquire \\(elided\\)", |
| "ret" |
| }; |
| break; |
| case "CMSCondMark": |
| // a card mark volatile barrier should be generated |
| // before the card mark strb from the StoreCM and the |
| // storestore barrier from the StoreCM should be elided |
| matches = new String[] { |
| "membar_release \\(elided\\)", |
| useCompressedOops ? "cmpxchgw?_acq" : "cmpxchg_acq", |
| "membar_volatile", |
| "dmb ish", |
| "storestore \\(elided\\)", |
| "strb", |
| "membar_acquire \\(elided\\)", |
| "ret" |
| }; |
| break; |
| case "CMS": |
| // a volatile card mark membar should not be generated |
| // before the card mark strb from the StoreCM and the |
| // storestore barrier from the StoreCM should be elided |
| matches = new String[] { |
| "membar_release \\(elided\\)", |
| useCompressedOops ? "cmpxchgw?_acq" : "cmpxchg_acq", |
| "storestore", |
| "dmb ishst", |
| "strb", |
| "membar_acquire \\(elided\\)", |
| "ret" |
| }; |
| break; |
| } |
| } else { |
| switch (testType) { |
| default: |
| // this is the basic sequence of instructions |
| matches = new String[] { |
| "membar_release", |
| "dmb ish", |
| useCompressedOops ? "cmpxchgw? " : "cmpxchg ", |
| "membar_acquire", |
| "dmb ish", |
| "ret" |
| }; |
| break; |
| case "G1": |
| // a card mark volatile barrier should be generated |
| // before the card mark strb |
| matches = new String[] { |
| "membar_release", |
| "dmb ish", |
| useCompressedOops ? "cmpxchgw? " : "cmpxchg ", |
| "membar_volatile", |
| "dmb ish", |
| "strb", |
| "membar_acquire", |
| "dmb ish", |
| "ret" |
| }; |
| break; |
| case "CMSCondMark": |
| // a card mark volatile barrier should be generated |
| // before the card mark strb from the StoreCM and the |
| // storestore barrier from the StoreCM should be elided |
| matches = new String[] { |
| "membar_release", |
| "dmb ish", |
| useCompressedOops ? "cmpxchgw? " : "cmpxchg ", |
| "membar_volatile", |
| "dmb ish", |
| "storestore \\(elided\\)", |
| "strb", |
| "membar_acquire", |
| "dmb ish", |
| "ret" |
| }; |
| break; |
| case "CMS": |
| // a volatile card mark membar should not be generated |
| // before the card mark strb from the StoreCM and the |
| // storestore barrier from the StoreCM should be generated |
| // as "dmb ishst" |
| matches = new String[] { |
| "membar_release", |
| "dmb ish", |
| useCompressedOops ? "cmpxchgw? " : "cmpxchg ", |
| "storestore", |
| "dmb ishst", |
| "strb", |
| "membar_acquire", |
| "dmb ish", |
| "ret" |
| }; |
| break; |
| case "Shenandoah": |
| case "ShenandoahIU": |
| // For volatile CAS, Shenanodoah generates normal |
| // graphs with a shenandoah-specific cmpxchg |
| matches = new String[] { |
| "membar_release", |
| "dmb ish", |
| useCompressedOops ? "cmpxchgw?_shenandoah" : "cmpxchg_shenandoah", |
| "membar_acquire", |
| "dmb ish", |
| "ret" |
| }; |
| break; |
| } |
| } |
| |
| checkCompile(iter, "testObj", matches, output, true); |
| } |
| |
| private void checkgas(OutputAnalyzer output, String testType, boolean useBarriersForVolatile, boolean useCompressedOops) throws Throwable |
| { |
| Iterator<String> iter = output.asLines().listIterator(); |
| |
| String[] matches; |
| String[][] tests = { |
| { "testInt", "atomic_xchgw" }, |
| { "testLong", "atomic_xchg" }, |
| }; |
| |
| for (String[] test : tests) { |
| // non object stores are straightforward |
| if (!useBarriersForVolatile) { |
| // this is the sequence of instructions for all cases |
| matches = new String[] { |
| "membar_release \\(elided\\)", |
| test[1] + "_acq", |
| "membar_acquire \\(elided\\)", |
| "ret" |
| }; |
| } else { |
| // this is the alternative sequence of instructions |
| matches = new String[] { |
| "membar_release", |
| "dmb ish", |
| test[1] + " ", |
| "membar_acquire", |
| "dmb ish", |
| "ret" |
| }; |
| } |
| |
| checkCompile(iter, test[0], matches, output, true); |
| } |
| |
| // object stores will be as above except for when the GC |
| // introduces barriers for card marking |
| |
| if (!useBarriersForVolatile) { |
| switch (testType) { |
| default: |
| // this is the basic sequence of instructions |
| matches = new String[] { |
| "membar_release \\(elided\\)", |
| useCompressedOops ? "atomic_xchgw?_acq" : "atomic_xchg_acq", |
| "strb", |
| "membar_acquire \\(elided\\)", |
| "ret" |
| }; |
| break; |
| case "G1": |
| // a card mark volatile barrier should be generated |
| // before the card mark strb |
| matches = new String[] { |
| "membar_release \\(elided\\)", |
| useCompressedOops ? "atomic_xchgw?_acq" : "atomic_xchg_acq", |
| "membar_volatile", |
| "dmb ish", |
| "strb", |
| "membar_acquire \\(elided\\)", |
| "ret" |
| }; |
| break; |
| case "CMSCondMark": |
| // a card mark volatile barrier should be generated |
| // before the card mark strb from the StoreCM and the |
| // storestore barrier from the StoreCM should be elided |
| matches = new String[] { |
| "membar_release \\(elided\\)", |
| useCompressedOops ? "atomic_xchgw?_acq" : "atomic_xchg_acq", |
| "membar_volatile", |
| "dmb ish", |
| "storestore \\(elided\\)", |
| "strb", |
| "membar_acquire \\(elided\\)", |
| "ret" |
| }; |
| break; |
| case "CMS": |
| // a volatile card mark membar should not be generated |
| // before the card mark strb from the StoreCM and the |
| // storestore barrier from the StoreCM should be elided |
| matches = new String[] { |
| "membar_release \\(elided\\)", |
| useCompressedOops ? "atomic_xchgw?_acq" : "atomic_xchg_acq", |
| "storestore", |
| "dmb ishst", |
| "strb", |
| "membar_acquire \\(elided\\)", |
| "ret" |
| }; |
| break; |
| } |
| } else { |
| switch (testType) { |
| default: |
| // this is the basic sequence of instructions |
| matches = new String[] { |
| "membar_release", |
| "dmb ish", |
| useCompressedOops ? "atomic_xchgw? " : "atomic_xchg ", |
| "membar_acquire", |
| "dmb ish", |
| "ret" |
| }; |
| break; |
| case "G1": |
| // a card mark volatile barrier should be generated |
| // before the card mark strb |
| matches = new String[] { |
| "membar_release", |
| "dmb ish", |
| useCompressedOops ? "atomic_xchgw? " : "atomic_xchg ", |
| "membar_volatile", |
| "dmb ish", |
| "strb", |
| "membar_acquire", |
| "dmb ish", |
| "ret" |
| }; |
| break; |
| case "CMSCondMark": |
| // a card mark volatile barrier should be generated |
| // before the card mark strb from the StoreCM and the |
| // storestore barrier from the StoreCM should be elided |
| matches = new String[] { |
| "membar_release", |
| "dmb ish", |
| useCompressedOops ? "atomic_xchgw? " : "atomic_xchg ", |
| "membar_volatile", |
| "dmb ish", |
| "storestore \\(elided\\)", |
| "strb", |
| "membar_acquire", |
| "dmb ish", |
| "ret" |
| }; |
| break; |
| case "CMS": |
| // a volatile card mark membar should not be generated |
| // before the card mark strb from the StoreCM and the |
| // storestore barrier from the StoreCM should be generated |
| // as "dmb ishst" |
| matches = new String[] { |
| "membar_release", |
| "dmb ish", |
| useCompressedOops ? "atomic_xchgw? " : "atomic_xchg ", |
| "storestore", |
| "dmb ishst", |
| "strb", |
| "membar_acquire", |
| "dmb ish", |
| "ret" |
| }; |
| break; |
| } |
| } |
| |
| checkCompile(iter, "testObj", matches, output, true); |
| } |
| |
| private void checkgaa(OutputAnalyzer output, String testType, boolean useBarriersForVolatile) throws Throwable |
| { |
| Iterator<String> iter = output.asLines().listIterator(); |
| |
| String[] matches; |
| String[][] tests = { |
| { "testInt", "get_and_addI" }, |
| { "testLong", "get_and_addL" }, |
| }; |
| |
| for (String[] test : tests) { |
| // non object stores are straightforward |
| if (!useBarriersForVolatile) { |
| // this is the sequence of instructions for all cases |
| matches = new String[] { |
| "membar_release \\(elided\\)", |
| test[1] + "_acq", |
| "membar_acquire \\(elided\\)", |
| "ret" |
| }; |
| } else { |
| // this is the alternative sequence of instructions |
| matches = new String[] { |
| "membar_release", |
| "dmb ish", |
| test[1] + " ", |
| "membar_acquire", |
| "dmb ish", |
| "ret" |
| }; |
| } |
| |
| checkCompile(iter, test[0], matches, output, true); |
| } |
| |
| } |
| |
| // perform a check appropriate to the classname |
| |
| private void checkoutput(OutputAnalyzer output, String classname, String testType, boolean useBarriersForVolatile, boolean useCompressedOops) throws Throwable |
| { |
| // trace call to allow eyeball check of what is being checked |
| System.out.println("checkoutput(" + |
| classname + ", " + |
| testType + ", " + |
| useBarriersForVolatile + ")\n" + |
| output.getOutput()); |
| |
| switch (classname) { |
| case "TestVolatileLoad": |
| checkload(output, testType, useBarriersForVolatile, useCompressedOops); |
| break; |
| case "TestVolatileStore": |
| checkstore(output, testType, useBarriersForVolatile, useCompressedOops); |
| break; |
| case "TestUnsafeVolatileLoad": |
| checkload(output, testType, useBarriersForVolatile, useCompressedOops); |
| break; |
| case "TestUnsafeVolatileStore": |
| checkstore(output, testType, useBarriersForVolatile, useCompressedOops); |
| break; |
| case "TestUnsafeVolatileCAS": |
| case "TestUnsafeVolatileWeakCAS": |
| checkcas(output, testType, useBarriersForVolatile, useCompressedOops); |
| break; |
| case "TestUnsafeVolatileCAE": |
| checkcae(output, testType, useBarriersForVolatile, useCompressedOops); |
| break; |
| case "TestUnsafeVolatileGAS": |
| checkgas(output, testType, useBarriersForVolatile, useCompressedOops); |
| break; |
| case "TestUnsafeVolatileGAA": |
| checkgaa(output, testType, useBarriersForVolatile); |
| break; |
| } |
| } |
| } |