8040213: C2 does not put all modified nodes on IGVN worklist
authorthartmann
Fri, 25 Jul 2014 10:06:17 +0200
changeset 25913 81dbc151e91c
parent 25742 07bedc8d1893
child 25914 ad0233fa8767
8040213: C2 does not put all modified nodes on IGVN worklist Summary: Verification code is added that checks if modified nodes are put on the IGVN worklist and modified nodes are processed by 'PhaseIterGVN::transform_old()' Reviewed-by: kvn, jrose
hotspot/src/share/vm/opto/cfgnode.cpp
hotspot/src/share/vm/opto/compile.cpp
hotspot/src/share/vm/opto/compile.hpp
hotspot/src/share/vm/opto/divnode.cpp
hotspot/src/share/vm/opto/loopPredicate.cpp
hotspot/src/share/vm/opto/loopTransform.cpp
hotspot/src/share/vm/opto/loopnode.cpp
hotspot/src/share/vm/opto/loopopts.cpp
hotspot/src/share/vm/opto/macro.cpp
hotspot/src/share/vm/opto/memnode.cpp
hotspot/src/share/vm/opto/node.cpp
hotspot/src/share/vm/opto/node.hpp
hotspot/src/share/vm/opto/phaseX.cpp
hotspot/src/share/vm/opto/phaseX.hpp
hotspot/src/share/vm/opto/rootnode.cpp
--- a/hotspot/src/share/vm/opto/cfgnode.cpp	Fri Jul 18 09:04:01 2014 +0200
+++ b/hotspot/src/share/vm/opto/cfgnode.cpp	Fri Jul 25 10:06:17 2014 +0200
@@ -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;
 }
 
 
--- a/hotspot/src/share/vm/opto/compile.cpp	Fri Jul 18 09:04:01 2014 +0200
+++ b/hotspot/src/share/vm/opto/compile.cpp	Fri Jul 25 10:06:17 2014 +0200
@@ -1060,6 +1060,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
 
@@ -1268,6 +1269,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
@@ -2056,6 +2069,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();
@@ -2218,6 +2234,7 @@
     }
   }
 
+  DEBUG_ONLY( _modified_nodes = NULL; )
  } // (End scope of igvn; run destructor if necessary for asserts.)
 
   process_print_inlining();
@@ -4052,6 +4069,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()) {
@@ -4064,20 +4082,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) {
--- a/hotspot/src/share/vm/opto/compile.hpp	Fri Jul 18 09:04:01 2014 +0200
+++ b/hotspot/src/share/vm/opto/compile.hpp	Fri Jul 25 10:06:17 2014 +0200
@@ -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=<idx>
   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; }
 
--- a/hotspot/src/share/vm/opto/divnode.cpp	Fri Jul 18 09:04:01 2014 +0200
+++ b/hotspot/src/share/vm/opto/divnode.cpp	Fri Jul 25 10:06:17 2014 +0200
@@ -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;
--- a/hotspot/src/share/vm/opto/loopPredicate.cpp	Fri Jul 18 09:04:01 2014 +0200
+++ b/hotspot/src/share/vm/opto/loopPredicate.cpp	Fri Jul 25 10:06:17 2014 +0200
@@ -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++)
--- a/hotspot/src/share/vm/opto/loopTransform.cpp	Fri Jul 18 09:04:01 2014 +0200
+++ b/hotspot/src/share/vm/opto/loopTransform.cpp	Fri Jul 25 10:06:17 2014 +0200
@@ -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.
--- a/hotspot/src/share/vm/opto/loopnode.cpp	Fri Jul 18 09:04:01 2014 +0200
+++ b/hotspot/src/share/vm/opto/loopnode.cpp	Fri Jul 25 10:06:17 2014 +0200
@@ -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 );
--- a/hotspot/src/share/vm/opto/loopopts.cpp	Fri Jul 18 09:04:01 2014 +0200
+++ b/hotspot/src/share/vm/opto/loopopts.cpp	Fri Jul 25 10:06:17 2014 +0200
@@ -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);
--- a/hotspot/src/share/vm/opto/macro.cpp	Fri Jul 18 09:04:01 2014 +0200
+++ b/hotspot/src/share/vm/opto/macro.cpp	Fri Jul 25 10:06:17 2014 +0200
@@ -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;
--- a/hotspot/src/share/vm/opto/memnode.cpp	Fri Jul 18 09:04:01 2014 +0200
+++ b/hotspot/src/share/vm/opto/memnode.cpp	Fri Jul 25 10:06:17 2014 +0200
@@ -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.
--- a/hotspot/src/share/vm/opto/node.cpp	Fri Jul 18 09:04:01 2014 +0200
+++ b/hotspot/src/share/vm/opto/node.cpp	Fri Jul 25 10:06:17 2014 +0200
@@ -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);
--- a/hotspot/src/share/vm/opto/node.hpp	Fri Jul 18 09:04:01 2014 +0200
+++ b/hotspot/src/share/vm/opto/node.hpp	Fri Jul 25 10:06:17 2014 +0200
@@ -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);
--- a/hotspot/src/share/vm/opto/phaseX.cpp	Fri Jul 18 09:04:01 2014 +0200
+++ b/hotspot/src/share/vm/opto/phaseX.cpp	Fri Jul 25 10:06:17 2014 +0200
@@ -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
   }
 
--- a/hotspot/src/share/vm/opto/phaseX.hpp	Fri Jul 18 09:04:01 2014 +0200
+++ b/hotspot/src/share/vm/opto/phaseX.hpp	Fri Jul 25 10:06:17 2014 +0200
@@ -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);
--- a/hotspot/src/share/vm/opto/rootnode.cpp	Fri Jul 18 09:04:01 2014 +0200
+++ b/hotspot/src/share/vm/opto/rootnode.cpp	Fri Jul 25 10:06:17 2014 +0200
@@ -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;
 }
 
 //=============================================================================