8004640: C2 assert failure in memnode.cpp: NULL+offs not RAW address
Summary: always transform AddP nodes in IdealKit by calling _gvn.transform().
Reviewed-by: roland, twisti
--- a/hotspot/src/share/vm/opto/graphKit.cpp Tue Mar 26 10:05:33 2013 +0100
+++ b/hotspot/src/share/vm/opto/graphKit.cpp Tue Mar 26 12:55:26 2013 -0700
@@ -3445,7 +3445,6 @@
void GraphKit::final_sync(IdealKit& ideal) {
// Final sync IdealKit and graphKit.
- __ drain_delay_transform();
sync_kit(ideal);
}
--- a/hotspot/src/share/vm/opto/idealKit.cpp Tue Mar 26 10:05:33 2013 +0100
+++ b/hotspot/src/share/vm/opto/idealKit.cpp Tue Mar 26 12:55:26 2013 -0700
@@ -48,9 +48,9 @@
_cvstate = NULL;
// We can go memory state free or else we need the entire memory state
assert(_initial_memory == NULL || _initial_memory->Opcode() == Op_MergeMem, "memory must be pre-split");
+ assert(!_gvn.is_IterGVN(), "IdealKit can't be used during Optimize phase");
int init_size = 5;
_pending_cvstates = new (C->node_arena()) GrowableArray<Node*>(C->node_arena(), init_size, 0, 0);
- _delay_transform = new (C->node_arena()) GrowableArray<Node*>(C->node_arena(), init_size, 0, 0);
DEBUG_ONLY(_state = new (C->node_arena()) GrowableArray<int>(C->node_arena(), init_size, 0, 0));
if (!has_declarations) {
declarations_done();
@@ -296,19 +296,16 @@
return delay_transform(n);
} else {
n = gvn().transform(n);
- if (!gvn().is_IterGVN()) {
- C->record_for_igvn(n);
- }
+ C->record_for_igvn(n);
return n;
}
}
//-----------------------------delay_transform-----------------------------------
Node* IdealKit::delay_transform(Node* n) {
- if (!gvn().is_IterGVN() || !gvn().is_IterGVN()->delay_transform()) {
- gvn().set_type(n, n->bottom_type());
- }
- _delay_transform->push(n);
+ // Delay transform until IterativeGVN
+ gvn().set_type(n, n->bottom_type());
+ C->record_for_igvn(n);
return n;
}
@@ -332,17 +329,6 @@
for (uint i = 0; i < m->req(); i++) m->set_req(i, NULL);
}
-//-----------------------------drain_delay_transform----------------------------
-void IdealKit::drain_delay_transform() {
- while (_delay_transform->length() > 0) {
- Node* n = _delay_transform->pop();
- gvn().transform(n);
- if (!gvn().is_IterGVN()) {
- C->record_for_igvn(n);
- }
- }
-}
-
//-----------------------------IdealVariable----------------------------
IdealVariable::IdealVariable(IdealKit &k) {
k.declare(this);
@@ -351,9 +337,7 @@
Node* IdealKit::memory(uint alias_idx) {
MergeMemNode* mem = merged_memory();
Node* p = mem->memory_at(alias_idx);
- if (!gvn().is_IterGVN() || !gvn().is_IterGVN()->delay_transform()) {
- _gvn.set_type(p, Type::MEMORY); // must be mapped
- }
+ _gvn.set_type(p, Type::MEMORY); // must be mapped
return p;
}
--- a/hotspot/src/share/vm/opto/idealKit.hpp Tue Mar 26 10:05:33 2013 +0100
+++ b/hotspot/src/share/vm/opto/idealKit.hpp Tue Mar 26 12:55:26 2013 -0700
@@ -102,7 +102,6 @@
Compile * const C;
PhaseGVN &_gvn;
GrowableArray<Node*>* _pending_cvstates; // stack of cvstates
- GrowableArray<Node*>* _delay_transform; // delay invoking gvn.transform until drain
Node* _cvstate; // current cvstate (control, memory and variables)
uint _var_ct; // number of variables
bool _delay_all_transforms; // flag forcing all transforms to be delayed
@@ -121,7 +120,7 @@
void clear(Node* m); // clear a cvstate
void stop() { clear(_cvstate); } // clear current cvstate
Node* delay_transform(Node* n);
- Node* transform(Node* n); // gvn.transform or push node on delay list
+ Node* transform(Node* n); // gvn.transform or skip it
Node* promote_to_phi(Node* n, Node* reg);// Promote "n" to a phi on region "reg"
bool was_promoted_to_phi(Node* n, Node* reg) {
return (n->is_Phi() && n->in(0) == reg);
@@ -146,7 +145,6 @@
IdealKit(GraphKit* gkit, bool delay_all_transforms = false, bool has_declarations = false);
~IdealKit() {
stop();
- drain_delay_transform();
}
void sync_kit(GraphKit* gkit);
@@ -173,7 +171,6 @@
void bind(Node* lab);
void goto_(Node* lab, bool bind = false);
void declarations_done();
- void drain_delay_transform();
Node* IfTrue(IfNode* iff) { return transform(new (C) IfTrueNode(iff)); }
Node* IfFalse(IfNode* iff) { return transform(new (C) IfFalseNode(iff)); }
@@ -198,7 +195,11 @@
Node* thread() { return gvn().transform(new (C) ThreadLocalNode()); }
// Pointers
- Node* AddP(Node *base, Node *ptr, Node *off) { return transform(new (C) AddPNode(base, ptr, off)); }
+
+ // Raw address should be transformed regardless 'delay_transform' flag
+ // to produce canonical form CastX2P(offset).
+ Node* AddP(Node *base, Node *ptr, Node *off) { return _gvn.transform(new (C) AddPNode(base, ptr, off)); }
+
Node* CmpP(Node* l, Node* r) { return transform(new (C) CmpPNode(l, r)); }
#ifdef _LP64
Node* XorX(Node* l, Node* r) { return transform(new (C) XorLNode(l, r)); }
@@ -208,8 +209,6 @@
Node* URShiftX(Node* l, Node* r) { return transform(new (C) URShiftXNode(l, r)); }
Node* ConX(jint k) { return (Node*)gvn().MakeConX(k); }
Node* CastPX(Node* ctl, Node* p) { return transform(new (C) CastP2XNode(ctl, p)); }
- // Add a fixed offset to a pointer
- Node* basic_plus_adr(Node* base, Node* ptr, intptr_t offset);
// Memory operations
--- a/hotspot/src/share/vm/opto/loopnode.cpp Tue Mar 26 10:05:33 2013 +0100
+++ b/hotspot/src/share/vm/opto/loopnode.cpp Tue Mar 26 12:55:26 2013 -0700
@@ -2251,6 +2251,11 @@
return;
}
+ // clear out the dead code after build_loop_late
+ while (_deadlist.size()) {
+ _igvn.remove_globally_dead_node(_deadlist.pop());
+ }
+
if (stop_early) {
assert(do_expensive_nodes, "why are we here?");
if (process_expensive_nodes()) {
@@ -2260,9 +2265,7 @@
// nodes again.
C->set_major_progress();
}
-
_igvn.optimize();
-
return;
}
@@ -2273,11 +2276,6 @@
eliminate_useless_predicates();
}
- // clear out the dead code
- while(_deadlist.size()) {
- _igvn.remove_globally_dead_node(_deadlist.pop());
- }
-
#ifndef PRODUCT
C->verify_graph_edges();
if (_verify_me) { // Nested verify pass?
--- a/hotspot/src/share/vm/opto/phaseX.cpp Tue Mar 26 10:05:33 2013 +0100
+++ b/hotspot/src/share/vm/opto/phaseX.cpp Tue Mar 26 12:55:26 2013 -0700
@@ -1166,31 +1166,30 @@
if (progress_state == PROCESS_INPUTS) {
// After following inputs, continue to outputs
_stack.set_index(PROCESS_OUTPUTS);
- // Remove from iterative worklist
- _worklist.remove(dead);
if (!dead->is_Con()) { // Don't kill cons but uses
bool recurse = false;
// Remove from hash table
_table.hash_delete( dead );
// Smash all inputs to 'dead', isolating him completely
- for( uint i = 0; i < dead->req(); i++ ) {
+ for (uint i = 0; i < dead->req(); i++) {
Node *in = dead->in(i);
- if( in ) { // Points to something?
- dead->set_req(i,NULL); // Kill the edge
- if (in->outcnt() == 0 && in != C->top()) {// Made input go dead?
+ if (in != NULL && in != C->top()) { // Points to something?
+ int nrep = dead->replace_edge(in, NULL); // Kill edges
+ assert((nrep > 0), "sanity");
+ if (in->outcnt() == 0) { // Made input go dead?
_stack.push(in, PROCESS_INPUTS); // Recursively remove
recurse = true;
} else if (in->outcnt() == 1 &&
in->has_special_unique_user()) {
_worklist.push(in->unique_out());
} else if (in->outcnt() <= 2 && dead->is_Phi()) {
- if( in->Opcode() == Op_Region )
+ if (in->Opcode() == Op_Region) {
_worklist.push(in);
- else if( in->is_Store() ) {
+ } else if (in->is_Store()) {
DUIterator_Fast imax, i = in->fast_outs(imax);
_worklist.push(in->fast_out(i));
i++;
- if(in->outcnt() == 2) {
+ if (in->outcnt() == 2) {
_worklist.push(in->fast_out(i));
i++;
}
@@ -1209,38 +1208,42 @@
}
}
}
- }
- }
- C->record_dead_node(dead->_idx);
- if (dead->is_macro()) {
- C->remove_macro_node(dead);
- }
- if (dead->is_expensive()) {
- C->remove_expensive_node(dead);
- }
-
+ } // if (in != NULL && in != C->top())
+ } // for (uint i = 0; i < dead->req(); i++)
if (recurse) {
continue;
}
- }
- // Constant node that has no out-edges and has only one in-edge from
- // root is usually dead. However, sometimes reshaping walk makes
- // it reachable by adding use edges. So, we will NOT count Con nodes
- // as dead to be conservative about the dead node count at any
- // given time.
- }
+ } // if (!dead->is_Con())
+ } // if (progress_state == PROCESS_INPUTS)
// Aggressively kill globally dead uses
// (Rather than pushing all the outs at once, we push one at a time,
// plus the parent to resume later, because of the indefinite number
// of edge deletions per loop trip.)
if (dead->outcnt() > 0) {
- // Recursively remove
+ // Recursively remove output edges
_stack.push(dead->raw_out(0), PROCESS_INPUTS);
} else {
+ // Finished disconnecting all input and output edges.
_stack.pop();
+ // Remove dead node from iterative worklist
+ _worklist.remove(dead);
+ // Constant node that has no out-edges and has only one in-edge from
+ // root is usually dead. However, sometimes reshaping walk makes
+ // it reachable by adding use edges. So, we will NOT count Con nodes
+ // as dead to be conservative about the dead node count at any
+ // given time.
+ if (!dead->is_Con()) {
+ C->record_dead_node(dead->_idx);
+ }
+ if (dead->is_macro()) {
+ C->remove_macro_node(dead);
+ }
+ if (dead->is_expensive()) {
+ C->remove_expensive_node(dead);
+ }
}
- }
+ } // while (_stack.is_nonempty())
}
//------------------------------subsume_node-----------------------------------