From 31596cfef912c3aa41d22d910befe1ff11330e57 Mon Sep 17 00:00:00 2001 From: Ashay Rane <253344819+raneashay@users.noreply.github.com> Date: Fri, 22 May 2026 18:24:41 +0000 Subject: [PATCH] 8358560: C2: convert some uses of GrowableArray to Unique_Node_List Reviewed-by: aseoane, chagedorn, bmaillard --- src/hotspot/share/opto/escape.cpp | 59 ++++++++++++++++--------------- src/hotspot/share/opto/escape.hpp | 8 ++--- src/hotspot/share/opto/gcm.cpp | 8 +++-- src/hotspot/share/opto/macro.cpp | 26 +++++++------- src/hotspot/share/opto/macro.hpp | 6 ++-- 5 files changed, 55 insertions(+), 52 deletions(-) diff --git a/src/hotspot/share/opto/escape.cpp b/src/hotspot/share/opto/escape.cpp index 366a9b3fb4b..22acbf1c53e 100644 --- a/src/hotspot/share/opto/escape.cpp +++ b/src/hotspot/share/opto/escape.cpp @@ -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 &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 &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 phi_list; + Unique_Node_List phi_list; GrowableArray 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 &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 &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 &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 &alloc_worklist, GrowableArray &mergemem_worklist, Unique_Node_List &reducible_merges) { DEBUG_ONLY(Unique_Node_List reduced_merges;) - GrowableArray memnode_worklist; - GrowableArray 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 &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 &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 &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 &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 &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 &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 &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++) { diff --git a/src/hotspot/share/opto/escape.hpp b/src/hotspot/share/opto/escape.hpp index dcb832889ec..f60807d786a 100644 --- a/src/hotspot/share/opto/escape.hpp +++ b/src/hotspot/share/opto/escape.hpp @@ -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 &orig_phi_worklist, bool &new_created); - PhiNode *split_memory_phi(PhiNode *orig_phi, int alias_idx, GrowableArray &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 &orig_phis); - Node* find_inst_mem(Node* mem, int alias_idx,GrowableArray &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 diff --git a/src/hotspot/share/opto/gcm.cpp b/src/hotspot/share/opto/gcm.cpp index ce1ea8a59e2..8536dec7662 100644 --- a/src/hotspot/share/opto/gcm.cpp +++ b/src/hotspot/share/opto/gcm.cpp @@ -595,7 +595,7 @@ private: }; GrowableArray _queue; - GrowableArray _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. diff --git a/src/hotspot/share/opto/macro.cpp b/src/hotspot/share/opto/macro.cpp index 8c5dbe7fb48..0ee073e8b06 100644 --- a/src/hotspot/share/opto/macro.cpp +++ b/src/hotspot/share/opto/macro.cpp @@ -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 * 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 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 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& safepoints) { - GrowableArray 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, GrowableArrayextract_projections(&_callprojs, false /*separate_io_proj*/, false /*do_asserts*/); - GrowableArray 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; } } diff --git a/src/hotspot/share/opto/macro.hpp b/src/hotspot/share/opto/macro.hpp index e4b20402e63..4d35cb40028 100644 --- a/src/hotspot/share/opto/macro.hpp +++ b/src/hotspot/share/opto/macro.hpp @@ -109,8 +109,8 @@ private: bool eliminate_boxing_node(CallStaticJavaNode *boxing); bool eliminate_allocate_node(AllocateNode *alloc); - void undo_previous_scalarizations(GrowableArray safepoints_done, AllocateNode* alloc); - bool scalar_replacement(AllocateNode *alloc, GrowableArray & 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 *safepoints); + static bool can_eliminate_allocation(PhaseIterGVN* igvn, AllocateNode* alloc, Unique_Node_List* safepoints); PhaseIterGVN &igvn() const { return _igvn; }