8333791: Fix memory barriers for @Stable fields

Reviewed-by: liach, vlivanov
This commit is contained in:
Aleksey Shipilev 2024-08-15 11:24:22 +00:00
parent da7311bbe3
commit 74fdd6868d
14 changed files with 1047 additions and 39 deletions

View File

@ -1563,7 +1563,7 @@ void GraphBuilder::method_return(Value x, bool ignore_return) {
// The conditions for a memory barrier are described in Parse::do_exits().
bool need_mem_bar = false;
if (method()->name() == ciSymbols::object_initializer_name() &&
(scope()->wrote_final() ||
(scope()->wrote_final() || scope()->wrote_stable() ||
(AlwaysSafeConstructors && scope()->wrote_fields()) ||
(support_IRIW_for_not_multiple_copy_atomic_cpu && scope()->wrote_volatile()))) {
need_mem_bar = true;
@ -1741,15 +1741,17 @@ void GraphBuilder::access_field(Bytecodes::Code code) {
}
}
if (field->is_final() && (code == Bytecodes::_putfield)) {
scope()->set_wrote_final();
}
if (code == Bytecodes::_putfield) {
scope()->set_wrote_fields();
if (field->is_volatile()) {
scope()->set_wrote_volatile();
}
if (field->is_final()) {
scope()->set_wrote_final();
}
if (field->is_stable()) {
scope()->set_wrote_stable();
}
}
const int offset = !needs_patching ? field->offset_in_bytes() : -1;

View File

@ -146,6 +146,7 @@ IRScope::IRScope(Compilation* compilation, IRScope* caller, int caller_bci, ciMe
_wrote_final = false;
_wrote_fields = false;
_wrote_volatile = false;
_wrote_stable = false;
_start = nullptr;
if (osr_bci != -1) {

View File

@ -149,6 +149,7 @@ class IRScope: public CompilationResourceObj {
bool _wrote_final; // has written final field
bool _wrote_fields; // has written fields
bool _wrote_volatile; // has written volatile field
bool _wrote_stable; // has written @Stable field
BlockBegin* _start; // the start block, successsors are method entries
ResourceBitMap _requires_phi_function; // bit is set if phi functions at loop headers are necessary for a local variable
@ -187,6 +188,8 @@ class IRScope: public CompilationResourceObj {
bool wrote_fields () const { return _wrote_fields; }
void set_wrote_volatile() { _wrote_volatile = true; }
bool wrote_volatile () const { return _wrote_volatile; }
void set_wrote_stable() { _wrote_stable = true; }
bool wrote_stable() const { return _wrote_stable; }
};

View File

@ -358,7 +358,7 @@ class Parse : public GraphKit {
bool _wrote_volatile; // Did we write a volatile field?
bool _wrote_stable; // Did we write a @Stable field?
bool _wrote_fields; // Did we write any field?
Node* _alloc_with_final; // An allocation node with final field
Node* _alloc_with_final_or_stable; // An allocation node with final or @Stable field
// Variables which track Java semantics during bytecode parsing:
@ -403,10 +403,10 @@ class Parse : public GraphKit {
void set_wrote_stable(bool z) { _wrote_stable = z; }
bool wrote_fields() const { return _wrote_fields; }
void set_wrote_fields(bool z) { _wrote_fields = z; }
Node* alloc_with_final() const { return _alloc_with_final; }
void set_alloc_with_final(Node* n) {
assert((_alloc_with_final == nullptr) || (_alloc_with_final == n), "different init objects?");
_alloc_with_final = n;
Node* alloc_with_final_or_stable() const { return _alloc_with_final_or_stable; }
void set_alloc_with_final_or_stable(Node* n) {
assert((_alloc_with_final_or_stable == nullptr) || (_alloc_with_final_or_stable == n), "different init objects?");
_alloc_with_final_or_stable = n;
}
Block* block() const { return _block; }

View File

@ -412,7 +412,7 @@ Parse::Parse(JVMState* caller, ciMethod* parse_method, float expected_uses)
_wrote_volatile = false;
_wrote_stable = false;
_wrote_fields = false;
_alloc_with_final = nullptr;
_alloc_with_final_or_stable = nullptr;
_block = nullptr;
_first_return = true;
_replaced_nodes_for_exceptions = false;
@ -988,8 +988,8 @@ void Parse::do_exits() {
// Figure out if we need to emit the trailing barrier. The barrier is only
// needed in the constructors, and only in three cases:
//
// 1. The constructor wrote a final. The effects of all initializations
// must be committed to memory before any code after the constructor
// 1. The constructor wrote a final or a @Stable field. All these
// initializations must be ordered before any code after the constructor
// publishes the reference to the newly constructed object. Rather
// than wait for the publication, we simply block the writes here.
// Rather than put a barrier on only those writes which are required
@ -1014,34 +1014,23 @@ void Parse::do_exits() {
// exceptional returns, since they cannot publish normally.
//
if (method()->is_object_initializer() &&
(wrote_final() ||
(wrote_final() || wrote_stable() ||
(AlwaysSafeConstructors && wrote_fields()) ||
(support_IRIW_for_not_multiple_copy_atomic_cpu && wrote_volatile()))) {
Node* recorded_alloc = alloc_with_final_or_stable();
_exits.insert_mem_bar(UseStoreStoreForCtor ? Op_MemBarStoreStore : Op_MemBarRelease,
alloc_with_final());
recorded_alloc);
// If Memory barrier is created for final fields write
// and allocation node does not escape the initialize method,
// then barrier introduced by allocation node can be removed.
if (DoEscapeAnalysis && alloc_with_final()) {
AllocateNode* alloc = AllocateNode::Ideal_allocation(alloc_with_final());
if (DoEscapeAnalysis && (recorded_alloc != nullptr)) {
AllocateNode* alloc = AllocateNode::Ideal_allocation(recorded_alloc);
alloc->compute_MemBar_redundancy(method());
}
if (PrintOpto && (Verbose || WizardMode)) {
method()->print_name();
tty->print_cr(" writes finals and needs a memory barrier");
}
}
// Any method can write a @Stable field; insert memory barriers
// after those also. Can't bind predecessor allocation node (if any)
// with barrier because allocation doesn't always dominate
// MemBarRelease.
if (wrote_stable()) {
_exits.insert_mem_bar(Op_MemBarRelease);
if (PrintOpto && (Verbose || WizardMode)) {
method()->print_name();
tty->print_cr(" writes @Stable and needs a memory barrier");
tty->print_cr(" writes finals/@Stable and needs a memory barrier");
}
}

View File

@ -236,22 +236,25 @@ void Parse::do_put_xxx(Node* obj, ciField* field, bool is_field) {
set_wrote_fields(true);
// If the field is final, the rules of Java say we are in <init> or <clinit>.
// Note the presence of writes to final non-static fields, so that we
// If the field is @Stable, we can be in any method, but we only care about
// constructors at this point.
//
// Note the presence of writes to final/@Stable non-static fields, so that we
// can insert a memory barrier later on to keep the writes from floating
// out of the constructor.
// Any method can write a @Stable field; insert memory barriers after those also.
if (field->is_final()) {
set_wrote_final(true);
if (field->is_final() || field->is_stable()) {
if (field->is_final()) {
set_wrote_final(true);
}
if (field->is_stable()) {
set_wrote_stable(true);
}
if (AllocateNode::Ideal_allocation(obj) != nullptr) {
// Preserve allocation ptr to create precedent edge to it in membar
// generated on exit from constructor.
// Can't bind stable with its allocation, only record allocation for final field.
set_alloc_with_final(obj);
set_alloc_with_final_or_stable(obj);
}
}
if (field->is_stable()) {
set_wrote_stable(true);
}
}
}

View File

@ -0,0 +1,170 @@
/*
* Copyright Amazon.com Inc. or its affiliates. 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
* @bug 8333791
* @requires os.arch=="aarch64" | os.arch=="riscv64" | os.arch=="x86_64" | os.arch=="amd64"
* @requires vm.gc.Parallel
* @requires vm.compiler2.enabled
* @summary Check stable field folding and barriers
* @modules java.base/jdk.internal.vm.annotation
* @library /test/lib /
* @run driver compiler.c2.irTests.stable.StablePrimArrayTest
*/
package compiler.c2.irTests.stable;
import compiler.lib.ir_framework.*;
import jdk.test.lib.Asserts;
import jdk.internal.vm.annotation.Stable;
public class StablePrimArrayTest {
public static void main(String[] args) {
TestFramework tf = new TestFramework();
tf.addTestClassesToBootClassPath();
tf.addFlags(
"-XX:+UnlockExperimentalVMOptions",
"-XX:CompileThreshold=100",
"-XX:-TieredCompilation",
"-XX:+UseParallelGC"
);
tf.start();
}
static final int[] EMPTY_INTEGER = new int[] { 0 };
static final int[] FULL_INTEGER = new int[] { 42 };
static class Carrier {
@Stable
int[] field;
@ForceInline
public Carrier(int initLevel) {
switch (initLevel) {
case 0:
// Do nothing.
break;
case 1:
field = EMPTY_INTEGER;
break;
case 2:
field = FULL_INTEGER;
break;
default:
throw new IllegalStateException("Unknown level");
}
}
@ForceInline
public void initEmpty() {
field = EMPTY_INTEGER;
}
@ForceInline
public void initFull() {
field = FULL_INTEGER;
}
}
static final Carrier BLANK_CARRIER = new Carrier(0);
static final Carrier INIT_EMPTY_CARRIER = new Carrier(1);
static final Carrier INIT_FULL_CARRIER = new Carrier(2);
@Test
@IR(counts = { IRNode.LOAD, ">0" })
@IR(failOn = { IRNode.MEMBAR })
static int testNoFold() {
// Access should not be folded.
// No barriers expected for plain fields.
int[] is = BLANK_CARRIER.field;
if (is != null) {
return is[0];
}
return 0;
}
@Test
@IR(counts = { IRNode.LOAD, ">0" })
@IR(failOn = { IRNode.MEMBAR })
static int testPartialFold() {
// Access should not be folded.
// No barriers expected for plain fields.
int[] is = INIT_EMPTY_CARRIER.field;
if (is != null) {
return is[0];
}
return 0;
}
@Test
@IR(failOn = { IRNode.LOAD, IRNode.MEMBAR })
static int testFold() {
// Access should be completely folded.
int[] is = INIT_FULL_CARRIER.field;
if (is != null) {
return is[0];
}
return 0;
}
@Test
@IR(counts = { IRNode.MEMBAR_STORESTORE, "1" })
static Carrier testConstructorBlankInit() {
// Only the header barrier.
return new Carrier(0);
}
@Test
@IR(counts = { IRNode.MEMBAR_STORESTORE, "1" })
static Carrier testConstructorEmptyInit() {
// Only the header barrier.
return new Carrier(1);
}
@Test
@IR(counts = { IRNode.MEMBAR_STORESTORE, "1" })
static Carrier testConstructorFullInit() {
// Only the header barrier.
return new Carrier(2);
}
@Test
@IR(failOn = { IRNode.MEMBAR })
static void testMethodEmptyInit() {
// Reference inits do not have membars.
INIT_EMPTY_CARRIER.initEmpty();
}
@Test
@IR(failOn = { IRNode.MEMBAR })
static void testMethodFullInit() {
// Reference inits do not have membars.
INIT_FULL_CARRIER.initFull();
}
}

View File

@ -0,0 +1,100 @@
/*
* Copyright Amazon.com Inc. or its affiliates. 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
* @bug 8333791
* @requires os.arch=="aarch64" | os.arch=="riscv64" | os.arch=="x86_64" | os.arch=="amd64"
* @requires vm.gc.Parallel
* @requires vm.compiler2.enabled
* @summary Check stable field folding and barriers
* @modules java.base/jdk.internal.vm.annotation
* @library /test/lib /
* @run driver compiler.c2.irTests.stable.StablePrimFinalTest
*/
package compiler.c2.irTests.stable;
import compiler.lib.ir_framework.*;
import jdk.test.lib.Asserts;
import jdk.internal.vm.annotation.Stable;
public class StablePrimFinalTest {
public static void main(String[] args) {
TestFramework tf = new TestFramework();
tf.addTestClassesToBootClassPath();
tf.addFlags(
"-XX:+UnlockExperimentalVMOptions",
"-XX:CompileThreshold=100",
"-XX:-TieredCompilation",
"-XX:+UseParallelGC"
);
tf.start();
}
static class Carrier {
@Stable
final int field;
@ForceInline
public Carrier(boolean init) {
field = init ? 42 : 0;
}
}
static final Carrier BLANK_CARRIER = new Carrier(false);
static final Carrier INIT_CARRIER = new Carrier(true);
@Test
@IR(counts = { IRNode.LOAD, "1" })
@IR(failOn = { IRNode.MEMBAR })
static int testNoFold() {
// Access should not be folded.
// No barriers expected for final fields.
return BLANK_CARRIER.field;
}
@Test
@IR(failOn = { IRNode.LOAD, IRNode.MEMBAR })
static int testFold() {
// Access should be completely folded.
return INIT_CARRIER.field;
}
@Test
@IR(counts = { IRNode.MEMBAR_STORESTORE, "1" })
static Carrier testConstructorBlankInit() {
// Single header+final barrier.
return new Carrier(false);
}
@Test
@IR(counts = { IRNode.MEMBAR_STORESTORE, "1" })
static Carrier testConstructorFullInit() {
// Single header+final barrier.
return new Carrier(true);
}
}

View File

@ -0,0 +1,114 @@
/*
* Copyright Amazon.com Inc. or its affiliates. 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
* @bug 8333791
* @requires os.arch=="aarch64" | os.arch=="riscv64" | os.arch=="x86_64" | os.arch=="amd64"
* @requires vm.gc.Parallel
* @requires vm.compiler2.enabled
* @summary Check stable field folding and barriers
* @modules java.base/jdk.internal.vm.annotation
* @library /test/lib /
* @run driver compiler.c2.irTests.stable.StablePrimPlainTest
*/
package compiler.c2.irTests.stable;
import compiler.lib.ir_framework.*;
import jdk.test.lib.Asserts;
import jdk.internal.vm.annotation.Stable;
public class StablePrimPlainTest {
public static void main(String[] args) {
TestFramework tf = new TestFramework();
tf.addTestClassesToBootClassPath();
tf.addFlags(
"-XX:+UnlockExperimentalVMOptions",
"-XX:CompileThreshold=100",
"-XX:-TieredCompilation",
"-XX:+UseParallelGC"
);
tf.start();
}
static class Carrier {
@Stable
int field;
@ForceInline
public Carrier(boolean init) {
if (init) {
field = 42;
}
}
@ForceInline
public void init() {
field = 42;
}
}
static final Carrier BLANK_CARRIER = new Carrier(false);
static final Carrier INIT_CARRIER = new Carrier(true);
@Test
@IR(counts = { IRNode.LOAD, "1" })
@IR(failOn = { IRNode.MEMBAR })
static int testNoFold() {
// Access should not be folded.
// No barriers expected for plain fields.
return BLANK_CARRIER.field;
}
@Test
@IR(failOn = { IRNode.LOAD, IRNode.MEMBAR })
static int testFold() {
// Access should be completely folded.
return INIT_CARRIER.field;
}
@Test
@IR(counts = { IRNode.MEMBAR_STORESTORE, "1" })
static Carrier testConstructorBlankInit() {
// Only the header barrier.
return new Carrier(false);
}
@Test
@IR(counts = { IRNode.MEMBAR_STORESTORE, "1" })
static Carrier testConstructorFullInit() {
// Only the header barrier.
return new Carrier(true);
}
@Test
@IR(failOn = { IRNode.MEMBAR })
static void testMethodInit() {
// Primitive inits have no membars.
INIT_CARRIER.init();
}
}

View File

@ -0,0 +1,114 @@
/*
* Copyright Amazon.com Inc. or its affiliates. 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
* @bug 8333791
* @requires os.arch=="aarch64" | os.arch=="riscv64" | os.arch=="x86_64" | os.arch=="amd64"
* @requires vm.gc.Parallel
* @requires vm.compiler2.enabled
* @summary Check stable field folding and barriers
* @modules java.base/jdk.internal.vm.annotation
* @library /test/lib /
* @run driver compiler.c2.irTests.stable.StablePrimVolatileTest
*/
package compiler.c2.irTests.stable;
import compiler.lib.ir_framework.*;
import jdk.test.lib.Asserts;
import jdk.internal.vm.annotation.Stable;
public class StablePrimVolatileTest {
public static void main(String[] args) {
TestFramework tf = new TestFramework();
tf.addTestClassesToBootClassPath();
tf.addFlags(
"-XX:+UnlockExperimentalVMOptions",
"-XX:CompileThreshold=100",
"-XX:-TieredCompilation",
"-XX:+UseParallelGC"
);
tf.start();
}
static class Carrier {
@Stable
volatile int field;
@ForceInline
public Carrier(boolean init) {
if (init) {
field = 42;
}
}
@ForceInline
public void init() {
field = 42;
}
}
static final Carrier BLANK_CARRIER = new Carrier(false);
static final Carrier INIT_CARRIER = new Carrier(true);
@Test
@IR(counts = { IRNode.LOAD, "1" })
@IR(counts = { IRNode.MEMBAR, ">0" })
static int testNoFold() {
// Access should not be folded.
// Barriers expected for volatile fields.
return BLANK_CARRIER.field;
}
@Test
@IR(failOn = { IRNode.LOAD, IRNode.MEMBAR })
static int testFold() {
// Access should be completely folded.
return INIT_CARRIER.field;
}
@Test
@IR(counts = { IRNode.MEMBAR_STORESTORE, "1" })
static Carrier testConstructorBlankInit() {
// Expect only the header barrier.
return new Carrier(false);
}
@Test
@IR(counts = { IRNode.MEMBAR, ">0" })
static Carrier testConstructorFullInit() {
// Volatile barriers expected.
return new Carrier(true);
}
@Test
@IR(counts = { IRNode.MEMBAR, ">0" })
static void testMethodInit() {
// Volatile barriers expected.
INIT_CARRIER.init();
}
}

View File

@ -0,0 +1,179 @@
/*
* Copyright Amazon.com Inc. or its affiliates. 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
* @bug 8333791
* @requires os.arch=="aarch64" | os.arch=="riscv64" | os.arch=="x86_64" | os.arch=="amd64"
* @requires vm.gc.Parallel
* @requires vm.compiler2.enabled
* @summary Check stable field folding and barriers
* @modules java.base/jdk.internal.vm.annotation
* @library /test/lib /
* @run driver compiler.c2.irTests.stable.StableRefArrayTest
*/
package compiler.c2.irTests.stable;
import compiler.lib.ir_framework.*;
import jdk.test.lib.Asserts;
import jdk.internal.vm.annotation.Stable;
public class StableRefArrayTest {
public static void main(String[] args) {
TestFramework tf = new TestFramework();
tf.addTestClassesToBootClassPath();
tf.addFlags(
"-XX:+UnlockExperimentalVMOptions",
"-XX:CompileThreshold=100",
"-XX:-TieredCompilation",
"-XX:+UseParallelGC"
);
tf.start();
}
static final Integer[] EMPTY_INTEGER = new Integer[] { null };
static final Integer[] FULL_INTEGER = new Integer[] { 42 };
static class Carrier {
@Stable
Integer[] field;
@ForceInline
public Carrier(int initLevel) {
switch (initLevel) {
case 0:
// Do nothing.
break;
case 1:
field = EMPTY_INTEGER;
break;
case 2:
field = FULL_INTEGER;
break;
default:
throw new IllegalStateException("Unknown level");
}
}
@ForceInline
public void initEmpty() {
field = EMPTY_INTEGER;
}
@ForceInline
public void initFull() {
field = FULL_INTEGER;
}
}
static final Carrier BLANK_CARRIER = new Carrier(0);
static final Carrier INIT_EMPTY_CARRIER = new Carrier(1);
static final Carrier INIT_FULL_CARRIER = new Carrier(2);
@Test
@IR(counts = { IRNode.LOAD, ">0" })
@IR(failOn = { IRNode.MEMBAR })
static int testNoFold() {
// Access should not be folded.
// No barriers expected for plain fields.
Integer[] is = BLANK_CARRIER.field;
if (is != null) {
Integer i = is[0];
if (i != null) {
return i;
}
}
return 0;
}
@Test
@IR(counts = { IRNode.LOAD, ">0" })
@IR(failOn = { IRNode.MEMBAR })
static int testPartialFold() {
// Access should not be folded.
// No barriers expected for plain fields.
Integer[] is = INIT_EMPTY_CARRIER.field;
if (is != null) {
Integer i = is[0];
if (i != null) {
return i;
}
}
return 0;
}
@Test
@IR(failOn = { IRNode.LOAD, IRNode.MEMBAR })
static int testFold() {
// Access should be completely folded.
Integer[] is = INIT_FULL_CARRIER.field;
if (is != null) {
Integer i = is[0];
if (i != null) {
return i;
}
}
return 0;
}
@Test
@IR(counts = { IRNode.MEMBAR_STORESTORE, "1" })
static Carrier testConstructorBlankInit() {
// Only the header barrier.
return new Carrier(0);
}
@Test
@IR(counts = { IRNode.MEMBAR_STORESTORE, "1" })
static Carrier testConstructorEmptyInit() {
// Only the header barrier.
return new Carrier(1);
}
@Test
@IR(counts = { IRNode.MEMBAR_STORESTORE, "1" })
static Carrier testConstructorFullInit() {
// Only the header barrier.
return new Carrier(2);
}
@Test
@IR(failOn = { IRNode.MEMBAR })
static void testMethodEmptyInit() {
// Reference inits do not have membars.
INIT_EMPTY_CARRIER.initEmpty();
}
@Test
@IR(failOn = { IRNode.MEMBAR })
static void testMethodFullInit() {
// Reference inits do not have membars.
INIT_FULL_CARRIER.initFull();
}
}

View File

@ -0,0 +1,97 @@
/*
* Copyright Amazon.com Inc. or its affiliates. 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
* @bug 8333791
* @requires os.arch=="aarch64" | os.arch=="riscv64" | os.arch=="x86_64" | os.arch=="amd64"
* @requires vm.gc.Parallel
* @requires vm.compiler2.enabled
* @summary Check stable field folding and barriers
* @modules java.base/jdk.internal.vm.annotation
* @library /test/lib /
* @run driver compiler.c2.irTests.stable.StableRefFinalTest
*/
package compiler.c2.irTests.stable;
import compiler.lib.ir_framework.*;
import jdk.test.lib.Asserts;
import jdk.internal.vm.annotation.Stable;
public class StableRefFinalTest {
public static void main(String[] args) {
TestFramework tf = new TestFramework();
tf.addTestClassesToBootClassPath();
tf.addFlags(
"-XX:+UnlockExperimentalVMOptions",
"-XX:CompileThreshold=100",
"-XX:-TieredCompilation",
"-XX:+UseParallelGC"
);
tf.start();
}
static final Integer INTEGER = 42;
static class Carrier {
@Stable
final Integer field;
@ForceInline
public Carrier(boolean init) {
field = init ? INTEGER : null;
}
}
static final Carrier BLANK_CARRIER = new Carrier(false);
static final Carrier INIT_CARRIER = new Carrier(true);
@Test
@IR(counts = { IRNode.LOAD, ">0" })
@IR(failOn = { IRNode.MEMBAR })
static int testNoFold() {
// Access should not be folded.
// No barriers expected for plain fields.
Integer i = BLANK_CARRIER.field;
return i != null ? i : 0;
}
@Test
@IR(failOn = { IRNode.LOAD, IRNode.MEMBAR })
static int testFold() {
// Access should be completely folded.
Integer i = INIT_CARRIER.field;
return i != null ? i : 0;
}
@Test
@IR(counts = { IRNode.MEMBAR_STORESTORE, "1" })
static Carrier testConstructorInit() {
// Only the header+final barrier.
return new Carrier(true);
}
}

View File

@ -0,0 +1,118 @@
/*
* Copyright Amazon.com Inc. or its affiliates. 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
* @bug 8333791
* @requires os.arch=="aarch64" | os.arch=="riscv64" | os.arch=="x86_64" | os.arch=="amd64"
* @requires vm.gc.Parallel
* @requires vm.compiler2.enabled
* @summary Check stable field folding and barriers
* @modules java.base/jdk.internal.vm.annotation
* @library /test/lib /
* @run driver compiler.c2.irTests.stable.StableRefPlainTest
*/
package compiler.c2.irTests.stable;
import compiler.lib.ir_framework.*;
import jdk.test.lib.Asserts;
import jdk.internal.vm.annotation.Stable;
public class StableRefPlainTest {
public static void main(String[] args) {
TestFramework tf = new TestFramework();
tf.addTestClassesToBootClassPath();
tf.addFlags(
"-XX:+UnlockExperimentalVMOptions",
"-XX:CompileThreshold=100",
"-XX:-TieredCompilation",
"-XX:+UseParallelGC"
);
tf.start();
}
static final Integer INTEGER = 42;
static class Carrier {
@Stable
Integer field;
@ForceInline
public Carrier(boolean init) {
if (init) {
field = INTEGER;
}
}
@ForceInline
public void init() {
field = INTEGER;
}
}
static final Carrier BLANK_CARRIER = new Carrier(false);
static final Carrier INIT_CARRIER = new Carrier(true);
@Test
@IR(counts = { IRNode.LOAD, ">0" })
@IR(failOn = { IRNode.MEMBAR })
static int testNoFold() {
// Access should not be folded.
// No barriers expected for plain fields.
Integer i = BLANK_CARRIER.field;
return i != null ? i : 0;
}
@Test
@IR(failOn = { IRNode.LOAD, IRNode.MEMBAR })
static int testFold() {
// Access should be completely folded.
Integer i = INIT_CARRIER.field;
return i != null ? i : 0;
}
@Test
@IR(counts = { IRNode.MEMBAR_STORESTORE, "1" })
static Carrier testConstructorBlankInit() {
// Only the header barrier.
return new Carrier(false);
}
@Test
@IR(counts = { IRNode.MEMBAR_STORESTORE, "1" })
static Carrier testConstructorFullInit() {
// Only the header barrier.
return new Carrier(true);
}
@Test
@IR(failOn = { IRNode.MEMBAR })
static void testMethodInit() {
// Reference inits do not have membars.
INIT_CARRIER.init();
}
}

View File

@ -0,0 +1,118 @@
/*
* Copyright Amazon.com Inc. or its affiliates. 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
* @bug 8333791
* @requires os.arch=="aarch64" | os.arch=="riscv64" | os.arch=="x86_64" | os.arch=="amd64"
* @requires vm.gc.Parallel
* @requires vm.compiler2.enabled
* @summary Check stable field folding and barriers
* @modules java.base/jdk.internal.vm.annotation
* @library /test/lib /
* @run driver compiler.c2.irTests.stable.StableRefVolatileTest
*/
package compiler.c2.irTests.stable;
import compiler.lib.ir_framework.*;
import jdk.test.lib.Asserts;
import jdk.internal.vm.annotation.Stable;
public class StableRefVolatileTest {
public static void main(String[] args) {
TestFramework tf = new TestFramework();
tf.addTestClassesToBootClassPath();
tf.addFlags(
"-XX:+UnlockExperimentalVMOptions",
"-XX:CompileThreshold=100",
"-XX:-TieredCompilation",
"-XX:+UseParallelGC"
);
tf.start();
}
static final Integer INTEGER = 42;
static class Carrier {
@Stable
volatile Integer field;
@ForceInline
public Carrier(boolean init) {
if (init) {
field = INTEGER;
}
}
@ForceInline
public void init() {
field = INTEGER;
}
}
static final Carrier BLANK_CARRIER = new Carrier(false);
static final Carrier INIT_CARRIER = new Carrier(true);
@Test
@IR(counts = { IRNode.LOAD, ">0" })
@IR(counts = { IRNode.MEMBAR, ">0" })
static int testNoFold() {
// Access should not be folded.
// Barriers are expected for volatile field.
Integer i = BLANK_CARRIER.field;
return i != null ? i : 0;
}
@Test
@IR(failOn = { IRNode.LOAD, IRNode.MEMBAR })
static int testFold() {
// Access should be completely folded.
Integer i = INIT_CARRIER.field;
return i != null ? i : 0;
}
@Test
@IR(counts = { IRNode.MEMBAR_STORESTORE, "1" })
static Carrier testConstructorBlankInit() {
// Only the header barrier.
return new Carrier(false);
}
@Test
@IR(counts = { IRNode.MEMBAR, ">0" })
static Carrier testConstructorFullInit() {
// Volatile writes, expect more barriers.
return new Carrier(true);
}
@Test
@IR(counts = { IRNode.MEMBAR, ">0" })
static void testMethodInit() {
// Barriers are expected for volatile fields.
INIT_CARRIER.init();
}
}