# HG changeset patch # User jcoomes # Date 1301099960 25200 # Node ID c6580380076b7258a7c78c09e1677ee678f334d3 # Parent 006b3750a4d439947e7c626ee21bfb5f5c8b4c64# Parent 5134fa1cfe6310c7ec06ac51996459b733eddcb3 Merge diff -r 5134fa1cfe63 -r c6580380076b .hgtags --- a/.hgtags Thu Mar 24 15:47:01 2011 -0700 +++ b/.hgtags Fri Mar 25 17:39:20 2011 -0700 @@ -154,3 +154,5 @@ 0e531ab5ba04967a0e9aa6aef65e6eb3a0dcf632 jdk7-b132 a8d643a4db47c7b58e0bcb49c77b5c3610de86a8 hs21-b03 1b3a350709e4325d759bb453ff3fb6a463270488 jdk7-b133 +447e6faab4a8755d4860c2366630729dbaec111c jdk7-b134 +3c76374706ea8a77e15aec8310e831e5734f8775 hs21-b04 diff -r 5134fa1cfe63 -r c6580380076b make/hotspot_version --- a/make/hotspot_version Thu Mar 24 15:47:01 2011 -0700 +++ b/make/hotspot_version Fri Mar 25 17:39:20 2011 -0700 @@ -35,7 +35,7 @@ HS_MAJOR_VER=21 HS_MINOR_VER=0 -HS_BUILD_NUMBER=04 +HS_BUILD_NUMBER=05 JDK_MAJOR_VER=1 JDK_MINOR_VER=7 diff -r 5134fa1cfe63 -r c6580380076b src/cpu/sparc/vm/methodHandles_sparc.cpp --- a/src/cpu/sparc/vm/methodHandles_sparc.cpp Thu Mar 24 15:47:01 2011 -0700 +++ b/src/cpu/sparc/vm/methodHandles_sparc.cpp Fri Mar 25 17:39:20 2011 -0700 @@ -775,9 +775,13 @@ switch (ek) { case _adapter_opt_i2l: { - __ ldsw(arg_lsw, O2_scratch); // Load LSW - NOT_LP64(__ srlx(O2_scratch, BitsPerInt, O3_scratch)); // Move high bits to lower bits for std - __ st_long(O2_scratch, arg_msw); // Uses O2/O3 on !_LP64 +#ifdef _LP64 + __ ldsw(arg_lsw, O2_scratch); // Load LSW sign-extended +#else + __ ldsw(arg_lsw, O3_scratch); // Load LSW sign-extended + __ srlx(O3_scratch, BitsPerInt, O2_scratch); // Move MSW value to lower 32-bits for std +#endif + __ st_long(O2_scratch, arg_msw); // Uses O2/O3 on !_LP64 } break; case _adapter_opt_unboxl: diff -r 5134fa1cfe63 -r c6580380076b src/os/windows/vm/os_windows.cpp --- a/src/os/windows/vm/os_windows.cpp Thu Mar 24 15:47:01 2011 -0700 +++ b/src/os/windows/vm/os_windows.cpp Fri Mar 25 17:39:20 2011 -0700 @@ -3297,9 +3297,14 @@ "possibility of dangling Thread pointer"); OSThread* osthread = thread->osthread(); - bool interrupted; - interrupted = osthread->interrupted(); - if (clear_interrupted == true) { + bool interrupted = osthread->interrupted(); + // There is no synchronization between the setting of the interrupt + // and it being cleared here. It is critical - see 6535709 - that + // we only clear the interrupt state, and reset the interrupt event, + // if we are going to report that we were indeed interrupted - else + // an interrupt can be "lost", leading to spurious wakeups or lost wakeups + // depending on the timing + if (interrupted && clear_interrupted) { osthread->set_interrupted(false); ResetEvent(osthread->interrupt_event()); } // Otherwise leave the interrupted state alone diff -r 5134fa1cfe63 -r c6580380076b src/share/vm/opto/c2_globals.hpp --- a/src/share/vm/opto/c2_globals.hpp Thu Mar 24 15:47:01 2011 -0700 +++ b/src/share/vm/opto/c2_globals.hpp Fri Mar 25 17:39:20 2011 -0700 @@ -180,6 +180,9 @@ develop(bool, TraceLoopPredicate, false, \ "Trace generation of loop predicates") \ \ + develop(bool, TraceLoopOpts, false, \ + "Trace executed loop optimizations") \ + \ product(bool, OptimizeFill, false, \ "convert fill/copy loops into intrinsic") \ \ diff -r 5134fa1cfe63 -r c6580380076b src/share/vm/opto/graphKit.cpp --- a/src/share/vm/opto/graphKit.cpp Thu Mar 24 15:47:01 2011 -0700 +++ b/src/share/vm/opto/graphKit.cpp Fri Mar 25 17:39:20 2011 -0700 @@ -3338,6 +3338,49 @@ return NULL; } +//----------------------------- loop predicates --------------------------- + +//------------------------------add_predicate_impl---------------------------- +void GraphKit::add_predicate_impl(Deoptimization::DeoptReason reason, int nargs) { + // Too many traps seen? + if (too_many_traps(reason)) { +#ifdef ASSERT + if (TraceLoopPredicate) { + int tc = C->trap_count(reason); + tty->print("too many traps=%s tcount=%d in ", + Deoptimization::trap_reason_name(reason), tc); + method()->print(); // which method has too many predicate traps + tty->cr(); + } +#endif + // We cannot afford to take more traps here, + // do not generate predicate. + return; + } + + Node *cont = _gvn.intcon(1); + Node* opq = _gvn.transform(new (C, 2) Opaque1Node(C, cont)); + Node *bol = _gvn.transform(new (C, 2) Conv2BNode(opq)); + IfNode* iff = create_and_map_if(control(), bol, PROB_MAX, COUNT_UNKNOWN); + Node* iffalse = _gvn.transform(new (C, 1) IfFalseNode(iff)); + C->add_predicate_opaq(opq); + { + PreserveJVMState pjvms(this); + set_control(iffalse); + _sp += nargs; + uncommon_trap(reason, Deoptimization::Action_maybe_recompile); + } + Node* iftrue = _gvn.transform(new (C, 1) IfTrueNode(iff)); + set_control(iftrue); +} + +//------------------------------add_predicate--------------------------------- +void GraphKit::add_predicate(int nargs) { + if (UseLoopPredicate) { + add_predicate_impl(Deoptimization::Reason_predicate, nargs); + } +} + //----------------------------- store barriers ---------------------------- #define __ ideal. diff -r 5134fa1cfe63 -r c6580380076b src/share/vm/opto/graphKit.hpp --- a/src/share/vm/opto/graphKit.hpp Thu Mar 24 15:47:01 2011 -0700 +++ b/src/share/vm/opto/graphKit.hpp Fri Mar 25 17:39:20 2011 -0700 @@ -793,6 +793,10 @@ if (!tst->is_Con()) record_for_igvn(iff); // Range-check and Null-check removal is later return iff; } + + // Insert a loop predicate into the graph + void add_predicate(int nargs = 0); + void add_predicate_impl(Deoptimization::DeoptReason reason, int nargs); }; // Helper class to support building of control flow branches. Upon diff -r 5134fa1cfe63 -r c6580380076b src/share/vm/opto/idealKit.cpp --- a/src/share/vm/opto/idealKit.cpp Thu Mar 24 15:47:01 2011 -0700 +++ b/src/share/vm/opto/idealKit.cpp Fri Mar 25 17:39:20 2011 -0700 @@ -154,8 +154,18 @@ // // Pushes the loop top cvstate first, then the else (loop exit) cvstate // onto the stack. -void IdealKit::loop(IdealVariable& iv, Node* init, BoolTest::mask relop, Node* limit, float prob, float cnt) { +void IdealKit::loop(GraphKit* gkit, int nargs, IdealVariable& iv, Node* init, BoolTest::mask relop, Node* limit, float prob, float cnt) { assert((state() & (BlockS|LoopS|IfThenS|ElseS)), "bad state for new loop"); + + // Sync IdealKit and graphKit. + gkit->set_all_memory(this->merged_memory()); + gkit->set_control(this->ctrl()); + // Add loop predicate. + gkit->add_predicate(nargs); + // Update IdealKit memory. + this->set_all_memory(gkit->merged_memory()); + this->set_ctrl(gkit->control()); + set(iv, init); Node* head = make_label(1); bind(head); diff -r 5134fa1cfe63 -r c6580380076b src/share/vm/opto/idealKit.hpp --- a/src/share/vm/opto/idealKit.hpp Thu Mar 24 15:47:01 2011 -0700 +++ b/src/share/vm/opto/idealKit.hpp Fri Mar 25 17:39:20 2011 -0700 @@ -29,6 +29,7 @@ #include "opto/cfgnode.hpp" #include "opto/connode.hpp" #include "opto/divnode.hpp" +#include "opto/graphKit.hpp" #include "opto/mulnode.hpp" #include "opto/phaseX.hpp" #include "opto/subnode.hpp" @@ -160,7 +161,7 @@ bool push_new_state = true); void else_(); void end_if(); - void loop(IdealVariable& iv, Node* init, BoolTest::mask cmp, Node* limit, + void loop(GraphKit* gkit, int nargs, IdealVariable& iv, Node* init, BoolTest::mask cmp, Node* limit, float prob = PROB_LIKELY(0.9), float cnt = COUNT_UNKNOWN); void end_loop(); Node* make_label(int goto_ct); diff -r 5134fa1cfe63 -r c6580380076b src/share/vm/opto/library_call.cpp --- a/src/share/vm/opto/library_call.cpp Thu Mar 24 15:47:01 2011 -0700 +++ b/src/share/vm/opto/library_call.cpp Fri Mar 25 17:39:20 2011 -0700 @@ -1101,6 +1101,8 @@ float likely = PROB_LIKELY(0.9); float unlikely = PROB_UNLIKELY(0.9); + const int nargs = 2; // number of arguments to push back for uncommon trap in predicate + const int value_offset = java_lang_String::value_offset_in_bytes(); const int count_offset = java_lang_String::count_offset_in_bytes(); const int offset_offset = java_lang_String::offset_offset_in_bytes(); @@ -1138,12 +1140,12 @@ Node* return_ = __ make_label(1); __ set(rtn,__ ConI(-1)); - __ loop(i, sourceOffset, BoolTest::lt, sourceEnd); { + __ loop(this, nargs, i, sourceOffset, BoolTest::lt, sourceEnd); { Node* i2 = __ AddI(__ value(i), targetCountLess1); // pin to prohibit loading of "next iteration" value which may SEGV (rare) Node* src = load_array_element(__ ctrl(), source, i2, TypeAryPtr::CHARS); __ if_then(src, BoolTest::eq, lastChar, unlikely); { - __ loop(j, zero, BoolTest::lt, targetCountLess1); { + __ loop(this, nargs, j, zero, BoolTest::lt, targetCountLess1); { Node* tpj = __ AddI(targetOffset, __ value(j)); Node* targ = load_array_element(no_ctrl, target, tpj, target_type); Node* ipj = __ AddI(__ value(i), __ value(j)); diff -r 5134fa1cfe63 -r c6580380076b src/share/vm/opto/loopTransform.cpp --- a/src/share/vm/opto/loopTransform.cpp Thu Mar 24 15:47:01 2011 -0700 +++ b/src/share/vm/opto/loopTransform.cpp Fri Mar 25 17:39:20 2011 -0700 @@ -205,6 +205,8 @@ } phase->register_new_node(addx, phase->get_ctrl(x)); phase->_igvn.replace_node(n1, addx); + assert(phase->get_loop(phase->get_ctrl(n1)) == this, ""); + _body.yank(n1); return addx; } @@ -307,15 +309,21 @@ // iterations adjusted. Therefore, we need to declare this loop as // no longer a 'main' loop; it will need new pre and post loops before // we can do further RCE. +#ifndef PRODUCT + if (TraceLoopOpts) { + tty->print("Peel "); + loop->dump_head(); + } +#endif Node *h = loop->_head; - if( h->is_CountedLoop() ) { + if (h->is_CountedLoop()) { CountedLoopNode *cl = h->as_CountedLoop(); assert(cl->trip_count() > 0, "peeling a fully unrolled loop"); cl->set_trip_count(cl->trip_count() - 1); - if( cl->is_main_loop() ) { + if (cl->is_main_loop()) { cl->set_normal_loop(); #ifndef PRODUCT - if( PrintOpto && VerifyLoopOptimizations ) { + if (PrintOpto && VerifyLoopOptimizations) { tty->print("Peeling a 'main' loop; resetting to 'normal' "); loop->dump_head(); } @@ -645,6 +653,15 @@ // alignment. Useful to unroll loops that do no array accesses. void PhaseIdealLoop::insert_pre_post_loops( IdealLoopTree *loop, Node_List &old_new, bool peel_only ) { +#ifndef PRODUCT + if (TraceLoopOpts) { + if (peel_only) + tty->print("PeelMainPost "); + else + tty->print("PreMainPost "); + loop->dump_head(); + } +#endif C->set_major_progress(); // Find common pieces of the loop being guarded with pre & post loops @@ -897,16 +914,19 @@ //------------------------------do_unroll-------------------------------------- // Unroll the loop body one step - make each trip do 2 iterations. void PhaseIdealLoop::do_unroll( IdealLoopTree *loop, Node_List &old_new, bool adjust_min_trip ) { - assert( LoopUnrollLimit, "" ); + assert(LoopUnrollLimit, ""); + CountedLoopNode *loop_head = loop->_head->as_CountedLoop(); + CountedLoopEndNode *loop_end = loop_head->loopexit(); + assert(loop_end, ""); #ifndef PRODUCT - if( PrintOpto && VerifyLoopOptimizations ) { + if (PrintOpto && VerifyLoopOptimizations) { tty->print("Unrolling "); loop->dump_head(); + } else if (TraceLoopOpts) { + tty->print("Unroll %d ", loop_head->unrolled_count()*2); + loop->dump_head(); } #endif - CountedLoopNode *loop_head = loop->_head->as_CountedLoop(); - CountedLoopEndNode *loop_end = loop_head->loopexit(); - assert( loop_end, "" ); // Remember loop node count before unrolling to detect // if rounds of unroll,optimize are making progress @@ -915,7 +935,7 @@ Node *ctrl = loop_head->in(LoopNode::EntryControl); Node *limit = loop_head->limit(); Node *init = loop_head->init_trip(); - Node *strid = loop_head->stride(); + Node *stride = loop_head->stride(); Node *opaq = NULL; if( adjust_min_trip ) { // If not maximally unrolling, need adjustment @@ -955,13 +975,13 @@ // odd iteration: (trip_cnt & ~1). Then back compute a new limit. Node *span = new (C, 3) SubINode( limit, init ); register_new_node( span, ctrl ); - Node *trip = new (C, 3) DivINode( 0, span, strid ); + Node *trip = new (C, 3) DivINode( 0, span, stride ); register_new_node( trip, ctrl ); Node *mtwo = _igvn.intcon(-2); set_ctrl(mtwo, C->root()); Node *rond = new (C, 3) AndINode( trip, mtwo ); register_new_node( rond, ctrl ); - Node *spn2 = new (C, 3) MulINode( rond, strid ); + Node *spn2 = new (C, 3) MulINode( rond, stride ); register_new_node( spn2, ctrl ); Node *lim2 = new (C, 3) AddINode( spn2, init ); register_new_node( lim2, ctrl ); @@ -1040,17 +1060,23 @@ void PhaseIdealLoop::do_maximally_unroll( IdealLoopTree *loop, Node_List &old_new ) { CountedLoopNode *cl = loop->_head->as_CountedLoop(); - assert( cl->trip_count() > 0, ""); + assert(cl->trip_count() > 0, ""); +#ifndef PRODUCT + if (TraceLoopOpts) { + tty->print("MaxUnroll %d ", cl->trip_count()); + loop->dump_head(); + } +#endif // If loop is tripping an odd number of times, peel odd iteration - if( (cl->trip_count() & 1) == 1 ) { - do_peeling( loop, old_new ); + if ((cl->trip_count() & 1) == 1) { + do_peeling(loop, old_new); } // Now its tripping an even number of times remaining. Double loop body. // Do not adjust pre-guards; they are not needed and do not exist. - if( cl->trip_count() > 0 ) { - do_unroll( loop, old_new, false ); + if (cl->trip_count() > 0) { + do_unroll(loop, old_new, false); } } @@ -1227,35 +1253,55 @@ // Eliminate range-checks and other trip-counter vs loop-invariant tests. void PhaseIdealLoop::do_range_check( IdealLoopTree *loop, Node_List &old_new ) { #ifndef PRODUCT - if( PrintOpto && VerifyLoopOptimizations ) { + if (PrintOpto && VerifyLoopOptimizations) { tty->print("Range Check Elimination "); loop->dump_head(); + } else if (TraceLoopOpts) { + tty->print("RangeCheck "); + loop->dump_head(); } #endif - assert( RangeCheckElimination, "" ); + assert(RangeCheckElimination, ""); CountedLoopNode *cl = loop->_head->as_CountedLoop(); - assert( cl->is_main_loop(), "" ); + assert(cl->is_main_loop(), ""); + + // protect against stride not being a constant + if (!cl->stride_is_con()) + return; // Find the trip counter; we are iteration splitting based on it Node *trip_counter = cl->phi(); // Find the main loop limit; we will trim it's iterations // to not ever trip end tests Node *main_limit = cl->limit(); + + // Need to find the main-loop zero-trip guard + Node *ctrl = cl->in(LoopNode::EntryControl); + assert(ctrl->Opcode() == Op_IfTrue || ctrl->Opcode() == Op_IfFalse, ""); + Node *iffm = ctrl->in(0); + assert(iffm->Opcode() == Op_If, ""); + Node *bolzm = iffm->in(1); + assert(bolzm->Opcode() == Op_Bool, ""); + Node *cmpzm = bolzm->in(1); + assert(cmpzm->is_Cmp(), ""); + Node *opqzm = cmpzm->in(2); + // Can not optimize a loop if pre-loop Opaque1 node is optimized + // away and then another round of loop opts attempted. + if (opqzm->Opcode() != Op_Opaque1) + return; + assert(opqzm->in(1) == main_limit, "do not understand situation"); + // Find the pre-loop limit; we will expand it's iterations to // not ever trip low tests. - Node *ctrl = cl->in(LoopNode::EntryControl); - assert( ctrl->Opcode() == Op_IfTrue || ctrl->Opcode() == Op_IfFalse, "" ); - Node *iffm = ctrl->in(0); - assert( iffm->Opcode() == Op_If, "" ); Node *p_f = iffm->in(0); - assert( p_f->Opcode() == Op_IfFalse, "" ); + assert(p_f->Opcode() == Op_IfFalse, ""); CountedLoopEndNode *pre_end = p_f->in(0)->as_CountedLoopEnd(); - assert( pre_end->loopnode()->is_pre_loop(), "" ); + assert(pre_end->loopnode()->is_pre_loop(), ""); Node *pre_opaq1 = pre_end->limit(); // Occasionally it's possible for a pre-loop Opaque1 node to be // optimized away and then another round of loop opts attempted. // We can not optimize this particular loop in that case. - if( pre_opaq1->Opcode() != Op_Opaque1 ) + if (pre_opaq1->Opcode() != Op_Opaque1) return; Opaque1Node *pre_opaq = (Opaque1Node*)pre_opaq1; Node *pre_limit = pre_opaq->in(1); @@ -1266,25 +1312,11 @@ // Ensure the original loop limit is available from the // pre-loop Opaque1 node. Node *orig_limit = pre_opaq->original_loop_limit(); - if( orig_limit == NULL || _igvn.type(orig_limit) == Type::TOP ) + if (orig_limit == NULL || _igvn.type(orig_limit) == Type::TOP) return; - // Need to find the main-loop zero-trip guard - Node *bolzm = iffm->in(1); - assert( bolzm->Opcode() == Op_Bool, "" ); - Node *cmpzm = bolzm->in(1); - assert( cmpzm->is_Cmp(), "" ); - Node *opqzm = cmpzm->in(2); - if( opqzm->Opcode() != Op_Opaque1 ) - return; - assert( opqzm->in(1) == main_limit, "do not understand situation" ); - // Must know if its a count-up or count-down loop - // protect against stride not being a constant - if ( !cl->stride_is_con() ) { - return; - } int stride_con = cl->stride_con(); Node *zero = _igvn.intcon(0); Node *one = _igvn.intcon(1); @@ -1566,16 +1598,24 @@ // have on the last iteration. This will break the loop. bool IdealLoopTree::policy_do_remove_empty_loop( PhaseIdealLoop *phase ) { // Minimum size must be empty loop - if( _body.size() > 7/*number of nodes in an empty loop*/ ) return false; + if (_body.size() > 7/*number of nodes in an empty loop*/) + return false; - if( !_head->is_CountedLoop() ) return false; // Dead loop + if (!_head->is_CountedLoop()) + return false; // Dead loop CountedLoopNode *cl = _head->as_CountedLoop(); - if( !cl->loopexit() ) return false; // Malformed loop - if( !phase->is_member(this,phase->get_ctrl(cl->loopexit()->in(CountedLoopEndNode::TestValue)) ) ) + if (!cl->loopexit()) + return false; // Malformed loop + if (!phase->is_member(this, phase->get_ctrl(cl->loopexit()->in(CountedLoopEndNode::TestValue)))) return false; // Infinite loop #ifndef PRODUCT - if( PrintOpto ) - tty->print_cr("Removing empty loop"); + if (PrintOpto) { + tty->print("Removing empty loop"); + this->dump_head(); + } else if (TraceLoopOpts) { + tty->print("Empty "); + this->dump_head(); + } #endif #ifdef ASSERT // Ensure only one phi which is the iv. @@ -1720,7 +1760,7 @@ //------------------------------iteration_split-------------------------------- bool IdealLoopTree::iteration_split( PhaseIdealLoop *phase, Node_List &old_new ) { // Recursively iteration split nested loops - if( _child && !_child->iteration_split( phase, old_new )) + if (_child && !_child->iteration_split(phase, old_new)) return false; // Clean out prior deadwood @@ -1729,21 +1769,20 @@ // Look for loop-exit tests with my 50/50 guesses from the Parsing stage. // Replace with a 1-in-10 exit guess. - if( _parent /*not the root loop*/ && + if (_parent /*not the root loop*/ && !_irreducible && // Also ignore the occasional dead backedge - !tail()->is_top() ) { + !tail()->is_top()) { adjust_loop_exit_prob(phase); } - // Gate unrolling, RCE and peeling efforts. - if( !_child && // If not an inner loop, do not split + if (!_child && // If not an inner loop, do not split !_irreducible && _allow_optimizations && - !tail()->is_top() ) { // Also ignore the occasional dead backedge + !tail()->is_top()) { // Also ignore the occasional dead backedge if (!_has_call) { - if (!iteration_split_impl( phase, old_new )) { + if (!iteration_split_impl(phase, old_new)) { return false; } } else if (policy_unswitching(phase)) { @@ -1752,16 +1791,17 @@ } // Minor offset re-organization to remove loop-fallout uses of - // trip counter. - if( _head->is_CountedLoop() ) phase->reorg_offsets( this ); - if( _next && !_next->iteration_split( phase, old_new )) + // trip counter when there was no major reshaping. + phase->reorg_offsets(this); + + if (_next && !_next->iteration_split(phase, old_new)) return false; return true; } //-------------------------------is_uncommon_trap_proj---------------------------- // Return true if proj is the form of "proj->[region->..]call_uct" -bool PhaseIdealLoop::is_uncommon_trap_proj(ProjNode* proj, bool must_reason_predicate) { +bool PhaseIdealLoop::is_uncommon_trap_proj(ProjNode* proj, Deoptimization::DeoptReason reason) { int path_limit = 10; assert(proj, "invalid argument"); Node* out = proj; @@ -1772,8 +1812,8 @@ if (out->is_CallStaticJava()) { int req = out->as_CallStaticJava()->uncommon_trap_request(); if (req != 0) { - Deoptimization::DeoptReason reason = Deoptimization::trap_request_reason(req); - if (!must_reason_predicate || reason == Deoptimization::Reason_predicate){ + Deoptimization::DeoptReason trap_reason = Deoptimization::trap_request_reason(req); + if (trap_reason == reason || reason == Deoptimization::Reason_none) { return true; } } @@ -1790,15 +1830,15 @@ // other_proj->[region->..]call_uct" // // "must_reason_predicate" means the uct reason must be Reason_predicate -bool PhaseIdealLoop::is_uncommon_trap_if_pattern(ProjNode *proj, bool must_reason_predicate) { +bool PhaseIdealLoop::is_uncommon_trap_if_pattern(ProjNode *proj, Deoptimization::DeoptReason reason) { Node *in0 = proj->in(0); if (!in0->is_If()) return false; // Variation of a dead If node. if (in0->outcnt() < 2) return false; IfNode* iff = in0->as_If(); - // we need "If(Conv2B(Opaque1(...)))" pattern for must_reason_predicate - if (must_reason_predicate) { + // we need "If(Conv2B(Opaque1(...)))" pattern for reason_predicate + if (reason != Deoptimization::Reason_none) { if (iff->in(1)->Opcode() != Op_Conv2B || iff->in(1)->in(1)->Opcode() != Op_Opaque1) { return false; @@ -1806,7 +1846,19 @@ } ProjNode* other_proj = iff->proj_out(1-proj->_con)->as_Proj(); - return is_uncommon_trap_proj(other_proj, must_reason_predicate); + return is_uncommon_trap_proj(other_proj, reason); +} + +//-------------------------------register_control------------------------- +void PhaseIdealLoop::register_control(Node* n, IdealLoopTree *loop, Node* pred) { + assert(n->is_CFG(), "must be control node"); + _igvn.register_new_node_with_optimizer(n); + loop->_body.push(n); + set_loop(n, loop); + // When called from beautify_loops() idom is not constructed yet. + if (_idom != NULL) { + set_idom(n, pred, dom_depth(pred)); + } } //------------------------------create_new_if_for_predicate------------------------ @@ -1843,8 +1895,10 @@ // // We will create a region to guard the uct call if there is no one there. // The true projecttion (if_cont) of the new_iff is returned. -ProjNode* PhaseIdealLoop::create_new_if_for_predicate(ProjNode* cont_proj) { - assert(is_uncommon_trap_if_pattern(cont_proj, true), "must be a uct if pattern!"); +// This code is also used to clone predicates to clonned loops. +ProjNode* PhaseIdealLoop::create_new_if_for_predicate(ProjNode* cont_proj, Node* new_entry, + Deoptimization::DeoptReason reason) { + assert(is_uncommon_trap_if_pattern(cont_proj, reason), "must be a uct if pattern!"); IfNode* iff = cont_proj->in(0)->as_If(); ProjNode *uncommon_proj = iff->proj_out(1 - cont_proj->_con); @@ -1854,57 +1908,84 @@ if (!rgn->is_Region()) { // create a region to guard the call assert(rgn->is_Call(), "must be call uct"); CallNode* call = rgn->as_Call(); + IdealLoopTree* loop = get_loop(call); rgn = new (C, 1) RegionNode(1); - _igvn.set_type(rgn, rgn->bottom_type()); rgn->add_req(uncommon_proj); - set_idom(rgn, idom(uncommon_proj), dom_depth(uncommon_proj)+1); + register_control(rgn, loop, uncommon_proj); _igvn.hash_delete(call); call->set_req(0, rgn); + // When called from beautify_loops() idom is not constructed yet. + if (_idom != NULL) { + set_idom(call, rgn, dom_depth(rgn)); + } } + Node* entry = iff->in(0); + if (new_entry != NULL) { + // Clonning the predicate to new location. + entry = new_entry; + } // Create new_iff - uint iffdd = dom_depth(iff); - IdealLoopTree* lp = get_loop(iff); - IfNode *new_iff = new (C, 2) IfNode(iff->in(0), NULL, iff->_prob, iff->_fcnt); - register_node(new_iff, lp, idom(iff), iffdd); + IdealLoopTree* lp = get_loop(entry); + IfNode *new_iff = new (C, 2) IfNode(entry, NULL, iff->_prob, iff->_fcnt); + register_control(new_iff, lp, entry); Node *if_cont = new (C, 1) IfTrueNode(new_iff); Node *if_uct = new (C, 1) IfFalseNode(new_iff); if (cont_proj->is_IfFalse()) { // Swap Node* tmp = if_uct; if_uct = if_cont; if_cont = tmp; } - register_node(if_cont, lp, new_iff, iffdd); - register_node(if_uct, get_loop(rgn), new_iff, iffdd); - - // if_cont to iff - _igvn.hash_delete(iff); - iff->set_req(0, if_cont); - set_idom(iff, if_cont, dom_depth(iff)); + register_control(if_cont, lp, new_iff); + register_control(if_uct, get_loop(rgn), new_iff); // if_uct to rgn _igvn.hash_delete(rgn); rgn->add_req(if_uct); - Node* ridom = idom(rgn); - Node* nrdom = dom_lca(ridom, new_iff); - set_idom(rgn, nrdom, dom_depth(rgn)); - + // When called from beautify_loops() idom is not constructed yet. + if (_idom != NULL) { + Node* ridom = idom(rgn); + Node* nrdom = dom_lca(ridom, new_iff); + set_idom(rgn, nrdom, dom_depth(rgn)); + } // rgn must have no phis assert(!rgn->as_Region()->has_phi(), "region must have no phis"); + if (new_entry == NULL) { + // Attach if_cont to iff + _igvn.hash_delete(iff); + iff->set_req(0, if_cont); + if (_idom != NULL) { + set_idom(iff, if_cont, dom_depth(iff)); + } + } return if_cont->as_Proj(); } -//------------------------------find_predicate_insertion_point-------------------------- +//--------------------------find_predicate_insertion_point------------------- // Find a good location to insert a predicate -ProjNode* PhaseIdealLoop::find_predicate_insertion_point(Node* start_c) { - if (start_c == C->root() || !start_c->is_Proj()) +ProjNode* PhaseIdealLoop::find_predicate_insertion_point(Node* start_c, Deoptimization::DeoptReason reason) { + if (start_c == NULL || !start_c->is_Proj()) return NULL; - if (is_uncommon_trap_if_pattern(start_c->as_Proj(), true/*Reason_Predicate*/)) { + if (is_uncommon_trap_if_pattern(start_c->as_Proj(), reason)) { return start_c->as_Proj(); } return NULL; } +//--------------------------find_predicate------------------------------------ +// Find a predicate +Node* PhaseIdealLoop::find_predicate(Node* entry) { + Node* predicate = NULL; + if (UseLoopPredicate) { + predicate = find_predicate_insertion_point(entry, Deoptimization::Reason_predicate); + if (predicate != NULL) { // right pattern that can be used by loop predication + assert(entry->in(0)->in(1)->in(1)->Opcode()==Op_Opaque1, "must be"); + return entry; + } + } + return NULL; +} + //------------------------------Invariance----------------------------------- // Helper class for loop_predication_impl to compute invariance on the fly and // clone invariants. @@ -2151,6 +2232,11 @@ return false; } + if (loop->_head->unique_ctrl_out()->Opcode() == Op_NeverBranch) { + // do nothing for infinite loops + return false; + } + CountedLoopNode *cl = NULL; if (loop->_head->is_CountedLoop()) { cl = loop->_head->as_CountedLoop(); @@ -2158,40 +2244,22 @@ if (!cl->is_normal_loop()) return false; } - // Too many traps seen? - bool tmt = C->too_many_traps(C->method(), 0, Deoptimization::Reason_predicate); - int tc = C->trap_count(Deoptimization::Reason_predicate); - if (tmt || tc > 0) { - if (TraceLoopPredicate) { - tty->print_cr("too many predicate traps: %d", tc); - C->method()->print(); // which method has too many predicate traps - tty->print_cr(""); - } - return false; - } - LoopNode *lpn = loop->_head->as_Loop(); Node* entry = lpn->in(LoopNode::EntryControl); - ProjNode *predicate_proj = find_predicate_insertion_point(entry); - if (!predicate_proj){ + ProjNode *predicate_proj = find_predicate_insertion_point(entry, Deoptimization::Reason_predicate); + if (!predicate_proj) { #ifndef PRODUCT if (TraceLoopPredicate) { tty->print("missing predicate:"); loop->dump_head(); + lpn->dump(1); } #endif return false; } - ConNode* zero = _igvn.intcon(0); set_ctrl(zero, C->root()); - Node *cond_false = new (C, 2) Conv2BNode(zero); - register_new_node(cond_false, C->root()); - ConNode* one = _igvn.intcon(1); - set_ctrl(one, C->root()); - Node *cond_true = new (C, 2) Conv2BNode(one); - register_new_node(cond_true, C->root()); ResourceArea *area = Thread::current()->resource_area(); Invariance invar(area, loop); @@ -2218,7 +2286,7 @@ ProjNode* proj = if_proj_list.pop()->as_Proj(); IfNode* iff = proj->in(0)->as_If(); - if (!is_uncommon_trap_if_pattern(proj)) { + if (!is_uncommon_trap_if_pattern(proj, Deoptimization::Reason_none)) { if (loop->is_loop_exit(iff)) { // stop processing the remaining projs in the list because the execution of them // depends on the condition of "iff" (iff->in(1)). @@ -2242,7 +2310,8 @@ BoolNode* bol = test->as_Bool(); if (invar.is_invariant(bol)) { // Invariant test - new_predicate_proj = create_new_if_for_predicate(predicate_proj); + new_predicate_proj = create_new_if_for_predicate(predicate_proj, NULL, + Deoptimization::Reason_predicate); Node* ctrl = new_predicate_proj->in(0)->as_If()->in(0); BoolNode* new_predicate_bol = invar.clone(bol, ctrl)->as_Bool(); @@ -2256,8 +2325,15 @@ IfNode* new_predicate_iff = new_predicate_proj->in(0)->as_If(); _igvn.hash_delete(new_predicate_iff); new_predicate_iff->set_req(1, new_predicate_bol); - if (TraceLoopPredicate) tty->print_cr("invariant if%s: %d", negated ? " negated" : "", new_predicate_iff->_idx); - +#ifndef PRODUCT + if (TraceLoopPredicate) { + tty->print("Predicate invariant if%s: %d ", negated ? " negated" : "", new_predicate_iff->_idx); + loop->dump_head(); + } else if (TraceLoopOpts) { + tty->print("Predicate IC "); + loop->dump_head(); + } +#endif } else if (cl != NULL && loop->is_range_check_if(iff, this, invar)) { assert(proj->_con == predicate_proj->_con, "must match"); @@ -2281,8 +2357,8 @@ // lower_bound test will dominate the upper bound test and all // cloned or created nodes will use the lower bound test as // their declared control. - ProjNode* lower_bound_proj = create_new_if_for_predicate(predicate_proj); - ProjNode* upper_bound_proj = create_new_if_for_predicate(predicate_proj); + ProjNode* lower_bound_proj = create_new_if_for_predicate(predicate_proj, NULL, Deoptimization::Reason_predicate); + ProjNode* upper_bound_proj = create_new_if_for_predicate(predicate_proj, NULL, Deoptimization::Reason_predicate); assert(upper_bound_proj->in(0)->as_If()->in(0) == lower_bound_proj, "should dominate"); Node *ctrl = lower_bound_proj->in(0)->as_If()->in(0); @@ -2311,41 +2387,24 @@ // Fall through into rest of the clean up code which will move // any dependent nodes onto the upper bound test. new_predicate_proj = upper_bound_proj; + +#ifndef PRODUCT + if (TraceLoopOpts && !TraceLoopPredicate) { + tty->print("Predicate RC "); + loop->dump_head(); + } +#endif } else { - // The other proj of the "iff" is a uncommon trap projection, and we can assume - // the other proj will not be executed ("executed" means uct raised). + // Loop variant check (for example, range check in non-counted loop) + // with uncommon trap. continue; } - + assert(new_predicate_proj != NULL, "sanity"); // Success - attach condition (new_predicate_bol) to predicate if invar.map_ctrl(proj, new_predicate_proj); // so that invariance test can be appropriate - // Eliminate the old if in the loop body - _igvn.hash_delete(iff); - iff->set_req(1, proj->is_IfFalse() ? cond_false : cond_true); - - Node* ctrl = new_predicate_proj; // new control - ProjNode* dp = proj; // old control - assert(get_loop(dp) == loop, "guaranteed at the time of collecting proj"); - // Find nodes (depends only on the test) off the surviving projection; - // move them outside the loop with the control of proj_clone - for (DUIterator_Fast imax, i = dp->fast_outs(imax); i < imax; i++) { - Node* cd = dp->fast_out(i); // Control-dependent node - if (cd->depends_only_on_test()) { - assert(cd->in(0) == dp, ""); - _igvn.hash_delete(cd); - cd->set_req(0, ctrl); // ctrl, not NULL - set_early_ctrl(cd); - _igvn._worklist.push(cd); - IdealLoopTree *new_loop = get_loop(get_ctrl(cd)); - if (new_loop != loop) { - if (!loop->_child) loop->_body.yank(cd); - if (!new_loop->_child ) new_loop->_body.push(cd); - } - --i; - --imax; - } - } + // Eliminate the old If in the loop body + dominated_by( new_predicate_proj, iff, proj->_con != new_predicate_proj->_con ); hoisted = true; C->set_major_progress(); diff -r 5134fa1cfe63 -r c6580380076b src/share/vm/opto/loopUnswitch.cpp --- a/src/share/vm/opto/loopUnswitch.cpp Thu Mar 24 15:47:01 2011 -0700 +++ b/src/share/vm/opto/loopUnswitch.cpp Fri Mar 25 17:39:20 2011 -0700 @@ -110,6 +110,13 @@ IfNode* unswitch_iff = find_unswitching_candidate((const IdealLoopTree *)loop); assert(unswitch_iff != NULL, "should be at least one"); +#ifndef PRODUCT + if (TraceLoopOpts) { + tty->print("Unswitch %d ", head->unswitch_count()+1); + loop->dump_head(); + } +#endif + // Need to revert back to normal loop if (head->is_CountedLoop() && !head->as_CountedLoop()->is_normal_loop()) { head->as_CountedLoop()->set_normal_loop(); diff -r 5134fa1cfe63 -r c6580380076b src/share/vm/opto/loopnode.cpp --- a/src/share/vm/opto/loopnode.cpp Thu Mar 24 15:47:01 2011 -0700 +++ b/src/share/vm/opto/loopnode.cpp Fri Mar 25 17:39:20 2011 -0700 @@ -56,12 +56,32 @@ // Dump special per-node info #ifndef PRODUCT void LoopNode::dump_spec(outputStream *st) const { - if( is_inner_loop () ) st->print( "inner " ); - if( is_partial_peel_loop () ) st->print( "partial_peel " ); - if( partial_peel_has_failed () ) st->print( "partial_peel_failed " ); + if (is_inner_loop()) st->print( "inner " ); + if (is_partial_peel_loop()) st->print( "partial_peel " ); + if (partial_peel_has_failed()) st->print( "partial_peel_failed " ); } #endif +//------------------------------is_valid_counted_loop------------------------- +bool LoopNode::is_valid_counted_loop() const { + if (is_CountedLoop()) { + CountedLoopNode* l = as_CountedLoop(); + CountedLoopEndNode* le = l->loopexit(); + if (le != NULL && + le->proj_out(1 /* true */) == l->in(LoopNode::LoopBackControl)) { + Node* phi = l->phi(); + Node* exit = le->proj_out(0 /* false */); + if (exit != NULL && exit->Opcode() == Op_IfFalse && + phi != NULL && phi->is_Phi() && + phi->in(LoopNode::LoopBackControl) == l->incr() && + le->loopnode() == l && le->stride_is_con()) { + return true; + } + } + } + return false; +} + //------------------------------get_early_ctrl--------------------------------- // Compute earliest legal control Node *PhaseIdealLoop::get_early_ctrl( Node *n ) { @@ -142,43 +162,44 @@ } //------------------------------is_counted_loop-------------------------------- -Node *PhaseIdealLoop::is_counted_loop( Node *x, IdealLoopTree *loop ) { +bool PhaseIdealLoop::is_counted_loop( Node *x, IdealLoopTree *loop ) { PhaseGVN *gvn = &_igvn; // Counted loop head must be a good RegionNode with only 3 not NULL // control input edges: Self, Entry, LoopBack. - if ( x->in(LoopNode::Self) == NULL || x->req() != 3 ) - return NULL; + if (x->in(LoopNode::Self) == NULL || x->req() != 3) + return false; Node *init_control = x->in(LoopNode::EntryControl); Node *back_control = x->in(LoopNode::LoopBackControl); - if( init_control == NULL || back_control == NULL ) // Partially dead - return NULL; + if (init_control == NULL || back_control == NULL) // Partially dead + return false; // Must also check for TOP when looking for a dead loop - if( init_control->is_top() || back_control->is_top() ) - return NULL; + if (init_control->is_top() || back_control->is_top()) + return false; // Allow funny placement of Safepoint - if( back_control->Opcode() == Op_SafePoint ) + if (back_control->Opcode() == Op_SafePoint) back_control = back_control->in(TypeFunc::Control); // Controlling test for loop Node *iftrue = back_control; uint iftrue_op = iftrue->Opcode(); - if( iftrue_op != Op_IfTrue && - iftrue_op != Op_IfFalse ) + if (iftrue_op != Op_IfTrue && + iftrue_op != Op_IfFalse) // I have a weird back-control. Probably the loop-exit test is in // the middle of the loop and I am looking at some trailing control-flow // merge point. To fix this I would have to partially peel the loop. - return NULL; // Obscure back-control + return false; // Obscure back-control // Get boolean guarding loop-back test Node *iff = iftrue->in(0); - if( get_loop(iff) != loop || !iff->in(1)->is_Bool() ) return NULL; + if (get_loop(iff) != loop || !iff->in(1)->is_Bool()) + return false; BoolNode *test = iff->in(1)->as_Bool(); BoolTest::mask bt = test->_test._test; float cl_prob = iff->as_If()->_prob; - if( iftrue_op == Op_IfFalse ) { + if (iftrue_op == Op_IfFalse) { bt = BoolTest(bt).negate(); cl_prob = 1.0 - cl_prob; } @@ -186,7 +207,7 @@ Node *cmp = test->in(1); int cmp_op = cmp->Opcode(); if( cmp_op != Op_CmpI ) - return NULL; // Avoid pointer & float compares + return false; // Avoid pointer & float compares // Find the trip-counter increment & limit. Limit must be loop invariant. Node *incr = cmp->in(1); @@ -196,55 +217,64 @@ // need 'loop()' test to tell if limit is loop invariant // --------- - if( !is_member( loop, get_ctrl(incr) ) ) { // Swapped trip counter and limit? - Node *tmp = incr; // Then reverse order into the CmpI + if (!is_member(loop, get_ctrl(incr))) { // Swapped trip counter and limit? + Node *tmp = incr; // Then reverse order into the CmpI incr = limit; limit = tmp; bt = BoolTest(bt).commute(); // And commute the exit test } - if( is_member( loop, get_ctrl(limit) ) ) // Limit must loop-invariant - return NULL; + if (is_member(loop, get_ctrl(limit))) // Limit must be loop-invariant + return false; + if (!is_member(loop, get_ctrl(incr))) // Trip counter must be loop-variant + return false; + Node* phi_incr = NULL; // Trip-counter increment must be commutative & associative. - uint incr_op = incr->Opcode(); - if( incr_op == Op_Phi && incr->req() == 3 ) { - incr = incr->in(2); // Assume incr is on backedge of Phi - incr_op = incr->Opcode(); + if (incr->is_Phi()) { + if (incr->as_Phi()->region() != x || incr->req() != 3) + return false; // Not simple trip counter expression + phi_incr = incr; + incr = phi_incr->in(LoopNode::LoopBackControl); // Assume incr is on backedge of Phi + if (!is_member(loop, get_ctrl(incr))) // Trip counter must be loop-variant + return false; } + Node* trunc1 = NULL; Node* trunc2 = NULL; const TypeInt* iv_trunc_t = NULL; if (!(incr = CountedLoopNode::match_incr_with_optional_truncation(incr, &trunc1, &trunc2, &iv_trunc_t))) { - return NULL; // Funny increment opcode + return false; // Funny increment opcode } + assert(incr->Opcode() == Op_AddI, "wrong increment code"); // Get merge point Node *xphi = incr->in(1); Node *stride = incr->in(2); - if( !stride->is_Con() ) { // Oops, swap these - if( !xphi->is_Con() ) // Is the other guy a constant? - return NULL; // Nope, unknown stride, bail out + if (!stride->is_Con()) { // Oops, swap these + if (!xphi->is_Con()) // Is the other guy a constant? + return false; // Nope, unknown stride, bail out Node *tmp = xphi; // 'incr' is commutative, so ok to swap xphi = stride; stride = tmp; } - //if( loop(xphi) != l) return NULL;// Merge point is in inner loop?? - if( !xphi->is_Phi() ) return NULL; // Too much math on the trip counter + // Stride must be constant + int stride_con = stride->get_int(); + assert(stride_con != 0, "missed some peephole opt"); + + if (!xphi->is_Phi()) + return false; // Too much math on the trip counter + if (phi_incr != NULL && phi_incr != xphi) + return false; PhiNode *phi = xphi->as_Phi(); - // Stride must be constant - const Type *stride_t = stride->bottom_type(); - int stride_con = stride_t->is_int()->get_con(); - assert( stride_con, "missed some peephole opt" ); - // Phi must be of loop header; backedge must wrap to increment - if( phi->region() != x ) return NULL; - if( trunc1 == NULL && phi->in(LoopNode::LoopBackControl) != incr || - trunc1 != NULL && phi->in(LoopNode::LoopBackControl) != trunc1 ) { - return NULL; + if (phi->region() != x) + return false; + if (trunc1 == NULL && phi->in(LoopNode::LoopBackControl) != incr || + trunc1 != NULL && phi->in(LoopNode::LoopBackControl) != trunc1) { + return false; } Node *init_trip = phi->in(LoopNode::EntryControl); - //if (!init_trip->is_Con()) return NULL; // avoid rolling over MAXINT/MININT // If iv trunc type is smaller than int, check for possible wrap. if (!TypeInt::INT->higher_equal(iv_trunc_t)) { @@ -267,12 +297,12 @@ if (stride_con > 0) { if (iv_trunc_t->_hi - phi_ft->_hi < stride_con || iv_trunc_t->_lo > phi_ft->_lo) { - return NULL; // truncation may occur + return false; // truncation may occur } } else if (stride_con < 0) { if (iv_trunc_t->_lo - phi_ft->_lo > stride_con || iv_trunc_t->_hi < phi_ft->_hi) { - return NULL; // truncation may occur + return false; // truncation may occur } } // No possibility of wrap so truncation can be discarded @@ -281,35 +311,45 @@ assert(trunc1 == NULL && trunc2 == NULL, "no truncation for int"); } + // If the condition is inverted and we will be rolling + // through MININT to MAXINT, then bail out. + if (bt == BoolTest::eq || // Bail out, but this loop trips at most twice! + // Odd stride + bt == BoolTest::ne && stride_con != 1 && stride_con != -1 || + // Count down loop rolls through MAXINT + (bt == BoolTest::le || bt == BoolTest::lt) && stride_con < 0 || + // Count up loop rolls through MININT + (bt == BoolTest::ge || bt == BoolTest::gt) && stride_con > 0 ) { + return false; // Bail out + } + + const TypeInt* init_t = gvn->type(init_trip)->is_int(); + const TypeInt* limit_t = gvn->type(limit)->is_int(); + + if (stride_con > 0) { + long init_p = (long)init_t->_lo + stride_con; + if (init_p > (long)max_jint || init_p > (long)limit_t->_hi) + return false; // cyclic loop or this loop trips only once + } else { + long init_p = (long)init_t->_hi + stride_con; + if (init_p < (long)min_jint || init_p < (long)limit_t->_lo) + return false; // cyclic loop or this loop trips only once + } + // ================================================= // ---- SUCCESS! Found A Trip-Counted Loop! ----- // - // Canonicalize the condition on the test. If we can exactly determine - // the trip-counter exit value, then set limit to that value and use - // a '!=' test. Otherwise use condition '<' for count-up loops and - // '>' for count-down loops. If the condition is inverted and we will - // be rolling through MININT to MAXINT, then bail out. - + assert(x->Opcode() == Op_Loop, "regular loops only"); C->print_method("Before CountedLoop", 3); - // Check for SafePoint on backedge and remove - Node *sfpt = x->in(LoopNode::LoopBackControl); - if( sfpt->Opcode() == Op_SafePoint && is_deleteable_safept(sfpt)) { - lazy_replace( sfpt, iftrue ); - loop->_tail = iftrue; - } - - // If compare points to incr, we are ok. Otherwise the compare // can directly point to the phi; in this case adjust the compare so that // it points to the incr by adjusting the limit. - if( cmp->in(1) == phi || cmp->in(2) == phi ) + if (cmp->in(1) == phi || cmp->in(2) == phi) limit = gvn->transform(new (C, 3) AddINode(limit,stride)); // trip-count for +-tive stride should be: (limit - init_trip + stride - 1)/stride. // Final value for iterator should be: trip_count * stride + init_trip. - const Type *limit_t = limit->bottom_type(); - const Type *init_t = init_trip->bottom_type(); Node *one_p = gvn->intcon( 1); Node *one_m = gvn->intcon(-1); @@ -317,15 +357,15 @@ Node *hook = new (C, 6) Node(6); switch( bt ) { case BoolTest::eq: - return NULL; // Bail out, but this loop trips at most twice! + ShouldNotReachHere(); case BoolTest::ne: // Ahh, the case we desire - if( stride_con == 1 ) + if (stride_con == 1) trip_count = gvn->transform(new (C, 3) SubINode(limit,init_trip)); - else if( stride_con == -1 ) + else if (stride_con == -1) trip_count = gvn->transform(new (C, 3) SubINode(init_trip,limit)); else - return NULL; // Odd stride; must prove we hit limit exactly - set_subtree_ctrl( trip_count ); + ShouldNotReachHere(); + set_subtree_ctrl(trip_count); //_loop.map(trip_count->_idx,loop(limit)); break; case BoolTest::le: // Maybe convert to '<' case @@ -338,7 +378,8 @@ //_loop.map(limit->_idx,limit_loop); // Fall into next case case BoolTest::lt: { // Maybe convert to '!=' case - if( stride_con < 0 ) return NULL; // Count down loop rolls through MAXINT + if (stride_con < 0) // Count down loop rolls through MAXINT + ShouldNotReachHere(); Node *range = gvn->transform(new (C, 3) SubINode(limit,init_trip)); set_subtree_ctrl( range ); hook->init_req(0, range); @@ -367,7 +408,8 @@ //_loop.map(limit->_idx,limit_loop); // Fall into next case case BoolTest::gt: { // Maybe convert to '!=' case - if( stride_con > 0 ) return NULL; // count up loop rolls through MININT + if (stride_con > 0) // count up loop rolls through MININT + ShouldNotReachHere(); Node *range = gvn->transform(new (C, 3) SubINode(limit,init_trip)); set_subtree_ctrl( range ); hook->init_req(0, range); @@ -385,7 +427,7 @@ hook->init_req(3, trip_count); break; } - } + } // switch( bt ) Node *span = gvn->transform(new (C, 3) MulINode(trip_count,stride)); set_subtree_ctrl( span ); @@ -394,83 +436,82 @@ limit = gvn->transform(new (C, 3) AddINode(span,init_trip)); set_subtree_ctrl( limit ); + // Check for SafePoint on backedge and remove + Node *sfpt = x->in(LoopNode::LoopBackControl); + if (sfpt->Opcode() == Op_SafePoint && is_deleteable_safept(sfpt)) { + lazy_replace( sfpt, iftrue ); + loop->_tail = iftrue; + } + // Build a canonical trip test. // Clone code, as old values may be in use. + Node* nphi = PhiNode::make(x, init_trip, TypeInt::INT); + nphi = _igvn.register_new_node_with_optimizer(nphi); + set_ctrl(nphi, get_ctrl(phi)); + incr = incr->clone(); - incr->set_req(1,phi); + incr->set_req(1,nphi); incr->set_req(2,stride); incr = _igvn.register_new_node_with_optimizer(incr); set_early_ctrl( incr ); - _igvn.hash_delete(phi); - phi->set_req_X( LoopNode::LoopBackControl, incr, &_igvn ); - // If phi type is more restrictive than Int, raise to - // Int to prevent (almost) infinite recursion in igvn - // which can only handle integer types for constants or minint..maxint. - if (!TypeInt::INT->higher_equal(phi->bottom_type())) { - Node* nphi = PhiNode::make(phi->in(0), phi->in(LoopNode::EntryControl), TypeInt::INT); - nphi->set_req(LoopNode::LoopBackControl, phi->in(LoopNode::LoopBackControl)); - nphi = _igvn.register_new_node_with_optimizer(nphi); - set_ctrl(nphi, get_ctrl(phi)); - _igvn.replace_node(phi, nphi); - phi = nphi->as_Phi(); - } + nphi->set_req(LoopNode::LoopBackControl, incr); + _igvn.replace_node(phi, nphi); + phi = nphi->as_Phi(); + cmp = cmp->clone(); cmp->set_req(1,incr); cmp->set_req(2,limit); cmp = _igvn.register_new_node_with_optimizer(cmp); set_ctrl(cmp, iff->in(0)); - Node *tmp = test->clone(); - assert( tmp->is_Bool(), "" ); - test = (BoolNode*)tmp; - (*(BoolTest*)&test->_test)._test = bt; //BoolTest::ne; + test = test->clone()->as_Bool(); + (*(BoolTest*)&test->_test)._test = bt; test->set_req(1,cmp); _igvn.register_new_node_with_optimizer(test); set_ctrl(test, iff->in(0)); - // If the exit test is dead, STOP! - if( test == NULL ) return NULL; - _igvn.hash_delete(iff); - iff->set_req_X( 1, test, &_igvn ); // Replace the old IfNode with a new LoopEndNode - Node *lex = _igvn.register_new_node_with_optimizer(new (C, 2) CountedLoopEndNode( iff->in(0), iff->in(1), cl_prob, iff->as_If()->_fcnt )); + Node *lex = _igvn.register_new_node_with_optimizer(new (C, 2) CountedLoopEndNode( iff->in(0), test, cl_prob, iff->as_If()->_fcnt )); IfNode *le = lex->as_If(); uint dd = dom_depth(iff); set_idom(le, le->in(0), dd); // Update dominance for loop exit set_loop(le, loop); // Get the loop-exit control - Node *if_f = iff->as_If()->proj_out(!(iftrue_op == Op_IfTrue)); + Node *iffalse = iff->as_If()->proj_out(!(iftrue_op == Op_IfTrue)); // Need to swap loop-exit and loop-back control? - if( iftrue_op == Op_IfFalse ) { + if (iftrue_op == Op_IfFalse) { Node *ift2=_igvn.register_new_node_with_optimizer(new (C, 1) IfTrueNode (le)); Node *iff2=_igvn.register_new_node_with_optimizer(new (C, 1) IfFalseNode(le)); loop->_tail = back_control = ift2; set_loop(ift2, loop); - set_loop(iff2, get_loop(if_f)); + set_loop(iff2, get_loop(iffalse)); // Lazy update of 'get_ctrl' mechanism. - lazy_replace_proj( if_f , iff2 ); - lazy_replace_proj( iftrue, ift2 ); + lazy_replace_proj( iffalse, iff2 ); + lazy_replace_proj( iftrue, ift2 ); // Swap names - if_f = iff2; - iftrue = ift2; + iffalse = iff2; + iftrue = ift2; } else { - _igvn.hash_delete(if_f ); + _igvn.hash_delete(iffalse); _igvn.hash_delete(iftrue); - if_f ->set_req_X( 0, le, &_igvn ); - iftrue->set_req_X( 0, le, &_igvn ); + iffalse->set_req_X( 0, le, &_igvn ); + iftrue ->set_req_X( 0, le, &_igvn ); } - set_idom(iftrue, le, dd+1); - set_idom(if_f, le, dd+1); + set_idom(iftrue, le, dd+1); + set_idom(iffalse, le, dd+1); + assert(iff->outcnt() == 0, "should be dead now"); + lazy_replace( iff, le ); // fix 'get_ctrl' // Now setup a new CountedLoopNode to replace the existing LoopNode CountedLoopNode *l = new (C, 3) CountedLoopNode(init_control, back_control); + l->set_unswitch_count(x->as_Loop()->unswitch_count()); // Preserve // The following assert is approximately true, and defines the intention // of can_be_counted_loop. It fails, however, because phase->type // is not yet initialized for this loop and its parts. @@ -491,10 +532,14 @@ // Free up intermediate goo _igvn.remove_dead_node(hook); +#ifdef ASSERT + assert(l->is_valid_counted_loop(), "counted loop shape is messed up"); + assert(l == loop->_head && l->phi() == phi && l->loopexit() == lex, "" ); +#endif + C->print_method("After CountedLoop", 3); - // Return trip counter - return trip_count; + return true; } @@ -1256,17 +1301,98 @@ return true; } +//---------------------------replace_parallel_iv------------------------------- +// Replace parallel induction variable (parallel to trip counter) +void PhaseIdealLoop::replace_parallel_iv(IdealLoopTree *loop) { + assert(loop->_head->is_CountedLoop(), ""); + CountedLoopNode *cl = loop->_head->as_CountedLoop(); + Node *incr = cl->incr(); + if (incr == NULL) + return; // Dead loop? + Node *init = cl->init_trip(); + Node *phi = cl->phi(); + // protect against stride not being a constant + if (!cl->stride_is_con()) + return; + int stride_con = cl->stride_con(); + + PhaseGVN *gvn = &_igvn; + + // Visit all children, looking for Phis + for (DUIterator i = cl->outs(); cl->has_out(i); i++) { + Node *out = cl->out(i); + // Look for other phis (secondary IVs). Skip dead ones + if (!out->is_Phi() || out == phi || !has_node(out)) + continue; + PhiNode* phi2 = out->as_Phi(); + Node *incr2 = phi2->in( LoopNode::LoopBackControl ); + // Look for induction variables of the form: X += constant + if (phi2->region() != loop->_head || + incr2->req() != 3 || + incr2->in(1) != phi2 || + incr2 == incr || + incr2->Opcode() != Op_AddI || + !incr2->in(2)->is_Con()) + continue; + + // Check for parallel induction variable (parallel to trip counter) + // via an affine function. In particular, count-down loops with + // count-up array indices are common. We only RCE references off + // the trip-counter, so we need to convert all these to trip-counter + // expressions. + Node *init2 = phi2->in( LoopNode::EntryControl ); + int stride_con2 = incr2->in(2)->get_int(); + + // The general case here gets a little tricky. We want to find the + // GCD of all possible parallel IV's and make a new IV using this + // GCD for the loop. Then all possible IVs are simple multiples of + // the GCD. In practice, this will cover very few extra loops. + // Instead we require 'stride_con2' to be a multiple of 'stride_con', + // where +/-1 is the common case, but other integer multiples are + // also easy to handle. + int ratio_con = stride_con2/stride_con; + + if ((ratio_con * stride_con) == stride_con2) { // Check for exact + // Convert to using the trip counter. The parallel induction + // variable differs from the trip counter by a loop-invariant + // amount, the difference between their respective initial values. + // It is scaled by the 'ratio_con'. + // Perform local Ideal transformation since in most cases ratio == 1. + Node* ratio = _igvn.intcon(ratio_con); + set_ctrl(ratio, C->root()); + Node* hook = new (C, 3) Node(3); + Node* ratio_init = gvn->transform(new (C, 3) MulINode(init, ratio)); + hook->init_req(0, ratio_init); + Node* diff = gvn->transform(new (C, 3) SubINode(init2, ratio_init)); + hook->init_req(1, diff); + Node* ratio_idx = gvn->transform(new (C, 3) MulINode(phi, ratio)); + hook->init_req(2, ratio_idx); + Node* add = gvn->transform(new (C, 3) AddINode(ratio_idx, diff)); + set_subtree_ctrl(add); + _igvn.replace_node( phi2, add ); + // Free up intermediate goo + _igvn.remove_dead_node(hook); + // Sometimes an induction variable is unused + if (add->outcnt() == 0) { + _igvn.remove_dead_node(add); + } + --i; // deleted this phi; rescan starting with next position + continue; + } + } +} + //------------------------------counted_loop----------------------------------- // Convert to counted loops where possible void IdealLoopTree::counted_loop( PhaseIdealLoop *phase ) { // For grins, set the inner-loop flag here - if( !_child ) { - if( _head->is_Loop() ) _head->as_Loop()->set_inner_loop(); + if (!_child) { + if (_head->is_Loop()) _head->as_Loop()->set_inner_loop(); } - if( _head->is_CountedLoop() || - phase->is_counted_loop( _head, this ) ) { + if (_head->is_CountedLoop() || + phase->is_counted_loop(_head, this)) { _has_sfpt = 1; // Indicate we do not need a safepoint here // Look for a safepoint to remove @@ -1275,79 +1401,9 @@ phase->is_deleteable_safept(n)) phase->lazy_replace(n,n->in(TypeFunc::Control)); - CountedLoopNode *cl = _head->as_CountedLoop(); - Node *incr = cl->incr(); - if( !incr ) return; // Dead loop? - Node *init = cl->init_trip(); - Node *phi = cl->phi(); - // protect against stride not being a constant - if( !cl->stride_is_con() ) return; - int stride_con = cl->stride_con(); - // Look for induction variables - - // Visit all children, looking for Phis - for (DUIterator i = cl->outs(); cl->has_out(i); i++) { - Node *out = cl->out(i); - // Look for other phis (secondary IVs). Skip dead ones - if (!out->is_Phi() || out == phi || !phase->has_node(out)) continue; - PhiNode* phi2 = out->as_Phi(); - Node *incr2 = phi2->in( LoopNode::LoopBackControl ); - // Look for induction variables of the form: X += constant - if( phi2->region() != _head || - incr2->req() != 3 || - incr2->in(1) != phi2 || - incr2 == incr || - incr2->Opcode() != Op_AddI || - !incr2->in(2)->is_Con() ) - continue; - - // Check for parallel induction variable (parallel to trip counter) - // via an affine function. In particular, count-down loops with - // count-up array indices are common. We only RCE references off - // the trip-counter, so we need to convert all these to trip-counter - // expressions. - Node *init2 = phi2->in( LoopNode::EntryControl ); - int stride_con2 = incr2->in(2)->get_int(); + phase->replace_parallel_iv(this); - // The general case here gets a little tricky. We want to find the - // GCD of all possible parallel IV's and make a new IV using this - // GCD for the loop. Then all possible IVs are simple multiples of - // the GCD. In practice, this will cover very few extra loops. - // Instead we require 'stride_con2' to be a multiple of 'stride_con', - // where +/-1 is the common case, but other integer multiples are - // also easy to handle. - int ratio_con = stride_con2/stride_con; - - if( ratio_con * stride_con == stride_con2 ) { // Check for exact - // Convert to using the trip counter. The parallel induction - // variable differs from the trip counter by a loop-invariant - // amount, the difference between their respective initial values. - // It is scaled by the 'ratio_con'. - Compile* C = phase->C; - Node* ratio = phase->_igvn.intcon(ratio_con); - phase->set_ctrl(ratio, C->root()); - Node* ratio_init = new (C, 3) MulINode(init, ratio); - phase->_igvn.register_new_node_with_optimizer(ratio_init, init); - phase->set_early_ctrl(ratio_init); - Node* diff = new (C, 3) SubINode(init2, ratio_init); - phase->_igvn.register_new_node_with_optimizer(diff, init2); - phase->set_early_ctrl(diff); - Node* ratio_idx = new (C, 3) MulINode(phi, ratio); - phase->_igvn.register_new_node_with_optimizer(ratio_idx, phi); - phase->set_ctrl(ratio_idx, cl); - Node* add = new (C, 3) AddINode(ratio_idx, diff); - phase->_igvn.register_new_node_with_optimizer(add); - phase->set_ctrl(add, cl); - phase->_igvn.replace_node( phi2, add ); - // Sometimes an induction variable is unused - if (add->outcnt() == 0) { - phase->_igvn.remove_dead_node(add); - } - --i; // deleted this phi; rescan starting with next position - continue; - } - } } else if (_parent != NULL && !_irreducible) { // Not a counted loop. // Look for a safepoint on the idom-path to remove, preserving the first one @@ -1366,24 +1422,31 @@ } // Recursively - if( _child ) _child->counted_loop( phase ); - if( _next ) _next ->counted_loop( phase ); + if (_child) _child->counted_loop( phase ); + if (_next) _next ->counted_loop( phase ); } #ifndef PRODUCT //------------------------------dump_head-------------------------------------- // Dump 1 liner for loop header info void IdealLoopTree::dump_head( ) const { - for( uint i=0; i<_nest; i++ ) + for (uint i=0; i<_nest; i++) tty->print(" "); tty->print("Loop: N%d/N%d ",_head->_idx,_tail->_idx); - if( _irreducible ) tty->print(" IRREDUCIBLE"); - if( _head->is_CountedLoop() ) { + if (_irreducible) tty->print(" IRREDUCIBLE"); + if (UseLoopPredicate) { + Node* entry = _head->in(LoopNode::EntryControl); + if (entry != NULL && entry->is_Proj() && + PhaseIdealLoop::is_uncommon_trap_if_pattern(entry->as_Proj(), Deoptimization::Reason_predicate)) { + tty->print(" predicated"); + } + } + if (_head->is_CountedLoop()) { CountedLoopNode *cl = _head->as_CountedLoop(); tty->print(" counted"); - if( cl->is_pre_loop () ) tty->print(" pre" ); - if( cl->is_main_loop() ) tty->print(" main"); - if( cl->is_post_loop() ) tty->print(" post"); + if (cl->is_pre_loop ()) tty->print(" pre" ); + if (cl->is_main_loop()) tty->print(" main"); + if (cl->is_post_loop()) tty->print(" post"); } tty->cr(); } @@ -1392,8 +1455,8 @@ // Dump loops by loop tree void IdealLoopTree::dump( ) const { dump_head(); - if( _child ) _child->dump(); - if( _next ) _next ->dump(); + if (_child) _child->dump(); + if (_next) _next ->dump(); } #endif @@ -1439,19 +1502,19 @@ } // self (only loops that we can apply loop predication may use their predicates) - if (loop->_head->is_Loop() && - !loop->_irreducible && + if (loop->_head->is_Loop() && + !loop->_irreducible && !loop->tail()->is_top()) { - LoopNode *lpn = loop->_head->as_Loop(); + LoopNode* lpn = loop->_head->as_Loop(); Node* entry = lpn->in(LoopNode::EntryControl); - ProjNode *predicate_proj = find_predicate_insertion_point(entry); + Node* predicate_proj = find_predicate(entry); if (predicate_proj != NULL ) { // right pattern that can be used by loop predication - assert(entry->in(0)->in(1)->in(1)->Opcode()==Op_Opaque1, "must be"); + assert(entry->in(0)->in(1)->in(1)->Opcode() == Op_Opaque1, "must be"); useful_predicates.push(entry->in(0)->in(1)->in(1)); // good one } } - if ( loop->_next ) { // sibling + if (loop->_next) { // sibling collect_potentially_useful_predicates(loop->_next, useful_predicates); } } @@ -1459,7 +1522,8 @@ //------------------------eliminate_useless_predicates----------------------------- // Eliminate all inserted predicates if they could not be used by loop predication. void PhaseIdealLoop::eliminate_useless_predicates() { - if (C->predicate_count() == 0) return; // no predicate left + if (C->predicate_count() == 0) + return; // no predicate left Unique_Node_List useful_predicates; // to store useful predicates if (C->has_loops()) { @@ -1647,12 +1711,15 @@ #ifndef PRODUCT C->verify_graph_edges(); - if( _verify_me ) { // Nested verify pass? + if (_verify_me) { // Nested verify pass? // Check to see if the verify mode is broken assert(C->unique() == unique, "non-optimize mode made Nodes? ? ?"); return; } - if( VerifyLoopOptimizations ) verify(); + if(VerifyLoopOptimizations) verify(); + if(TraceLoopOpts && C->has_loops()) { + _ltree_root->dump(); + } #endif if (ReassociateInvariants) { diff -r 5134fa1cfe63 -r c6580380076b src/share/vm/opto/loopnode.hpp --- a/src/share/vm/opto/loopnode.hpp Thu Mar 24 15:47:01 2011 -0700 +++ b/src/share/vm/opto/loopnode.hpp Fri Mar 25 17:39:20 2011 -0700 @@ -93,6 +93,7 @@ in(1) != NULL && phase->type(in(1)) != Type::TOP && in(2) != NULL && phase->type(in(2)) != Type::TOP; } + bool is_valid_counted_loop() const; #ifndef PRODUCT virtual void dump_spec(outputStream *st) const; #endif @@ -101,9 +102,8 @@ //------------------------------Counted Loops---------------------------------- // Counted loops are all trip-counted loops, with exactly 1 trip-counter exit // path (and maybe some other exit paths). The trip-counter exit is always -// last in the loop. The trip-counter does not have to stride by a constant, -// but it does have to stride by a loop-invariant amount; the exit value is -// also loop invariant. +// last in the loop. The trip-counter have to stride by a constant; +// the exit value is also loop invariant. // CountedLoopNodes and CountedLoopEndNodes come in matched pairs. The // CountedLoopNode has the incoming loop control and the loop-back-control @@ -112,7 +112,7 @@ // CountedLoopNode if there is control flow in the loop), the post-increment // trip-counter value, and the limit. The trip-counter value is always of // the form (Op old-trip-counter stride). The old-trip-counter is produced -// by a Phi connected to the CountedLoopNode. The stride is loop invariant. +// by a Phi connected to the CountedLoopNode. The stride is constant. // The Op is any commutable opcode, including Add, Mul, Xor. The // CountedLoopEndNode also takes in the loop-invariant limit value. @@ -696,6 +696,9 @@ // Is safept not required by an outer loop? bool is_deleteable_safept(Node* sfpt); + // Replace parallel induction variable (parallel to trip counter) + void replace_parallel_iv(IdealLoopTree *loop); + // Perform verification that the graph is valid. PhaseIdealLoop( PhaseIterGVN &igvn) : PhaseTransform(Ideal_Loop), @@ -751,7 +754,7 @@ // Per-Node transform virtual Node *transform( Node *a_node ) { return 0; } - Node *is_counted_loop( Node *x, IdealLoopTree *loop ); + bool is_counted_loop( Node *x, IdealLoopTree *loop ); // Return a post-walked LoopNode IdealLoopTree *get_loop( Node *n ) const { @@ -815,16 +818,22 @@ bool is_scaled_iv_plus_offset(Node* exp, Node* iv, int* p_scale, Node** p_offset, int depth = 0); // Return true if proj is for "proj->[region->..]call_uct" - bool is_uncommon_trap_proj(ProjNode* proj, bool must_reason_predicate = false); + // Return true if proj is for "proj->[region->..]call_uct" + static bool is_uncommon_trap_proj(ProjNode* proj, Deoptimization::DeoptReason reason); // Return true for "if(test)-> proj -> ... // | // V // other_proj->[region->..]call_uct" - bool is_uncommon_trap_if_pattern(ProjNode* proj, bool must_reason_predicate = false); + static bool is_uncommon_trap_if_pattern(ProjNode* proj, Deoptimization::DeoptReason reason); // Create a new if above the uncommon_trap_if_pattern for the predicate to be promoted - ProjNode* create_new_if_for_predicate(ProjNode* cont_proj); - // Find a good location to insert a predicate - ProjNode* find_predicate_insertion_point(Node* start_c); + ProjNode* create_new_if_for_predicate(ProjNode* cont_proj, Node* new_entry, + Deoptimization::DeoptReason reason); + void register_control(Node* n, IdealLoopTree *loop, Node* pred); + + // Find a good location to insert a predicate + static ProjNode* find_predicate_insertion_point(Node* start_c, Deoptimization::DeoptReason reason); + // Find a predicate + static Node* find_predicate(Node* entry); // Construct a range check for a predicate if BoolNode* rc_predicate(Node* ctrl, int scale, Node* offset, @@ -936,7 +945,7 @@ Node *has_local_phi_input( Node *n ); // Mark an IfNode as being dominated by a prior test, // without actually altering the CFG (and hence IDOM info). - void dominated_by( Node *prevdom, Node *iff ); + void dominated_by( Node *prevdom, Node *iff, bool flip = false ); // Split Node 'n' through merge point Node *split_thru_region( Node *n, Node *region ); diff -r 5134fa1cfe63 -r c6580380076b src/share/vm/opto/loopopts.cpp --- a/src/share/vm/opto/loopopts.cpp Thu Mar 24 15:47:01 2011 -0700 +++ b/src/share/vm/opto/loopopts.cpp Fri Mar 25 17:39:20 2011 -0700 @@ -42,13 +42,13 @@ return NULL; } int wins = 0; - assert( !n->is_CFG(), "" ); - assert( region->is_Region(), "" ); + assert(!n->is_CFG(), ""); + assert(region->is_Region(), ""); const Type* type = n->bottom_type(); const TypeOopPtr *t_oop = _igvn.type(n)->isa_oopptr(); Node *phi; - if( t_oop != NULL && t_oop->is_known_instance_field() ) { + if (t_oop != NULL && t_oop->is_known_instance_field()) { int iid = t_oop->instance_id(); int index = C->get_alias_index(t_oop); int offset = t_oop->offset(); @@ -57,20 +57,20 @@ phi = PhiNode::make_blank(region, n); } uint old_unique = C->unique(); - for( uint i = 1; i < region->req(); i++ ) { + for (uint i = 1; i < region->req(); i++) { Node *x; Node* the_clone = NULL; - if( region->in(i) == C->top() ) { + if (region->in(i) == C->top()) { x = C->top(); // Dead path? Use a dead data op } else { x = n->clone(); // Else clone up the data op the_clone = x; // Remember for possible deletion. // Alter data node to use pre-phi inputs - if( n->in(0) == region ) + if (n->in(0) == region) x->set_req( 0, region->in(i) ); - for( uint j = 1; j < n->req(); j++ ) { + for (uint j = 1; j < n->req(); j++) { Node *in = n->in(j); - if( in->is_Phi() && in->in(0) == region ) + if (in->is_Phi() && in->in(0) == region) x->set_req( j, in->in(i) ); // Use pre-Phi input for the clone } } @@ -85,7 +85,7 @@ // happen if the singleton occurs on loop entry, as the elimination of // the PhiNode may cause the resulting node to migrate back to a previous // loop iteration. - if( singleton && t == Type::TOP ) { + if (singleton && t == Type::TOP) { // Is_Loop() == false does not confirm the absence of a loop (e.g., an // irreducible loop may not be indicated by an affirmative is_Loop()); // therefore, the only top we can split thru a phi is on a backedge of @@ -93,7 +93,7 @@ singleton &= region->is_Loop() && (i != LoopNode::EntryControl); } - if( singleton ) { + if (singleton) { wins++; x = ((PhaseGVN&)_igvn).makecon(t); } else { @@ -108,12 +108,12 @@ // igvn->type(x) is set to x->Value() already. x->raise_bottom_type(t); Node *y = x->Identity(&_igvn); - if( y != x ) { + if (y != x) { wins++; x = y; } else { y = _igvn.hash_find(x); - if( y ) { + if (y) { wins++; x = y; } else { @@ -129,7 +129,7 @@ phi->set_req( i, x ); } // Too few wins? - if( wins <= policy ) { + if (wins <= policy) { _igvn.remove_dead_node(phi); return NULL; } @@ -137,7 +137,7 @@ // Record Phi register_new_node( phi, region ); - for( uint i2 = 1; i2 < phi->req(); i2++ ) { + for (uint i2 = 1; i2 < phi->req(); i2++) { Node *x = phi->in(i2); // If we commoned up the cloned 'x' with another existing Node, // the existing Node picks up a new use. We need to make the @@ -145,24 +145,44 @@ Node *old_ctrl; IdealLoopTree *old_loop; + if (x->is_Con()) { + // Constant's control is always root. + set_ctrl(x, C->root()); + continue; + } // The occasional new node - if( x->_idx >= old_unique ) { // Found a new, unplaced node? - old_ctrl = x->is_Con() ? C->root() : NULL; - old_loop = NULL; // Not in any prior loop + if (x->_idx >= old_unique) { // Found a new, unplaced node? + old_ctrl = NULL; + old_loop = NULL; // Not in any prior loop } else { - old_ctrl = x->is_Con() ? C->root() : get_ctrl(x); + old_ctrl = get_ctrl(x); old_loop = get_loop(old_ctrl); // Get prior loop } // New late point must dominate new use - Node *new_ctrl = dom_lca( old_ctrl, region->in(i2) ); + Node *new_ctrl = dom_lca(old_ctrl, region->in(i2)); + if (new_ctrl == old_ctrl) // Nothing is changed + continue; + + IdealLoopTree *new_loop = get_loop(new_ctrl); + + // Don't move x into a loop if its uses are + // outside of loop. Otherwise x will be cloned + // for each use outside of this loop. + IdealLoopTree *use_loop = get_loop(region); + if (!new_loop->is_member(use_loop) && + (old_loop == NULL || !new_loop->is_member(old_loop))) { + // Take early control, later control will be recalculated + // during next iteration of loop optimizations. + new_ctrl = get_early_ctrl(x); + new_loop = get_loop(new_ctrl); + } // Set new location set_ctrl(x, new_ctrl); - IdealLoopTree *new_loop = get_loop( new_ctrl ); // If changing loop bodies, see if we need to collect into new body - if( old_loop != new_loop ) { - if( old_loop && !old_loop->_child ) + if (old_loop != new_loop) { + if (old_loop && !old_loop->_child) old_loop->_body.yank(x); - if( !new_loop->_child ) + if (!new_loop->_child) new_loop->_body.push(x); // Collect body info } } @@ -174,9 +194,9 @@ // Replace the dominated test with an obvious true or false. Place it on the // IGVN worklist for later cleanup. Move control-dependent data Nodes on the // live path up to the dominating control. -void PhaseIdealLoop::dominated_by( Node *prevdom, Node *iff ) { +void PhaseIdealLoop::dominated_by( Node *prevdom, Node *iff, bool flip ) { #ifndef PRODUCT - if( VerifyLoopOptimizations && PrintOpto ) tty->print_cr("dominating test"); + if (VerifyLoopOptimizations && PrintOpto) tty->print_cr("dominating test"); #endif @@ -185,6 +205,12 @@ assert( iff->Opcode() == Op_If || iff->Opcode() == Op_CountedLoopEnd, "Check this code when new subtype is added"); int pop = prevdom->Opcode(); assert( pop == Op_IfFalse || pop == Op_IfTrue, "" ); + if (flip) { + if (pop == Op_IfTrue) + pop = Op_IfFalse; + else + pop = Op_IfTrue; + } // 'con' is set to true or false to kill the dominated test. Node *con = _igvn.makecon(pop == Op_IfTrue ? TypeInt::ONE : TypeInt::ZERO); set_ctrl(con, C->root()); // Constant gets a new use @@ -197,7 +223,7 @@ // I can assume this path reaches an infinite loop. In this case it's not // important to optimize the data Nodes - either the whole compilation will // be tossed or this path (and all data Nodes) will go dead. - if( iff->outcnt() != 2 ) return; + if (iff->outcnt() != 2) return; // Make control-dependent data Nodes on the live path (path that will remain // once the dominated IF is removed) become control-dependent on the @@ -207,16 +233,16 @@ for (DUIterator_Fast imax, i = dp->fast_outs(imax); i < imax; i++) { Node* cd = dp->fast_out(i); // Control-dependent node - if( cd->depends_only_on_test() ) { - assert( cd->in(0) == dp, "" ); - _igvn.hash_delete( cd ); + if (cd->depends_only_on_test()) { + assert(cd->in(0) == dp, ""); + _igvn.hash_delete(cd); cd->set_req(0, prevdom); - set_early_ctrl( cd ); + set_early_ctrl(cd); _igvn._worklist.push(cd); IdealLoopTree *new_loop = get_loop(get_ctrl(cd)); - if( old_loop != new_loop ) { - if( !old_loop->_child ) old_loop->_body.yank(cd); - if( !new_loop->_child ) new_loop->_body.push(cd); + if (old_loop != new_loop) { + if (!old_loop->_child) old_loop->_body.yank(cd); + if (!new_loop->_child) new_loop->_body.push(cd); } --i; --imax; @@ -2338,6 +2364,11 @@ } #if !defined(PRODUCT) + if (TraceLoopOpts) { + tty->print("PartialPeel "); + loop->dump_head(); + } + if (TracePartialPeeling) { tty->print_cr("before partial peel one iteration"); Node_List wl; @@ -2481,6 +2512,7 @@ // Create new loop head for new phis and to hang // the nodes being moved (sinked) from the peel region. LoopNode* new_head = new (C, 3) LoopNode(last_peel, last_peel); + new_head->set_unswitch_count(head->unswitch_count()); // Preserve _igvn.register_new_node_with_optimizer(new_head); assert(first_not_peeled->in(0) == last_peel, "last_peel <- first_not_peeled"); first_not_peeled->set_req(0, new_head); @@ -2651,24 +2683,23 @@ // prevent loop-fallout uses of the pre-incremented trip counter (which are // then alive with the post-incremented trip counter forcing an extra // register move) -void PhaseIdealLoop::reorg_offsets( IdealLoopTree *loop ) { +void PhaseIdealLoop::reorg_offsets(IdealLoopTree *loop) { + // Perform it only for canonical counted loops. + // Loop's shape could be messed up by iteration_split_impl. + if (!loop->_head->is_CountedLoop()) + return; + if (!loop->_head->as_Loop()->is_valid_counted_loop()) + return; CountedLoopNode *cl = loop->_head->as_CountedLoop(); CountedLoopEndNode *cle = cl->loopexit(); - if( !cle ) return; // The occasional dead loop - // Find loop exit control Node *exit = cle->proj_out(false); - assert( exit->Opcode() == Op_IfFalse, "" ); + Node *phi = cl->phi(); // Check for the special case of folks using the pre-incremented // trip-counter on the fall-out path (forces the pre-incremented // and post-incremented trip counter to be live at the same time). // Fix this by adjusting to use the post-increment trip counter. - Node *phi = cl->phi(); - if( !phi ) return; // Dead infinite loop - - // Shape messed up, probably by iteration_split_impl - if (phi->in(LoopNode::LoopBackControl) != cl->incr()) return; bool progress = true; while (progress) { @@ -2677,21 +2708,19 @@ Node* use = phi->fast_out(i); // User of trip-counter if (!has_ctrl(use)) continue; Node *u_ctrl = get_ctrl(use); - if( use->is_Phi() ) { + if (use->is_Phi()) { u_ctrl = NULL; - for( uint j = 1; j < use->req(); j++ ) - if( use->in(j) == phi ) - u_ctrl = dom_lca( u_ctrl, use->in(0)->in(j) ); + for (uint j = 1; j < use->req(); j++) + if (use->in(j) == phi) + u_ctrl = dom_lca(u_ctrl, use->in(0)->in(j)); } IdealLoopTree *u_loop = get_loop(u_ctrl); // Look for loop-invariant use - if( u_loop == loop ) continue; - if( loop->is_member( u_loop ) ) continue; + if (u_loop == loop) continue; + if (loop->is_member(u_loop)) continue; // Check that use is live out the bottom. Assuming the trip-counter // update is right at the bottom, uses of of the loop middle are ok. - if( dom_lca( exit, u_ctrl ) != exit ) continue; - // protect against stride not being a constant - if( !cle->stride_is_con() ) continue; + if (dom_lca(exit, u_ctrl) != exit) continue; // Hit! Refactor use to use the post-incremented tripcounter. // Compute a post-increment tripcounter. Node *opaq = new (C, 2) Opaque2Node( C, cle->incr() ); @@ -2702,9 +2731,10 @@ register_new_node( post, u_ctrl ); _igvn.hash_delete(use); _igvn._worklist.push(use); - for( uint j = 1; j < use->req(); j++ ) - if( use->in(j) == phi ) + for (uint j = 1; j < use->req(); j++) { + if (use->in(j) == phi) use->set_req(j, post); + } // Since DU info changed, rerun loop progress = true; break; diff -r 5134fa1cfe63 -r c6580380076b src/share/vm/opto/parse.hpp --- a/src/share/vm/opto/parse.hpp Thu Mar 24 15:47:01 2011 -0700 +++ b/src/share/vm/opto/parse.hpp Fri Mar 25 17:39:20 2011 -0700 @@ -136,6 +136,7 @@ uint _count; // how many times executed? Currently only set by _goto's bool _is_parsed; // has this block been parsed yet? bool _is_handler; // is this block an exception handler? + bool _has_merged_backedge; // does this block have merged backedge? SafePointNode* _start_map; // all values flowing into this block MethodLivenessResult _live_locals; // lazily initialized liveness bitmap @@ -168,6 +169,18 @@ // True after any predecessor flows control into this block bool is_merged() const { return _start_map != NULL; } +#ifdef ASSERT + // True after backedge predecessor flows control into this block + bool has_merged_backedge() const { return _has_merged_backedge; } + void mark_merged_backedge(Block* pred) { + assert(is_SEL_head(), "should be loop head"); + if (pred != NULL && is_SEL_backedge(pred)) { + assert(is_parsed(), "block should be parsed before merging backedges"); + _has_merged_backedge = true; + } + } +#endif + // True when all non-exception predecessors have been parsed. bool is_ready() const { return preds_parsed() == pred_count(); } @@ -441,11 +454,6 @@ } } - // Return true if the parser should add a loop predicate - bool should_add_predicate(int target_bci); - // Insert a loop predicate into the graph - void add_predicate(); - // Note: Intrinsic generation routines may be found in library_call.cpp. // Helper function to setup Ideal Call nodes diff -r 5134fa1cfe63 -r c6580380076b src/share/vm/opto/parse1.cpp --- a/src/share/vm/opto/parse1.cpp Thu Mar 24 15:47:01 2011 -0700 +++ b/src/share/vm/opto/parse1.cpp Fri Mar 25 17:39:20 2011 -0700 @@ -637,6 +637,25 @@ // (Note that dead locals do not get phis built, ever.) ensure_phis_everywhere(); + if (block->is_SEL_head() && + UseLoopPredicate) { + // Add predicate to single entry (not irreducible) loop head. + assert(!block->has_merged_backedge(), "only entry paths should be merged for now"); + // Need correct bci for predicate. + // It is fine to set it here since do_one_block() will set it anyway. + set_parse_bci(block->start()); + add_predicate(); + // Add new region for back branches. + int edges = block->pred_count() - block->preds_parsed() + 1; // +1 for original region + RegionNode *r = new (C, edges+1) RegionNode(edges+1); + _gvn.set_type(r, Type::CONTROL); + record_for_igvn(r); + r->init_req(edges, control()); + set_control(r); + // Add new phis. + ensure_phis_everywhere(); + } + // Leave behind an undisturbed copy of the map, for future merges. set_map(clone_map()); } @@ -1113,7 +1132,7 @@ _preds_parsed = 0; _count = 0; assert(pred_count() == 0 && preds_parsed() == 0, "sanity"); - assert(!(is_merged() || is_parsed() || is_handler()), "sanity"); + assert(!(is_merged() || is_parsed() || is_handler() || has_merged_backedge()), "sanity"); assert(_live_locals.size() == 0, "sanity"); // entry point has additional predecessor @@ -1350,10 +1369,6 @@ set_parse_bci(iter().cur_bci()); if (bci() == block()->limit()) { - // insert a predicate if it falls through to a loop head block - if (should_add_predicate(bci())){ - add_predicate(); - } // Do not walk into the next block until directed by do_all_blocks. merge(bci()); break; @@ -1498,17 +1513,29 @@ || target->is_handler() // These have unpredictable inputs. || target->is_loop_head() // Known multiple inputs || control()->is_Region()) { // We must hide this guy. + + int current_bci = bci(); + set_parse_bci(target->start()); // Set target bci + if (target->is_SEL_head()) { + DEBUG_ONLY( target->mark_merged_backedge(block()); ) + if (target->start() == 0) { + // Add loop predicate for the special case when + // there are backbranches to the method entry. + add_predicate(); + } + } // Add a Region to start the new basic block. Phis will be added // later lazily. int edges = target->pred_count(); if (edges < pnum) edges = pnum; // might be a new path! - Node *r = new (C, edges+1) RegionNode(edges+1); + RegionNode *r = new (C, edges+1) RegionNode(edges+1); gvn().set_type(r, Type::CONTROL); record_for_igvn(r); // zap all inputs to NULL for debugging (done in Node(uint) constructor) // for (int j = 1; j < edges+1; j++) { r->init_req(j, NULL); } r->init_req(pnum, control()); set_control(r); + set_parse_bci(current_bci); // Restore bci } // Convert the existing Parser mapping into a mapping at this bci. @@ -1517,7 +1544,11 @@ } else { // Prior mapping at this bci if (TraceOptoParse) { tty->print(" with previous state"); } - +#ifdef ASSERT + if (target->is_SEL_head()) { + target->mark_merged_backedge(block()); + } +#endif // We must not manufacture more phis if the target is already parsed. bool nophi = target->is_parsed(); @@ -2054,37 +2085,6 @@ } } -//------------------------------should_add_predicate-------------------------- -bool Parse::should_add_predicate(int target_bci) { - if (!UseLoopPredicate) return false; - Block* target = successor_for_bci(target_bci); - if (target != NULL && - target->is_loop_head() && - block()->rpo() < target->rpo()) { - return true; - } - return false; -} - -//------------------------------add_predicate--------------------------------- -void Parse::add_predicate() { - assert(UseLoopPredicate,"use only for loop predicate"); - Node *cont = _gvn.intcon(1); - Node* opq = _gvn.transform(new (C, 2) Opaque1Node(C, cont)); - Node *bol = _gvn.transform(new (C, 2) Conv2BNode(opq)); - IfNode* iff = create_and_map_if(control(), bol, PROB_MAX, COUNT_UNKNOWN); - Node* iffalse = _gvn.transform(new (C, 1) IfFalseNode(iff)); - C->add_predicate_opaq(opq); - { - PreserveJVMState pjvms(this); - set_control(iffalse); - uncommon_trap(Deoptimization::Reason_predicate, - Deoptimization::Action_maybe_recompile); - } - Node* iftrue = _gvn.transform(new (C, 1) IfTrueNode(iff)); - set_control(iftrue); -} - #ifndef PRODUCT //------------------------show_parse_info-------------------------------------- void Parse::show_parse_info() { diff -r 5134fa1cfe63 -r c6580380076b src/share/vm/opto/parse2.cpp --- a/src/share/vm/opto/parse2.cpp Thu Mar 24 15:47:01 2011 -0700 +++ b/src/share/vm/opto/parse2.cpp Fri Mar 25 17:39:20 2011 -0700 @@ -293,11 +293,6 @@ if (len < 1) { // If this is a backward branch, add safepoint maybe_add_safepoint(default_dest); - if (should_add_predicate(default_dest)){ - _sp += 1; // set original stack for use by uncommon_trap - add_predicate(); - _sp -= 1; - } merge(default_dest); return; } @@ -344,11 +339,6 @@ if (len < 1) { // If this is a backward branch, add safepoint maybe_add_safepoint(default_dest); - if (should_add_predicate(default_dest)){ - _sp += 1; // set original stack for use by uncommon_trap - add_predicate(); - _sp -= 1; - } merge(default_dest); return; } @@ -756,9 +746,6 @@ push(_gvn.makecon(ret_addr)); // Flow to the jsr. - if (should_add_predicate(jsr_bci)){ - add_predicate(); - } merge(jsr_bci); } @@ -1040,11 +1027,6 @@ profile_taken_branch(target_bci); adjust_map_after_if(btest, c, prob, branch_block, next_block); if (!stopped()) { - if (should_add_predicate(target_bci)){ // add a predicate if it branches to a loop - int nargs = repush_if_args(); // set original stack for uncommon_trap - add_predicate(); - _sp -= nargs; - } merge(target_bci); } } @@ -1168,11 +1150,6 @@ profile_taken_branch(target_bci); adjust_map_after_if(taken_btest, c, prob, branch_block, next_block); if (!stopped()) { - if (should_add_predicate(target_bci)){ // add a predicate if it branches to a loop - int nargs = repush_if_args(); // set original stack for the uncommon_trap - add_predicate(); - _sp -= nargs; - } merge(target_bci); } } @@ -2166,10 +2143,6 @@ // Update method data profile_taken_branch(target_bci); - // Add loop predicate if it goes to a loop - if (should_add_predicate(target_bci)){ - add_predicate(); - } // Merge the current control into the target basic block merge(target_bci); diff -r 5134fa1cfe63 -r c6580380076b src/share/vm/opto/stringopts.cpp --- a/src/share/vm/opto/stringopts.cpp Thu Mar 24 15:47:01 2011 -0700 +++ b/src/share/vm/opto/stringopts.cpp Fri Mar 25 17:39:20 2011 -0700 @@ -969,6 +969,10 @@ // for (int i=0; ; i++) // if (x <= sizeTable[i]) // return i+1; + + // Add loop predicate first. + kit.add_predicate(); + RegionNode *loop = new (C, 3) RegionNode(3); loop->init_req(1, kit.control()); kit.gvn().set_type(loop, Type::CONTROL); @@ -1086,6 +1090,9 @@ // } { + // Add loop predicate first. + kit.add_predicate(); + RegionNode *head = new (C, 3) RegionNode(3); head->init_req(1, kit.control()); kit.gvn().set_type(head, Type::CONTROL); diff -r 5134fa1cfe63 -r c6580380076b src/share/vm/runtime/os.cpp --- a/src/share/vm/runtime/os.cpp Thu Mar 24 15:47:01 2011 -0700 +++ b/src/share/vm/runtime/os.cpp Fri Mar 25 17:39:20 2011 -0700 @@ -1079,11 +1079,6 @@ "%/lib/jsse.jar:" "%/lib/jce.jar:" "%/lib/charsets.jar:" - - // ## TEMPORARY hack to keep the legacy launcher working when - // ## only the boot module is installed (cf. j.l.ClassLoader) - "%/lib/modules/jdk.boot.jar:" - "%/classes"; char* sysclasspath = format_boot_path(classpath_format, home, home_len, fileSep, pathSep); if (sysclasspath == NULL) return false; diff -r 5134fa1cfe63 -r c6580380076b src/share/vm/runtime/osThread.hpp --- a/src/share/vm/runtime/osThread.hpp Thu Mar 24 15:47:01 2011 -0700 +++ b/src/share/vm/runtime/osThread.hpp Fri Mar 25 17:39:20 2011 -0700 @@ -1,5 +1,5 @@ /* - * Copyright (c) 1997, 2010, Oracle and/or its affiliates. All rights reserved. + * Copyright (c) 1997, 2011, Oracle and/or its affiliates. All rights reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it @@ -65,7 +65,7 @@ OSThreadStartFunc _start_proc; // Thread start routine void* _start_parm; // Thread start routine parameter volatile ThreadState _state; // Thread state *hint* - jint _interrupted; // Thread.isInterrupted state + volatile jint _interrupted; // Thread.isInterrupted state // Note: _interrupted must be jint, so that Java intrinsics can access it. // The value stored there must be either 0 or 1. It must be possible @@ -89,7 +89,7 @@ void* start_parm() const { return _start_parm; } void set_start_parm(void* start_parm) { _start_parm = start_parm; } - bool interrupted() const { return _interrupted != 0; } + volatile bool interrupted() const { return _interrupted != 0; } void set_interrupted(bool z) { _interrupted = z ? 1 : 0; } // Printing diff -r 5134fa1cfe63 -r c6580380076b src/share/vm/runtime/vmStructs.cpp --- a/src/share/vm/runtime/vmStructs.cpp Thu Mar 24 15:47:01 2011 -0700 +++ b/src/share/vm/runtime/vmStructs.cpp Fri Mar 25 17:39:20 2011 -0700 @@ -840,7 +840,7 @@ /* OSThread */ \ /************/ \ \ - nonstatic_field(OSThread, _interrupted, jint) \ + volatile_nonstatic_field(OSThread, _interrupted, jint) \ \ /************************/ \ /* OopMap and OopMapSet */ \ diff -r 5134fa1cfe63 -r c6580380076b test/compiler/6987555/Test6987555.java --- a/test/compiler/6987555/Test6987555.java Thu Mar 24 15:47:01 2011 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,177 +0,0 @@ -/* - * Copyright (c) 2010, 2011, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - * - */ - -/** - * @test - * @bug 6987555 - * @summary JSR 292 unboxing to a boolean value fails on big-endian SPARC - * - * @run main/othervm -Xint -ea -XX:+UnlockExperimentalVMOptions -XX:+EnableMethodHandles -XX:+EnableInvokeDynamic -XX:+UnlockDiagnosticVMOptions -XX:+VerifyMethodHandles Test6987555 - */ - -import java.dyn.*; - -public class Test6987555 { - private static final Class CLASS = Test6987555.class; - private static final String NAME = "foo"; - private static final boolean DEBUG = false; - - public static void main(String[] args) throws Throwable { - testboolean(); - testbyte(); - testchar(); - testshort(); - testint(); - } - - // boolean - static void testboolean() throws Throwable { - doboolean(false); - doboolean(true); - } - static void doboolean(boolean x) throws Throwable { - if (DEBUG) System.out.println("boolean=" + x); - MethodHandle mh1 = MethodHandles.lookup().findStatic(CLASS, NAME, MethodType.methodType(boolean.class, boolean.class)); - MethodHandle mh2 = mh1.asType(MethodType.methodType(boolean.class, Boolean.class)); - boolean a = (boolean) mh1.invokeExact(x); - boolean b = (boolean) mh2.invokeExact(Boolean.valueOf(x)); - assert a == b : a + " != " + b; - } - - // byte - static void testbyte() throws Throwable { - byte[] a = new byte[] { - Byte.MIN_VALUE, - Byte.MIN_VALUE + 1, - -0x0F, - -1, - 0, - 1, - 0x0F, - Byte.MAX_VALUE - 1, - Byte.MAX_VALUE - }; - for (int i = 0; i < a.length; i++) { - dobyte(a[i]); - } - } - static void dobyte(byte x) throws Throwable { - if (DEBUG) System.out.println("byte=" + x); - MethodHandle mh1 = MethodHandles.lookup().findStatic(CLASS, NAME, MethodType.methodType(byte.class, byte.class)); - MethodHandle mh2 = mh1.asType(MethodType.methodType(byte.class, Byte.class)); - byte a = (byte) mh1.invokeExact(x); - byte b = (byte) mh2.invokeExact(Byte.valueOf(x)); - assert a == b : a + " != " + b; - } - - // char - static void testchar() throws Throwable { - char[] a = new char[] { - Character.MIN_VALUE, - Character.MIN_VALUE + 1, - 0x000F, - 0x00FF, - 0x0FFF, - Character.MAX_VALUE - 1, - Character.MAX_VALUE - }; - for (int i = 0; i < a.length; i++) { - dochar(a[i]); - } - } - static void dochar(char x) throws Throwable { - if (DEBUG) System.out.println("char=" + x); - MethodHandle mh1 = MethodHandles.lookup().findStatic(CLASS, NAME, MethodType.methodType(char.class, char.class)); - MethodHandle mh2 = mh1.asType(MethodType.methodType(char.class, Character.class)); - char a = (char) mh1.invokeExact(x); - char b = (char) mh2.invokeExact(Character.valueOf(x)); - assert a == b : a + " != " + b; - } - - // short - static void testshort() throws Throwable { - short[] a = new short[] { - Short.MIN_VALUE, - Short.MIN_VALUE + 1, - -0x0FFF, - -0x00FF, - -0x000F, - -1, - 0, - 1, - 0x000F, - 0x00FF, - 0x0FFF, - Short.MAX_VALUE - 1, - Short.MAX_VALUE - }; - for (int i = 0; i < a.length; i++) { - doshort(a[i]); - } - } - static void doshort(short x) throws Throwable { - if (DEBUG) System.out.println("short=" + x); - MethodHandle mh1 = MethodHandles.lookup().findStatic(CLASS, NAME, MethodType.methodType(short.class, short.class)); - MethodHandle mh2 = mh1.asType(MethodType.methodType(short.class, Short.class)); - short a = (short) mh1.invokeExact(x); - short b = (short) mh2.invokeExact(Short.valueOf(x)); - assert a == b : a + " != " + b; - } - - // int - static void testint() throws Throwable { - int[] a = new int[] { - Integer.MIN_VALUE, - Integer.MIN_VALUE + 1, - -0x00000FFF, - -0x000000FF, - -0x0000000F, - -1, - 0, - 1, - 0x0000000F, - 0x000000FF, - 0x00000FFF, - Integer.MAX_VALUE - 1, - Integer.MAX_VALUE - }; - for (int i = 0; i < a.length; i++) { - doint(a[i]); - } - } - static void doint(int x) throws Throwable { - if (DEBUG) System.out.println("int=" + x); - MethodHandle mh1 = MethodHandles.lookup().findStatic(CLASS, NAME, MethodType.methodType(int.class, int.class)); - MethodHandle mh2 = mh1.asType(MethodType.methodType(int.class, Integer.class)); - int a = (int) mh1.invokeExact(x); - int b = (int) mh2.invokeExact(Integer.valueOf(x)); - assert a == b : a + " != " + b; - } - - public static boolean foo(boolean i) { return i; } - public static byte foo(byte i) { return i; } - public static char foo(char i) { return i; } - public static short foo(short i) { return i; } - public static int foo(int i) { return i; } -} diff -r 5134fa1cfe63 -r c6580380076b test/compiler/6991596/Test6991596.java --- a/test/compiler/6991596/Test6991596.java Thu Mar 24 15:47:01 2011 -0700 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,465 +0,0 @@ -/* - * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * This code is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License version 2 only, as - * published by the Free Software Foundation. - * - * This code is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License - * version 2 for more details (a copy is included in the LICENSE file that - * accompanied this code). - * - * You should have received a copy of the GNU General Public License version - * 2 along with this work; if not, write to the Free Software Foundation, - * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. - * - * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA - * or visit www.oracle.com if you need additional information or have any - * questions. - * - */ - -/** - * @test - * @bug 6991596 - * @summary JSR 292 unimplemented adapter_opt_i2i and adapter_opt_l2i on SPARC - * - * @run main/othervm -ea -XX:+UnlockExperimentalVMOptions -XX:+EnableMethodHandles -XX:+EnableInvokeDynamic -XX:+UnlockDiagnosticVMOptions -XX:+VerifyMethodHandles Test6991596 - */ - -import java.dyn.*; - -public class Test6991596 { - private static final Class CLASS = Test6991596.class; - private static final String NAME = "foo"; - private static final boolean DEBUG = System.getProperty("DEBUG", "false").equals("true"); - - public static void main(String[] args) throws Throwable { - testboolean(); - testbyte(); - testchar(); - testshort(); - testint(); - testlong(); - } - - // Helpers to get various methods. - static MethodHandle getmh1(Class ret, Class arg) throws NoAccessException { - return MethodHandles.lookup().findStatic(CLASS, NAME, MethodType.methodType(ret, arg)); - } - static MethodHandle getmh2(MethodHandle mh1, Class ret, Class arg) { - return MethodHandles.convertArguments(mh1, MethodType.methodType(ret, arg)); - } - static MethodHandle getmh3(MethodHandle mh1, Class ret, Class arg) { - return MethodHandles.convertArguments(mh1, MethodType.methodType(ret, arg)); - } - - // test adapter_opt_i2i - static void testboolean() throws Throwable { - boolean[] a = new boolean[] { - true, - false - }; - for (int i = 0; i < a.length; i++) { - doboolean(a[i]); - } - } - static void doboolean(boolean x) throws Throwable { - if (DEBUG) System.out.println("boolean=" + x); - - // boolean - { - MethodHandle mh1 = getmh1( boolean.class, boolean.class); - MethodHandle mh2 = getmh2(mh1, boolean.class, boolean.class); - // TODO add this for all cases when the bugs are fixed. - //MethodHandle mh3 = getmh3(mh1, boolean.class, boolean.class); - boolean a = (boolean) mh1.invokeExact((boolean) x); - boolean b = (boolean) mh2.invokeExact(x); - //boolean c = mh3.invokeExact((boolean) x); - check(x, a, b); - //check(x, c, x); - } - - // byte - { - MethodHandle mh1 = getmh1( byte.class, byte.class ); - MethodHandle mh2 = getmh2(mh1, byte.class, boolean.class); - byte a = (byte) mh1.invokeExact((byte) (x ? 1 : 0)); - byte b = (byte) mh2.invokeExact(x); - check(x, a, b); - } - - // char - { - MethodHandle mh1 = getmh1( char.class, char.class); - MethodHandle mh2 = getmh2(mh1, char.class, boolean.class); - char a = (char) mh1.invokeExact((char) (x ? 1 : 0)); - char b = (char) mh2.invokeExact(x); - check(x, a, b); - } - - // short - { - MethodHandle mh1 = getmh1( short.class, short.class); - MethodHandle mh2 = getmh2(mh1, short.class, boolean.class); - short a = (short) mh1.invokeExact((short) (x ? 1 : 0)); - short b = (short) mh2.invokeExact(x); - check(x, a, b); - } - } - - static void testbyte() throws Throwable { - byte[] a = new byte[] { - Byte.MIN_VALUE, - Byte.MIN_VALUE + 1, - -0x0F, - -1, - 0, - 1, - 0x0F, - Byte.MAX_VALUE - 1, - Byte.MAX_VALUE - }; - for (int i = 0; i < a.length; i++) { - dobyte(a[i]); - } - } - static void dobyte(byte x) throws Throwable { - if (DEBUG) System.out.println("byte=" + x); - - // boolean - { - MethodHandle mh1 = getmh1( boolean.class, boolean.class); - MethodHandle mh2 = getmh2(mh1, boolean.class, byte.class); - boolean a = (boolean) mh1.invokeExact((x & 1) == 1); - boolean b = (boolean) mh2.invokeExact(x); - check(x, a, b); - } - - // byte - { - MethodHandle mh1 = getmh1( byte.class, byte.class); - MethodHandle mh2 = getmh2(mh1, byte.class, byte.class); - byte a = (byte) mh1.invokeExact((byte) x); - byte b = (byte) mh2.invokeExact(x); - check(x, a, b); - } - - // char - { - MethodHandle mh1 = getmh1( char.class, char.class); - MethodHandle mh2 = getmh2(mh1, char.class, byte.class); - char a = (char) mh1.invokeExact((char) x); - char b = (char) mh2.invokeExact(x); - check(x, a, b); - } - - // short - { - MethodHandle mh1 = getmh1( short.class, short.class); - MethodHandle mh2 = getmh2(mh1, short.class, byte.class); - short a = (short) mh1.invokeExact((short) x); - short b = (short) mh2.invokeExact(x); - check(x, a, b); - } - } - - static void testchar() throws Throwable { - char[] a = new char[] { - Character.MIN_VALUE, - Character.MIN_VALUE + 1, - 0x000F, - 0x00FF, - 0x0FFF, - Character.MAX_VALUE - 1, - Character.MAX_VALUE - }; - for (int i = 0; i < a.length; i++) { - dochar(a[i]); - } - } - static void dochar(char x) throws Throwable { - if (DEBUG) System.out.println("char=" + x); - - // boolean - { - MethodHandle mh1 = getmh1( boolean.class, boolean.class); - MethodHandle mh2 = getmh2(mh1, boolean.class, char.class); - boolean a = (boolean) mh1.invokeExact((x & 1) == 1); - boolean b = (boolean) mh2.invokeExact(x); - check(x, a, b); - } - - // byte - { - MethodHandle mh1 = getmh1( byte.class, byte.class); - MethodHandle mh2 = getmh2(mh1, byte.class, char.class); - byte a = (byte) mh1.invokeExact((byte) x); - byte b = (byte) mh2.invokeExact(x); - check(x, a, b); - } - - // char - { - MethodHandle mh1 = getmh1( char.class, char.class); - MethodHandle mh2 = getmh2(mh1, char.class, char.class); - char a = (char) mh1.invokeExact((char) x); - char b = (char) mh2.invokeExact(x); - check(x, a, b); - } - - // short - { - MethodHandle mh1 = getmh1( short.class, short.class); - MethodHandle mh2 = getmh2(mh1, short.class, char.class); - short a = (short) mh1.invokeExact((short) x); - short b = (short) mh2.invokeExact(x); - check(x, a, b); - } - } - - static void testshort() throws Throwable { - short[] a = new short[] { - Short.MIN_VALUE, - Short.MIN_VALUE + 1, - -0x0FFF, - -0x00FF, - -0x000F, - -1, - 0, - 1, - 0x000F, - 0x00FF, - 0x0FFF, - Short.MAX_VALUE - 1, - Short.MAX_VALUE - }; - for (int i = 0; i < a.length; i++) { - doshort(a[i]); - } - } - static void doshort(short x) throws Throwable { - if (DEBUG) System.out.println("short=" + x); - - // boolean - { - MethodHandle mh1 = getmh1( boolean.class, boolean.class); - MethodHandle mh2 = getmh2(mh1, boolean.class, short.class); - boolean a = (boolean) mh1.invokeExact((x & 1) == 1); - boolean b = (boolean) mh2.invokeExact(x); - check(x, a, b); - } - - // byte - { - MethodHandle mh1 = getmh1( byte.class, byte.class); - MethodHandle mh2 = getmh2(mh1, byte.class, short.class); - byte a = (byte) mh1.invokeExact((byte) x); - byte b = (byte) mh2.invokeExact(x); - check(x, a, b); - } - - // char - { - MethodHandle mh1 = getmh1( char.class, char.class); - MethodHandle mh2 = getmh2(mh1, char.class, short.class); - char a = (char) mh1.invokeExact((char) x); - char b = (char) mh2.invokeExact(x); - check(x, a, b); - } - - // short - { - MethodHandle mh1 = getmh1( short.class, short.class); - MethodHandle mh2 = getmh2(mh1, short.class, short.class); - short a = (short) mh1.invokeExact((short) x); - short b = (short) mh2.invokeExact(x); - check(x, a, b); - } - } - - static void testint() throws Throwable { - int[] a = new int[] { - Integer.MIN_VALUE, - Integer.MIN_VALUE + 1, - -0x0FFFFFFF, - -0x00FFFFFF, - -0x000FFFFF, - -0x0000FFFF, - -0x00000FFF, - -0x000000FF, - -0x0000000F, - -1, - 0, - 1, - 0x0000000F, - 0x000000FF, - 0x00000FFF, - 0x0000FFFF, - 0x000FFFFF, - 0x00FFFFFF, - 0x0FFFFFFF, - Integer.MAX_VALUE - 1, - Integer.MAX_VALUE - }; - for (int i = 0; i < a.length; i++) { - doint(a[i]); - } - } - static void doint(int x) throws Throwable { - if (DEBUG) System.out.println("int=" + x); - - // boolean - { - MethodHandle mh1 = getmh1( boolean.class, boolean.class); - MethodHandle mh2 = getmh2(mh1, boolean.class, int.class); - boolean a = (boolean) mh1.invokeExact((x & 1) == 1); - boolean b = (boolean) mh2.invokeExact(x); - check(x, a, b); - } - - // byte - { - MethodHandle mh1 = getmh1( byte.class, byte.class); - MethodHandle mh2 = getmh2(mh1, byte.class, int.class); - byte a = (byte) mh1.invokeExact((byte) x); - byte b = (byte) mh2.invokeExact(x); - check(x, a, b); - } - - // char - { - MethodHandle mh1 = getmh1( char.class, char.class); - MethodHandle mh2 = getmh2(mh1, char.class, int.class); - char a = (char) mh1.invokeExact((char) x); - char b = (char) mh2.invokeExact(x); - check(x, a, b); - } - - // short - { - MethodHandle mh1 = getmh1( short.class, short.class); - MethodHandle mh2 = getmh2(mh1, short.class, int.class); - short a = (short) mh1.invokeExact((short) x); - short b = (short) mh2.invokeExact(x); - assert a == b : a + " != " + b; - check(x, a, b); - } - - // int - { - MethodHandle mh1 = getmh1( int.class, int.class); - MethodHandle mh2 = getmh2(mh1, int.class, int.class); - int a = (int) mh1.invokeExact((int) x); - int b = (int) mh2.invokeExact(x); - check(x, a, b); - } - } - - // test adapter_opt_l2i - static void testlong() throws Throwable { - long[] a = new long[] { - Long.MIN_VALUE, - Long.MIN_VALUE + 1, - -0x000000000FFFFFFFL, - -0x0000000000FFFFFFL, - -0x00000000000FFFFFL, - -0x000000000000FFFFL, - -0x0000000000000FFFL, - -0x00000000000000FFL, - -0x000000000000000FL, - -1L, - 0L, - 1L, - 0x000000000000000FL, - 0x00000000000000FFL, - 0x0000000000000FFFL, - 0x0000000000000FFFL, - 0x000000000000FFFFL, - 0x00000000000FFFFFL, - 0x0000000000FFFFFFL, - 0x000000000FFFFFFFL, - Long.MAX_VALUE - 1, - Long.MAX_VALUE - }; - for (int i = 0; i < a.length; i++) { - dolong(a[i]); - } - } - static void dolong(long x) throws Throwable { - if (DEBUG) System.out.println("long=" + x); - - // boolean - { - MethodHandle mh1 = getmh1( boolean.class, boolean.class); - MethodHandle mh2 = getmh2(mh1, boolean.class, long.class); - boolean a = (boolean) mh1.invokeExact((x & 1L) == 1L); - boolean b = (boolean) mh2.invokeExact(x); - check(x, a, b); - } - - // byte - { - MethodHandle mh1 = getmh1( byte.class, byte.class); - MethodHandle mh2 = getmh2(mh1, byte.class, long.class); - byte a = (byte) mh1.invokeExact((byte) x); - byte b = (byte) mh2.invokeExact(x); - check(x, a, b); - } - - // char - { - MethodHandle mh1 = getmh1( char.class, char.class); - MethodHandle mh2 = getmh2(mh1, char.class, long.class); - char a = (char) mh1.invokeExact((char) x); - char b = (char) mh2.invokeExact(x); - check(x, a, b); - } - - // short - { - MethodHandle mh1 = getmh1( short.class, short.class); - MethodHandle mh2 = getmh2(mh1, short.class, long.class); - short a = (short) mh1.invokeExact((short) x); - short b = (short) mh2.invokeExact(x); - check(x, a, b); - } - - // int - { - MethodHandle mh1 = getmh1( int.class, int.class); - MethodHandle mh2 = getmh2(mh1, int.class, long.class); - int a = (int) mh1.invokeExact((int) x); - int b = (int) mh2.invokeExact(x); - check(x, a, b); - } - } - - static void check(boolean x, boolean e, boolean a) { p(z2h(x), z2h(e), z2h(a)); assert e == a : z2h(x) + ": " + z2h(e) + " != " + z2h(a); } - static void check(boolean x, byte e, byte a) { p(z2h(x), i2h(e), i2h(a)); assert e == a : z2h(x) + ": " + i2h(e) + " != " + i2h(a); } - static void check(boolean x, int e, int a) { p(z2h(x), i2h(e), i2h(a)); assert e == a : z2h(x) + ": " + i2h(e) + " != " + i2h(a); } - - static void check(int x, boolean e, boolean a) { p(i2h(x), z2h(e), z2h(a)); assert e == a : i2h(x) + ": " + z2h(e) + " != " + z2h(a); } - static void check(int x, byte e, byte a) { p(i2h(x), i2h(e), i2h(a)); assert e == a : i2h(x) + ": " + i2h(e) + " != " + i2h(a); } - static void check(int x, int e, int a) { p(i2h(x), i2h(e), i2h(a)); assert e == a : i2h(x) + ": " + i2h(e) + " != " + i2h(a); } - - static void check(long x, boolean e, boolean a) { p(l2h(x), z2h(e), z2h(a)); assert e == a : l2h(x) + ": " + z2h(e) + " != " + z2h(a); } - static void check(long x, byte e, byte a) { p(l2h(x), i2h(e), i2h(a)); assert e == a : l2h(x) + ": " + i2h(e) + " != " + i2h(a); } - static void check(long x, int e, int a) { p(l2h(x), i2h(e), i2h(a)); assert e == a : l2h(x) + ": " + i2h(e) + " != " + i2h(a); } - - static void p(String x, String e, String a) { if (DEBUG) System.out.println(x + ": expected: " + e + ", actual: " + a); } - - static String z2h(boolean x) { return x ? "1" : "0"; } - static String i2h(int x) { return Integer.toHexString(x); } - static String l2h(long x) { return Long.toHexString(x); } - - // to int - public static boolean foo(boolean i) { return i; } - public static byte foo(byte i) { return i; } - public static char foo(char i) { return i; } - public static short foo(short i) { return i; } - public static int foo(int i) { return i; } -}