--- old/src/share/vm/opto/loopnode.hpp	2016-09-16 09:01:27.920399108 +0200
+++ new/src/share/vm/opto/loopnode.hpp	2016-09-16 09:01:24.300457078 +0200
@@ -1176,6 +1176,7 @@
 #endif
   bool shenandoah_fix_mem_phis(Node* mem, Node* mem_ctrl, Node* rep_ctrl, int alias);
   bool shenandoah_fix_mem_phis_helper(Node* c, Node* mem, Node* mem_ctrl, Node* rep_ctrl, int alias, VectorSet& controls, GrowableArray<Node*>& phis);
+  void try_move_shenandoah_read_barrier(Node* n, Node *n_ctrl);
   Node* shenandoah_dom_mem(Node* mem, Node*& mem_ctrl, Node* n, Node* rep_ctrl, int alias);
   Node* try_move_shenandoah_barrier_before_pre_loop(Node* c, Node* val_ctrl);
   Node* try_move_shenandoah_barrier_before_loop_helper(Node* n, Node* cl,  Node* val_ctrl, Node* mem);
--- old/src/share/vm/opto/loopopts.cpp	2016-09-16 09:01:31.720338255 +0200
+++ new/src/share/vm/opto/loopopts.cpp	2016-09-16 09:01:28.196394688 +0200
@@ -956,6 +956,8 @@
     return res;
   }
 
+  try_move_shenandoah_read_barrier(n, n_ctrl);
+
   // Attempt to remix address expressions for loop invariants
   Node *m = remix_address_expressions( n );
   if( m ) return m;
@@ -1368,7 +1370,7 @@
             // For inner loop uses get the preheader area.
             x_ctrl = place_near_use(x_ctrl);
 
-            if (n->is_Load()) {
+            if (n->is_Load() || n->Opcode() == Op_ShenandoahReadBarrier) {
               // For loads, add a control edge to a CFG node outside of the loop
               // to force them to not combine and return back inside the loop
               // during GVN optimization (4641526).
@@ -1376,7 +1378,9 @@
               // Because we are setting the actual control input, factor in
               // the result from get_late_ctrl() so we respect any
               // anti-dependences. (6233005).
-              x_ctrl = dom_lca(late_load_ctrl, x_ctrl);
+              if (n->is_Load()) {
+                x_ctrl = dom_lca(late_load_ctrl, x_ctrl);
+              }
 
               // Don't allow the control input to be a CFG splitting node.
               // Such nodes should only have ProjNodes as outs, e.g. IfNode
--- old/src/share/vm/opto/shenandoahSupport.cpp	2016-09-16 09:01:36.101268098 +0200
+++ new/src/share/vm/opto/shenandoahSupport.cpp	2016-09-16 09:01:31.983334043 +0200
@@ -170,7 +170,7 @@
   VectorSet visited(Thread::current()->resource_area());
   Node_Stack phis(0);
 
-  for(;;) {
+  for(int i = 0; i < 10; i++) {
     if (current == NULL) {
       return false;
     } else if (visited.test_set(current->_idx) || current->is_top() || current == b1) {
@@ -227,8 +227,31 @@
       return false;
     }
   }
+  return false;
+}
+
+bool ShenandoahReadBarrierNode::is_independent(Node* mem) {
+  if (mem->is_Phi() || mem->is_Proj() || mem->is_MergeMem()) {
+    return true;
+  } else if (mem->Opcode() == Op_ShenandoahWriteBarrier) {
+    const Type* mem_type = mem->bottom_type();
+    const Type* this_type = bottom_type();
+    if (is_independent(mem_type, this_type)) {
+      return true;
+    } else {
+      return false;
+    }
+  } else if (mem->is_Call() || mem->is_MemBar()) {
+    return false;
+  }
+#ifdef ASSERT
+  mem->dump();
+#endif
+  ShouldNotReachHere();
+  return true;
 }
 
+
 bool ShenandoahReadBarrierNode::dominates_memory_rb(PhaseGVN* phase, Node* b1, Node* b2, bool linear) {
   return dominates_memory_rb_impl(phase, b1->in(Memory), b2, b2->in(Memory), linear);
 }
@@ -2243,3 +2266,126 @@
   }
   return NULL;
 }
+
+void PhaseIdealLoop::try_move_shenandoah_read_barrier(Node* n, Node *n_ctrl) {
+  if (n->Opcode() == Op_ShenandoahReadBarrier) {
+    ShenandoahReadBarrierNode* rb = (ShenandoahReadBarrierNode*)n;
+    Node* mem = n->in(MemNode::Memory);
+    int alias = C->get_alias_index(n->adr_type());
+    const bool trace = false;
+
+#ifdef ASSERT
+    if (trace) { tty->print("Trying to move mem of"); n->dump(); }
+#endif
+
+    Node* new_mem = mem;
+
+    ResourceMark rm;
+    VectorSet seen(Thread::current()->resource_area());
+    Node_List phis;
+
+    for (;;) {
+#ifdef ASSERT
+      if (trace) { tty->print("Looking for dominator from"); mem->dump(); }
+#endif
+      if (mem->is_Proj() && mem->in(0)->is_Start()) {
+        if (new_mem != n->in(MemNode::Memory)) {
+#ifdef ASSERT
+          if (trace) { tty->print("XXX Setting mem to"); new_mem->dump(); tty->print(" for "); n->dump(); }
+#endif
+          _igvn.replace_input_of(n, MemNode::Memory, new_mem);
+        }
+        return;
+      }
+
+      Node* candidate = mem;
+      do {
+        if (!rb->is_independent(mem)) {
+          if (trace) { tty->print_cr("Not independent"); }
+          if (new_mem != n->in(MemNode::Memory)) {
+#ifdef ASSERT
+            if (trace) { tty->print("XXX Setting mem to"); new_mem->dump(); tty->print(" for "); n->dump(); }
+#endif
+            _igvn.replace_input_of(n, MemNode::Memory, new_mem);
+          }
+          return;
+        }
+        if (seen.test_set(mem->_idx)) {
+          if (trace) { tty->print_cr("Already seen"); }
+          ShouldNotReachHere();
+          // Strange graph
+          if (new_mem != n->in(MemNode::Memory)) {
+#ifdef ASSERT
+            if (trace) { tty->print("XXX Setting mem to"); new_mem->dump(); tty->print(" for "); n->dump(); }
+#endif
+            _igvn.replace_input_of(n, MemNode::Memory, new_mem);
+          }
+          return;
+        }
+        if (mem->is_Phi()) {
+          phis.push(mem);
+        }
+        mem = shenandoah_next_mem(mem, alias);
+        if (mem->bottom_type() == Type::MEMORY) {
+          candidate = mem;
+        }
+        assert(shenandoah_is_dominator(ctrl_or_self(mem), n_ctrl, mem, n) == is_dominator(ctrl_or_self(mem), n_ctrl), "strange dominator");
+#ifdef ASSERT
+        if (trace) { tty->print("Next mem is"); mem->dump(); }
+#endif
+      } while (mem->bottom_type() != Type::MEMORY || !is_dominator(ctrl_or_self(mem), n_ctrl));
+
+      assert(mem->bottom_type() == Type::MEMORY, "bad mem");
+
+      bool not_dom = false;
+      for (uint i = 0; i < phis.size() && !not_dom; i++) {
+        Node* nn = phis.at(i);
+      
+#ifdef ASSERT
+        if (trace) { tty->print("Looking from phi"); nn->dump(); }
+#endif
+        assert(nn->is_Phi(), "phis only");
+        for (uint j = 2; j < nn->req() && !not_dom; j++) {
+          Node* m = nn->in(j);
+#ifdef ASSERT
+          if (trace) { tty->print("Input %d is", j); m->dump(); }
+#endif
+          while (m != mem && !seen.test_set(m->_idx)) {
+            if (shenandoah_is_dominator(ctrl_or_self(m), ctrl_or_self(mem), m, mem)) {
+              not_dom = true;
+              // Scheduling anomaly
+#ifdef ASSERT
+              if (trace) { tty->print("Giving up"); m->dump(); }
+#endif
+              break;
+            }
+            if (!rb->is_independent(m)) {
+              if (trace) { tty->print_cr("Not independent"); }
+              if (new_mem != n->in(MemNode::Memory)) {
+#ifdef ASSERT
+                if (trace) { tty->print("XXX Setting mem to"); new_mem->dump(); tty->print(" for "); n->dump(); }
+#endif
+                _igvn.replace_input_of(n, MemNode::Memory, new_mem);
+              }
+              return;
+            }
+            if (m->is_Phi()) {
+              phis.push(m);
+            }
+            m = shenandoah_next_mem(m, alias);
+#ifdef ASSERT
+            if (trace) { tty->print("Next mem is"); m->dump(); }
+#endif
+          }
+        }
+      }
+      if (!not_dom) {
+        new_mem = mem;
+        phis.clear();
+      } else {
+        seen.Clear();
+      }
+    }
+  }
+}
+
--- old/src/share/vm/opto/shenandoahSupport.hpp	2016-09-16 09:01:40.598196083 +0200
+++ new/src/share/vm/opto/shenandoahSupport.hpp	2016-09-16 09:01:36.379263646 +0200
@@ -134,6 +134,8 @@
   virtual Node* Identity(PhaseGVN* phase);
   virtual int Opcode() const;
 
+  bool is_independent(Node* mem);
+
 private:
   static bool is_independent(const Type* in_type, const Type* this_type);
   static bool dominates_memory_rb(PhaseGVN* phase, Node* b1, Node* b2, bool linear);