Skip to content

Commit 5d414da

Browse files
committed
8325372: Shenandoah: SIGSEGV crash in unnecessary_acquire due to LoadStore split through phi
Reviewed-by: shade, rkennke, thartmann
1 parent 93a2e77 commit 5d414da

File tree

4 files changed

+100
-1
lines changed

4 files changed

+100
-1
lines changed

src/hotspot/share/gc/shenandoah/c2/shenandoahSupport.cpp

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1734,11 +1734,26 @@ bool ShenandoahBarrierC2Support::identical_backtoback_ifs(Node* n, PhaseIdealLoo
17341734
return true;
17351735
}
17361736

1737+
bool ShenandoahBarrierC2Support::merge_point_safe(Node* region) {
1738+
for (DUIterator_Fast imax, i = region->fast_outs(imax); i < imax; i++) {
1739+
Node* n = region->fast_out(i);
1740+
if (n->is_LoadStore()) {
1741+
// Splitting a LoadStore node through phi, causes it to lose its SCMemProj: the split if code doesn't have support
1742+
// for a LoadStore at the region the if is split through because that's not expected to happen (LoadStore nodes
1743+
// should be between barrier nodes). It does however happen with Shenandoah though because barriers can get
1744+
// expanded around a LoadStore node.
1745+
return false;
1746+
}
1747+
}
1748+
return true;
1749+
}
1750+
1751+
17371752
void ShenandoahBarrierC2Support::merge_back_to_back_tests(Node* n, PhaseIdealLoop* phase) {
17381753
assert(is_heap_stable_test(n), "no other tests");
17391754
if (identical_backtoback_ifs(n, phase)) {
17401755
Node* n_ctrl = n->in(0);
1741-
if (phase->can_split_if(n_ctrl)) {
1756+
if (phase->can_split_if(n_ctrl) && merge_point_safe(n_ctrl)) {
17421757
IfNode* dom_if = phase->idom(n_ctrl)->as_If();
17431758
if (is_heap_stable_test(n)) {
17441759
Node* gc_state_load = n->in(1)->in(1)->in(1)->in(1);

src/hotspot/share/gc/shenandoah/c2/shenandoahSupport.hpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ class ShenandoahBarrierC2Support : public AllStatic {
6565
static void test_in_cset(Node*& ctrl, Node*& not_cset_ctrl, Node* val, Node* raw_mem, PhaseIdealLoop* phase);
6666
static void move_gc_state_test_out_of_loop(IfNode* iff, PhaseIdealLoop* phase);
6767
static void merge_back_to_back_tests(Node* n, PhaseIdealLoop* phase);
68+
static bool merge_point_safe(Node* region);
6869
static bool identical_backtoback_ifs(Node *n, PhaseIdealLoop* phase);
6970
static void fix_ctrl(Node* barrier, Node* region, const MemoryGraphFixer& fixer, Unique_Node_List& uses, Unique_Node_List& uses_to_ignore, uint last, PhaseIdealLoop* phase);
7071
static IfNode* find_unswitching_candidate(const IdealLoopTree *loop, PhaseIdealLoop* phase);

src/hotspot/share/opto/memnode.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3408,6 +3408,7 @@ Node *MemBarNode::Ideal(PhaseGVN *phase, bool can_reshape) {
34083408
my_mem = load_node;
34093409
} else {
34103410
assert(my_mem->unique_out() == this, "sanity");
3411+
assert(!trailing_load_store(), "load store node can't be eliminated");
34113412
del_req(Precedent);
34123413
phase->is_IterGVN()->_worklist.push(my_mem); // remove dead node later
34133414
my_mem = nullptr;
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
/*
2+
* Copyright (c) 2024, Red Hat, Inc. All rights reserved.
3+
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+
*
5+
* This code is free software; you can redistribute it and/or modify it
6+
* under the terms of the GNU General Public License version 2 only, as
7+
* published by the Free Software Foundation.
8+
*
9+
* This code is distributed in the hope that it will be useful, but WITHOUT
10+
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11+
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12+
* version 2 for more details (a copy is included in the LICENSE file that
13+
* accompanied this code).
14+
*
15+
* You should have received a copy of the GNU General Public License version
16+
* 2 along with this work; if not, write to the Free Software Foundation,
17+
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18+
*
19+
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20+
* or visit www.oracle.com if you need additional information or have any
21+
* questions.
22+
*/
23+
24+
/**
25+
* @test
26+
* @bug 8325372
27+
* @summary fusion of heap stable test causes GetAndSet node to be removed
28+
* @requires vm.gc.Shenandoah
29+
* @modules java.base/jdk.internal.misc:+open
30+
*
31+
* @run main/othervm -XX:+UseShenandoahGC -XX:-BackgroundCompilation TestUnsafeLoadStoreMergedHeapStableTests
32+
*/
33+
34+
import jdk.internal.misc.Unsafe;
35+
36+
import java.lang.reflect.Field;
37+
38+
public class TestUnsafeLoadStoreMergedHeapStableTests {
39+
40+
static final jdk.internal.misc.Unsafe UNSAFE = Unsafe.getUnsafe();
41+
static long F_OFFSET;
42+
43+
static class A {
44+
Object f;
45+
}
46+
47+
static {
48+
try {
49+
Field fField = A.class.getDeclaredField("f");
50+
F_OFFSET = UNSAFE.objectFieldOffset(fField);
51+
} catch (Exception e) {
52+
throw new RuntimeException(e);
53+
}
54+
}
55+
56+
static Object testHelper(boolean flag, Object o, long offset, Object x) {
57+
if (flag) {
58+
return UNSAFE.getAndSetObject(o, offset, x);
59+
}
60+
return null;
61+
}
62+
63+
static Object field;
64+
65+
66+
static Object test1(boolean flag, Object o, long offset) {
67+
return testHelper(flag, null, offset, field);
68+
}
69+
70+
static Object test2(Object o, long offset) {
71+
return UNSAFE.getAndSetObject(o, offset, field);
72+
}
73+
74+
static public void main(String[] args) {
75+
A a = new A();
76+
for (int i = 0; i < 20_000; i++) {
77+
testHelper(true, a, F_OFFSET, null);
78+
test1(false, a, F_OFFSET);
79+
test2(a, F_OFFSET);
80+
}
81+
}
82+
}

0 commit comments

Comments
 (0)