8205694: AArch64: Add test to validate volatile load, store and CAS code generation

Implement tests to check volatile operations are translated to valid code

Reviewed-by: aph, kvn, dpochepk
This commit is contained in:
Andrew Dinn 2018-06-28 10:09:58 +00:00
parent 5fcc705378
commit c61ba730c1
12 changed files with 1267 additions and 27 deletions

@ -1627,7 +1627,7 @@ source %{
// which looks like this
//
// MemBarRelease
// MemBarCPUOrder_(leading)__________________
// {MemBarCPUOrder}_(leading)_________________
// C | M \ \\ C \
// | \ StoreN/P[mo_release] CastP2X
// | Bot \ /
@ -1663,7 +1663,7 @@ source %{
// The graph for a CAS varies slightly, the difference being
// that the StoreN/P node is replaced by a CompareAndSwapP/N node
// and the trailing MemBarVolatile by a MemBarCPUOrder +
// MemBarAcquire pair.
// MemBarAcquire pair (also the MemBarCPUOrder nodes are not optional).
//
// MemBarRelease
// MemBarCPUOrder_(leading)_______________
@ -1691,7 +1691,7 @@ source %{
// | . . . \ / Bot
// | MergeMem
// | |
// {MemBarCPUOrder}
// MemBarCPUOrder
// MemBarVolatile (trailing)
//
//
@ -1716,7 +1716,8 @@ source %{
// So with G1 the pre-write and releasing store subgraph looks like
// this (the nested Ifs are omitted).
//
// MemBarRelease (leading)____________
// MemBarRelease
// {MemBarCPUOrder}_(leading)___________
// C | || M \ M \ M \ M \ . . .
// | LoadB \ LoadL LoadN \
// | / \ \
@ -1932,7 +1933,7 @@ source %{
// the following 3 Mem flow subgraphs is present.
//
// MemBarRelease
// MemBarCPUOrder {leading}
// {MemBarCPUOrder} {leading}
// | \ . . .
// | StoreN/P[mo_release] . . .
// | /
@ -1961,7 +1962,7 @@ source %{
// MemBarAcquire {trailing}
//
// if the correct configuration is present returns the trailing
// membar otherwise NULL.
// or cardmark membar otherwise NULL.
//
// the input membar is expected to be either a cpuorder membar or a
// release membar. in the latter case it should not have a cpu membar
@ -2070,8 +2071,8 @@ source %{
// for a volatile store this can be either a trailing membar
// or a card mark membar. for a cas it must be a card mark
// membar
assert(cas == NULL || is_card_mark_membar(mbar),
"in CAS graph volatile membar must be a card mark");
guarantee(cas == NULL || is_card_mark_membar(mbar),
"in CAS graph volatile membar must be a card mark");
} else if (cas != NULL && x->Opcode() == Op_MemBarAcquire) {
mbar = x->as_MemBar();
}
@ -2197,15 +2198,16 @@ source %{
}
}
// we should not have both a store and a cas
if (st == NULL & cas == NULL) {
// we cannot have both a store and a cas
if (st == NULL && cas == NULL) {
// we have neither -- this is not a normal graph
return NULL;
}
if (st == NULL) {
// if we started from a volatile membar and found a CAS then the
// original membar ought to be for a card mark
assert((barrier_is_acquire || is_card_mark_membar(barrier)),
"unexpected volatile barrier (i.e. not card mark) in CAS graph");
guarantee((barrier_is_acquire || is_card_mark_membar(barrier)),
"unexpected volatile barrier (i.e. not card mark) in CAS graph");
// check that the CAS feeds the merge we used to get here via an
// intermediary SCMemProj
Node *scmemproj = NULL;
@ -2227,8 +2229,8 @@ source %{
}
} else {
// we should not have found a store if we started from an acquire
assert(!barrier_is_acquire,
"unexpected trailing acquire barrier in volatile store graph");
guarantee(!barrier_is_acquire,
"unexpected trailing acquire barrier in volatile store graph");
// the store should feed the merge we used to get here
for (DUIterator_Fast imax, i = st->fast_outs(imax); i < imax; i++) {
@ -2396,7 +2398,7 @@ source %{
}
// sanity check this feed turns up as the expected slice
assert(mm->as_MergeMem()->in(Compile::AliasIdxBot) == feed, "expecting membar to feed AliasIdxBot slice to Merge");
guarantee(mm->as_MergeMem()->in(Compile::AliasIdxBot) == feed, "expecting membar to feed AliasIdxBot slice to Merge");
MemBarNode *trailing = NULL;
// be sure we have a trailing membar fed by the merge
@ -2831,8 +2833,8 @@ bool needs_acquiring_load_exclusive(const Node *n)
// the barrier must be a cpuorder mmebar fed by a release membar
assert(barrier->Opcode() == Op_MemBarCPUOrder,
"CAS not fed by cpuorder membar!");
guarantee(barrier->Opcode() == Op_MemBarCPUOrder,
"CAS not fed by cpuorder membar!");
MemBarNode *b = parent_membar(barrier);
assert ((b != NULL && b->Opcode() == Op_MemBarRelease),
@ -2841,7 +2843,7 @@ bool needs_acquiring_load_exclusive(const Node *n)
// does this lead a normal subgraph?
MemBarNode *mbar = leading_to_normal(barrier);
assert(mbar != NULL, "CAS not embedded in normal graph!");
guarantee(mbar != NULL, "CAS not embedded in normal graph!");
// if this is a card mark membar check we have a trailing acquire
@ -2849,9 +2851,9 @@ bool needs_acquiring_load_exclusive(const Node *n)
mbar = card_mark_to_trailing(mbar);
}
assert(mbar != NULL, "card mark membar for CAS not embedded in normal graph!");
guarantee(mbar != NULL, "card mark membar for CAS not embedded in normal graph!");
assert(mbar->Opcode() == Op_MemBarAcquire, "trailing membar should be an acquire");
guarantee(mbar->Opcode() == Op_MemBarAcquire, "trailing membar should be an acquire");
#endif // ASSERT
// so we can just return true here
return true;
@ -2875,7 +2877,7 @@ bool unnecessary_storestore(const Node *storecm)
}
// if we are implementing volatile puts using barriers then the
// object put as an str so we must insert the dmb ishst
// object put is an str so we must insert the dmb ishst
if (UseBarriersForVolatile) {
return false;
@ -8400,7 +8402,8 @@ instruct storeimmCM0(immI0 zero, memory mem)
predicate(unnecessary_storestore(n));
ins_cost(INSN_COST);
format %{ "strb zr, $mem\t# byte" %}
format %{ "storestore (elided)\n\t"
"strb zr, $mem\t# byte" %}
ins_encode(aarch64_enc_strb0(mem));
@ -8414,8 +8417,9 @@ instruct storeimmCM0_ordered(immI0 zero, memory mem)
match(Set mem (StoreCM mem zero));
ins_cost(INSN_COST * 2);
format %{ "dmb ishst"
"\n\tstrb zr, $mem\t# byte" %}
format %{ "storestore\n\t"
"dmb ishst"
"\n\tstrb zr, $mem\t# byte" %}
ins_encode(aarch64_enc_strb0_ordered(mem));
@ -9193,7 +9197,8 @@ instruct membar_acquire() %{
match(MemBarAcquire);
ins_cost(VOLATILE_REF_COST);
format %{ "membar_acquire" %}
format %{ "membar_acquire\n\t"
"dmb ish" %}
ins_encode %{
__ block_comment("membar_acquire");
@ -9246,7 +9251,8 @@ instruct membar_release() %{
match(MemBarRelease);
ins_cost(VOLATILE_REF_COST);
format %{ "membar_release" %}
format %{ "membar_release\n\t"
"dmb ish" %}
ins_encode %{
__ block_comment("membar_release");
@ -9298,7 +9304,8 @@ instruct membar_volatile() %{
match(MemBarVolatile);
ins_cost(VOLATILE_REF_COST*100);
format %{ "membar_volatile" %}
format %{ "membar_volatile\n\t"
"dmb ish"%}
ins_encode %{
__ block_comment("membar_volatile");

@ -0,0 +1,80 @@
/*
* 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.
*/
package compiler.c2.aarch64;
import java.lang.reflect.Field;
import jdk.internal.misc.Unsafe;
class TestUnsafeVolatileCAS
{
public volatile int f_int = 0;
public volatile Integer f_obj = Integer.valueOf(0);
public static Unsafe unsafe = Unsafe.getUnsafe();
public static Field f_int_field;
public static Field f_obj_field;
public static long f_int_off;
public static long f_obj_off;
static {
try {
f_int_field = TestUnsafeVolatileCAS.class.getField("f_int");
f_obj_field = TestUnsafeVolatileCAS.class.getField("f_obj");
f_int_off = unsafe.objectFieldOffset(f_int_field);
f_obj_off = unsafe.objectFieldOffset(f_obj_field);
} catch (Exception e) {
System.out.println("reflection failed " + e);
e.printStackTrace();
}
}
public static void main(String[] args)
{
final TestUnsafeVolatileCAS t = new TestUnsafeVolatileCAS();
for (int i = 0; i < 100_000; i++) {
t.f_int = -1;
t.testInt(-1, i);
if (t.f_int != i) {
throw new RuntimeException("bad result!");
}
}
Integer minusOne = Integer.valueOf(-1);
for (int i = 0; i < 100_000; i++) {
t.f_obj = minusOne;
t.testObj(minusOne, Integer.valueOf(i));
if (t.f_obj != i) {
throw new RuntimeException("bad result!");
}
}
}
public void testInt(int x, int i)
{
unsafe.compareAndSetInt(this, f_int_off, x, i);
}
public void testObj(Object x, Object o)
{
unsafe.compareAndSetObject(this, f_obj_off, x, o);
}
}

@ -0,0 +1,56 @@
package compiler.c2.aarch64;
import java.lang.reflect.Field;
import jdk.internal.misc.Unsafe;
class TestUnsafeVolatileLoad
{
public volatile int f_int = 0;
public volatile Integer f_obj = Integer.valueOf(0);
public static Unsafe unsafe = Unsafe.getUnsafe();
public static Field f_int_field;
public static Field f_obj_field;
public static long f_int_off;
public static long f_obj_off;
static {
try {
f_int_field = TestUnsafeVolatileLoad.class.getField("f_int");
f_obj_field = TestUnsafeVolatileLoad.class.getField("f_obj");
f_int_off = unsafe.objectFieldOffset(f_int_field);
f_obj_off = unsafe.objectFieldOffset(f_obj_field);
} catch (Exception e) {
System.out.println("reflection failed " + e);
e.printStackTrace();
}
}
public static void main(String[] args)
{
final TestUnsafeVolatileLoad t = new TestUnsafeVolatileLoad();
for (int i = 0; i < 100_000; i++) {
t.f_int = i;
int r = t.testInt();
if (r != i) {
throw new RuntimeException("bad result!");
}
}
for (int i = 0; i < 100_000; i++) {
t.f_obj = Integer.valueOf(i);
int r = t.testObj();
if (r != i) {
throw new RuntimeException("bad result!");
}
}
}
public int testInt()
{
return unsafe.getIntVolatile(this, f_int_off);
}
public int testObj()
{
return ((Integer)unsafe.getObjectVolatile(this, f_obj_off));
}
}

@ -0,0 +1,79 @@
/*
* 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.
*/
package compiler.c2.aarch64;
import java.lang.reflect.Field;
import jdk.internal.misc.Unsafe;
class TestUnsafeVolatileStore
{
public volatile int f_int = 0;
public volatile Integer f_obj = Integer.valueOf(0);
public static Unsafe unsafe = Unsafe.getUnsafe();
public static Field f_int_field;
public static Field f_obj_field;
public static long f_int_off;
public static long f_obj_off;
static {
try {
f_int_field = TestUnsafeVolatileStore.class.getField("f_int");
f_obj_field = TestUnsafeVolatileStore.class.getField("f_obj");
f_int_off = unsafe.objectFieldOffset(f_int_field);
f_obj_off = unsafe.objectFieldOffset(f_obj_field);
} catch (Exception e) {
System.out.println("reflection failed " + e);
e.printStackTrace();
}
}
public static void main(String[] args)
{
final TestUnsafeVolatileStore t = new TestUnsafeVolatileStore();
for (int i = 0; i < 100_000; i++) {
t.f_int = -1;
t.testInt(i);
if (t.f_int != i) {
throw new RuntimeException("bad result!");
}
}
for (int i = 0; i < 100_000; i++) {
t.f_obj = null;
t.testObj(Integer.valueOf(i));
if (t.f_obj != i) {
throw new RuntimeException("bad result!");
}
}
}
public void testInt(int i)
{
unsafe.putIntVolatile(this, f_int_off, i);
}
public void testObj(Object o)
{
unsafe.putObjectVolatile(this, f_obj_off, o);
}
}

@ -0,0 +1,58 @@
/*
* 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.
*/
package compiler.c2.aarch64;
class TestVolatileLoad
{
public volatile int f_int = 0;
public volatile Integer f_obj = Integer.valueOf(0);
public static void main(String[] args)
{
final TestVolatileLoad t = new TestVolatileLoad();
for (int i = 0; i < 100_000; i++) {
t.f_int = i;
int r = t.testInt();
if (r != i) {
throw new RuntimeException("bad result!");
}
}
for (int i = 0; i < 100_000; i++) {
t.f_obj = Integer.valueOf(i);
int r = t.testObj();
if (r != i) {
throw new RuntimeException("bad result!");
}
}
}
public int testInt()
{
return f_int;
}
public int testObj()
{
return f_obj;
}
}

@ -0,0 +1,58 @@
/*
* 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.
*/
package compiler.c2.aarch64;
class TestVolatileStore
{
public volatile int f_int = 0;
public volatile Integer f_obj = Integer.valueOf(0);
public static void main(String[] args)
{
final TestVolatileStore t = new TestVolatileStore();
for (int i = 0; i < 100_000; i++) {
t.f_int = -1;
t.testInt(i);
if (t.f_int != i) {
throw new RuntimeException("bad result!");
}
}
for (int i = 0; i < 100_000; i++) {
t.f_obj = null;
t.testObj(Integer.valueOf(i));
if (t.f_obj != i) {
throw new RuntimeException("bad result!");
}
}
}
public void testInt(int i)
{
f_int = i;
}
public void testObj(Integer o)
{
f_obj = o;
}
}

@ -0,0 +1,572 @@
/*
* 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}
* and <testtype> in {G1,
* CMS,
* CMSCondCardMark,
* Serial,
* Parallel}
*/
package compiler.c2.aarch64;
import java.util.List;
import java.util.Iterator;
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;
// 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 = 8;
procArgs = new String[argcount];
procArgs[argcount - 2] = "-XX:+UseG1GC";
break;
case "Parallel":
argcount = 8;
procArgs = new String[argcount];
procArgs[argcount - 2] = "-XX:+UseParallelGC";
break;
case "Serial":
argcount = 8;
procArgs = new String[argcount];
procArgs[argcount - 2] = "-XX:+UseSerialGC";
break;
case "CMS":
argcount = 9 ;
procArgs = new String[argcount];
procArgs[argcount - 3] = "-XX:+UseConcMarkSweepGC";
procArgs[argcount - 2] = "-XX:-UseCondCardMark";
break;
case "CMSCondMark":
argcount = 9 ;
procArgs = new String[argcount];
procArgs[argcount - 3] = "-XX:+UseConcMarkSweepGC";
procArgs[argcount - 2] = "-XX:+UseCondCardMark";
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:-TieredCompilation";
procArgs[2] = "-XX:+PrintOptoAssembly";
procArgs[3] = "-XX:CompileCommand=compileonly," + fullclassname + "::" + "test*";
procArgs[4] = "--add-exports";
procArgs[5] = "java.base/jdk.internal.misc=ALL-UNNAMED";
procArgs[argcount - 1] = fullclassname;
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, false);
// rerun the test class without the transform applied and
// check the alternative generation is as expected
procArgs[0] = "-XX:+UseBarriersForVolatile";
pb = ProcessTools.createJavaProcessBuilder(procArgs);
output = new OutputAnalyzer(pb.start());
output.stderrShouldBeEmptyIgnoreVMWarnings();
output.stdoutShouldNotBeEmpty();
output.shouldHaveExitValue(0);
// again check the output for the correct asm sequence
checkoutput(output, classname, testType, true);
}
// 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.contains(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 void checkCompile(Iterator<String> iter, String methodname, String[] expected, OutputAnalyzer output)
{
// 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, "{method}");
if (match == null) {
throw new RuntimeException("Missing compiler output for " + methodname + "!\n\n" + output.getOutput());
}
// check the compiled method name is right
match = skipTo(iter, "- name:");
if (match == null) {
throw new RuntimeException("Missing compiled method name!\n\n" + output.getOutput());
}
if (!match.contains(methodname)) {
throw new RuntimeException("Wrong method " + match + "!\n -- expecting " + methodname + "\n\n" + output.getOutput());
}
// make sure we can match each expected term in order
for (String s : expected) {
match = skipTo(iter, s);
if (match == null) {
throw new RuntimeException("Missing expected output " + s + "!\n\n" + output.getOutput());
}
}
}
// check for expected asm output from a volatile load
private void checkload(OutputAnalyzer output, String testType, boolean useBarriersForVolatile) 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);
checkCompile(iter, "testObj", matches, output) ;
}
// check for expected asm output from a volatile store
private void checkstore(OutputAnalyzer output, String testType, boolean useBarriersForVolatile) 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);
// 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)",
"stlrw",
"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)",
"stlrw",
"membar_volatile",
"dmb ish",
"strb",
"membar_volatile (elided)",
"ret"
};
break;
case "CMSCondCardMark":
// 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)",
"stlrw",
"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 elided
matches = new String[] {
"membar_release (elided)",
"stlrw",
"storestore (elided)",
"strb",
"membar_volatile (elided)",
"ret"
};
break;
}
} else {
switch (testType) {
default:
// this is the basic sequence of instructions
matches = new String[] {
"membar_release",
"dmb ish",
"strw",
"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",
"strw",
"membar_volatile",
"dmb ish",
"strb",
"membar_volatile",
"dmb ish",
"ret"
};
break;
case "CMSCondCardMark":
// 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",
"strw",
"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",
"strw",
"storestore",
"dmb ishst",
"strb",
"membar_volatile",
"dmb ish",
"ret"
};
break;
}
}
checkCompile(iter, "testObj", matches, output);
}
// check for expected asm output from a volatile cas
private void checkcas(OutputAnalyzer output, String testType, boolean useBarriersForVolatile) 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)",
"cmpxchgw_acq",
"membar_acquire (elided)",
"ret"
};
} else {
// this is the alternative sequence of instructions
matches = new String[] {
"membar_release",
"dmb ish",
"cmpxchgw",
"membar_acquire",
"dmb ish",
"ret"
};
}
checkCompile(iter, "testInt", matches, output);
// 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)",
"cmpxchgw_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)",
"cmpxchgw_acq",
"membar_volatile",
"dmb ish",
"strb",
"membar_acquire (elided)",
"ret"
};
break;
case "CMSCondCardMark":
// 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)",
"cmpxchgw_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)",
"cmpxchgw_acq",
"storestore (elided)",
"strb",
"membar_acquire (elided)",
"ret"
};
break;
}
} else {
switch (testType) {
default:
// this is the basic sequence of instructions
matches = new String[] {
"membar_release",
"dmb ish",
"cmpxchgw",
"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",
"cmpxchgw",
"membar_volatile",
"dmb ish",
"strb",
"membar_acquire",
"dmb ish",
"ret"
};
break;
case "CMSCondCardMark":
// 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",
"cmpxchgw",
"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",
"cmpxchgw",
"storestore",
"dmb ishst",
"strb",
"membar_acquire",
"dmb ish",
"ret"
};
break;
}
}
checkCompile(iter, "testObj", matches, output);
}
// perform a check appropriate to the classname
private void checkoutput(OutputAnalyzer output, String classname, String testType, boolean useBarriersForVolatile) 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);
break;
case "TestVolatileStore":
checkstore(output, testType, useBarriersForVolatile);
break;
case "TestUnsafeVolatileLoad":
checkload(output, testType, useBarriersForVolatile);
break;
case "TestUnsafeVolatileStore":
checkstore(output, testType, useBarriersForVolatile);
break;
case "TestUnsafeVolatileCAS":
checkcas(output, testType, useBarriersForVolatile);
break;
}
}
}

@ -0,0 +1,66 @@
/*
* 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.
*/
/*
* @test
* @summary C2 should use ldar, stlr and ldaxr+stlxr insns for volatile operations
* @library /test/lib /
*
* @modules java.base/jdk.internal.misc
*
* @requires os.arch=="aarch64" & vm.debug == true &
* vm.flavor == "server" & !vm.graal.enabled &
* vm.gc.ConcMarkSweep
*
* @build compiler.c2.aarch64.TestVolatiles
* compiler.c2.aarch64.TestVolatileLoad
* compiler.c2.aarch64.TestUnsafeVolatileLoad
* compiler.c2.aarch64.TestVolatileStore
* compiler.c2.aarch64.TestUnsafeVolatileStore
* compiler.c2.aarch64.TestUnsafeVolatileCAS
*
* @run driver compiler.c2.aarch64.TestVolatilesCMS
* TestVolatileLoad CMS
*
* @run driver compiler.c2.aarch64.TestVolatilesCMS
* TestVolatileStore CMS
*
* @run driver compiler.c2.aarch64.TestVolatilesCMS
* TestUnsafeVolatileLoad CMS
*
* @run driver compiler.c2.aarch64.TestVolatilesCMS
* TestUnsafeVolatileStore CMS
*
* @run driver compiler.c2.aarch64.TestVolatilesCMS
* TestUnsafeVolatileCAS CMS
*/
package compiler.c2.aarch64;
public class TestVolatilesCMS {
public static void main(String args[]) throws Throwable
{
// delegate work to shared code
new TestVolatiles().runtest(args[0], args[1]);
}
}

@ -0,0 +1,66 @@
/*
* 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.
*/
/*
* @test
* @summary C2 should use ldar, stlr and ldaxr+stlxr insns for volatile operations
* @library /test/lib /
*
* @modules java.base/jdk.internal.misc
*
* @requires os.arch=="aarch64" & vm.debug == true &
* vm.flavor == "server" & !vm.graal.enabled &
* vm.gc.ConcMarkSweep
*
* @build compiler.c2.aarch64.TestVolatiles
* compiler.c2.aarch64.TestVolatileLoad
* compiler.c2.aarch64.TestUnsafeVolatileLoad
* compiler.c2.aarch64.TestVolatileStore
* compiler.c2.aarch64.TestUnsafeVolatileStore
* compiler.c2.aarch64.TestUnsafeVolatileCAS
*
* @run driver compiler.c2.aarch64.TestVolatilesCMSCondMark
* TestVolatileLoad CMSCondMark
*
* @run driver compiler.c2.aarch64.TestVolatilesCMSCondMark
* TestVolatileStore CMSCondMark
*
* @run driver compiler.c2.aarch64.TestVolatilesCMSCondMark
* TestUnsafeVolatileLoad CMSCondMark
*
* @run driver compiler.c2.aarch64.TestVolatilesCMSCondMark
* TestUnsafeVolatileStore CMSCondMark
*
* @run driver compiler.c2.aarch64.TestVolatilesCMSCondMark
* TestUnsafeVolatileCAS CMSCondMark
*/
package compiler.c2.aarch64;
public class TestVolatilesCMSCondMark {
public static void main(String args[]) throws Throwable
{
// delegate work to shared code
new TestVolatiles().runtest(args[0], args[1]);
}
}

@ -0,0 +1,66 @@
/*
* 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.
*/
/*
* @test
* @summary C2 should use ldar, stlr and ldaxr+stlxr insns for volatile operations
* @library /test/lib /
*
* @modules java.base/jdk.internal.misc
*
* @requires os.arch=="aarch64" & vm.debug == true &
* vm.flavor == "server" & !vm.graal.enabled &
* vm.gc.G1
*
* @build compiler.c2.aarch64.TestVolatiles
* compiler.c2.aarch64.TestVolatileLoad
* compiler.c2.aarch64.TestUnsafeVolatileLoad
* compiler.c2.aarch64.TestVolatileStore
* compiler.c2.aarch64.TestUnsafeVolatileStore
* compiler.c2.aarch64.TestUnsafeVolatileCAS
*
* @run driver compiler.c2.aarch64.TestVolatilesG1
* TestVolatileLoad G1
*
* @run driver compiler.c2.aarch64.TestVolatilesG1
* TestVolatileStore G1
*
* @run driver compiler.c2.aarch64.TestVolatilesG1
* TestUnsafeVolatileLoad G1
*
* @run driver compiler.c2.aarch64.TestVolatilesG1
* TestUnsafeVolatileStore G1
*
* @run driver compiler.c2.aarch64.TestVolatilesG1
* TestUnsafeVolatileCAS G1
*/
package compiler.c2.aarch64;
public class TestVolatilesG1 {
public static void main(String args[]) throws Throwable
{
// delegate work to shared code
new TestVolatiles().runtest(args[0], args[1]);
}
}

@ -0,0 +1,66 @@
/*
* 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.
*/
/*
* @test
* @summary C2 should use ldar, stlr and ldaxr+stlxr insns for volatile operations
* @library /test/lib /
*
* @modules java.base/jdk.internal.misc
*
* @requires os.arch=="aarch64" & vm.debug == true &
* vm.flavor == "server" & !vm.graal.enabled &
* vm.gc.Parallel
*
* @build compiler.c2.aarch64.TestVolatiles
* compiler.c2.aarch64.TestVolatileLoad
* compiler.c2.aarch64.TestUnsafeVolatileLoad
* compiler.c2.aarch64.TestVolatileStore
* compiler.c2.aarch64.TestUnsafeVolatileStore
* compiler.c2.aarch64.TestUnsafeVolatileCAS
*
* @run driver compiler.c2.aarch64.TestVolatilesParallel
* TestVolatileLoad Parallel
*
* @run driver compiler.c2.aarch64.TestVolatilesParallel
* TestVolatileStore Parallel
*
* @run driver compiler.c2.aarch64.TestVolatilesParallel
* TestUnsafeVolatileLoad Parallel
*
* @run driver compiler.c2.aarch64.TestVolatilesParallel
* TestUnsafeVolatileStore Parallel
*
* @run driver compiler.c2.aarch64.TestVolatilesParallel
* TestUnsafeVolatileCAS Parallel
*/
package compiler.c2.aarch64;
public class TestVolatilesParallel {
public static void main(String args[]) throws Throwable
{
// delegate work to shared code
new TestVolatiles().runtest(args[0], args[1]);
}
}

@ -0,0 +1,66 @@
/*
* 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.
*/
/*
* @test
* @summary C2 should use ldar, stlr and ldaxr+stlxr insns for volatile operations
* @library /test/lib /
*
* @modules java.base/jdk.internal.misc
*
* @requires os.arch=="aarch64" & vm.debug == true &
* vm.flavor == "server" & !vm.graal.enabled &
* vm.gc.Serial
*
* @build compiler.c2.aarch64.TestVolatiles
* compiler.c2.aarch64.TestVolatileLoad
* compiler.c2.aarch64.TestUnsafeVolatileLoad
* compiler.c2.aarch64.TestVolatileStore
* compiler.c2.aarch64.TestUnsafeVolatileStore
* compiler.c2.aarch64.TestUnsafeVolatileCAS
*
* @run driver compiler.c2.aarch64.TestVolatilesSerial
* TestVolatileLoad Serial
*
* @run driver compiler.c2.aarch64.TestVolatilesSerial
* TestVolatileStore Serial
*
* @run driver compiler.c2.aarch64.TestVolatilesSerial
* TestUnsafeVolatileLoad Serial
*
* @run driver compiler.c2.aarch64.TestVolatilesSerial
* TestUnsafeVolatileStore Serial
*
* @run driver compiler.c2.aarch64.TestVolatilesSerial
* TestUnsafeVolatileCAS Serial
*/
package compiler.c2.aarch64;
public class TestVolatilesSerial {
public static void main(String args[]) throws Throwable
{
// delegate work to shared code
new TestVolatiles().runtest(args[0], args[1]);
}
}