Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

8300148: Consider using a StoreStore barrier instead of Release barrier on ctor exit #2426

Draft
wants to merge 1 commit into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions src/hotspot/share/opto/c2_globals.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -770,6 +770,10 @@
\
product(bool, VerifyReceiverTypes, trueInDebug, DIAGNOSTIC, \
"Verify receiver types at runtime") \
\
product(bool, UseStoreStoreForCtor, true, DIAGNOSTIC, \
"Use StoreStore barrier instead of Release barrier at the end " \
"of constructors") \

// end of C2_FLAGS

Expand Down
4 changes: 3 additions & 1 deletion src/hotspot/share/opto/escape.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -173,7 +173,9 @@ bool ConnectionGraph::compute_escape() {
// Collect all MemBarStoreStore nodes so that depending on the
// escape status of the associated Allocate node some of them
// may be eliminated.
storestore_worklist.append(n);
if (!UseStoreStoreForCtor || n->req() > MemBarNode::Precedent) {
storestore_worklist.append(n);
}
} else if (n->is_MemBar() && (n->Opcode() == Op_MemBarRelease) &&
(n->req() > MemBarNode::Precedent)) {
record_for_optimizer(n);
Expand Down
2 changes: 1 addition & 1 deletion src/hotspot/share/opto/memnode.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3369,7 +3369,7 @@ Node *MemBarNode::Ideal(PhaseGVN *phase, bool can_reshape) {
eliminate = true;
}
}
} else if (opc == Op_MemBarRelease) {
} else if (opc == Op_MemBarRelease || (UseStoreStoreForCtor && opc == Op_MemBarStoreStore)) {
// Final field stores.
Node* alloc = AllocateNode::Ideal_allocation(in(MemBarNode::Precedent), phase);
if ((alloc != nullptr) && alloc->is_Allocate() &&
Expand Down
3 changes: 2 additions & 1 deletion src/hotspot/share/opto/parse1.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1001,7 +1001,8 @@ void Parse::do_exits() {
(wrote_final() ||
(AlwaysSafeConstructors && wrote_fields()) ||
(support_IRIW_for_not_multiple_copy_atomic_cpu && wrote_volatile()))) {
_exits.insert_mem_bar(Op_MemBarRelease, alloc_with_final());
_exits.insert_mem_bar(UseStoreStoreForCtor ? Op_MemBarStoreStore : Op_MemBarRelease,
alloc_with_final());

// If Memory barrier is created for final fields write
// and allocation node does not escape the initialize method,
Expand Down
2 changes: 1 addition & 1 deletion src/hotspot/share/opto/stringopts.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2067,7 +2067,7 @@ void PhaseStringOpts::replace_string_concat(StringConcat* sc) {
// of the initialization is committed to memory before any code publishes
// a reference to the newly constructed object (see Parse::do_exits()).
assert(AllocateNode::Ideal_allocation(result, _gvn) != nullptr, "should be newly allocated");
kit.insert_mem_bar(Op_MemBarRelease, result);
kit.insert_mem_bar(UseStoreStoreForCtor ? Op_MemBarStoreStore : Op_MemBarRelease, result);
} else {
result = C->top();
}
Expand Down
309 changes: 309 additions & 0 deletions test/hotspot/jtreg/compiler/c2/irTests/ConstructorBarriers.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,309 @@
/*
* 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.
*/

package compiler.c2.irTests;

import compiler.lib.ir_framework.*;

/*
* @test
* @bug 8300148
* @summary Test barriers emitted in constructors
* @library /test/lib /
* @requires os.arch=="aarch64" | os.arch=="riscv64" | os.arch=="x86_64" | os.arch=="amd64"
* @run main compiler.c2.irTests.ConstructorBarriers
*/
public class ConstructorBarriers {
public static void main(String[] args) {
TestFramework.run();
}

// Checks the barrier coalescing/optimization around field initializations.
// Uses long fields to avoid store merging.

public static class PlainPlain {
long f1;
long f2;
public PlainPlain(long i) {
f1 = i;
f2 = i;
}
}

private static class FinalPlain {
final long f1;
long f2;
public FinalPlain(long i) {
f1 = i;
f2 = i;
}
}

private static class PlainFinal {
long f1;
final long f2;
public PlainFinal(long i) {
f1 = i;
f2 = i;
}
}

private static class FinalFinal {
final long f1;
final long f2;
public FinalFinal(long i) {
f1 = i;
f2 = i;
}
}

private static class PlainVolatile {
long f1;
volatile long f2;
public PlainVolatile(long i) {
f1 = i;
f2 = i;
}
}

private static class VolatilePlain {
volatile long f1;
long f2;
public VolatilePlain(long i) {
f1 = i;
f2 = i;
}
}

private static class FinalVolatile {
final long f1;
volatile long f2;
public FinalVolatile(long i) {
f1 = i;
f2 = i;
}
}

private static class VolatileFinal {
volatile long f1;
final long f2;
public VolatileFinal(long i) {
f1 = i;
f2 = i;
}
}

private static class VolatileVolatile {
volatile long f1;
volatile long f2;
public VolatileVolatile(long i) {
f1 = i;
f2 = i;
}
}

long l = 42;

@DontInline
public void consume(Object o) {}

@Test
@IR(counts = {IRNode.MEMBAR_STORESTORE, "1"})
@IR(failOn = IRNode.MEMBAR_RELEASE)
@IR(failOn = IRNode.MEMBAR_VOLATILE)
public long escaping_plainPlain() {
PlainPlain c = new PlainPlain(l);
consume(c);
return c.f1 + c.f2;
}

@Test
@IR(counts = {IRNode.MEMBAR_STORESTORE, "1"})
@IR(failOn = IRNode.MEMBAR_RELEASE)
@IR(failOn = IRNode.MEMBAR_VOLATILE)
public long escaping_plainFinal() {
PlainFinal c = new PlainFinal(l);
consume(c);
return c.f1 + c.f2;
}

@Test
@IR(counts = {IRNode.MEMBAR_STORESTORE, "1"})
@IR(failOn = IRNode.MEMBAR_RELEASE)
@IR(failOn = IRNode.MEMBAR_VOLATILE)
public long escaping_finalPlain() {
FinalPlain c = new FinalPlain(l);
consume(c);
return c.f1 + c.f2;
}

@Test
@IR(counts = {IRNode.MEMBAR_STORESTORE, "1"})
@IR(failOn = IRNode.MEMBAR_RELEASE)
@IR(failOn = IRNode.MEMBAR_VOLATILE)
public long escaping_finalFinal() {
FinalFinal c = new FinalFinal(l);
consume(c);
return c.f1 + c.f2;
}

@Test
@IR(counts = {IRNode.MEMBAR_RELEASE, "1"})
@IR(counts = {IRNode.MEMBAR_STORESTORE, "1"})
@IR(counts = {IRNode.MEMBAR_VOLATILE, "1"})
public long escaping_plainVolatile() {
PlainVolatile c = new PlainVolatile(l);
consume(c);
return c.f1 + c.f2;
}

@Test
@IR(counts = {IRNode.MEMBAR_RELEASE, "1"})
@IR(counts = {IRNode.MEMBAR_STORESTORE, "1"})
@IR(counts = {IRNode.MEMBAR_VOLATILE, "1"})
public long escaping_volatilePlain() {
VolatilePlain c = new VolatilePlain(l);
consume(c);
return c.f1 + c.f2;
}

@Test
@IR(counts = {IRNode.MEMBAR_RELEASE, "2"})
@IR(counts = {IRNode.MEMBAR_STORESTORE, "1"})
@IR(counts = {IRNode.MEMBAR_VOLATILE, "2"})
public long escaping_volatileVolatile() {
VolatileVolatile c = new VolatileVolatile(l);
consume(c);
return c.f1 + c.f2;
}

@Test
@IR(counts = {IRNode.MEMBAR_RELEASE, "1"})
@IR(counts = {IRNode.MEMBAR_STORESTORE, "1"})
@IR(counts = {IRNode.MEMBAR_VOLATILE, "1"})
public long escaping_finalVolatile() {
FinalVolatile c = new FinalVolatile(l);
consume(c);
return c.f1 + c.f2;
}

@Test
@IR(counts = {IRNode.MEMBAR_RELEASE, "1"})
@IR(counts = {IRNode.MEMBAR_STORESTORE, "1"})
@IR(counts = {IRNode.MEMBAR_VOLATILE, "1"})
public long escaping_volatileFinal() {
VolatileFinal c = new VolatileFinal(l);
consume(c);
return c.f1 + c.f2;
}

@Test
@IR(failOn = IRNode.MEMBAR)
public long non_escaping_plainPlain() {
PlainPlain c = new PlainPlain(l);
return c.f1 + c.f2;
}

@Test
@IR(failOn = IRNode.MEMBAR)
public long non_escaping_plainFinal() {
PlainFinal c = new PlainFinal(l);
return c.f1 + c.f2;
}

@Test
@IR(failOn = IRNode.MEMBAR)
public long non_escaping_finalPlain() {
FinalPlain c = new FinalPlain(l);
return c.f1 + c.f2;
}

@Test
@IR(failOn = IRNode.MEMBAR)
public long non_escaping_finalFinal() {
FinalFinal c = new FinalFinal(l);
return c.f1 + c.f2;
}

@Test
@IR(failOn = IRNode.MEMBAR_RELEASE)
@IR(failOn = IRNode.MEMBAR_STORESTORE)
@IR(failOn = IRNode.MEMBAR_VOLATILE)
@IR(counts = {IRNode.MEMBAR_ACQUIRE, "1"})
public long non_escaping_plainVolatile() {
PlainVolatile c = new PlainVolatile(l);
return c.f1 + c.f2;
}

@Test
@IR(failOn = IRNode.MEMBAR_RELEASE)
@IR(failOn = IRNode.MEMBAR_STORESTORE)
@IR(failOn = IRNode.MEMBAR_VOLATILE)
@IR(counts = {IRNode.MEMBAR_ACQUIRE, "1"})
public long non_escaping_volatilePlain() {
VolatilePlain c = new VolatilePlain(l);
return c.f1 + c.f2;
}

@Test
@IR(failOn = IRNode.MEMBAR_RELEASE)
@IR(failOn = IRNode.MEMBAR_STORESTORE)
@IR(failOn = IRNode.MEMBAR_VOLATILE)
@IR(counts = {IRNode.MEMBAR_ACQUIRE, "2"})
public long non_escaping_volatileVolatile() {
VolatileVolatile c = new VolatileVolatile(l);
return c.f1 + c.f2;
}

@Test
@IR(failOn = IRNode.MEMBAR_RELEASE)
@IR(failOn = IRNode.MEMBAR_STORESTORE)
@IR(failOn = IRNode.MEMBAR_VOLATILE)
@IR(counts = {IRNode.MEMBAR_ACQUIRE, "1"})
public long non_escaping_finalVolatile() {
FinalVolatile c = new FinalVolatile(l);
return c.f1 + c.f2;
}

@Test
@IR(failOn = IRNode.MEMBAR_RELEASE)
@IR(failOn = IRNode.MEMBAR_STORESTORE)
@IR(failOn = IRNode.MEMBAR_VOLATILE)
@IR(counts = {IRNode.MEMBAR_ACQUIRE, "1"})
public long non_escaping_volatileFinal() {
VolatileFinal c = new VolatileFinal(l);
return c.f1 + c.f2;
}

String s1 = "foo";
String s2 = "bar";
String s3 = "baz";

@Test
@IR(failOn = IRNode.MEMBAR_RELEASE)
@IR(failOn = IRNode.MEMBAR_VOLATILE)
@IR(counts = {IRNode.MEMBAR_STORESTORE, "3"})
public String stringBuilder() {
return new StringBuilder().append(s1).append(s2).append(s3).toString();
}
}
4 changes: 4 additions & 0 deletions test/hotspot/jtreg/compiler/lib/ir_framework/IRNode.java
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,11 @@ public class IRNode {

public static final String SCOPE_OBJECT = "(.*# ScObj.*" + END;
public static final String MEMBAR = START + "MemBar" + MID + END;
public static final String MEMBAR_ACQUIRE = START + "MemBarAcquire" + MID + END;
public static final String MEMBAR_RELEASE = START + "MemBarRelease" + MID + END;
public static final String MEMBAR_STORESTORE = START + "MemBarStoreStore" + MID + END;
public static final String MEMBAR_VOLATILE = START + "MemBarVolatile" + MID + END;

public static final String SAFEPOINT = START + "SafePoint" + MID + END;

public static final String CMP_U = START + "CmpU" + MID + END;
Expand Down
Loading