diff --git a/src/hotspot/cpu/x86/x86_64.ad b/src/hotspot/cpu/x86/x86_64.ad
index 3dad39fe8bf..51a015e25f4 100644
--- a/src/hotspot/cpu/x86/x86_64.ad
+++ b/src/hotspot/cpu/x86/x86_64.ad
@@ -5263,7 +5263,6 @@ instruct loadRange(rRegI dst, memory mem)
 instruct loadP(rRegP dst, memory mem)
 %{
   match(Set dst (LoadP mem));
-  predicate(n->as_Load()->barrier_data() == 0);
 
   ins_cost(125); // XXX
   format %{ "movq    $dst, $mem\t# ptr" %}
@@ -12767,7 +12766,6 @@ instruct compP_rReg(rFlagsRegU cr, rRegP op1, rRegP op2)
 instruct compP_rReg_mem(rFlagsRegU cr, rRegP op1, memory op2)
 %{
   match(Set cr (CmpP op1 (LoadP op2)));
-  predicate(n->in(2)->as_Load()->barrier_data() == 0);
 
   ins_cost(500); // XXX
   format %{ "cmpq    $op1, $op2\t# ptr" %}
@@ -12794,8 +12792,7 @@ instruct compP_rReg_mem(rFlagsRegU cr, rRegP op1, memory op2)
 // and raw pointers have no anti-dependencies.
 instruct compP_mem_rReg(rFlagsRegU cr, rRegP op1, memory op2)
 %{
-  predicate(n->in(2)->in(2)->bottom_type()->reloc() == relocInfo::none &&
-            n->in(2)->as_Load()->barrier_data() == 0);
+  predicate(n->in(2)->in(2)->bottom_type()->reloc() == relocInfo::none);
   match(Set cr (CmpP op1 (LoadP op2)));
 
   format %{ "cmpq    $op1, $op2\t# raw ptr" %}
@@ -12822,8 +12819,7 @@ instruct testP_reg(rFlagsReg cr, rRegP src, immP0 zero)
 // any compare to a zero should be eq/neq.
 instruct testP_mem(rFlagsReg cr, memory op, immP0 zero)
 %{
-  predicate((!UseCompressedOops || (CompressedOops::base() != NULL)) &&
-            n->in(1)->as_Load()->barrier_data() == 0);
+  predicate((!UseCompressedOops || (CompressedOops::base() != NULL)));
   match(Set cr (CmpP (LoadP op) zero));
 
   ins_cost(500); // XXX
@@ -12836,8 +12832,7 @@ instruct testP_mem(rFlagsReg cr, memory op, immP0 zero)
 
 instruct testP_mem_reg0(rFlagsReg cr, memory mem, immP0 zero)
 %{
-  predicate(UseCompressedOops && (CompressedOops::base() == NULL) &&
-            n->in(1)->as_Load()->barrier_data() == 0);
+  predicate(UseCompressedOops && (CompressedOops::base() == NULL));
   match(Set cr (CmpP (LoadP mem) zero));
 
   format %{ "cmpq    R12, $mem\t# ptr (R12_heapbase==0)" %}
diff --git a/src/hotspot/share/gc/g1/c2/g1BarrierSetC2.cpp b/src/hotspot/share/gc/g1/c2/g1BarrierSetC2.cpp
index f599b111908..14be797c23d 100644
--- a/src/hotspot/share/gc/g1/c2/g1BarrierSetC2.cpp
+++ b/src/hotspot/share/gc/g1/c2/g1BarrierSetC2.cpp
@@ -31,10 +31,12 @@
 #include "gc/g1/g1ThreadLocalData.hpp"
 #include "gc/g1/heapRegion.hpp"
 #include "opto/arraycopynode.hpp"
+#include "opto/block.hpp"
 #include "opto/compile.hpp"
 #include "opto/escape.hpp"
 #include "opto/graphKit.hpp"
 #include "opto/idealKit.hpp"
+#include "opto/machnode.hpp"
 #include "opto/macro.hpp"
 #include "opto/rootnode.hpp"
 #include "opto/type.hpp"
@@ -261,7 +263,8 @@ void G1BarrierSetC2::pre_barrier(GraphKit* kit,
 
         // Now get the buffer location we will log the previous value into and store it
         Node *log_addr = __ AddP(no_base, buffer, next_index);
-        __ store(__ ctrl(), log_addr, pre_val, T_OBJECT, Compile::AliasIdxRaw, MemNode::unordered);
+        StoreNode* s = (__ store(__ ctrl(), log_addr, pre_val, T_OBJECT, Compile::AliasIdxRaw, MemNode::unordered))->as_Store();
+        s->set_barrier_data(get_barrier_number());
         // update the index
         __ store(__ ctrl(), index_adr, next_index, index_bt, Compile::AliasIdxRaw, MemNode::unordered);
 
@@ -278,6 +281,133 @@ void G1BarrierSetC2::pre_barrier(GraphKit* kit,
   kit->final_sync(ideal);
 }
 
+void G1BarrierSetC2::increment_barrier_number() const {
+  *reinterpret_cast<int*>(Compile::current()->barrier_set_state()) =*reinterpret_cast<int*>(Compile::current()->barrier_set_state()) + 1;
+}
+
+int G1BarrierSetC2::get_barrier_number() const {
+  return *reinterpret_cast<int*>(Compile::current()->barrier_set_state());
+}
+
+void* G1BarrierSetC2::create_barrier_state(Arena* comp_arena) const {
+  int* result = new (comp_arena) int;
+  *result = 0;
+  return result;
+}
+
+static void verify_block_has_no_safepoint(const Block* block, uint from, uint to) {
+  for (uint i = from; i < to; i++) {
+    if (block->get_node(i)->is_MachSafePoint()) {
+      // Safepoint found. Game over.
+      block->get_node(i)->dump();
+      ShouldNotReachHere();
+    }
+  }
+}
+
+static void verify_block_has_no_safepoint(const Block* block) {
+  verify_block_has_no_safepoint(block, 0, block->number_of_nodes());
+}
+
+static uint block_index(const Block* block, const Node* node) {
+  for (uint j = 0; j < block->number_of_nodes(); ++j) {
+    if (block->get_node(j) == node) {
+      return j;
+    }
+  }
+  ShouldNotReachHere();
+  return 0;
+}
+
+void G1BarrierSetC2::late_barrier_analysis() const {
+  ResourceMark rm;
+  Compile* const C = Compile::current();
+  PhaseCFG* const cfg = C->cfg();
+  Block_List worklist;
+  Node_List barrier_stores;
+  Node_List barrier_loads;
+
+  for (uint i = 0; i < cfg->number_of_blocks(); ++i) {
+    const Block* const block = cfg->get_block(i);
+    for (uint j = 0; j < block->number_of_nodes(); ++j) {
+      const Node* const node = block->get_node(j);
+      if (!node->is_Mach()) {
+        continue;
+      }
+
+      MachNode* const mach = node->as_Mach();
+      switch (mach->ideal_Opcode()) {
+      case Op_LoadP:
+        if (mach->barrier_data() != 0) {
+          barrier_loads.push(mach);
+        }
+        break;
+      case Op_StoreP:
+        if (mach->barrier_data() != 0) {
+          barrier_stores.push(mach);
+        }
+        break;
+
+      default:
+        break;
+      }
+    }
+  }
+
+  for (uint i = 0; i < barrier_loads.size(); i++) {
+    MachNode* const load = barrier_loads.at(i)->as_Mach();
+    const TypePtr* load_adr_type = NULL;
+    intptr_t load_offset = 0;
+    const Node* const load_obj = load->get_base_and_disp(load_offset, load_adr_type);
+    Block* const load_block = cfg->get_block_for_node(load);
+    const uint load_index = block_index(load_block, load);
+    int load_barrier_index = load->barrier_data();
+
+    for (uint j = 0; j < barrier_stores.size(); j++) {
+      MachNode* store = barrier_stores.at(j)->as_Mach();
+      const TypePtr* store_adr_type = NULL;
+      intptr_t store_offset = 0;
+      const Node* store_obj = store->get_base_and_disp(store_offset, store_adr_type);
+      Block* store_block = cfg->get_block_for_node(store);
+      uint store_index = block_index(store_block, store);
+      int store_barrier_index = store->barrier_data();
+
+      if (store_index != load_index) {
+        continue;
+      }
+
+      if (load_block == store_block) {
+        ShouldNotReachHere();
+      } else if (load_block->dominates(store_block)) {
+        // Dominating block? Look around for safepoints
+        ResourceMark rm;
+        Block_List stack;
+        VectorSet visited(Thread::current()->resource_area());
+        stack.push(store_block);
+        verify_block_has_no_safepoint(store_block);
+        while (stack.size() > 0) {
+          Block* block = stack.pop();
+          if (visited.test_set(block->_pre_order)) {
+            continue;
+          }
+          verify_block_has_no_safepoint(block);
+          if (block == load_block) {
+            continue;
+          }
+
+          // Push predecessor blocks
+          for (uint p = 1; p < block->num_preds(); ++p) {
+            Block* pred = cfg->get_block_for_node(block->pred(p));
+            stack.push(pred);
+          }
+        }
+      } else {
+        ShouldNotReachHere();
+      }
+    }
+  }
+}
+
 /*
  * G1 similar to any GC with a Young Generation requires a way to keep track of
  * references from Old Generation to Young Generation to make sure all live
@@ -594,6 +724,10 @@ void G1BarrierSetC2::insert_pre_barrier(GraphKit* kit, Node* base_oop, Node* off
 #undef __
 
 Node* G1BarrierSetC2::load_at_resolved(C2Access& access, const Type* val_type) const {
+  if (access.decorators() & ON_WEAK_OOP_REF) {
+    increment_barrier_number();
+    access.set_barrier_data(get_barrier_number());
+  }
   DecoratorSet decorators = access.decorators();
   Node* adr = access.addr().node();
   Node* obj = access.base();
@@ -646,6 +780,10 @@ Node* G1BarrierSetC2::load_at_resolved(C2Access& access, const Type* val_type) c
     insert_pre_barrier(kit, obj, offset, load, !need_cpu_mem_bar);
   }
 
+  if (access.decorators() & ON_WEAK_OOP_REF) {
+    increment_barrier_number();
+  }
+
   return load;
 }
 
diff --git a/src/hotspot/share/gc/g1/c2/g1BarrierSetC2.hpp b/src/hotspot/share/gc/g1/c2/g1BarrierSetC2.hpp
index 3002daa5cfc..2bab9696217 100644
--- a/src/hotspot/share/gc/g1/c2/g1BarrierSetC2.hpp
+++ b/src/hotspot/share/gc/g1/c2/g1BarrierSetC2.hpp
@@ -83,8 +83,12 @@ protected:
   static const TypeFunc* write_ref_field_post_entry_Type();
 
   virtual Node* load_at_resolved(C2Access& access, const Type* val_type) const;
+  void increment_barrier_number() const;
+  int get_barrier_number() const;
+  void late_barrier_analysis() const;
 
  public:
+  virtual void* create_barrier_state(Arena* comp_arena) const;
   virtual bool is_gc_barrier_node(Node* node) const;
   virtual void eliminate_gc_barrier(PhaseMacroExpand* macro, Node* node) const;
   virtual Node* step_over_gc_barrier(Node* c) const;
