8358560: C2: convert some uses of GrowableArray<Node*> to Unique_Node_List

Reviewed-by: aseoane, chagedorn, bmaillard
This commit is contained in:
Ashay Rane 2026-05-22 18:24:41 +00:00 committed by Mat Carter
parent 29a7130d98
commit 31596cfef9
5 changed files with 55 additions and 52 deletions

View File

@ -3970,7 +3970,7 @@ bool ConnectionGraph::split_AddP(Node *addp, Node *base) {
// created phi or an existing phi. Sets create_new to indicate whether a new
// phi was created. Cache the last newly created phi in the node map.
//
PhiNode *ConnectionGraph::create_split_phi(PhiNode *orig_phi, int alias_idx, GrowableArray<PhiNode *> &orig_phi_worklist, bool &new_created) {
PhiNode* ConnectionGraph::create_split_phi(PhiNode* orig_phi, int alias_idx, Unique_Node_List& orig_phi_worklist, bool& new_created) {
Compile *C = _compile;
PhaseGVN* igvn = _igvn;
new_created = false;
@ -4006,7 +4006,7 @@ PhiNode *ConnectionGraph::create_split_phi(PhiNode *orig_phi, int alias_idx, Gro
}
return nullptr;
}
orig_phi_worklist.append_if_missing(orig_phi);
orig_phi_worklist.push(orig_phi);
const TypePtr *atype = C->get_adr_type(alias_idx);
result = PhiNode::make(orig_phi->in(0), nullptr, Type::MEMORY, atype);
C->copy_node_notes_to(result, orig_phi);
@ -4021,7 +4021,7 @@ PhiNode *ConnectionGraph::create_split_phi(PhiNode *orig_phi, int alias_idx, Gro
// Return a new version of Memory Phi "orig_phi" with the inputs having the
// specified alias index.
//
PhiNode *ConnectionGraph::split_memory_phi(PhiNode *orig_phi, int alias_idx, GrowableArray<PhiNode *> &orig_phi_worklist, uint rec_depth) {
PhiNode* ConnectionGraph::split_memory_phi(PhiNode* orig_phi, int alias_idx, Unique_Node_List& orig_phi_worklist, uint rec_depth) {
assert(alias_idx != Compile::AliasIdxBot, "can't split out bottom memory");
Compile *C = _compile;
PhaseGVN* igvn = _igvn;
@ -4030,7 +4030,7 @@ PhiNode *ConnectionGraph::split_memory_phi(PhiNode *orig_phi, int alias_idx, Gro
if (!new_phi_created) {
return result;
}
GrowableArray<PhiNode *> phi_list;
Unique_Node_List phi_list;
GrowableArray<uint> cur_input;
PhiNode *phi = orig_phi;
uint idx = 1;
@ -4070,9 +4070,9 @@ PhiNode *ConnectionGraph::split_memory_phi(PhiNode *orig_phi, int alias_idx, Gro
assert((phi->in(i) == nullptr) == (in == nullptr), "inputs must correspond.");
}
// we have finished processing a Phi, see if there are any more to do
finished = (phi_list.length() == 0 );
finished = (phi_list.size() == 0);
if (!finished) {
phi = phi_list.pop();
phi = phi_list.pop()->as_Phi();
idx = cur_input.pop();
PhiNode *prev_result = get_map_phi(phi->_idx);
prev_result->set_req(idx++, result);
@ -4103,7 +4103,7 @@ Node* ConnectionGraph::step_through_mergemem(MergeMemNode *mmem, int alias_idx,
//
// Move memory users to their memory slices.
//
void ConnectionGraph::move_inst_mem(Node* n, GrowableArray<PhiNode *> &orig_phis) {
void ConnectionGraph::move_inst_mem(Node* n, Unique_Node_List& orig_phis) {
Compile* C = _compile;
PhaseGVN* igvn = _igvn;
const TypePtr* tp = igvn->type(n->in(MemNode::Address))->isa_ptr();
@ -4176,7 +4176,7 @@ void ConnectionGraph::move_inst_mem(Node* n, GrowableArray<PhiNode *> &orig_phi
// is the specified alias index.
//
#define FIND_INST_MEM_RECURSION_DEPTH_LIMIT 1000
Node* ConnectionGraph::find_inst_mem(Node *orig_mem, int alias_idx, GrowableArray<PhiNode *> &orig_phis, uint rec_depth) {
Node* ConnectionGraph::find_inst_mem(Node* orig_mem, int alias_idx, Unique_Node_List& orig_phis, uint rec_depth) {
if (rec_depth > FIND_INST_MEM_RECURSION_DEPTH_LIMIT) {
_compile->record_failure(_invocation > 0 ? C2Compiler::retry_no_iterative_escape_analysis() : C2Compiler::retry_no_escape_analysis());
return nullptr;
@ -4269,7 +4269,7 @@ Node* ConnectionGraph::find_inst_mem(Node *orig_mem, int alias_idx, GrowableArra
C->get_alias_index(result->as_Phi()->adr_type()) != alias_idx) {
Node *un = result->as_Phi()->unique_input(igvn);
if (un != nullptr) {
orig_phis.append_if_missing(result->as_Phi());
orig_phis.push(result);
result = un;
} else {
break;
@ -4324,7 +4324,7 @@ Node* ConnectionGraph::find_inst_mem(Node *orig_mem, int alias_idx, GrowableArra
if (!is_instance) {
// Push all non-instance Phis on the orig_phis worklist to update inputs
// during Phase 4 if needed.
orig_phis.append_if_missing(mphi);
orig_phis.push(mphi);
} else if (C->get_alias_index(t) != alias_idx) {
// Create a new Phi with the specified alias index type.
result = split_memory_phi(mphi, alias_idx, orig_phis, rec_depth + 1);
@ -4428,8 +4428,8 @@ void ConnectionGraph::split_unique_types(GrowableArray<Node *> &alloc_worklist,
GrowableArray<MergeMemNode*> &mergemem_worklist,
Unique_Node_List &reducible_merges) {
DEBUG_ONLY(Unique_Node_List reduced_merges;)
GrowableArray<Node *> memnode_worklist;
GrowableArray<PhiNode *> orig_phis;
Unique_Node_List memnode_worklist;
Unique_Node_List orig_phis;
PhaseIterGVN *igvn = _igvn;
uint new_index_start = (uint) _compile->num_alias_types();
VectorSet visited;
@ -4585,7 +4585,7 @@ void ConnectionGraph::split_unique_types(GrowableArray<Node *> &alloc_worklist,
}
alloc_worklist.append_if_missing(use);
} else if (use->is_MemBar()) {
memnode_worklist.append_if_missing(use);
memnode_worklist.push(use);
}
}
}
@ -4682,10 +4682,10 @@ void ConnectionGraph::split_unique_types(GrowableArray<Node *> &alloc_worklist,
Node *use = n->fast_out(i);
if(use->is_Mem() && use->in(MemNode::Address) == n) {
// Load/store to instance's field
memnode_worklist.append_if_missing(use);
memnode_worklist.push(use);
} else if (use->is_MemBar()) {
if (use->in(TypeFunc::Memory) == n) { // Ignore precedent edge
memnode_worklist.append_if_missing(use);
memnode_worklist.push(use);
}
} else if (use->is_AddP() && use->outcnt() > 0) { // No dead nodes
Node* addp2 = find_second_addp(use, n);
@ -4714,14 +4714,14 @@ void ConnectionGraph::split_unique_types(GrowableArray<Node *> &alloc_worklist,
} else if (use->Opcode() == Op_EncodeISOArray) {
if (use->in(MemNode::Memory) == n || use->in(3) == n) {
// EncodeISOArray overwrites destination array
memnode_worklist.append_if_missing(use);
memnode_worklist.push(use);
}
} else {
uint op = use->Opcode();
if ((op == Op_StrCompressedCopy || op == Op_StrInflatedCopy) &&
(use->in(MemNode::Memory) == n)) {
// They overwrite memory edge corresponding to destination array,
memnode_worklist.append_if_missing(use);
memnode_worklist.push(use);
} else if (!(op == Op_CmpP || op == Op_Conv2B ||
op == Op_CastP2X ||
op == Op_FastLock || op == Op_AryEq ||
@ -4806,18 +4806,19 @@ void ConnectionGraph::split_unique_types(GrowableArray<Node *> &alloc_worklist,
// Phase 2: Process MemNode's from memnode_worklist. compute new address type and
// compute new values for Memory inputs (the Memory inputs are not
// actually updated until phase 4.)
if (memnode_worklist.length() == 0)
if (memnode_worklist.size() == 0) {
return; // nothing to do
while (memnode_worklist.length() != 0) {
}
while (memnode_worklist.size() != 0) {
Node *n = memnode_worklist.pop();
if (visited.test_set(n->_idx)) {
continue;
}
if (n->is_Phi()) {
if ((uint) _compile->get_alias_index(n->as_Phi()->adr_type()) < new_index_start) {
if ((uint) _compile->get_alias_index(n->adr_type()) < new_index_start) {
// Push memory phis on the orig_phis worklist to update
// during Phase 4 if needed.
orig_phis.append_if_missing(n->as_Phi());
orig_phis.push(n);
}
} else if (n->is_ClearArray()) {
// we don't need to do anything, but the users must be pushed
@ -4882,17 +4883,17 @@ void ConnectionGraph::split_unique_types(GrowableArray<Node *> &alloc_worklist,
for (DUIterator_Fast imax, i = n->fast_outs(imax); i < imax; i++) {
Node *use = n->fast_out(i);
if (use->is_Phi() || use->is_ClearArray()) {
memnode_worklist.append_if_missing(use);
memnode_worklist.push(use);
} else if (use->is_Mem() && use->in(MemNode::Memory) == n) {
memnode_worklist.append_if_missing(use);
memnode_worklist.push(use);
} else if (use->is_MemBar() || use->is_CallLeaf()) {
if (use->in(TypeFunc::Memory) == n) { // Ignore precedent edge
memnode_worklist.append_if_missing(use);
memnode_worklist.push(use);
}
} else if (use->is_Proj()) {
assert(n->is_Initialize(), "We only push projections of Initialize");
if (use->as_Proj()->_con == TypeFunc::Memory) { // Ignore precedent edge
memnode_worklist.append_if_missing(use);
memnode_worklist.push(use);
}
#ifdef ASSERT
} else if(use->is_Mem()) {
@ -4902,14 +4903,14 @@ void ConnectionGraph::split_unique_types(GrowableArray<Node *> &alloc_worklist,
} else if (use->Opcode() == Op_EncodeISOArray) {
if (use->in(MemNode::Memory) == n || use->in(3) == n) {
// EncodeISOArray overwrites destination array
memnode_worklist.append_if_missing(use);
memnode_worklist.push(use);
}
} else {
uint op = use->Opcode();
if ((use->in(MemNode::Memory) == n) &&
(op == Op_StrCompressedCopy || op == Op_StrInflatedCopy)) {
// They overwrite memory edge corresponding to destination array,
memnode_worklist.append_if_missing(use);
memnode_worklist.push(use);
} else if (!(BarrierSet::barrier_set()->barrier_set_c2()->is_gc_barrier_node(use) ||
op == Op_AryEq || op == Op_StrComp || op == Op_CountPositives ||
op == Op_StrCompressedCopy || op == Op_StrInflatedCopy || op == Op_VectorizedHashCode ||
@ -5018,8 +5019,8 @@ void ConnectionGraph::split_unique_types(GrowableArray<Node *> &alloc_worklist,
// to recursively process Phi's encountered on the input memory
// chains as is done in split_memory_phi() since they will
// also be processed here.
for (int j = 0; j < orig_phis.length(); j++) {
PhiNode *phi = orig_phis.at(j);
for (uint j = 0; j < orig_phis.size(); j++) {
PhiNode* phi = orig_phis.at(j)->as_Phi();
int alias_idx = _compile->get_alias_index(phi->adr_type());
igvn->hash_delete(phi);
for (uint i = 1; i < phi->req(); i++) {

View File

@ -556,11 +556,11 @@ private:
// Helper methods for unique types split.
bool split_AddP(Node *addp, Node *base);
PhiNode *create_split_phi(PhiNode *orig_phi, int alias_idx, GrowableArray<PhiNode *> &orig_phi_worklist, bool &new_created);
PhiNode *split_memory_phi(PhiNode *orig_phi, int alias_idx, GrowableArray<PhiNode *> &orig_phi_worklist, uint rec_depth);
PhiNode* create_split_phi(PhiNode* orig_phi, int alias_idx, Unique_Node_List& orig_phi_worklist, bool& new_created);
PhiNode* split_memory_phi(PhiNode* orig_phi, int alias_idx, Unique_Node_List& orig_phi_worklist, uint rec_depth);
void move_inst_mem(Node* n, GrowableArray<PhiNode *> &orig_phis);
Node* find_inst_mem(Node* mem, int alias_idx,GrowableArray<PhiNode *> &orig_phi_worklist, uint rec_depth = 0);
void move_inst_mem(Node* n, Unique_Node_List& orig_phis);
Node* find_inst_mem(Node* mem, int alias_idx, Unique_Node_List& orig_phi_worklist, uint rec_depth = 0);
Node* step_through_mergemem(MergeMemNode *mmem, int alias_idx, const TypeOopPtr *toop);
Node_Array _node_map; // used for bookkeeping during type splitting

View File

@ -595,7 +595,7 @@ private:
};
GrowableArray<DefUsePair> _queue;
GrowableArray<MergeMemNode*> _worklist_visited; // visited mergemem nodes
Unique_Node_List _worklist_visited; // visited mergemem nodes
bool already_enqueued(Node* def_mem, PhiNode* use_phi) const {
// def_mem is one of the inputs of use_phi and at least one input of use_phi is
@ -635,9 +635,11 @@ public:
void push(Node* def_mem_state, Node* use_mem_state) {
if (use_mem_state->is_MergeMem()) {
// Be sure we don't get into combinatorial problems.
if (!_worklist_visited.append_if_missing(use_mem_state->as_MergeMem())) {
return; // already on work list; do not repeat
if (_worklist_visited.member(use_mem_state)) {
// already on work list; do not repeat
return;
}
_worklist_visited.push(use_mem_state);
} else if (use_mem_state->is_Phi()) {
// A Phi could have the same mem as input multiple times. If that's the case, we don't need to enqueue it
// more than once. We otherwise allow phis to be repeated; they can merge two relevant states.

View File

@ -612,7 +612,7 @@ Node* PhaseMacroExpand::value_from_mem(Node* origin, Node* ctl, BasicType ft, co
}
// Check the possibility of scalar replacement.
bool PhaseMacroExpand::can_eliminate_allocation(PhaseIterGVN* igvn, AllocateNode *alloc, GrowableArray <SafePointNode *>* safepoints) {
bool PhaseMacroExpand::can_eliminate_allocation(PhaseIterGVN* igvn, AllocateNode* alloc, Unique_Node_List* safepoints) {
// Scan the uses of the allocation to check for anything that would
// prevent us from eliminating it.
NOT_PRODUCT( const char* fail_eliminate = nullptr; )
@ -700,7 +700,7 @@ bool PhaseMacroExpand::can_eliminate_allocation(PhaseIterGVN* igvn, AllocateNode
NOT_PRODUCT(fail_eliminate = "null or TOP memory";)
can_eliminate = false;
} else if (!reduce_merge_precheck) {
safepoints->append_if_missing(sfpt);
safepoints->push(sfpt);
}
} else if (reduce_merge_precheck &&
(use->is_Phi() || use->is_EncodeP() ||
@ -759,7 +759,7 @@ bool PhaseMacroExpand::can_eliminate_allocation(PhaseIterGVN* igvn, AllocateNode
return can_eliminate;
}
void PhaseMacroExpand::undo_previous_scalarizations(GrowableArray <SafePointNode *> safepoints_done, AllocateNode* alloc) {
void PhaseMacroExpand::undo_previous_scalarizations(Unique_Node_List& safepoints_done, AllocateNode* alloc) {
Node* res = alloc->result_cast();
int nfields = 0;
assert(res == nullptr || res->is_CheckCastPP(), "unexpected AllocateNode result");
@ -779,8 +779,8 @@ void PhaseMacroExpand::undo_previous_scalarizations(GrowableArray <SafePointNode
}
// rollback processed safepoints
while (safepoints_done.length() > 0) {
SafePointNode* sfpt_done = safepoints_done.pop();
while (safepoints_done.size() > 0) {
SafePointNode* sfpt_done = safepoints_done.pop()->as_SafePoint();
SafePointNode::NodeEdgeTempStorage non_debug_edges_worklist(igvn());
@ -978,16 +978,16 @@ SafePointScalarObjectNode* PhaseMacroExpand::create_scalarized_object_descriptio
}
// Do scalar replacement.
bool PhaseMacroExpand::scalar_replacement(AllocateNode* alloc, GrowableArray<SafePointNode*>& safepoints) {
GrowableArray<SafePointNode*> safepoints_done;
bool PhaseMacroExpand::scalar_replacement(AllocateNode* alloc, Unique_Node_List& safepoints) {
Unique_Node_List safepoints_done;
Node* res = alloc->result_cast();
assert(res == nullptr || res->is_CheckCastPP(), "unexpected AllocateNode result");
// Process the safepoint uses
while (safepoints.length() > 0) {
SafePointNode* sfpt = safepoints.pop();
while (safepoints.size() > 0) {
SafePointNode* sfpt = safepoints.pop()->as_SafePoint();
SafePointNode::NodeEdgeTempStorage non_debug_edges_worklist(igvn());
SafePointNode::NodeEdgeTempStorage non_debug_edges_worklist(igvn());
// All sfpt inputs are implicitly included into debug info during the scalarization process below.
// Keep non-debug inputs separately, so they stay non-debug.
@ -1010,7 +1010,7 @@ bool PhaseMacroExpand::scalar_replacement(AllocateNode* alloc, GrowableArray<Saf
_igvn._worklist.push(sfpt);
// keep it for rollback
safepoints_done.append_if_missing(sfpt);
safepoints_done.push(sfpt);
}
return true;
@ -1199,7 +1199,7 @@ bool PhaseMacroExpand::eliminate_allocate_node(AllocateNode *alloc) {
alloc->extract_projections(&_callprojs, false /*separate_io_proj*/, false /*do_asserts*/);
GrowableArray <SafePointNode *> safepoints;
Unique_Node_List safepoints;
if (!can_eliminate_allocation(&_igvn, alloc, &safepoints)) {
return false;
}
@ -1209,7 +1209,7 @@ bool PhaseMacroExpand::eliminate_allocate_node(AllocateNode *alloc) {
// We can only eliminate allocation if all debug info references
// are already replaced with SafePointScalarObject because
// we can't search for a fields value without instance_id.
if (safepoints.length() > 0) {
if (safepoints.size() > 0) {
return false;
}
}

View File

@ -109,8 +109,8 @@ private:
bool eliminate_boxing_node(CallStaticJavaNode *boxing);
bool eliminate_allocate_node(AllocateNode *alloc);
void undo_previous_scalarizations(GrowableArray <SafePointNode *> safepoints_done, AllocateNode* alloc);
bool scalar_replacement(AllocateNode *alloc, GrowableArray <SafePointNode *>& safepoints);
void undo_previous_scalarizations(Unique_Node_List& safepoints_done, AllocateNode* alloc);
bool scalar_replacement(AllocateNode* alloc, Unique_Node_List& safepoints);
void process_users_of_allocation(CallNode *alloc);
void eliminate_gc_barrier(Node *p2x);
@ -218,7 +218,7 @@ public:
void eliminate_opaque_looplimit_macro_nodes();
SafePointScalarObjectNode* create_scalarized_object_description(AllocateNode *alloc, SafePointNode* sfpt);
static bool can_eliminate_allocation(PhaseIterGVN *igvn, AllocateNode *alloc, GrowableArray <SafePointNode *> *safepoints);
static bool can_eliminate_allocation(PhaseIterGVN* igvn, AllocateNode* alloc, Unique_Node_List* safepoints);
PhaseIterGVN &igvn() const { return _igvn; }