diff --git a/src/hotspot/share/gc/shared/c2/barrierSetC2.hpp b/src/hotspot/share/gc/shared/c2/barrierSetC2.hpp index 37eda34..f630e89 100644 --- a/src/hotspot/share/gc/shared/c2/barrierSetC2.hpp +++ b/src/hotspot/share/gc/shared/c2/barrierSetC2.hpp @@ -27,6 +27,7 @@ #include "memory/allocation.hpp" #include "oops/accessDecorators.hpp" +#include "opto/loopnode.hpp" #include "opto/memnode.hpp" #include "utilities/globalDefinitions.hpp" @@ -190,19 +191,31 @@ public: virtual void clone(GraphKit* kit, Node* src, Node* dst, Node* size, bool is_array) const; // These are general helper methods used by C2 - virtual bool is_gc_barrier_node(Node* node) const { return false; } - virtual void eliminate_gc_barrier(PhaseMacroExpand* macro, Node* node) const { } virtual bool array_copy_requires_gc_barriers(BasicType type) const { return false; } + + // Support for GC barriers emitted during parsing + virtual bool is_gc_barrier_node(Node* node) const { return false; } virtual Node* step_over_gc_barrier(Node* c) const { return c; } - virtual void loop_optimize_gc_barrier(Node* node) const { } + // Support for macro expanded GC barriers + virtual void register_potential_barrier_node(Node* node) const { } + virtual void unregister_potential_barrier_node(Node* node) const { } + virtual void eliminate_gc_barrier(PhaseMacroExpand* macro, Node* node) const { } + virtual void enqueue_useful_gc_barrier(Unique_Node_List &worklist, Node* node) const {} + virtual void eliminate_useless_gc_barriers(Unique_Node_List &useful) const {} + virtual void find_dominating_barriers(PhaseIterGVN& igvn) const {} + virtual void add_users_to_worklist(Unique_Node_List* worklist) const {} + + virtual void loop_optimize_gc_barrier(PhaseIdealLoop* phase, Node* node, + bool last_round) const { } // Allow barrier sets to have shared state that is preserved across a compilation unit. // This could for example comprise macro nodes to be expanded during macro expansion. - virtual void* create_barrier_state() const { return NULL; } + virtual void* create_barrier_state(Arena* comp_arena) const { return NULL; } // If the BarrierSetC2 state has kept macro nodes in its compilation unit state to be // expanded later, then now is the time to do so. virtual bool expand_macro_nodes(PhaseMacroExpand* macro) const { return false; } + virtual void verify_gc_barriers(bool post_parse) const {} }; #endif // SHARE_GC_SHARED_C2_BARRIERSETC2_HPP diff --git a/src/hotspot/share/opto/compile.cpp b/src/hotspot/share/opto/compile.cpp index 7e5883e..d9043cc 100644 --- a/src/hotspot/share/opto/compile.cpp +++ b/src/hotspot/share/opto/compile.cpp @@ -416,6 +416,8 @@ void Compile::remove_useless_nodes(Unique_Node_List &useful) { remove_opaque4_node(opaq); } } + BarrierSetC2* bs = BarrierSet::barrier_set()->barrier_set_c2(); + bs->eliminate_useless_gc_barriers(useful); // clean up the late inline lists remove_useless_late_inlines(&_string_late_inlines, useful); remove_useless_late_inlines(&_boxing_late_inlines, useful); @@ -639,7 +641,7 @@ Compile::Compile( ciEnv* ci_env, C2Compiler* compiler, ciMethod* target, int osr _stub_function(NULL), _stub_entry_point(NULL), _method(target), - _barrier_set_state(BarrierSet::barrier_set()->barrier_set_c2()->create_barrier_state()), + _barrier_set_state(BarrierSet::barrier_set()->barrier_set_c2()->create_barrier_state(comp_arena())), _entry_bci(osr_bci), _initial_gvn(NULL), _for_igvn(NULL), @@ -2332,6 +2334,11 @@ void Compile::Optimize() { if (failing()) return; } } + + BarrierSetC2* bs = BarrierSet::barrier_set()->barrier_set_c2(); + bs->find_dominating_barriers(igvn); + if (failing()) return; + // Ensure that major progress is now clear C->clear_major_progress(); @@ -2348,6 +2355,10 @@ void Compile::Optimize() { igvn.optimize(); } +#ifdef ASSERT + bs->verify_gc_barriers(false); +#endif + { TracePhase tp("macroExpand", &timers[_t_macroExpand]); PhaseMacroExpand mex(igvn); diff --git a/src/hotspot/share/opto/compile.hpp b/src/hotspot/share/opto/compile.hpp index de6adc9..9bc9325 100644 --- a/src/hotspot/share/opto/compile.hpp +++ b/src/hotspot/share/opto/compile.hpp @@ -1354,7 +1354,6 @@ class Compile : public Phase { // supporting clone_map CloneMap& clone_map(); void set_clone_map(Dict* d); - }; #endif // SHARE_VM_OPTO_COMPILE_HPP diff --git a/src/hotspot/share/opto/loopnode.hpp b/src/hotspot/share/opto/loopnode.hpp index 192c05c..e49564e 100644 --- a/src/hotspot/share/opto/loopnode.hpp +++ b/src/hotspot/share/opto/loopnode.hpp @@ -684,10 +684,12 @@ class PhaseIdealLoop : public PhaseTransform { // Mark as post visited void set_postvisited( Node *n ) { assert( !is_postvisited( n ), "" ); _preorders[n->_idx] |= 1; } +public: // Set/get control node out. Set lower bit to distinguish from IdealLoopTree // Returns true if "n" is a data node, false if it's a control node. bool has_ctrl( Node *n ) const { return ((intptr_t)_nodes[n->_idx]) & 1; } +private: // clear out dead code after build_loop_late Node_List _deadlist; @@ -736,6 +738,8 @@ class PhaseIdealLoop : public PhaseTransform { public: + PhaseIterGVN &igvn() const { return _igvn; } + static bool is_canonical_loop_entry(CountedLoopNode* cl); bool has_node( Node* n ) const { @@ -789,7 +793,6 @@ public: } } -private: Node *get_ctrl_no_update_helper(Node *i) const { assert(has_ctrl(i), "should be control, not loop"); return (Node*)(((intptr_t)_nodes[i->_idx]) & ~1); @@ -822,7 +825,6 @@ private: // the 'old_node' with 'new_node'. Kill old-node. Add a reference // from old_node to new_node to support the lazy update. Reference // replaces loop reference, since that is not needed for dead node. -public: void lazy_update(Node *old_node, Node *new_node) { assert(old_node != new_node, "no cycles please"); // Re-use the side array slot for this node to provide the @@ -856,6 +858,7 @@ private: uint *_dom_depth; // Used for fast LCA test GrowableArray* _dom_stk; // For recomputation of dom depth +public: Node* idom_no_update(Node* d) const { assert(d->_idx < _idom_size, "oob"); Node* n = _idom[d->_idx]; @@ -903,7 +906,6 @@ private: // build the loop tree and perform any requested optimizations void build_and_optimize(bool do_split_if, bool skip_loop_opts); -public: // Dominators for the sea of nodes void Dominators(); Node *dom_lca( Node *n1, Node *n2 ) const { @@ -960,6 +962,8 @@ public: return (IdealLoopTree*)_nodes[n->_idx]; } + IdealLoopTree *ltree_root() const { return _ltree_root; } + // Is 'n' a (nested) member of 'loop'? int is_member( const IdealLoopTree *loop, Node *n ) const { return loop->is_member(get_loop(n)); } diff --git a/src/hotspot/share/opto/loopopts.cpp b/src/hotspot/share/opto/loopopts.cpp index f21a5e5..a3b9a2b 100644 --- a/src/hotspot/share/opto/loopopts.cpp +++ b/src/hotspot/share/opto/loopopts.cpp @@ -1379,7 +1379,7 @@ void PhaseIdealLoop::split_if_with_blocks_post(Node *n) { } BarrierSetC2* bs = BarrierSet::barrier_set()->barrier_set_c2(); - bs->loop_optimize_gc_barrier(n); + bs->loop_optimize_gc_barrier(this, n, true); } //------------------------------split_if_with_blocks--------------------------- diff --git a/src/hotspot/share/opto/macro.hpp b/src/hotspot/share/opto/macro.hpp index f58dd5d..b100f3c 100644 --- a/src/hotspot/share/opto/macro.hpp +++ b/src/hotspot/share/opto/macro.hpp @@ -37,6 +37,7 @@ class PhaseMacroExpand : public Phase { private: PhaseIterGVN &_igvn; +public: // Helper methods roughly modeled after GraphKit: Node* basic_plus_adr(Node* base, int offset) { return (offset == 0)? base: basic_plus_adr(base, MakeConX(offset)); @@ -62,6 +63,7 @@ private: Node* make_store(Node* ctl, Node* mem, Node* base, int offset, Node* value, BasicType bt); +private: // projections extracted from a call node ProjNode *_fallthroughproj; ProjNode *_fallthroughcatchproj; @@ -205,6 +207,8 @@ public: void eliminate_macro_nodes(); bool expand_macro_nodes(); + PhaseIterGVN &igvn() const { return _igvn; } + // Members accessed from BarrierSetC2 void replace_node(Node* source, Node* target) { _igvn.replace_node(source, target); } Node* intcon(jint con) const { return _igvn.intcon(con); } diff --git a/src/hotspot/share/opto/node.cpp b/src/hotspot/share/opto/node.cpp index f3142ce..32e8118 100644 --- a/src/hotspot/share/opto/node.cpp +++ b/src/hotspot/share/opto/node.cpp @@ -23,6 +23,8 @@ */ #include "precompiled.hpp" +#include "gc/shared/barrierSet.hpp" +#include "gc/shared/c2/barrierSetC2.hpp" #include "libadt/vectset.hpp" #include "memory/allocation.inline.hpp" #include "memory/resourceArea.hpp" @@ -37,6 +39,7 @@ #include "opto/regmask.hpp" #include "opto/type.hpp" #include "utilities/copy.hpp" +#include "utilities/macros.hpp" class RegMask; // #include "phase.hpp" @@ -499,6 +502,8 @@ Node *Node::clone() const { C->add_macro_node(n); if (is_expensive()) C->add_expensive_node(n); + BarrierSetC2* bs = BarrierSet::barrier_set()->barrier_set_c2(); + bs->register_potential_barrier_node(n); // If the cloned node is a range check dependent CastII, add it to the list. CastIINode* cast = n->isa_CastII(); if (cast != NULL && cast->has_range_check()) { @@ -622,6 +627,8 @@ void Node::destruct() { if (is_SafePoint()) { as_SafePoint()->delete_replaced_nodes(); } + BarrierSetC2* bs = BarrierSet::barrier_set()->barrier_set_c2(); + bs->unregister_potential_barrier_node(this); #ifdef ASSERT // We will not actually delete the storage, but we'll make the node unusable. *(address*)this = badAddress; // smash the C++ vtbl, probably @@ -1361,6 +1368,8 @@ static void kill_dead_code( Node *dead, PhaseIterGVN *igvn ) { if (dead->Opcode() == Op_Opaque4) { igvn->C->remove_range_check_cast(dead); } + BarrierSetC2* bs = BarrierSet::barrier_set()->barrier_set_c2(); + bs->unregister_potential_barrier_node(dead); igvn->C->record_dead_node(dead->_idx); // Kill all inputs to the dead guy for (uint i=0; i < dead->req(); i++) { @@ -1379,6 +1388,8 @@ static void kill_dead_code( Node *dead, PhaseIterGVN *igvn ) { // The restriction (outcnt() <= 2) is the same as in set_req_X() // and remove_globally_dead_node(). igvn->add_users_to_worklist( n ); + } else { + BarrierSet::barrier_set()->barrier_set_c2()->enqueue_useful_gc_barrier(igvn->_worklist, n); } } } diff --git a/src/hotspot/share/opto/phaseX.cpp b/src/hotspot/share/opto/phaseX.cpp index 8f12615..2f8dbb5 100644 --- a/src/hotspot/share/opto/phaseX.cpp +++ b/src/hotspot/share/opto/phaseX.cpp @@ -23,6 +23,8 @@ */ #include "precompiled.hpp" +#include "gc/shared/barrierSet.hpp" +#include "gc/shared/c2/barrierSetC2.hpp" #include "memory/allocation.inline.hpp" #include "memory/resourceArea.hpp" #include "opto/block.hpp" @@ -36,6 +38,7 @@ #include "opto/phaseX.hpp" #include "opto/regalloc.hpp" #include "opto/rootnode.hpp" +#include "utilities/macros.hpp" //============================================================================= #define NODE_HASH_MINIMUM_SIZE 255 @@ -939,6 +942,9 @@ PhaseIterGVN::PhaseIterGVN( PhaseGVN *gvn ) : PhaseGVN(gvn), n->is_Mem() ) add_users_to_worklist(n); } + + BarrierSetC2* bs = BarrierSet::barrier_set()->barrier_set_c2(); + bs->add_users_to_worklist(&_worklist); } /** @@ -1369,6 +1375,8 @@ void PhaseIterGVN::remove_globally_dead_node( Node *dead ) { } assert(!(i < imax), "sanity"); } + } else { + BarrierSet::barrier_set()->barrier_set_c2()->enqueue_useful_gc_barrier(_worklist, in); } if (ReduceFieldZeroing && dead->is_Load() && i == MemNode::Memory && in->is_Proj() && in->in(0) != NULL && in->in(0)->is_Initialize()) { @@ -1424,6 +1432,8 @@ void PhaseIterGVN::remove_globally_dead_node( Node *dead ) { if (dead->Opcode() == Op_Opaque4) { C->remove_opaque4_node(dead); } + BarrierSetC2* bs = BarrierSet::barrier_set()->barrier_set_c2(); + bs->unregister_potential_barrier_node(dead); } } // while (_stack.is_nonempty()) }