Mercurial > hg > jdk9-shenandoah > hotspot
changeset 9627:c02a7038ce96
Reworked C2 Shenandoah optimizer. Fixes some methods that couldn't be compiled, a SEGV caused by implicit null checks, and improves performance.
author | rkennke |
---|---|
date | Tue, 29 Sep 2015 16:51:31 +0200 |
parents | fd59c4412e00 |
children | 82e2de7b5401 |
files | src/cpu/x86/vm/x86_64.ad src/share/vm/opto/graphKit.cpp src/share/vm/opto/phaseX.cpp src/share/vm/opto/phaseX.hpp src/share/vm/opto/shenandoahSupport.cpp src/share/vm/opto/shenandoahSupport.hpp |
diffstat | 6 files changed, 362 insertions(+), 224 deletions(-) [+] |
line wrap: on
line diff
--- a/src/cpu/x86/vm/x86_64.ad Fri Sep 25 16:45:39 2015 +0200 +++ b/src/cpu/x86/vm/x86_64.ad Tue Sep 29 16:51:31 2015 +0200 @@ -6404,28 +6404,6 @@ %} instruct shenandoahRB(rRegP dst, rRegP src, rFlagsReg cr) %{ - predicate(n->bottom_type()->make_ptr()->ptr() != TypePtr::NotNull); - match(Set dst (ShenandoahReadBarrier src)); - effect(DEF dst, USE src, KILL cr); - ins_cost(300); // XXX - format %{ "shenandoah_rb $dst,$src" %} - ins_encode %{ - Register s = $src$$Register; - Register d = $dst$$Register; - Label is_null; - if (s != d) { - __ movptr(d, 0); - } - __ testptr(s, s); - __ jcc(Assembler::zero, is_null); - __ movptr(d, Address(s, -8)); - __ bind(is_null); - %} - ins_pipe(ialu_reg_mem); -%} - -instruct shenandoahRBNotNull(rRegP dst, rRegP src, rFlagsReg cr) %{ - predicate(n->bottom_type()->make_ptr()->ptr() == TypePtr::NotNull); match(Set dst (ShenandoahReadBarrier src)); effect(DEF dst, USE src); ins_cost(125); // XXX @@ -6439,32 +6417,6 @@ %} instruct shenandoahWB(rax_RegP dst, rdi_RegP src, rFlagsReg cr) %{ - predicate(n->bottom_type()->make_ptr()->ptr() != TypePtr::NotNull); - match(Set dst (ShenandoahWriteBarrier src)); - effect(DEF dst, USE_KILL src, KILL cr); - ins_cost(125); // XXX - format %{ "shenandoah_wb $dst,$src" %} - ins_encode %{ - Label done; - Register s = $src$$Register; - Register d = $dst$$Register; - assert(s == rdi, "need rdi"); - assert(d == rax, "result in rax"); - __ movptr(d, 0); - __ testptr(s, s); - __ jcc(Assembler::zero, done); - Address evacuation_in_progress = Address(r15_thread, in_bytes(JavaThread::evacuation_in_progress_offset())); - __ cmpb(evacuation_in_progress, 0); - __ movptr(d, Address(s, -8)); - __ jcc(Assembler::equal, done); - __ call(RuntimeAddress(CAST_FROM_FN_PTR(address, StubRoutines::x86::shenandoah_wb()))); - __ bind(done); - %} - ins_pipe(pipe_slow); -%} - -instruct shenandoahWBNotNull(rax_RegP dst, rdi_RegP src, rFlagsReg cr) %{ - predicate(n->bottom_type()->make_ptr()->ptr() == TypePtr::NotNull); match(Set dst (ShenandoahWriteBarrier src)); effect(DEF dst, USE_KILL src, KILL cr); ins_cost(300); // XXX
--- a/src/share/vm/opto/graphKit.cpp Fri Sep 25 16:45:39 2015 +0200 +++ b/src/share/vm/opto/graphKit.cpp Tue Sep 29 16:51:31 2015 +0200 @@ -4435,17 +4435,43 @@ const TypePtr* adr_type = obj_type->is_ptr()->add_offset(-8); Node* mem = use_mem ? memory(adr_type) : immutable_memory(); - if (! ShenandoahBarrierNode::needs_barrier(&_gvn, obj, mem)) { + if (! ShenandoahBarrierNode::needs_barrier(&_gvn, NULL, obj, mem)) { // We know it is null, no barrier needed. return obj; } - Node* ctrl = use_ctrl ? control() : NULL; - ShenandoahReadBarrierNode* rb = new ShenandoahReadBarrierNode(ctrl, mem, obj); - Node* n = _gvn.transform(rb); - record_for_igvn(n); - return n; + if (obj_type->meet(TypePtr::NULL_PTR) == obj_type->remove_speculative()) { + + // We don't know if it's null or not. Need null-check. + enum { _not_null_path = 1, _null_path, PATH_LIMIT }; + RegionNode* region = new RegionNode(PATH_LIMIT); + Node* phi = new PhiNode(region, obj_type); + Node* null_ctrl = top(); + Node* not_null_obj = null_check_oop(obj, &null_ctrl); + + region->init_req(_null_path, null_ctrl); + phi ->init_req(_null_path, obj); + + Node* ctrl = use_ctrl ? control() : NULL; + ShenandoahReadBarrierNode* rb = new ShenandoahReadBarrierNode(ctrl, mem, not_null_obj); + Node* n = _gvn.transform(rb); + + region->init_req(_not_null_path, control()); + phi ->init_req(_not_null_path, n); + + set_control(_gvn.transform(region)); + record_for_igvn(region); + return _gvn.transform(phi); + + } else { + // We know it is not null. Simple barrier is sufficient. + Node* ctrl = use_ctrl ? control() : NULL; + ShenandoahReadBarrierNode* rb = new ShenandoahReadBarrierNode(ctrl, mem, obj); + Node* n = _gvn.transform(rb); + record_for_igvn(n); + return n; + } } else { return obj; @@ -4456,22 +4482,60 @@ if (UseShenandoahGC && ShenandoahWriteBarrier) { - if (! ShenandoahBarrierNode::needs_barrier(&_gvn, obj, NULL)) { + if (! ShenandoahBarrierNode::needs_barrier(&_gvn, NULL, obj, NULL)) { return obj; } const Type* obj_type = obj->bottom_type(); const TypePtr* adr_type = obj_type->is_ptr()->add_offset(-8); - // tty->print("wb for: "); obj->dump(); - ShenandoahWriteBarrierNode* wb = new ShenandoahWriteBarrierNode(NULL, immutable_memory(), obj); - // tty->print("........"); wb->dump(); - Node* n = _gvn.transform(wb); - if (wb == n) { - Node* proj = _gvn.transform(new ShenandoahWBMemProjNode(wb)); - set_memory(proj, adr_type); + // tty->print_cr("memory at:"); + // adr_type->dump(); + // tty->print_cr("\n"); + // memory(adr_type)->dump(); + if (obj_type->meet(TypePtr::NULL_PTR) == obj_type->remove_speculative()) { + // We don't know if it's null or not. Need null-check. + enum { _not_null_path = 1, _null_path, PATH_LIMIT }; + RegionNode* region = new RegionNode(PATH_LIMIT); + Node* phi = new PhiNode(region, obj_type); + Node* memphi = PhiNode::make(region, memory(adr_type), Type::MEMORY, C->alias_type(adr_type)->adr_type()); + + Node* prev_mem = memory(adr_type); + Node* null_ctrl = top(); + Node* not_null_obj = null_check_oop(obj, &null_ctrl); + + region->init_req(_null_path, null_ctrl); + phi ->init_req(_null_path, null()); + memphi->init_req(_null_path, prev_mem); + + ShenandoahWriteBarrierNode* wb = new ShenandoahWriteBarrierNode(NULL, memory(adr_type), not_null_obj); + Node* n = _gvn.transform(wb); + if (n == wb) { // New barrier needs memory projection. + Node* proj = _gvn.transform(new ShenandoahWBMemProjNode(n)); + set_memory(proj, adr_type); + } + + region->init_req(_not_null_path, control()); + phi ->init_req(_not_null_path, n); + memphi->init_req(_not_null_path, memory(adr_type)); + + set_control(_gvn.transform(region)); + record_for_igvn(region); + set_memory(_gvn.transform(memphi), adr_type); + + Node* res_val = _gvn.transform(phi); + // replace_in_map(obj, res_val); + return res_val; + } else { + // We know it is not null. Simple barrier is sufficient. + ShenandoahWriteBarrierNode* wb = new ShenandoahWriteBarrierNode(NULL, memory(adr_type), obj); + Node* n = _gvn.transform(wb); + if (n == wb) { + Node* proj = _gvn.transform(new ShenandoahWBMemProjNode(wb)); + set_memory(proj, adr_type); + } + // replace_in_map(obj, n); + record_for_igvn(n); + return n; } - record_for_igvn(n); - replace_in_map(obj, n); - return n; } else { return obj;
--- a/src/share/vm/opto/phaseX.cpp Fri Sep 25 16:45:39 2015 +0200 +++ b/src/share/vm/opto/phaseX.cpp Tue Sep 29 16:51:31 2015 +0200 @@ -1224,7 +1224,7 @@ Node* con = makecon(t); // Make a constant add_users_to_worklist(k); if (k->Opcode() == Op_ShenandoahWriteBarrier) { - con = k->as_ShenandoahBarrier()->kill_mem_proj(this, con); + assert(con->is_top(), "can only replace barrier with top"); } subsume_node(k, con); // Everybody using k now uses con return con; @@ -1241,12 +1241,9 @@ // Global Value Numbering i = hash_find_insert(k); // Check for pre-existing node - if (i && (i != k) && k->Opcode() != Op_ShenandoahWriteBarrier) { + if (i && (i != k)) { // Return the pre-existing node if it isn't dead NOT_PRODUCT(set_progress();) - if (k->Opcode() == Op_ShenandoahWriteBarrier) { - i = k->as_ShenandoahBarrier()->kill_mem_proj(this, i); - } add_users_to_worklist(k); subsume_node(k, i); // Everybody using k now uses i return i;
--- a/src/share/vm/opto/phaseX.hpp Fri Sep 25 16:45:39 2015 +0200 +++ b/src/share/vm/opto/phaseX.hpp Tue Sep 29 16:51:31 2015 +0200 @@ -190,6 +190,8 @@ // _nodes is used in varying ways by subclasses, which define local accessors public: + virtual PhaseIterGVN *is_IterGVN() { return 0; } + // Get a previously recorded type for the node n. // This type must already have been recorded. // If you want the type of a very new (untransformed) node,
--- a/src/share/vm/opto/shenandoahSupport.cpp Fri Sep 25 16:45:39 2015 +0200 +++ b/src/share/vm/opto/shenandoahSupport.cpp Tue Sep 29 16:51:31 2015 +0200 @@ -12,69 +12,21 @@ } } -Node* ShenandoahBarrierNode::kill_mem_proj(PhaseTransform* phase, Node* n) { - Node* mem_proj = find_out_with(Op_ShenandoahWBMemProj); - if (mem_proj != NULL) { - Node* in_mem = in(Memory); - for (DUIterator j = mem_proj->outs(); mem_proj->has_out(j); j++) { - Node* o = mem_proj->out(j); - phase->igvn_rehash_node_delayed(o); - o->replace_edge(mem_proj, in_mem); - --j; - } - - phase->igvn_rehash_node_delayed(mem_proj); - mem_proj->set_req(0, Compile::current()->top()); - } - assert(! has_out_with(Op_ShenandoahWBMemProj), "only one memory projection"); - // tty->print("replace: "); dump(); - // tty->print("with: "); n->dump(); -#ifdef ASSERT - if (Opcode() == Op_ShenandoahWriteBarrier) { - // tty->print("killed mem-proj for: "); dump(); - if (_idx == 7140) { - // tty->print_cr("break here"); - } - } - if (n->is_ShenandoahBarrier()) { - // assert(n->as_ShenandoahBarrier()->num_mem_projs() <= 1, "0 or 1 memory proj"); - n->as_ShenandoahBarrier()->check_invariants(); - } -#endif - return n; +bool ShenandoahBarrierNode::needs_barrier(PhaseTransform* phase, Node* orig, Node* n, Node* rb_mem) { + Unique_Node_List visited; + return needs_barrier_impl(phase, orig, n, rb_mem, visited); } -bool ShenandoahBarrierNode::phi_needs_barrier(PhaseTransform* phase, Node* phi, Node* rb_mem, GrowableArray<Node*>* phistack) { - assert(phi->is_Phi(), "expect phi"); - if (phistack->contains(phi)) { - // If we came back to the same phi, then it's a loop in which we don't need a barrier. - // Unless we need on another path. - return false; +bool ShenandoahBarrierNode::needs_barrier_impl(PhaseTransform* phase, Node* orig, Node* n, Node* rb_mem, Unique_Node_List &visited) { + + if (visited.member(n)) { + return false; // Been there. } - bool need_barrier = false; - phistack->push(phi); - for (uint i = 1; i < phi->req() && ! need_barrier; i++) { - Node* input = phi->in(i); - if (input == NULL) { - need_barrier = true; // Phi not complete yet? - } else if (needs_barrier_impl(phase, input, rb_mem, phistack)) { - need_barrier = true; - } - } - phistack->pop(); - return need_barrier; -} + visited.push(n); -bool ShenandoahBarrierNode::needs_barrier(PhaseTransform* phase, Node* n, Node* rb_mem) { - Arena* a = phase->arena(); - GrowableArray<Node*>* phistack = new (a) GrowableArray<Node*>(a, 4, 0, NULL); - return needs_barrier_impl(phase, n, rb_mem, phistack); -} - -bool ShenandoahBarrierNode::needs_barrier_impl(PhaseTransform* phase, Node* n, Node* rb_mem, GrowableArray<Node*>* phistack) { if (n->is_Allocate()) { // tty->print_cr("killed barrier for newly allocated object"); - return false;; + return false; } if (n->is_CallJava()) { @@ -92,20 +44,29 @@ } if (n->is_CheckCastPP() || n->is_ConstraintCast()) { - return needs_barrier_impl(phase, n->in(1), rb_mem, phistack); + return needs_barrier_impl(phase, orig, n->in(1), rb_mem, visited); } if (n->is_Parm()) { return true; } if (n->is_Proj()) { - return needs_barrier_impl(phase, n->in(0), rb_mem, phistack); + return needs_barrier_impl(phase, orig, n->in(0), rb_mem, visited); } if (n->is_Phi()) { - return phi_needs_barrier(phase, n, rb_mem, phistack); + bool need_barrier = false; + for (uint i = 1; i < n->req() && ! need_barrier; i++) { + Node* input = n->in(i); + if (input == NULL) { + need_barrier = true; // Phi not complete yet? + } else if (needs_barrier_impl(phase, orig, input, rb_mem, visited)) { + need_barrier = true; + } + } + return need_barrier; } if (n->is_CMove()) { - return needs_barrier_impl(phase, n->in(CMoveNode::IfFalse), rb_mem, phistack) || - needs_barrier_impl(phase, n->in(CMoveNode::IfTrue ), rb_mem, phistack); + return needs_barrier_impl(phase, orig, n->in(CMoveNode::IfFalse), rb_mem, visited) || + needs_barrier_impl(phase, orig, n->in(CMoveNode::IfTrue ), rb_mem, visited); } if (n->Opcode() == Op_CreateEx) { return true; @@ -167,17 +128,33 @@ Node* ShenandoahReadBarrierNode::Ideal(PhaseGVN *phase, bool can_reshape) { - if (true || ! can_reshape) { + if (! can_reshape) { return NULL; } + // if (true) return NULL; + + if (in(Memory) == phase->C->immutable_memory()) return NULL; + + // If memory input is a MergeMem, take the appropriate slice out of it. + Node* mem_in = in(Memory); + if (mem_in->isa_MergeMem()) { + const TypePtr* adr_type = bottom_type()->is_ptr()->add_offset(-8); + uint alias_idx = phase->C->get_alias_index(adr_type); + mem_in = mem_in->as_MergeMem()->memory_at(alias_idx); + set_req(Memory, mem_in); + return this; + } + Node* input = in(Memory); if (input->Opcode() == Op_ShenandoahWBMemProj) { input = input->in(0); + if (input->is_top()) return NULL; // Dead path. assert(input->Opcode() == Op_ShenandoahWriteBarrier, "expect write barrier"); const Type* in_type = phase->type(input); const Type* this_type = phase->type(this); if (is_independent(in_type, this_type)) { + phase->igvn_rehash_node_delayed(input); set_req(Memory, input->in(Memory)); return this; } @@ -185,45 +162,59 @@ return NULL; } -uint ShenandoahWriteBarrierNode::count_rb_users(Node* n, GrowableArray<Node*>* phistack) { - uint count = 0; - for (DUIterator_Fast jmax, j = n->fast_outs(jmax); j < jmax; j++) { +bool ShenandoahBarrierNode::has_barrier_users(Node* n, Unique_Node_List &visited) { + if (visited.member(n)) { + return false; + } + visited.push(n); + + bool has_users = false; + for (DUIterator_Fast jmax, j = n->fast_outs(jmax); j < jmax && ! has_users; j++) { Node* o = n->fast_out(j); if (o->Opcode() == Op_ShenandoahReadBarrier || o->Opcode() == Op_ShenandoahWriteBarrier) { // tty->print("counting barrier"); o->dump(); - count++; + has_users = true; } else if (o->isa_Phi()) { - if (! phistack->contains(o)) { - phistack->push(o); - count += count_rb_users(o, phistack); - phistack->pop(); - } + has_users = has_barrier_users(o, visited); + } else if (o->Opcode() == Op_MergeMem) { + // Not a user. ? } else { - // tty->print("not counting: "); o->dump(); + // tty->print_cr("unknown user"); o->dump(); + ShouldNotReachHere(); } } - return count; + return has_users; } Node* ShenandoahWriteBarrierNode::Ideal(PhaseGVN *phase, bool can_reshape) { - if (true || ! can_reshape) return NULL; + if (! can_reshape) return NULL; if (in(Memory) == phase->C->immutable_memory()) return NULL; + Node* mem_in = in(Memory); + if (mem_in->isa_MergeMem()) { + const TypePtr* adr_type = bottom_type()->is_ptr()->add_offset(-8); + uint alias_idx = phase->C->get_alias_index(adr_type); + mem_in = mem_in->as_MergeMem()->memory_at(alias_idx); + set_req(Memory, mem_in); + return this; + } + Node* mem_proj = find_out_with(Op_ShenandoahWBMemProj); if (mem_proj == NULL) { - // tty->print_cr("no mem proj: kill input mem"); + // tty->print_cr("no mem proj: kill input mem"); dump(); set_req(Memory, phase->C->immutable_memory()); return this; } - Arena* a = phase->arena(); - GrowableArray<Node*>* phistack = new (a) GrowableArray<Node*>(a, 4, 0, NULL); - uint num_users = count_rb_users(mem_proj, phistack); - if (num_users == 0) { - // tty->print_cr("no users of mem projection. kill input mem"); + if (true) return NULL; + + Unique_Node_List visited; + if (! has_barrier_users(mem_proj, visited)) { + // tty->print_cr("no users of mem projection. kill input mem"); dump(); + phase->igvn_rehash_node_delayed(in(Memory)); set_req(Memory, phase->C->immutable_memory()); // tty->print_cr("reshaped wb: "); @@ -233,35 +224,137 @@ // tty->print_cr("leave mem proj alone"); return NULL; } - -Node* ShenandoahBarrierNode::Identity(PhaseTransform* phase) { +/* +bool ShenandoahBarrierNode::dominates_control_impl(PhaseTransform* phase, + Node* c1, + Node* c2, + Node* current, + Unique_Node_List & visited) { + if (current == NULL) { + return true; + } else if (visited.member(current)) { + return true; + } + visited.push(current); -#ifdef ASSERT - // check_invariants(); -#endif - - if (Opcode() == Op_ShenandoahWriteBarrier) return this; + current->dump(); + ShouldNotReachHere(); +} +*/ - Node* n = in(ValueIn); - Node* rb_mem = Opcode() == Op_ShenandoahReadBarrier ? in(Memory) : NULL; - if (! needs_barrier(phase, n, rb_mem)) { - if (Opcode() == Op_ShenandoahWriteBarrier) { - if (n->Opcode() == Op_ShenandoahWriteBarrier) { - return n; - } else { +bool ShenandoahBarrierNode::dominates_control(PhaseTransform* phase, + Node* c1, + Node* c2) { + if (c1 == c2) { + return true; + } + if (c1 == NULL) { + return true; + } #ifdef ASSERT - tty->print("could not elide wb: "); dump(); - tty->print("with..............: "); n->dump(); + tty->print("c1: "); c1->dump(2); + tty->print("c2: "); c2->dump(2); #endif - return this; - } - } else { - return n; - } + ShouldNotReachHere(); + return false; +} + +bool ShenandoahBarrierNode::dominates_memory_impl(PhaseTransform* phase, + Node* b1, + Node* b2, + Node* current, + Unique_Node_List &visited) { + /* + tty->print_cr("phistack:"); + for (int x = 0; x < phistack->length(); x++) { + tty->print("-->"); + phistack->at(x)->dump(); + } + */ + if (current == NULL) { + return false; + } else if (visited.member(current)) { + // We have already seen it. + return true; } - if (Opcode() == Op_ShenandoahWriteBarrier) return this; + visited.push(current); + if (current == b1) { + // tty->print_cr("current == b1: "); current->dump(); + return true; + } else if (current == b2) { + // tty->print_cr("current == b2: "); current->dump(); + return false; + } else if (current == phase->C->immutable_memory()) { + // tty->print_cr("current == immutable_memory: "); current->dump(); + return false; + } else if (current->isa_Phi()) { + // tty->print_cr("current == phi: "); current->dump(); + bool dominates = true; + for (uint i = 1; i < current->req() && dominates == true; i++) { + Node* in = current->in(i); + dominates = dominates && dominates_memory_impl(phase, b1, b2, in, visited); + } + return dominates; + } else if (current->Opcode() == Op_ShenandoahWriteBarrier) { + // tty->print_cr("current == wb: "); current->dump(); + // Follow through memory input. + Node* in = current->in(Memory); + return dominates_memory_impl(phase, b1, b2, in, visited); + } else if (current->Opcode() == Op_ShenandoahWBMemProj) { + // tty->print_cr("current == wb-memproj: "); current->dump(); + // Follow through memory input. + Node* in = current->in(0); + return dominates_memory_impl(phase, b1, b2, in, visited); + } else if (current->is_top()) { + return false; // Dead path + } else if (current->is_Proj()) { + // tty->print_cr("current == proj: "); current->dump(); + return dominates_memory_impl(phase, b1, b2, current->in(0), visited); + } else if (current->is_Call()) { + // tty->print_cr("current == call: "); current->dump(); + return dominates_memory_impl(phase, b1, b2, current->in(TypeFunc::Memory), visited); + } else if (current->is_MemBar()) { + // tty->print_cr("current == membar: "); current->dump(); + return dominates_memory_impl(phase, b1, b2, current->in(TypeFunc::Memory), visited); + } else if (current->is_MergeMem()) { + // tty->print_cr("current == mergemem: "); current->dump(); + const TypePtr* adr_type = phase->type(b2)->is_ptr()->add_offset(-8); + uint alias_idx = phase->C->get_alias_index(adr_type); + Node* mem_in = current->as_MergeMem()->memory_at(alias_idx); + return dominates_memory_impl(phase, b1, b2, current->in(TypeFunc::Memory), visited); + } else { + // tty->print_cr("what else can we see here:"); +#ifdef ASSERT + current->dump(); +#endif + ShouldNotReachHere(); + return false; + } +} + +/** + * Determines if b1 dominates b2 through memory inputs. It returns true if: + * - b1 can be reached by following each branch in b2's memory input (through phis, etc) + * - or we get back to b2 (i.e. through a loop) without seeing b1 + * In all other cases, (in particular, if we reach immutable_memory without having seen b1) + * we return false. + */ +bool ShenandoahBarrierNode::dominates_memory(PhaseTransform* phase, Node* b1, Node* b2) { + Unique_Node_List visited; + return dominates_memory_impl(phase, b1->in(Memory), b2, b2->in(Memory), visited); +} + +Node* ShenandoahBarrierNode::Identity_impl(PhaseTransform* phase) { + Node* n = in(ValueIn); + + Node* rb_mem = Opcode() == Op_ShenandoahReadBarrier ? in(Memory) : NULL; + if (! needs_barrier(phase, this, n, rb_mem)) { + return n; + } + + // tty->print_cr("find sibling for: "); dump(2); // Try to find a write barrier sibling with identical inputs that we can fold into. for (DUIterator i = n->outs(); n->has_out(i); i++) { Node* sibling = n->out(i); @@ -276,58 +369,52 @@ if (sibling->Opcode() != Op_ShenandoahWriteBarrier) { continue; } + /* if (sibling->outcnt() == 0) { // Some dead node. continue; } -#ifdef ASSERT - sibling->as_ShenandoahBarrier()->check_invariants(); -#endif - // Match any free-floating write barrier. - if (sibling->Opcode() == Op_ShenandoahWriteBarrier && - sibling->in(Control) == NULL && - sibling->in(Memory) == Compile::current()->immutable_memory() && - sibling->in(ValueIn) == in(ValueIn)) { - return kill_mem_proj(phase, sibling); - } + */ + assert(sibling->in(ValueIn) == in(ValueIn), "sanity"); + assert(sibling->Opcode() == Op_ShenandoahWriteBarrier, "sanity"); + // tty->print_cr("candidate: "); sibling->dump(); + + if (dominates_control(phase, sibling->in(Control), in(Control)) && + dominates_memory(phase, sibling, this)) { - // Identical barriers. Match both read&write to write barriers. Read-only matches in - // ShenandoahReadBarrier::Identity. - if (sibling->Opcode() == Op_ShenandoahWriteBarrier && - sibling->in(Control) == in(Control) && - sibling->in(Memory) == in(Memory) && - sibling->in(ValueIn) == in(ValueIn)) { - return kill_mem_proj(phase, sibling); + /* + tty->print_cr("matched barrier:"); + sibling->dump(); + tty->print_cr("for: "); + dump(); + */ + return sibling; } - if (sibling->Opcode() == Op_ShenandoahWriteBarrier) { - if (sibling->in(ValueIn) == in(ValueIn)) { - // Hot candidate. Check control and memory. - if (sibling->in(Control) == in(Control)) { - // This can only work if our memory feeds from the write barrier we want - // to fold into. - Node* in_mem = in(Memory); - if (in_mem->Opcode() == Op_ShenandoahWBMemProj) { - if (in_mem->in(0) == sibling) { - // Gotcha! - // tty->print("found sibling: "); - // sibling->dump(); - // tty->print("to replace this node: "); - // dump(); - return kill_mem_proj(phase, sibling); - } - } - } - /* - tty->print_cr("couldn't match candidate:"); - sibling->dump(2); - tty->print_cr("to replace this:"); - dump(2); - */ - } + /* + tty->print_cr("couldn't match candidate:"); + sibling->dump(2); + */ + } + /* + tty->print_cr("couldn't match barrier to any:"); + dump(); + */ + return this; +} + +Node* ShenandoahBarrierNode::Identity(PhaseTransform* phase) { + + Node* replacement = Identity_impl(phase); + if (replacement != this) { + // If we have a memory projection, we first need to make it go away. + Node* mem_proj = find_out_with(Op_ShenandoahWBMemProj); + if (mem_proj != NULL) { + phase->igvn_rehash_node_delayed(mem_proj); + return this; } } - return this; + return replacement; } Node* ShenandoahReadBarrierNode::Identity(PhaseTransform* phase) { @@ -376,7 +463,7 @@ Node* input = in(ValueIn); const Type* type = phase->type(input); - return type->remove_speculative(); + return type; } #ifdef ASSERT @@ -402,3 +489,32 @@ // } } #endif + +Node* ShenandoahWBMemProjNode::Identity(PhaseTransform* phase) { + + Node* wb = in(0); + if (wb->is_top()) return phase->C->top(); // Dead path. + + assert(wb->Opcode() == Op_ShenandoahWriteBarrier, "expect write barrier"); + if (wb->as_ShenandoahBarrier()->Identity_impl(phase) != wb) { + // If the parent write barrier would go away, make this mem proj go away first. + // Poke parent to give it a chance to go away too. + phase->igvn_rehash_node_delayed(wb); + return wb->in(ShenandoahBarrierNode::Memory); + } + + // We can't do the below unless the graph is fully constructed. + if (! phase->is_IterGVN()) { + return this; + } + + // If the mem projection has no barrier users, it's not needed anymore. + Unique_Node_List visited; + if (! ShenandoahWriteBarrierNode::has_barrier_users(this, visited)) { + // tty->print_cr("mem proj has no users. kill"); dump(); + phase->igvn_rehash_node_delayed(wb); + return wb->in(ShenandoahBarrierNode::Memory); + } + + return this; +}
--- a/src/share/vm/opto/shenandoahSupport.hpp Fri Sep 25 16:45:39 2015 +0200 +++ b/src/share/vm/opto/shenandoahSupport.hpp Tue Sep 29 16:51:31 2015 +0200 @@ -13,8 +13,6 @@ class ShenandoahBarrierNode : public TypeNode { public: - Node* kill_mem_proj(PhaseTransform* phase, Node* n); - public: enum { Control, Memory, @@ -48,6 +46,8 @@ virtual uint size_of() const { return sizeof(*this); } virtual Node* Identity(PhaseTransform* phase); + Node* Identity_impl(PhaseTransform* phase); + virtual const Type* Value(PhaseTransform* phase) const; virtual bool depends_only_on_test() const { return true; @@ -57,11 +57,17 @@ uint num_mem_projs(); #endif - static bool needs_barrier(PhaseTransform* phase, Node* n, Node* rb_mem); + static bool needs_barrier(PhaseTransform* phase, Node* orig, Node* n, Node* rb_mem); + + static bool has_barrier_users(Node* n, Unique_Node_List &visited); private: - static bool phi_needs_barrier(PhaseTransform* phase, Node* phi, Node* rb_mem, GrowableArray<Node*>* phistack); - static bool needs_barrier_impl(PhaseTransform* phase, Node* n, Node* rb_mem, GrowableArray<Node*>* phistack); + static bool needs_barrier_impl(PhaseTransform* phase, Node* orig, Node* n, Node* rb_mem, Unique_Node_List &visited); + + + bool dominates_control(PhaseTransform* phase, Node* c1, Node* c2); + bool dominates_memory(PhaseTransform* phase, Node* b1, Node* b2); + bool dominates_memory_impl(PhaseTransform* phase, Node* b1, Node* b2, Node* current, Unique_Node_List &visisted); }; class ShenandoahReadBarrierNode : public ShenandoahBarrierNode { @@ -73,6 +79,7 @@ virtual Node *Ideal(PhaseGVN *phase, bool can_reshape); virtual Node* Identity(PhaseTransform* phase); virtual int Opcode() const; + private: bool is_independent(const Type* in_type, const Type* this_type) const; @@ -92,8 +99,6 @@ // if (i == MemNode::Memory) { assert(n == Compiler::current()->immutable_memory(), "set only immutable mem on wb"); } // Node::set_req(i, n); // } -private: - static uint count_rb_users(Node* n, GrowableArray<Node*>* phistack); }; class ShenandoahWBMemProjNode : public ProjNode { @@ -105,6 +110,8 @@ in(0)->as_ShenandoahBarrier()->check_invariants(); #endif } + virtual Node* Identity(PhaseTransform* phase); + virtual int Opcode() const; virtual bool is_CFG() const { return false; } virtual const Type *bottom_type() const {return Type::MEMORY;}