# HG changeset patch # User anoll # Date 1406285877 0 # Node ID f43b5dab2dd398e879ad1eff4693e9056176e31d # Parent 54911b14d5ee28d560925d490fa8e3354d5b831f# Parent ad0233fa8767cc686a41219005572177367c61b2 Merge diff -r 54911b14d5ee -r f43b5dab2dd3 hotspot/src/share/vm/opto/cfgnode.cpp --- a/hotspot/src/share/vm/opto/cfgnode.cpp Fri Jul 25 09:44:53 2014 +0000 +++ b/hotspot/src/share/vm/opto/cfgnode.cpp Fri Jul 25 10:57:57 2014 +0000 @@ -108,6 +108,7 @@ rreq++; // One more input to Region } // Found a region to merge into Region + igvn->_worklist.push(r); // Clobber pointer to the now dead 'r' region->set_req(i, phase->C->top()); } @@ -449,6 +450,7 @@ // Remove TOP or NULL input paths. If only 1 input path remains, this Region // degrades to a copy. bool add_to_worklist = false; + bool modified = false; int cnt = 0; // Count of values merging DEBUG_ONLY( int cnt_orig = req(); ) // Save original inputs count int del_it = 0; // The last input path we delete @@ -459,6 +461,7 @@ // Remove useless control copy inputs if( n->is_Region() && n->as_Region()->is_copy() ) { set_req(i, n->nonnull_req()); + modified = true; i--; continue; } @@ -466,12 +469,14 @@ Node *call = n->in(0); if (call->is_Call() && call->as_Call()->entry_point() == OptoRuntime::rethrow_stub()) { set_req(i, call->in(0)); + modified = true; i--; continue; } } if( phase->type(n) == Type::TOP ) { set_req(i, NULL); // Ignore TOP inputs + modified = true; i--; continue; } @@ -691,7 +696,7 @@ } } - return NULL; + return modified ? this : NULL; } diff -r 54911b14d5ee -r f43b5dab2dd3 hotspot/src/share/vm/opto/compile.cpp --- a/hotspot/src/share/vm/opto/compile.cpp Fri Jul 25 09:44:53 2014 +0000 +++ b/hotspot/src/share/vm/opto/compile.cpp Fri Jul 25 10:57:57 2014 +0000 @@ -1039,6 +1039,7 @@ _node_note_array = NULL; _default_node_notes = NULL; + DEBUG_ONLY( _modified_nodes = NULL; ) // Used in Optimize() _immutable_memory = NULL; // filled in at first inquiry @@ -1247,6 +1248,18 @@ } } } +void Compile::record_modified_node(Node* n) { + if (_modified_nodes != NULL && !_inlining_incrementally && + n->outcnt() != 0 && !n->is_Con()) { + _modified_nodes->push(n); + } +} + +void Compile::remove_modified_node(Node* n) { + if (_modified_nodes != NULL) { + _modified_nodes->remove(n); + } +} #endif #ifndef PRODUCT @@ -2035,6 +2048,9 @@ // Iterative Global Value Numbering, including ideal transforms // Initialize IterGVN with types and values from parse-time GVN PhaseIterGVN igvn(initial_gvn()); +#ifdef ASSERT + _modified_nodes = new (comp_arena()) Unique_Node_List(comp_arena()); +#endif { NOT_PRODUCT( TracePhase t2("iterGVN", &_t_iterGVN, TimeCompiler); ) igvn.optimize(); @@ -2197,6 +2213,7 @@ } } + DEBUG_ONLY( _modified_nodes = NULL; ) } // (End scope of igvn; run destructor if necessary for asserts.) process_print_inlining(); @@ -4031,6 +4048,7 @@ int j = 0; int identical = 0; int i = 0; + bool modified = false; for (; i < _expensive_nodes->length()-1; i++) { assert(j <= i, "can't write beyond current index"); if (_expensive_nodes->at(i)->Opcode() == _expensive_nodes->at(i+1)->Opcode()) { @@ -4043,20 +4061,23 @@ identical = 0; } else { Node* n = _expensive_nodes->at(i); - igvn.hash_delete(n); - n->set_req(0, NULL); + igvn.replace_input_of(n, 0, NULL); igvn.hash_insert(n); + modified = true; } } if (identical > 0) { _expensive_nodes->at_put(j++, _expensive_nodes->at(i)); } else if (_expensive_nodes->length() >= 1) { Node* n = _expensive_nodes->at(i); - igvn.hash_delete(n); - n->set_req(0, NULL); + igvn.replace_input_of(n, 0, NULL); igvn.hash_insert(n); + modified = true; } _expensive_nodes->trunc_to(j); + if (modified) { + igvn.optimize(); + } } void Compile::add_expensive_node(Node * n) { diff -r 54911b14d5ee -r f43b5dab2dd3 hotspot/src/share/vm/opto/compile.hpp --- a/hotspot/src/share/vm/opto/compile.hpp Fri Jul 25 09:44:53 2014 +0000 +++ b/hotspot/src/share/vm/opto/compile.hpp Fri Jul 25 10:57:57 2014 +0000 @@ -344,6 +344,8 @@ VectorSet _dead_node_list; // Set of dead nodes uint _dead_node_count; // Number of dead nodes; VectorSet::Size() is O(N). // So use this to keep count and make the call O(1). + DEBUG_ONLY( Unique_Node_List* _modified_nodes; ) // List of nodes which inputs were modified + debug_only(static int _debug_idx;) // Monotonic counter (not reset), use -XX:BreakAtNode= Arena _node_arena; // Arena for new-space Nodes Arena _old_arena; // Arena for old-space Nodes, lifetime during xform @@ -766,6 +768,11 @@ void print_missing_nodes(); #endif + // Record modified nodes to check that they are put on IGVN worklist + void record_modified_node(Node* n) NOT_DEBUG_RETURN; + void remove_modified_node(Node* n) NOT_DEBUG_RETURN; + DEBUG_ONLY( Unique_Node_List* modified_nodes() const { return _modified_nodes; } ) + // Constant table ConstantTable& constant_table() { return _constant_table; } diff -r 54911b14d5ee -r f43b5dab2dd3 hotspot/src/share/vm/opto/divnode.cpp --- a/hotspot/src/share/vm/opto/divnode.cpp Fri Jul 25 09:44:53 2014 +0000 +++ b/hotspot/src/share/vm/opto/divnode.cpp Fri Jul 25 10:57:57 2014 +0000 @@ -479,7 +479,10 @@ if (i == 0) return NULL; // Dividing by zero constant does not idealize - set_req(0,NULL); // Dividing by a not-zero constant; no faulting + if (in(0) != NULL) { + phase->igvn_rehash_node_delayed(this); + set_req(0, NULL); // Dividing by a not-zero constant; no faulting + } // Dividing by MININT does not optimize as a power-of-2 shift. if( i == min_jint ) return NULL; @@ -578,7 +581,10 @@ if (l == 0) return NULL; // Dividing by zero constant does not idealize - set_req(0,NULL); // Dividing by a not-zero constant; no faulting + if (in(0) != NULL) { + phase->igvn_rehash_node_delayed(this); + set_req(0, NULL); // Dividing by a not-zero constant; no faulting + } // Dividing by MINLONG does not optimize as a power-of-2 shift. if( l == min_jlong ) return NULL; diff -r 54911b14d5ee -r f43b5dab2dd3 hotspot/src/share/vm/opto/loopPredicate.cpp --- a/hotspot/src/share/vm/opto/loopPredicate.cpp Fri Jul 25 09:44:53 2014 +0000 +++ b/hotspot/src/share/vm/opto/loopPredicate.cpp Fri Jul 25 10:57:57 2014 +0000 @@ -107,8 +107,7 @@ rgn = new RegionNode(1); rgn->add_req(uncommon_proj); register_control(rgn, loop, uncommon_proj); - _igvn.hash_delete(call); - call->set_req(0, rgn); + _igvn.replace_input_of(call, 0, rgn); // When called from beautify_loops() idom is not constructed yet. if (_idom != NULL) { set_idom(call, rgn, dom_depth(rgn)); @@ -166,8 +165,7 @@ if (new_entry == NULL) { // Attach if_cont to iff - _igvn.hash_delete(iff); - iff->set_req(0, if_cont); + _igvn.replace_input_of(iff, 0, if_cont); if (_idom != NULL) { set_idom(iff, if_cont, dom_depth(iff)); } @@ -194,8 +192,7 @@ rgn = new RegionNode(1); register_new_node_with_optimizer(rgn); rgn->add_req(uncommon_proj); - hash_delete(call); - call->set_req(0, rgn); + replace_input_of(call, 0, rgn); } else { // Find region's edge corresponding to uncommon_proj for (; proj_index < rgn->req(); proj_index++) diff -r 54911b14d5ee -r f43b5dab2dd3 hotspot/src/share/vm/opto/loopTransform.cpp --- a/hotspot/src/share/vm/opto/loopTransform.cpp Fri Jul 25 09:44:53 2014 +0000 +++ b/hotspot/src/share/vm/opto/loopTransform.cpp Fri Jul 25 10:57:57 2014 +0000 @@ -924,15 +924,13 @@ if( bol->outcnt() != 1 ) { bol = bol->clone(); register_new_node(bol,main_end->in(CountedLoopEndNode::TestControl)); - _igvn.hash_delete(main_end); - main_end->set_req(CountedLoopEndNode::TestValue, bol); + _igvn.replace_input_of(main_end, CountedLoopEndNode::TestValue, bol); } // Need only 1 user of 'cmp' because I will be hacking the loop bounds. if( cmp->outcnt() != 1 ) { cmp = cmp->clone(); register_new_node(cmp,main_end->in(CountedLoopEndNode::TestControl)); - _igvn.hash_delete(bol); - bol->set_req(1, cmp); + _igvn.replace_input_of(bol, 1, cmp); } //------------------------------ @@ -1118,8 +1116,7 @@ Node* pre_bol = pre_end->in(CountedLoopEndNode::TestValue)->as_Bool(); BoolNode* new_bol0 = new BoolNode(pre_bol->in(1), new_test); register_new_node( new_bol0, pre_head->in(0) ); - _igvn.hash_delete(pre_end); - pre_end->set_req(CountedLoopEndNode::TestValue, new_bol0); + _igvn.replace_input_of(pre_end, CountedLoopEndNode::TestValue, new_bol0); // Modify main loop guard condition assert(min_iff->in(CountedLoopEndNode::TestValue) == min_bol, "guard okay"); BoolNode* new_bol1 = new BoolNode(min_bol->in(1), new_test); @@ -1130,8 +1127,7 @@ BoolNode* main_bol = main_end->in(CountedLoopEndNode::TestValue)->as_Bool(); BoolNode* new_bol2 = new BoolNode(main_bol->in(1), new_test); register_new_node( new_bol2, main_end->in(CountedLoopEndNode::TestControl) ); - _igvn.hash_delete(main_end); - main_end->set_req(CountedLoopEndNode::TestValue, new_bol2); + _igvn.replace_input_of(main_end, CountedLoopEndNode::TestValue, new_bol2); } // Flag main loop @@ -1346,8 +1342,7 @@ Node* bol2 = loop_end->in(1)->clone(); bol2->set_req(1, cmp2); register_new_node(bol2, ctrl2); - _igvn.hash_delete(loop_end); - loop_end->set_req(1, bol2); + _igvn.replace_input_of(loop_end, 1, bol2); } // Step 3: Find the min-trip test guaranteed before a 'main' loop. // Make it a 1-trip test (means at least 2 trips). @@ -1356,8 +1351,7 @@ // can edit it's inputs directly. Hammer in the new limit for the // minimum-trip guard. assert(opaq->outcnt() == 1, ""); - _igvn.hash_delete(opaq); - opaq->set_req(1, new_limit); + _igvn.replace_input_of(opaq, 1, new_limit); } // Adjust max trip count. The trip count is intentionally rounded @@ -1407,8 +1401,7 @@ register_new_node( cmp2, ctrl2 ); Node *bol2 = new BoolNode( cmp2, loop_end->test_trip() ); register_new_node( bol2, ctrl2 ); - _igvn.hash_delete(loop_end); - loop_end->set_req(CountedLoopEndNode::TestValue, bol2); + _igvn.replace_input_of(loop_end, CountedLoopEndNode::TestValue, bol2); // Step 3: Find the min-trip test guaranteed before a 'main' loop. // Make it a 1-trip test (means at least 2 trips). @@ -1997,8 +1990,7 @@ : (Node*)new MaxINode(pre_limit, orig_limit); register_new_node(pre_limit, pre_ctrl); } - _igvn.hash_delete(pre_opaq); - pre_opaq->set_req(1, pre_limit); + _igvn.replace_input_of(pre_opaq, 1, pre_limit); // Note:: we are making the main loop limit no longer precise; // need to round up based on stride. diff -r 54911b14d5ee -r f43b5dab2dd3 hotspot/src/share/vm/opto/loopnode.cpp --- a/hotspot/src/share/vm/opto/loopnode.cpp Fri Jul 25 09:44:53 2014 +0000 +++ b/hotspot/src/share/vm/opto/loopnode.cpp Fri Jul 25 10:57:57 2014 +0000 @@ -133,7 +133,7 @@ // Return earliest legal location assert(early == find_non_split_ctrl(early), "unexpected early control"); - if (n->is_expensive()) { + if (n->is_expensive() && !_verify_only && !_verify_me) { assert(n->in(0), "should have control input"); early = get_early_ctrl_for_expensive(n, early); } @@ -226,8 +226,7 @@ } if (ctl != n->in(0)) { - _igvn.hash_delete(n); - n->set_req(0, ctl); + _igvn.replace_input_of(n, 0, ctl); _igvn.hash_insert(n); } @@ -521,8 +520,7 @@ assert(check_iff->in(1)->Opcode() == Op_Conv2B && check_iff->in(1)->in(1)->Opcode() == Op_Opaque1, ""); Node* opq = check_iff->in(1)->in(1); - _igvn.hash_delete(opq); - opq->set_req(1, bol); + _igvn.replace_input_of(opq, 1, bol); // Update ctrl. set_ctrl(opq, check_iff->in(0)); set_ctrl(check_iff->in(1), check_iff->in(0)); @@ -690,7 +688,7 @@ incr->set_req(2,stride); incr = _igvn.register_new_node_with_optimizer(incr); set_early_ctrl( incr ); - _igvn.hash_delete(phi); + _igvn.rehash_node_delayed(phi); phi->set_req_X( LoopNode::LoopBackControl, incr, &_igvn ); // If phi type is more restrictive than Int, raise to @@ -743,8 +741,8 @@ iffalse = iff2; iftrue = ift2; } else { - _igvn.hash_delete(iffalse); - _igvn.hash_delete(iftrue); + _igvn.rehash_node_delayed(iffalse); + _igvn.rehash_node_delayed(iftrue); iffalse->set_req_X( 0, le, &_igvn ); iftrue ->set_req_X( 0, le, &_igvn ); } @@ -1257,6 +1255,7 @@ _head->del_req(i); } } + igvn.rehash_node_delayed(_head); // Transform landing pad igvn.register_new_node_with_optimizer(landing_pad, _head); // Insert landing pad into the header @@ -1397,7 +1396,7 @@ igvn.register_new_node_with_optimizer(r, _head); // Plug region into end of loop _head, followed by hot_tail while( _head->req() > 3 ) _head->del_req( _head->req()-1 ); - _head->set_req(2, r); + igvn.replace_input_of(_head, 2, r); if( hot_idx ) _head->add_req(hot_tail); // Split all the Phis up between '_head' loop and the Region 'r' @@ -1419,7 +1418,7 @@ igvn.register_new_node_with_optimizer(phi, n); // Add the merge phi to the old Phi while( n->req() > 3 ) n->del_req( n->req()-1 ); - n->set_req(2, phi); + igvn.replace_input_of(n, 2, phi); if( hot_idx ) n->add_req(hot_phi); } } @@ -1495,13 +1494,14 @@ if( fall_in_cnt > 1 ) { // Since I am just swapping inputs I do not need to update def-use info Node *tmp = _head->in(1); + igvn.rehash_node_delayed(_head); _head->set_req( 1, _head->in(fall_in_cnt) ); _head->set_req( fall_in_cnt, tmp ); // Swap also all Phis for (DUIterator_Fast imax, i = _head->fast_outs(imax); i < imax; i++) { Node* phi = _head->fast_out(i); if( phi->is_Phi() ) { - igvn.hash_delete(phi); // Yank from hash before hacking edges + igvn.rehash_node_delayed(phi); // Yank from hash before hacking edges tmp = phi->in(1); phi->set_req( 1, phi->in(fall_in_cnt) ); phi->set_req( fall_in_cnt, tmp ); @@ -2905,6 +2905,7 @@ uint k = 0; // Probably cfg->in(0) while( cfg->in(k) != m ) k++; // But check incase cfg is a Region cfg->set_req( k, if_t ); // Now point to NeverBranch + _igvn._worklist.push(cfg); // Now create the never-taken loop exit Node *if_f = new CProjNode( iff, 1 ); diff -r 54911b14d5ee -r f43b5dab2dd3 hotspot/src/share/vm/opto/loopopts.cpp --- a/hotspot/src/share/vm/opto/loopopts.cpp Fri Jul 25 09:44:53 2014 +0000 +++ b/hotspot/src/share/vm/opto/loopopts.cpp Fri Jul 25 10:57:57 2014 +0000 @@ -2574,7 +2574,7 @@ 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); + _igvn.replace_input_of(first_not_peeled, 0, new_head); set_loop(new_head, loop); loop->_body.push(new_head); not_peel.set(new_head->_idx); diff -r 54911b14d5ee -r f43b5dab2dd3 hotspot/src/share/vm/opto/macro.cpp --- a/hotspot/src/share/vm/opto/macro.cpp Fri Jul 25 09:44:53 2014 +0000 +++ b/hotspot/src/share/vm/opto/macro.cpp Fri Jul 25 10:57:57 2014 +0000 @@ -855,6 +855,7 @@ int start = jvms->debug_start(); int end = jvms->debug_end(); sfpt->replace_edges_in_range(res, sobj, start, end); + _igvn._worklist.push(sfpt); safepoints_done.append_if_missing(sfpt); // keep it for rollback } return true; @@ -1775,6 +1776,7 @@ Node *pf_region = new RegionNode(3); Node *pf_phi_rawmem = new PhiNode( pf_region, Type::MEMORY, TypeRawPtr::BOTTOM ); + transform_later(pf_region); // Generate several prefetch instructions. uint lines = (length != NULL) ? AllocatePrefetchLines : AllocateInstancePrefetchLines; diff -r 54911b14d5ee -r f43b5dab2dd3 hotspot/src/share/vm/opto/memnode.cpp --- a/hotspot/src/share/vm/opto/memnode.cpp Fri Jul 25 09:44:53 2014 +0000 +++ b/hotspot/src/share/vm/opto/memnode.cpp Fri Jul 25 10:57:57 2014 +0000 @@ -1471,6 +1471,7 @@ Node* ctrl = in(MemNode::Control); Node* address = in(MemNode::Address); + bool progress = false; // Skip up past a SafePoint control. Cannot do this for Stores because // pointer stores & cardmarks must stay on the same side of a SafePoint. @@ -1478,6 +1479,7 @@ phase->C->get_alias_index(phase->type(address)->is_ptr()) != Compile::AliasIdxRaw ) { ctrl = ctrl->in(0); set_req(MemNode::Control,ctrl); + progress = true; } intptr_t ignore = 0; @@ -1490,6 +1492,7 @@ && all_controls_dominate(base, phase->C->start())) { // A method-invariant, non-null address (constant or 'this' argument). set_req(MemNode::Control, NULL); + progress = true; } } @@ -1550,7 +1553,7 @@ } } - return NULL; // No further progress + return progress ? this : NULL; } // Helper to recognize certain Klass fields which are invariant across @@ -2944,6 +2947,7 @@ return NULL; } + bool progress = false; // Eliminate volatile MemBars for scalar replaced objects. if (can_reshape && req() == (Precedent+1)) { bool eliminate = false; @@ -2966,6 +2970,7 @@ phase->is_IterGVN()->_worklist.push(my_mem); // remove dead node later my_mem = NULL; } + progress = true; } if (my_mem != NULL && my_mem->is_Mem()) { const TypeOopPtr* t_oop = my_mem->in(MemNode::Address)->bottom_type()->isa_oopptr(); @@ -2995,7 +3000,7 @@ return new ConINode(TypeInt::ZERO); } } - return NULL; + return progress ? this : NULL; } //------------------------------Value------------------------------------------ @@ -3497,6 +3502,7 @@ // if it redundantly stored the same value (or zero to fresh memory). // In any case, wire it in: + phase->igvn_rehash_node_delayed(this); set_req(i, new_st); // The caller may now kill the old guy. diff -r 54911b14d5ee -r f43b5dab2dd3 hotspot/src/share/vm/opto/node.cpp --- a/hotspot/src/share/vm/opto/node.cpp Fri Jul 25 09:44:53 2014 +0000 +++ b/hotspot/src/share/vm/opto/node.cpp Fri Jul 25 10:57:57 2014 +0000 @@ -620,6 +620,7 @@ *(address*)this = badAddress; // smash the C++ vtbl, probably _in = _out = (Node**) badAddress; _max = _cnt = _outmax = _outcnt = 0; + compile->remove_modified_node(this); #endif } @@ -765,6 +766,7 @@ if (n != NULL) n->del_out((Node *)this); _in[idx] = in(--_cnt); // Compact the array _in[_cnt] = NULL; // NULL out emptied slot + Compile::current()->record_modified_node(this); } //------------------------------del_req_ordered-------------------------------- @@ -780,6 +782,7 @@ Copy::conjoint_words_to_lower((HeapWord*)&_in[idx+1], (HeapWord*)&_in[idx], ((_cnt-idx-1)*sizeof(Node*))); } _in[--_cnt] = NULL; // NULL out emptied slot + Compile::current()->record_modified_node(this); } //------------------------------ins_req---------------------------------------- @@ -1297,6 +1300,7 @@ // Done with outputs. igvn->hash_delete(dead); igvn->_worklist.remove(dead); + igvn->C->remove_modified_node(dead); igvn->set_type(dead, Type::TOP); if (dead->is_macro()) { igvn->C->remove_macro_node(dead); diff -r 54911b14d5ee -r f43b5dab2dd3 hotspot/src/share/vm/opto/node.hpp --- a/hotspot/src/share/vm/opto/node.hpp Fri Jul 25 09:44:53 2014 +0000 +++ b/hotspot/src/share/vm/opto/node.hpp Fri Jul 25 10:57:57 2014 +0000 @@ -398,6 +398,7 @@ if (*p != NULL) (*p)->del_out((Node *)this); (*p) = n; if (n != NULL) n->add_out((Node *)this); + Compile::current()->record_modified_node(this); } // Light version of set_req() to init inputs after node creation. void init_req( uint i, Node *n ) { @@ -409,6 +410,7 @@ assert( _in[i] == NULL, "sanity"); _in[i] = n; if (n != NULL) n->add_out((Node *)this); + Compile::current()->record_modified_node(this); } // Find first occurrence of n among my edges: int find_edge(Node* n); diff -r 54911b14d5ee -r f43b5dab2dd3 hotspot/src/share/vm/opto/phaseX.cpp --- a/hotspot/src/share/vm/opto/phaseX.cpp Fri Jul 25 09:44:53 2014 +0000 +++ b/hotspot/src/share/vm/opto/phaseX.cpp Fri Jul 25 10:57:57 2014 +0000 @@ -933,9 +933,32 @@ for (int i = 0; i < _verify_window_size; i++) { _verify_window[i] = NULL; } +#ifdef ASSERT + // Verify that all modified nodes are on _worklist + Unique_Node_List* modified_list = C->modified_nodes(); + while (modified_list != NULL && modified_list->size()) { + Node* n = modified_list->pop(); + if (n->outcnt() != 0 && !n->is_Con() && !_worklist.member(n)) { + n->dump(); + assert(false, "modified node is not on IGVN._worklist"); + } + } +#endif } void PhaseIterGVN::verify_PhaseIterGVN() { +#ifdef ASSERT + // Verify nodes with changed inputs. + Unique_Node_List* modified_list = C->modified_nodes(); + while (modified_list != NULL && modified_list->size()) { + Node* n = modified_list->pop(); + if (n->outcnt() != 0 && !n->is_Con()) { // skip dead and Con nodes + n->dump(); + assert(false, "modified node was not processed by IGVN.transform_old()"); + } + } +#endif + C->verify_graph_edges(); if( VerifyOpto && allow_progress() ) { // Must turn off allow_progress to enable assert and break recursion @@ -964,6 +987,14 @@ (int) _verify_counter, (int) _verify_full_passes); } } + +#ifdef ASSERT + while (modified_list->size()) { + Node* n = modified_list->pop(); + n->dump(); + assert(false, "VerifyIterativeGVN: new modified node was added"); + } +#endif } #endif /* PRODUCT */ @@ -1066,6 +1097,7 @@ Node* k = n; DEBUG_ONLY(dead_loop_check(k);) DEBUG_ONLY(bool is_new = (k->outcnt() == 0);) + C->remove_modified_node(k); Node* i = k->Ideal(this, /*can_reshape=*/true); assert(i != k || is_new || i->outcnt() > 0, "don't return dead nodes"); #ifndef PRODUCT @@ -1107,6 +1139,7 @@ DEBUG_ONLY(dead_loop_check(k);) // Try idealizing again DEBUG_ONLY(is_new = (k->outcnt() == 0);) + C->remove_modified_node(k); i = k->Ideal(this, /*can_reshape=*/true); assert(i != k || is_new || (i->outcnt() > 0), "don't return dead nodes"); #ifndef PRODUCT @@ -1259,6 +1292,7 @@ _stack.pop(); // Remove dead node from iterative worklist _worklist.remove(dead); + C->remove_modified_node(dead); // Constant node that has no out-edges and has only one in-edge from // root is usually dead. However, sometimes reshaping walk makes // it reachable by adding use edges. So, we will NOT count Con nodes @@ -1288,7 +1322,7 @@ for (DUIterator_Last imin, i = old->last_outs(imin); i >= imin; ) { Node* use = old->last_out(i); // for each use... // use might need re-hashing (but it won't if it's a new node) - bool is_in_table = _table.hash_delete( use ); + rehash_node_delayed(use); // Update use-def info as well // We remove all occurrences of old within use->in, // so as to avoid rehashing any node more than once. @@ -1300,11 +1334,6 @@ ++num_edges; } } - // Insert into GVN hash table if unique - // If a duplicate, 'use' will be cleaned up when pulled off worklist - if( is_in_table ) { - hash_find_insert(use); - } i -= num_edges; // we deleted 1 or more copies of this edge } diff -r 54911b14d5ee -r f43b5dab2dd3 hotspot/src/share/vm/opto/phaseX.hpp --- a/hotspot/src/share/vm/opto/phaseX.hpp Fri Jul 25 09:44:53 2014 +0000 +++ b/hotspot/src/share/vm/opto/phaseX.hpp Fri Jul 25 10:57:57 2014 +0000 @@ -311,6 +311,9 @@ const Type* limit_type) const { ShouldNotCallThis(); return NULL; } + // Delayed node rehash if this is an IGVN phase + virtual void igvn_rehash_node_delayed(Node* n) {} + #ifndef PRODUCT void dump_old2new_map() const; void dump_new( uint new_lidx ) const; @@ -488,6 +491,10 @@ _worklist.push(n); } + void igvn_rehash_node_delayed(Node* n) { + rehash_node_delayed(n); + } + // Replace ith edge of "n" with "in" void replace_input_of(Node* n, int i, Node* in) { rehash_node_delayed(n); diff -r 54911b14d5ee -r f43b5dab2dd3 hotspot/src/share/vm/opto/rootnode.cpp --- a/hotspot/src/share/vm/opto/rootnode.cpp Fri Jul 25 09:44:53 2014 +0000 +++ b/hotspot/src/share/vm/opto/rootnode.cpp Fri Jul 25 10:57:57 2014 +0000 @@ -35,10 +35,12 @@ //------------------------------Ideal------------------------------------------ // Remove dead inputs Node *RootNode::Ideal(PhaseGVN *phase, bool can_reshape) { + bool modified = false; for( uint i = 1; i < req(); i++ ) { // For all inputs // Check for and remove dead inputs if( phase->type(in(i)) == Type::TOP ) { del_req(i--); // Delete TOP inputs + modified = true; } } @@ -56,7 +58,7 @@ // If we want to get the rest of the win later, we should pattern match // simple recursive call trees to closed-form solutions. - return NULL; // No further opportunities exposed + return modified ? this : NULL; } //=============================================================================