# HG changeset patch # Parent 1791eaa73e810a987ddd5fe110c1fd39325e3aa6 diff -r 1791eaa73e81 src/hotspot/share/gc/shenandoah/c2/shenandoahSupport.cpp --- a/src/hotspot/share/gc/shenandoah/c2/shenandoahSupport.cpp Tue Jun 04 12:50:15 2019 -0700 +++ b/src/hotspot/share/gc/shenandoah/c2/shenandoahSupport.cpp Wed Jun 05 13:35:20 2019 +0200 @@ -934,6 +934,33 @@ inner->clear_strip_mined(); } +Node* ShenandoahBarrierC2Support::gen_heapstable_test(PhaseIdealLoop* phase, Node*& ctrl, Node*& raw_mem, Node* value) { + IdealLoopTree* loop = phase->get_loop(ctrl); + enum { _heap_stable = 1, _heap_unstable, PATH_LIMIT }; + Node* region = new RegionNode(PATH_LIMIT); + Node* val_phi = new PhiNode(region, value->bottom_type()->is_oopptr()); + Node* raw_mem_phi = PhiNode::make(region, raw_mem, Type::MEMORY, TypeRawPtr::BOTTOM); + + Node* heap_stable_ctrl; + test_heap_stable(ctrl, raw_mem, heap_stable_ctrl, phase); + IfNode* heap_stable_iff = heap_stable_ctrl->in(0)->as_If(); + + region->init_req(_heap_stable, heap_stable_ctrl); + val_phi->init_req(_heap_stable, value); + raw_mem_phi->init_req(_heap_stable, raw_mem); + + Node* new_value = gen_null_test(phase, ctrl, raw_mem, value); + region->init_req(_heap_unstable, ctrl); + val_phi->init_req(_heap_unstable, new_value); + raw_mem_phi->init_req(_heap_unstable, raw_mem); + phase->register_control(region, loop, heap_stable_iff); + phase->register_new_node(val_phi, region); + phase->register_new_node(raw_mem_phi, region); + ctrl = region; + raw_mem = raw_mem_phi; + return val_phi; +} + void ShenandoahBarrierC2Support::test_heap_stable(Node*& ctrl, Node* raw_mem, Node*& heap_stable_ctrl, PhaseIdealLoop* phase) { IdealLoopTree* loop = phase->get_loop(ctrl); @@ -966,6 +993,37 @@ assert(is_heap_stable_test(heap_stable_iff), "Should match the shape"); } +Node* ShenandoahBarrierC2Support::gen_null_test(PhaseIdealLoop* phase, Node*& ctrl, Node*& raw_mem, Node* value) { + Node* null_ctrl = NULL; + test_null(ctrl, value, null_ctrl, phase); + if (null_ctrl == NULL) { + return gen_cset_test(phase, ctrl, raw_mem, value); + } + + IdealLoopTree* loop = phase->get_loop(ctrl); + enum { _null = 1, _not_null, PATH_LIMIT }; + Node* region = new RegionNode(PATH_LIMIT); + Node* val_phi = new PhiNode(region, value->bottom_type()->is_oopptr()); + Node* raw_mem_phi = PhiNode::make(region, raw_mem, Type::MEMORY, TypeRawPtr::BOTTOM); + + region->init_req(_null, null_ctrl); + val_phi->init_req(_null, value); + raw_mem_phi->init_req(_null, raw_mem); + + Node* new_value = gen_cset_test(phase, ctrl, raw_mem, value); + region->init_req(_not_null, ctrl); + val_phi->init_req(_not_null, new_value); + raw_mem_phi->init_req(_not_null, raw_mem); + + IfNode* null_iff = null_ctrl->in(0)->as_If(); + phase->register_control(region, loop, null_iff); + phase->register_new_node(val_phi, region); + phase->register_new_node(raw_mem_phi, region); + ctrl = region; + raw_mem = raw_mem_phi; + return val_phi; +} + void ShenandoahBarrierC2Support::test_null(Node*& ctrl, Node* val, Node*& null_ctrl, PhaseIdealLoop* phase) { const Type* val_t = phase->igvn().type(val); if (val_t->meet(TypePtr::NULL_PTR) == val_t) { @@ -983,6 +1041,111 @@ } } +Node* ShenandoahBarrierC2Support::gen_cset_test(PhaseIdealLoop* phase, Node*& ctrl, Node*& raw_mem, Node* value) { + IdealLoopTree *loop = phase->get_loop(ctrl); + enum { _not_cset = 1, _cset, PATH_LIMIT }; + Node* region = new RegionNode(PATH_LIMIT); + Node* val_phi = new PhiNode(region, value->bottom_type()->is_oopptr()); + Node* raw_mem_phi = PhiNode::make(region, raw_mem, Type::MEMORY, TypeRawPtr::BOTTOM); + + Node* raw_rbtrue = new CastP2XNode(ctrl, value); + phase->register_new_node(raw_rbtrue, ctrl); + Node* cset_offset = new URShiftXNode(raw_rbtrue, phase->igvn().intcon(ShenandoahHeapRegion::region_size_bytes_shift_jint())); + phase->register_new_node(cset_offset, ctrl); + Node* in_cset_fast_test_base_addr = phase->igvn().makecon(TypeRawPtr::make(ShenandoahHeap::in_cset_fast_test_addr())); + phase->set_ctrl(in_cset_fast_test_base_addr, phase->C->root()); + Node* in_cset_fast_test_adr = new AddPNode(phase->C->top(), in_cset_fast_test_base_addr, cset_offset); + phase->register_new_node(in_cset_fast_test_adr, ctrl); + uint in_cset_fast_test_idx = Compile::AliasIdxRaw; + const TypePtr* in_cset_fast_test_adr_type = NULL; // debug-mode-only argument + debug_only(in_cset_fast_test_adr_type = phase->C->get_adr_type(in_cset_fast_test_idx)); + Node* in_cset_fast_test_load = new LoadBNode(ctrl, raw_mem, in_cset_fast_test_adr, in_cset_fast_test_adr_type, TypeInt::BYTE, MemNode::unordered); + phase->register_new_node(in_cset_fast_test_load, ctrl); + Node* in_cset_fast_test_cmp = new CmpINode(in_cset_fast_test_load, phase->igvn().zerocon(T_INT)); + phase->register_new_node(in_cset_fast_test_cmp, ctrl); + Node* in_cset_fast_test_test = new BoolNode(in_cset_fast_test_cmp, BoolTest::eq); + phase->register_new_node(in_cset_fast_test_test, ctrl); + IfNode* in_cset_fast_test_iff = new IfNode(ctrl, in_cset_fast_test_test, PROB_UNLIKELY(0.999), COUNT_UNKNOWN); + phase->register_control(in_cset_fast_test_iff, loop, ctrl); + + Node* not_cset_ctrl = new IfTrueNode(in_cset_fast_test_iff); + phase->register_control(not_cset_ctrl, loop, in_cset_fast_test_iff); + + ctrl = new IfFalseNode(in_cset_fast_test_iff); + phase->register_control(ctrl, loop, in_cset_fast_test_iff); + + region->init_req(_not_cset, not_cset_ctrl); + val_phi->init_req(_not_cset, value); + raw_mem_phi->init_req(_not_cset, raw_mem); + + Node* new_value = gen_forwarded_test(phase, ctrl, raw_mem, value); + region->init_req(_cset, ctrl); + val_phi->init_req(_cset, new_value); + raw_mem_phi->init_req(_cset, raw_mem); + phase->register_control(region, loop, in_cset_fast_test_iff); + phase->register_new_node(val_phi, region); + phase->register_new_node(raw_mem_phi, region); + ctrl = region; + raw_mem = raw_mem_phi; + return val_phi; +} + +Node* ShenandoahBarrierC2Support::gen_forwarded_test(PhaseIdealLoop* phase, Node*& ctrl, Node*& raw_mem, Node* value) { + IdealLoopTree *loop = phase->get_loop(ctrl); + enum { _fwded = 1, _not_fwdwd, PATH_LIMIT }; + Node* region = new RegionNode(PATH_LIMIT); + Node* val_phi = new PhiNode(region, value->bottom_type()->is_oopptr()); + Node* raw_mem_phi = PhiNode::make(region, raw_mem, Type::MEMORY, TypeRawPtr::BOTTOM); + + Node* addr = new AddPNode(value, value, phase->igvn().MakeConX(oopDesc::mark_offset_in_bytes())); + phase->register_new_node(addr, ctrl); + assert(value->bottom_type()->isa_oopptr(), "what else?"); + Node* markword = new LoadXNode(ctrl, raw_mem, addr, TypeRawPtr::BOTTOM, TypeX_X, MemNode::unordered); + phase->register_new_node(markword, ctrl); + + // Test if object is forwarded. This is the case if lowest two bits are set. + Node* masked = new AndXNode(markword, phase->igvn().MakeConX(markOopDesc::lock_mask_in_place)); + phase->register_new_node(masked, ctrl); + Node* cmp = new CmpXNode(masked, phase->igvn().MakeConX(markOopDesc::marked_value)); + phase->register_new_node(cmp, ctrl); + + // Only branch to LRB stub if object is not forwarded; otherwise reply with fwd ptr + Node* bol = new BoolNode(cmp, BoolTest::eq); // Equals 3 means it's forwarded + phase->register_new_node(bol, ctrl); + + IfNode* iff = new IfNode(ctrl, bol, PROB_LIKELY(0.999), COUNT_UNKNOWN); + phase->register_control(iff, loop, ctrl); + Node* if_fwd = new IfTrueNode(iff); + phase->register_control(if_fwd, loop, iff); + Node* if_not_fwd = new IfFalseNode(iff); + phase->register_control(if_not_fwd, loop, iff); + + // Decode forward pointer: since we already have the lowest bits, we can just subtract them + // from the mark word without the need for large immediate mask. + Node* masked2 = new SubXNode(markword, masked); + phase->register_new_node(masked2, if_fwd); + Node* fwdraw = new CastX2PNode(masked2); + fwdraw->init_req(0, if_fwd); + phase->register_new_node(fwdraw, if_fwd); + Node* fwd = new CheckCastPPNode(NULL, fwdraw, value->bottom_type()); + phase->register_new_node(fwd, if_fwd); + + region->init_req(_fwded, if_fwd); + val_phi->init_req(_fwded, fwd); + raw_mem_phi->init_req(_fwded, raw_mem); + + Node* new_value = call_lrb_stub(phase, ctrl, raw_mem, value); + region->init_req(_not_fwdwd, ctrl); + val_phi->init_req(_not_fwdwd, new_value); + raw_mem_phi->init_req(_not_fwdwd, raw_mem); + phase->register_control(region, loop, iff); + phase->register_new_node(val_phi, region); + phase->register_new_node(raw_mem_phi, region); + ctrl = region; + raw_mem = raw_mem_phi; + return val_phi; +} + Node* ShenandoahBarrierC2Support::clone_null_check(Node*& c, Node* val, Node* unc_ctrl, PhaseIdealLoop* phase) { IdealLoopTree *loop = phase->get_loop(c); Node* iff = unc_ctrl->in(0); @@ -1053,38 +1216,9 @@ assert(nb == 1, "only use expected"); } -void ShenandoahBarrierC2Support::in_cset_fast_test(Node*& ctrl, Node*& not_cset_ctrl, Node* val, Node* raw_mem, PhaseIdealLoop* phase) { - IdealLoopTree *loop = phase->get_loop(ctrl); - Node* raw_rbtrue = new CastP2XNode(ctrl, val); - phase->register_new_node(raw_rbtrue, ctrl); - Node* cset_offset = new URShiftXNode(raw_rbtrue, phase->igvn().intcon(ShenandoahHeapRegion::region_size_bytes_shift_jint())); - phase->register_new_node(cset_offset, ctrl); - Node* in_cset_fast_test_base_addr = phase->igvn().makecon(TypeRawPtr::make(ShenandoahHeap::in_cset_fast_test_addr())); - phase->set_ctrl(in_cset_fast_test_base_addr, phase->C->root()); - Node* in_cset_fast_test_adr = new AddPNode(phase->C->top(), in_cset_fast_test_base_addr, cset_offset); - phase->register_new_node(in_cset_fast_test_adr, ctrl); - uint in_cset_fast_test_idx = Compile::AliasIdxRaw; - const TypePtr* in_cset_fast_test_adr_type = NULL; // debug-mode-only argument - debug_only(in_cset_fast_test_adr_type = phase->C->get_adr_type(in_cset_fast_test_idx)); - Node* in_cset_fast_test_load = new LoadBNode(ctrl, raw_mem, in_cset_fast_test_adr, in_cset_fast_test_adr_type, TypeInt::BYTE, MemNode::unordered); - phase->register_new_node(in_cset_fast_test_load, ctrl); - Node* in_cset_fast_test_cmp = new CmpINode(in_cset_fast_test_load, phase->igvn().zerocon(T_INT)); - phase->register_new_node(in_cset_fast_test_cmp, ctrl); - Node* in_cset_fast_test_test = new BoolNode(in_cset_fast_test_cmp, BoolTest::eq); - phase->register_new_node(in_cset_fast_test_test, ctrl); - IfNode* in_cset_fast_test_iff = new IfNode(ctrl, in_cset_fast_test_test, PROB_UNLIKELY(0.999), COUNT_UNKNOWN); - phase->register_control(in_cset_fast_test_iff, loop, ctrl); - - not_cset_ctrl = new IfTrueNode(in_cset_fast_test_iff); - phase->register_control(not_cset_ctrl, loop, in_cset_fast_test_iff); - - ctrl = new IfFalseNode(in_cset_fast_test_iff); - phase->register_control(ctrl, loop, in_cset_fast_test_iff); -} - -void ShenandoahBarrierC2Support::call_lrb_stub(Node*& ctrl, Node*& val, Node*& result_mem, Node* raw_mem, PhaseIdealLoop* phase) { +Node* ShenandoahBarrierC2Support::call_lrb_stub(PhaseIdealLoop* phase, Node*& ctrl, Node*& raw_mem, Node* value) { IdealLoopTree*loop = phase->get_loop(ctrl); - const TypePtr* obj_type = phase->igvn().type(val)->is_oopptr()->cast_to_nonconst(); + const TypePtr* obj_type = phase->igvn().type(value)->is_oopptr()->cast_to_nonconst(); // The slow path stub consumes and produces raw memory in addition // to the existing memory edges @@ -1099,16 +1233,17 @@ call->init_req(TypeFunc::Memory, mm); call->init_req(TypeFunc::FramePtr, phase->C->top()); call->init_req(TypeFunc::ReturnAdr, phase->C->top()); - call->init_req(TypeFunc::Parms, val); + call->init_req(TypeFunc::Parms, value); phase->register_control(call, loop, ctrl); ctrl = new ProjNode(call, TypeFunc::Control); phase->register_control(ctrl, loop, call); - result_mem = new ProjNode(call, TypeFunc::Memory); - phase->register_new_node(result_mem, call); - val = new ProjNode(call, TypeFunc::Parms); - phase->register_new_node(val, call); - val = new CheckCastPPNode(ctrl, val, obj_type); - phase->register_new_node(val, ctrl); + raw_mem = new ProjNode(call, TypeFunc::Memory); + phase->register_new_node(raw_mem, call); + Node* new_value = new ProjNode(call, TypeFunc::Parms); + phase->register_new_node(new_value, call); + new_value = new CheckCastPPNode(ctrl, new_value, obj_type); + phase->register_new_node(new_value, ctrl); + return new_value; } void ShenandoahBarrierC2Support::fix_ctrl(Node* barrier, Node* region, const MemoryGraphFixer& fixer, Unique_Node_List& uses, Unique_Node_List& uses_to_ignore, uint last, PhaseIdealLoop* phase) { @@ -1464,117 +1599,15 @@ assert(val->bottom_type()->make_oopptr(), "need oop"); assert(val->bottom_type()->make_oopptr()->const_oop() == NULL, "expect non-constant"); - enum { _heap_stable = 1, _not_cset, _fwded, _evac_path, _null_path, PATH_LIMIT }; - Node* region = new RegionNode(PATH_LIMIT); - Node* val_phi = new PhiNode(region, uncasted_val->bottom_type()->is_oopptr()); - Node* raw_mem_phi = PhiNode::make(region, raw_mem, Type::MEMORY, TypeRawPtr::BOTTOM); + Node* out_val = gen_heapstable_test(phase, ctrl, raw_mem, val); - // Stable path. - test_heap_stable(ctrl, raw_mem, heap_stable_ctrl, phase); - IfNode* heap_stable_iff = heap_stable_ctrl->in(0)->as_If(); + fix_ctrl(lrb, ctrl, fixer, uses, uses_to_ignore, last, phase); - // Heap stable case - region->init_req(_heap_stable, heap_stable_ctrl); - val_phi->init_req(_heap_stable, uncasted_val); - raw_mem_phi->init_req(_heap_stable, raw_mem); - - Node* reg2_ctrl = NULL; - // Null case - test_null(ctrl, val, null_ctrl, phase); - if (null_ctrl != NULL) { - reg2_ctrl = null_ctrl->in(0); - region->init_req(_null_path, null_ctrl); - val_phi->init_req(_null_path, uncasted_val); - raw_mem_phi->init_req(_null_path, raw_mem); - } else { - region->del_req(_null_path); - val_phi->del_req(_null_path); - raw_mem_phi->del_req(_null_path); - } - - // Test for in-cset. - // Wires !in_cset(obj) to slot 2 of region and phis - Node* not_cset_ctrl = NULL; - in_cset_fast_test(ctrl, not_cset_ctrl, uncasted_val, raw_mem, phase); - if (not_cset_ctrl != NULL) { - if (reg2_ctrl == NULL) reg2_ctrl = not_cset_ctrl->in(0); - region->init_req(_not_cset, not_cset_ctrl); - val_phi->init_req(_not_cset, uncasted_val); - raw_mem_phi->init_req(_not_cset, raw_mem); - } - - // Resolve object when orig-value is in cset. - // Make the unconditional resolve for fwdptr. - Node* new_val = uncasted_val; - if (unc_ctrl != NULL) { - // Clone the null check in this branch to allow implicit null check - new_val = clone_null_check(ctrl, val, unc_ctrl, phase); - fix_null_check(unc, unc_ctrl, ctrl->in(0)->as_If()->proj_out(0), uses, phase); - - IfNode* iff = unc_ctrl->in(0)->as_If(); - phase->igvn().replace_input_of(iff, 1, phase->igvn().intcon(1)); - } - Node* addr = new AddPNode(new_val, uncasted_val, phase->igvn().MakeConX(oopDesc::mark_offset_in_bytes())); - phase->register_new_node(addr, ctrl); - assert(new_val->bottom_type()->isa_oopptr(), "what else?"); - Node* markword = new LoadXNode(ctrl, raw_mem, addr, TypeRawPtr::BOTTOM, TypeX_X, MemNode::unordered); - phase->register_new_node(markword, ctrl); - - // Test if object is forwarded. This is the case if lowest two bits are set. - Node* masked = new AndXNode(markword, phase->igvn().MakeConX(markOopDesc::lock_mask_in_place)); - phase->register_new_node(masked, ctrl); - Node* cmp = new CmpXNode(masked, phase->igvn().MakeConX(markOopDesc::marked_value)); - phase->register_new_node(cmp, ctrl); - - // Only branch to LRB stub if object is not forwarded; otherwise reply with fwd ptr - Node* bol = new BoolNode(cmp, BoolTest::eq); // Equals 3 means it's forwarded - phase->register_new_node(bol, ctrl); - - IfNode* iff = new IfNode(ctrl, bol, PROB_LIKELY(0.999), COUNT_UNKNOWN); - phase->register_control(iff, loop, ctrl); - Node* if_fwd = new IfTrueNode(iff); - phase->register_control(if_fwd, loop, iff); - Node* if_not_fwd = new IfFalseNode(iff); - phase->register_control(if_not_fwd, loop, iff); - - // Decode forward pointer: since we already have the lowest bits, we can just subtract them - // from the mark word without the need for large immediate mask. - Node* masked2 = new SubXNode(markword, masked); - phase->register_new_node(masked2, if_fwd); - Node* fwdraw = new CastX2PNode(masked2); - fwdraw->init_req(0, if_fwd); - phase->register_new_node(fwdraw, if_fwd); - Node* fwd = new CheckCastPPNode(NULL, fwdraw, val->bottom_type()); - phase->register_new_node(fwd, if_fwd); - - // Wire up not-equal-path in slots 3. - region->init_req(_fwded, if_fwd); - val_phi->init_req(_fwded, fwd); - raw_mem_phi->init_req(_fwded, raw_mem); - - // Call lrb-stub and wire up that path in slots 4 - Node* result_mem = NULL; - ctrl = if_not_fwd; - fwd = new_val; - call_lrb_stub(ctrl, fwd, result_mem, raw_mem, phase); - region->init_req(_evac_path, ctrl); - val_phi->init_req(_evac_path, fwd); - raw_mem_phi->init_req(_evac_path, result_mem); - - phase->register_control(region, loop, heap_stable_iff); - Node* out_val = val_phi; - phase->register_new_node(val_phi, region); - phase->register_new_node(raw_mem_phi, region); - - fix_ctrl(lrb, region, fixer, uses, uses_to_ignore, last, phase); - - ctrl = orig_ctrl; - - if (unc != NULL) { + if (false && unc != NULL) { for (DUIterator_Fast imax, i = val->fast_outs(imax); i < imax; i++) { Node* u = val->fast_out(i); Node* c = phase->ctrl_or_self(u); - if (u != lrb && (c != ctrl || is_dominator_same_ctrl(c, lrb, u, phase))) { + if (u != lrb && (c != orig_ctrl || is_dominator_same_ctrl(c, lrb, u, phase))) { phase->igvn().rehash_node_delayed(u); int nb = u->replace_edge(val, out_val); --i, imax -= nb; @@ -1586,14 +1619,14 @@ } phase->igvn().replace_node(lrb, out_val); - follow_barrier_uses(out_val, ctrl, uses, phase); + follow_barrier_uses(out_val, orig_ctrl, uses, phase); for(uint next = 0; next < uses.size(); next++ ) { Node *n = uses.at(next); - assert(phase->get_ctrl(n) == ctrl, "bad control"); + assert(phase->get_ctrl(n) == orig_ctrl, "bad control"); assert(n != init_raw_mem, "should leave input raw mem above the barrier"); - phase->set_ctrl(n, region); - follow_barrier_uses(n, ctrl, uses, phase); + phase->set_ctrl(n, ctrl); + follow_barrier_uses(n, orig_ctrl, uses, phase); } // The slow path call produces memory: hook the raw memory phi @@ -1602,7 +1635,7 @@ // region and at enclosing loop heads. Use the memory state // collected in memory_nodes to fix the memory graph. Update that // memory state as we go. - fixer.fix_mem(ctrl, region, init_raw_mem, raw_mem_for_ctrl, raw_mem_phi, uses); + fixer.fix_mem(orig_ctrl, ctrl, init_raw_mem, raw_mem_for_ctrl, raw_mem, uses); } // Done expanding load-reference-barriers. assert(ShenandoahBarrierSetC2::bsc2()->state()->load_reference_barriers_count() == 0, "all load reference barrier nodes should have been replaced"); diff -r 1791eaa73e81 src/hotspot/share/gc/shenandoah/c2/shenandoahSupport.hpp --- a/src/hotspot/share/gc/shenandoah/c2/shenandoahSupport.hpp Tue Jun 04 12:50:15 2019 -0700 +++ b/src/hotspot/share/gc/shenandoah/c2/shenandoahSupport.hpp Wed Jun 05 13:35:20 2019 +0200 @@ -60,11 +60,16 @@ static void test_null(Node*& ctrl, Node* val, Node*& null_ctrl, PhaseIdealLoop* phase); static void test_heap_stable(Node*& ctrl, Node* raw_mem, Node*& heap_stable_ctrl, PhaseIdealLoop* phase); - static void call_lrb_stub(Node*& ctrl, Node*& val, Node*& result_mem, Node* raw_mem, PhaseIdealLoop* phase); static Node* clone_null_check(Node*& c, Node* val, Node* unc_ctrl, PhaseIdealLoop* phase); static void fix_null_check(Node* unc, Node* unc_ctrl, Node* new_unc_ctrl, Unique_Node_List& uses, PhaseIdealLoop* phase); - static void in_cset_fast_test(Node*& ctrl, Node*& not_cset_ctrl, Node* val, Node* raw_mem, PhaseIdealLoop* phase); + + static Node* gen_heapstable_test(PhaseIdealLoop* phase, Node*& ctrl, Node*& raw_mem, Node* value); + static Node* gen_null_test(PhaseIdealLoop* phase, Node*& ctrl, Node*& raw_mem, Node* value); + static Node* gen_cset_test(PhaseIdealLoop* phase, Node*& ctrl, Node*& raw_mem, Node* value); + static Node* gen_forwarded_test(PhaseIdealLoop* phase, Node*& ctrl, Node*& raw_mem, Node* value); + static Node* call_lrb_stub(PhaseIdealLoop* phase, Node*& ctrl, Node*& raw_mem, Node* value); + static void move_heap_stable_test_out_of_loop(IfNode* iff, PhaseIdealLoop* phase); static void merge_back_to_back_tests(Node* n, PhaseIdealLoop* phase); static bool identical_backtoback_ifs(Node *n, PhaseIdealLoop* phase);