7143491: G1 C2 CTW: assert(p2x->outcnt() == 2) failed: expects 2 users: Xor and URShift nodes
Summary: Adjust the assert and code in eliminate_card_mark() method for case when stored value is NULL.
Reviewed-by: iveresov, never
--- a/hotspot/src/share/vm/opto/graphKit.cpp Tue Feb 07 11:33:15 2012 -0800
+++ b/hotspot/src/share/vm/opto/graphKit.cpp Tue Feb 07 16:33:43 2012 -0800
@@ -1522,6 +1522,11 @@
const TypeOopPtr* val_type,
BasicType bt,
bool use_precise) {
+ // Transformation of a value which could be NULL pointer (CastPP #NULL)
+ // could be delayed during Parse (for example, in adjust_map_after_if()).
+ // Execute transformation here to avoid barrier generation in such case.
+ if (_gvn.type(val) == TypePtr::NULL_PTR)
+ val = _gvn.makecon(TypePtr::NULL_PTR);
set_control(ctl);
if (stopped()) return top(); // Dead path ?
--- a/hotspot/src/share/vm/opto/library_call.cpp Tue Feb 07 11:33:15 2012 -0800
+++ b/hotspot/src/share/vm/opto/library_call.cpp Tue Feb 07 16:33:43 2012 -0800
@@ -2678,7 +2678,13 @@
cas = _gvn.transform(new (C, 5) CompareAndSwapLNode(control(), mem, adr, newval, oldval));
break;
case T_OBJECT:
- // reference stores need a store barrier.
+ // Transformation of a value which could be NULL pointer (CastPP #NULL)
+ // could be delayed during Parse (for example, in adjust_map_after_if()).
+ // Execute transformation here to avoid barrier generation in such case.
+ if (_gvn.type(newval) == TypePtr::NULL_PTR)
+ newval = _gvn.makecon(TypePtr::NULL_PTR);
+
+ // Reference stores need a store barrier.
// (They don't if CAS fails, but it isn't worth checking.)
pre_barrier(true /* do_load*/,
control(), base, adr, alias_idx, newval, value_type->make_oopptr(),
--- a/hotspot/src/share/vm/opto/macro.cpp Tue Feb 07 11:33:15 2012 -0800
+++ b/hotspot/src/share/vm/opto/macro.cpp Tue Feb 07 16:33:43 2012 -0800
@@ -234,11 +234,20 @@
}
} else {
// G1 pre/post barriers
- assert(p2x->outcnt() == 2, "expects 2 users: Xor and URShift nodes");
+ assert(p2x->outcnt() <= 2, "expects 1 or 2 users: Xor and URShift nodes");
// It could be only one user, URShift node, in Object.clone() instrinsic
// but the new allocation is passed to arraycopy stub and it could not
// be scalar replaced. So we don't check the case.
+ // An other case of only one user (Xor) is when the value check for NULL
+ // in G1 post barrier is folded after CCP so the code which used URShift
+ // is removed.
+
+ // Take Region node before eliminating post barrier since it also
+ // eliminates CastP2X node when it has only one user.
+ Node* this_region = p2x->in(0);
+ assert(this_region != NULL, "");
+
// Remove G1 post barrier.
// Search for CastP2X->Xor->URShift->Cmp path which
@@ -263,8 +272,6 @@
// Remove G1 pre barrier.
// Search "if (marking != 0)" check and set it to "false".
- Node* this_region = p2x->in(0);
- assert(this_region != NULL, "");
// There is no G1 pre barrier if previous stored value is NULL
// (for example, after initialization).
if (this_region->is_Region() && this_region->req() == 3) {
@@ -292,7 +299,7 @@
}
// Now CastP2X can be removed since it is used only on dead path
// which currently still alive until igvn optimize it.
- assert(p2x->unique_out()->Opcode() == Op_URShiftX, "");
+ assert(p2x->outcnt() == 0 || p2x->unique_out()->Opcode() == Op_URShiftX, "");
_igvn.replace_node(p2x, top());
}
}