8146612: C2: Precedence edges specification violated

Reviewed-by: kvn
diff --git a/hotspot/src/share/vm/opto/lcm.cpp b/hotspot/src/share/vm/opto/lcm.cpp
index 57614f7..3edfc5e 100644
--- a/hotspot/src/share/vm/opto/lcm.cpp
+++ b/hotspot/src/share/vm/opto/lcm.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1998, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1998, 2016, 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
@@ -949,6 +949,13 @@
         // and the edge will be lost. This is why this code should be
         // executed only when Precedent (== TypeFunc::Parms) edge is present.
         Node *x = n->in(TypeFunc::Parms);
+        if (x != NULL && get_block_for_node(x) == block && n->find_prec_edge(x) != -1) {
+          // Old edge to node within same block will get removed, but no precedence
+          // edge will get added because it already exists. Update ready count.
+          int cnt = ready_cnt.at(n->_idx);
+          assert(cnt > 1, "MemBar node %d must not get ready here", n->_idx);
+          ready_cnt.at_put(n->_idx, cnt-1);
+        }
         n->del_req(TypeFunc::Parms);
         n->add_prec(x);
       }
diff --git a/hotspot/src/share/vm/opto/node.cpp b/hotspot/src/share/vm/opto/node.cpp
index ac09369..433cfaf 100644
--- a/hotspot/src/share/vm/opto/node.cpp
+++ b/hotspot/src/share/vm/opto/node.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2016, 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
@@ -796,8 +796,9 @@
   // First remove corresponding def-use edge
   Node *n = in(idx);
   if (n != NULL) n->del_out((Node *)this);
-  _in[idx] = in(--_cnt);  // Compact the array
-  _in[_cnt] = NULL;       // NULL out emptied slot
+  _in[idx] = in(--_cnt); // Compact the array
+  // Avoid spec violation: Gap in prec edges.
+  close_prec_gap_at(_cnt);
   Compile::current()->record_modified_node(this);
 }
 
@@ -810,10 +811,11 @@
   // First remove corresponding def-use edge
   Node *n = in(idx);
   if (n != NULL) n->del_out((Node *)this);
-  if (idx < _cnt - 1) { // Not last edge ?
-    Copy::conjoint_words_to_lower((HeapWord*)&_in[idx+1], (HeapWord*)&_in[idx], ((_cnt-idx-1)*sizeof(Node*)));
+  if (idx < --_cnt) {    // Not last edge ?
+    Copy::conjoint_words_to_lower((HeapWord*)&_in[idx+1], (HeapWord*)&_in[idx], ((_cnt-idx)*sizeof(Node*)));
   }
-  _in[--_cnt] = NULL;   // NULL out emptied slot
+  // Avoid spec violation: Gap in prec edges.
+  close_prec_gap_at(_cnt);
   Compile::current()->record_modified_node(this);
 }
 
@@ -845,10 +847,12 @@
   uint nrep = 0;
   for (uint i = 0; i < len(); i++) {
     if (in(i) == old) {
-      if (i < req())
+      if (i < req()) {
         set_req(i, neww);
-      else
+      } else {
+        assert(find_prec_edge(neww) == -1, "spec violation: duplicated prec edge (node %d -> %d)", _idx, neww->_idx);
         set_prec(i, neww);
+      }
       nrep++;
     }
   }
@@ -982,24 +986,27 @@
 
   // Find a precedence edge to move
   uint i = _cnt;
-  while( in(i) != NULL ) i++;
+  while( in(i) != NULL ) {
+    if (in(i) == n) return; // Avoid spec violation: duplicated prec edge.
+    i++;
+  }
   _in[i] = n;                                // Stuff prec edge over NULL
   if ( n != NULL) n->add_out((Node *)this);  // Add mirror edge
+
+#ifdef ASSERT
+  while ((++i)<_max) { assert(_in[i] == NULL, "spec violation: Gap in prec edges (node %d)", _idx); }
+#endif
 }
 
 //------------------------------rm_prec----------------------------------------
 // Remove a precedence input.  Precedence inputs are unordered, with
 // duplicates removed and NULLs packed down at the end.
 void Node::rm_prec( uint j ) {
-
-  // Find end of precedence list to pack NULLs
-  uint i;
-  for( i=j; i<_max; i++ )
-    if( !_in[i] )               // Find the NULL at end of prec edge list
-      break;
-  if (_in[j] != NULL) _in[j]->del_out((Node *)this);
-  _in[j] = _in[--i];            // Move last element over removed guy
-  _in[i] = NULL;                // NULL out last element
+  assert(j < _max, "oob: i=%d, _max=%d", j, _max);
+  assert(j >= _cnt, "not a precedence edge");
+  if (_in[j] == NULL) return;   // Avoid spec violation: Gap in prec edges.
+  _in[j]->del_out((Node *)this);
+  close_prec_gap_at(j);
 }
 
 //------------------------------size_of----------------------------------------
diff --git a/hotspot/src/share/vm/opto/node.hpp b/hotspot/src/share/vm/opto/node.hpp
index d737f53..559a449 100644
--- a/hotspot/src/share/vm/opto/node.hpp
+++ b/hotspot/src/share/vm/opto/node.hpp
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 1997, 2015, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 1997, 2016, 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
@@ -423,6 +423,16 @@
   }
   // Find first occurrence of n among my edges:
   int find_edge(Node* n);
+  int find_prec_edge(Node* n) {
+    for (uint i = req(); i < len(); i++) {
+      if (_in[i] == n) return i;
+      if (_in[i] == NULL) {
+        DEBUG_ONLY( while ((++i) < len()) assert(_in[i] == NULL, "Gap in prec edges!"); )
+        break;
+      }
+    }
+    return -1;
+  }
   int replace_edge(Node* old, Node* neww);
   int replace_edges_in_range(Node* old, Node* neww, int start, int end);
   // NULL out all inputs to eliminate incoming Def-Use edges.
@@ -476,6 +486,19 @@
     debug_only(_last_del = n; ++_del_tick);
     #endif
   }
+  // Close gap after removing edge.
+  void close_prec_gap_at(uint gap) {
+    assert(_cnt <= gap && gap < _max, "no valid prec edge");
+    uint i = gap;
+    Node *last = NULL;
+    for (; i < _max-1; ++i) {
+      Node *next = _in[i+1];
+      if (next == NULL) break;
+      last = next;
+    }
+    _in[gap] = last; // Move last slot to empty one.
+    _in[i] = NULL;   // NULL out last slot.
+  }
 
 public:
   // Globally replace this node by a given new node, updating all uses.
@@ -492,13 +515,23 @@
   // Add or remove precedence edges
   void add_prec( Node *n );
   void rm_prec( uint i );
+
+  // Note: prec(i) will not necessarily point to n if edge already exists.
   void set_prec( uint i, Node *n ) {
-    assert( is_not_dead(n), "can not use dead node");
-    assert( i >= _cnt, "not a precedence edge");
+    assert(i < _max, "oob: i=%d, _max=%d", i, _max);
+    assert(is_not_dead(n), "can not use dead node");
+    assert(i >= _cnt, "not a precedence edge");
+    // Avoid spec violation: duplicated prec edge.
+    if (_in[i] == n) return;
+    if (n == NULL || find_prec_edge(n) != -1) {
+      rm_prec(i);
+      return;
+    }
     if (_in[i] != NULL) _in[i]->del_out((Node *)this);
     _in[i] = n;
     if (n != NULL) n->add_out((Node *)this);
   }
+
   // Set this node's index, used by cisc_version to replace current node
   void set_idx(uint new_idx) {
     const node_idx_t* ref = &_idx;