Skip to content

Commit 8d1e402

Browse files
committed
8265132: C2 compilation fails with assert "missing precedence edge"
Reviewed-by: roland Backport-of: 5644c4f
1 parent cbd3b0f commit 8d1e402

File tree

3 files changed

+41
-21
lines changed

3 files changed

+41
-21
lines changed

src/hotspot/share/opto/block.hpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -507,6 +507,8 @@ class PhaseCFG : public Phase {
507507
bool _trace_opto_pipelining; // tracing flag
508508
#endif
509509

510+
bool unrelated_load_in_store_null_block(Node* store, Node* load);
511+
510512
public:
511513
PhaseCFG(Arena* arena, RootNode* root, Matcher& matcher);
512514

src/hotspot/share/opto/gcm.cpp

Lines changed: 24 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -540,6 +540,28 @@ static Block* memory_early_block(Node* load, Block* early, const PhaseCFG* cfg)
540540
return early;
541541
}
542542

543+
// This function is used by insert_anti_dependences to find unrelated loads for stores in implicit null checks.
544+
bool PhaseCFG::unrelated_load_in_store_null_block(Node* store, Node* load) {
545+
// We expect an anti-dependence edge from 'load' to 'store', except when
546+
// implicit_null_check() has hoisted 'store' above its early block to
547+
// perform an implicit null check, and 'load' is placed in the null
548+
// block. In this case it is safe to ignore the anti-dependence, as the
549+
// null block is only reached if 'store' tries to write to null object and
550+
// 'load' read from non-null object (there is preceding check for that)
551+
// These objects can't be the same.
552+
Block* store_block = get_block_for_node(store);
553+
Block* load_block = get_block_for_node(load);
554+
Node* end = store_block->end();
555+
if (end->is_MachNullCheck() && (end->in(1) == store) && store_block->dominates(load_block)) {
556+
Node* if_true = end->find_out_with(Op_IfTrue);
557+
assert(if_true != NULL, "null check without null projection");
558+
Node* null_block_region = if_true->find_out_with(Op_Region);
559+
assert(null_block_region != NULL, "null check without null region");
560+
return get_block_for_node(null_block_region) == load_block;
561+
}
562+
return false;
563+
}
564+
543565
//--------------------------insert_anti_dependences---------------------------
544566
// A load may need to witness memory that nearby stores can overwrite.
545567
// For each nearby store, either insert an "anti-dependence" edge
@@ -793,7 +815,7 @@ Block* PhaseCFG::insert_anti_dependences(Block* LCA, Node* load, bool verify) {
793815
// will find him on the non_early_stores list and stick him
794816
// with a precedence edge.
795817
// (But, don't bother if LCA is already raised all the way.)
796-
if (LCA != early) {
818+
if (LCA != early && !unrelated_load_in_store_null_block(store, load)) {
797819
store_block->set_raise_LCA_mark(load_index);
798820
must_raise_LCA = true;
799821
non_early_stores.push(store);
@@ -804,23 +826,7 @@ Block* PhaseCFG::insert_anti_dependences(Block* LCA, Node* load, bool verify) {
804826
// Add an anti-dep edge, and squeeze 'load' into the highest block.
805827
assert(store != load->find_exact_control(load->in(0)), "dependence cycle found");
806828
if (verify) {
807-
#ifdef ASSERT
808-
// We expect an anti-dependence edge from 'load' to 'store', except when
809-
// implicit_null_check() has hoisted 'store' above its early block to
810-
// perform an implicit null check, and 'load' is placed in the null
811-
// block. In this case it is safe to ignore the anti-dependence, as the
812-
// null block is only reached if 'store' tries to write to null.
813-
Block* store_null_block = NULL;
814-
Node* store_null_check = store->find_out_with(Op_MachNullCheck);
815-
if (store_null_check != NULL) {
816-
Node* if_true = store_null_check->find_out_with(Op_IfTrue);
817-
assert(if_true != NULL, "null check without null projection");
818-
Node* null_block_region = if_true->find_out_with(Op_Region);
819-
assert(null_block_region != NULL, "null check without null region");
820-
store_null_block = get_block_for_node(null_block_region);
821-
}
822-
#endif
823-
assert(LCA == store_null_block || store->find_edge(load) != -1,
829+
assert(store->find_edge(load) != -1 || unrelated_load_in_store_null_block(store, load),
824830
"missing precedence edge");
825831
} else {
826832
store->add_prec(load);

test/hotspot/jtreg/compiler/uncommontrap/TestNullCheckAntiDependence.java

Lines changed: 15 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@
2525

2626
/**
2727
* @test
28-
* @bug 8261730
28+
* @bug 8261730 8265132
2929
* @summary Test that no anti-dependence violation is reported between a store
3030
* used as an implicit null check and a load placed in the null block.
3131
* @run main/othervm -XX:-BackgroundCompilation
@@ -40,8 +40,9 @@ private static class MyInteger {
4040

4141
private static MyInteger foo = new MyInteger();
4242
private static MyInteger bar = new MyInteger();
43+
private static MyInteger[] global = {new MyInteger()};
4344

44-
static void setFooToZero() {
45+
static void test1() {
4546
for (int i = 0; i < 1; i++) {
4647
// This load is placed in the null block.
4748
foo.val = -bar.val;
@@ -52,10 +53,21 @@ static void setFooToZero() {
5253
}
5354
}
5455

56+
static void test2(MyInteger a, MyInteger b) {
57+
global[0].val = a.val + b.val * 31;
58+
global[0].val = 0;
59+
return;
60+
}
61+
5562
public static void main(String[] args) {
5663
for (int i = 0; i < 10_000; i++) {
57-
setFooToZero();
64+
test1();
65+
}
66+
67+
for (int i = 0; i < 10_000; i++) {
68+
test2(new MyInteger(), new MyInteger());
5869
}
70+
5971
}
6072

6173
}

0 commit comments

Comments
 (0)