diff a/src/hotspot/share/gc/shenandoah/shenandoahNMethod.cpp b/src/hotspot/share/gc/shenandoah/shenandoahNMethod.cpp
--- a/src/hotspot/share/gc/shenandoah/shenandoahNMethod.cpp
+++ b/src/hotspot/share/gc/shenandoah/shenandoahNMethod.cpp
@@ -22,19 +22,20 @@
  * questions.
  *
  */
 
 
+#include "gc/shenandoah/shenandoahBarrierSetAssembler.hpp"
 #include "gc/shenandoah/shenandoahClosures.inline.hpp"
 #include "gc/shenandoah/shenandoahHeap.inline.hpp"
 #include "gc/shenandoah/shenandoahNMethod.inline.hpp"
 #include "memory/resourceArea.hpp"
 #include "runtime/continuation.hpp"
 #include "runtime/safepointVerifiers.hpp"
 
-ShenandoahNMethod::ShenandoahNMethod(nmethod* nm, GrowableArray<oop*>& oops, bool non_immediate_oops) :
-  _nm(nm), _oops(nullptr), _oops_count(0), _unregistered(false), _lock(), _ic_lock() {
+ShenandoahNMethod::ShenandoahNMethod(nmethod* nm, GrowableArray<oop*>& oops, bool non_immediate_oops, GrowableArray<ShenandoahNMethodBarrier>& barriers) :
+  _nm(nm), _oops(nullptr), _oops_count(0), _barriers(nullptr), _barriers_count(0), _unregistered(false), _lock(), _ic_lock() {
 
   if (!oops.is_empty()) {
     _oops_count = oops.length();
     _oops = NEW_C_HEAP_ARRAY(oop*, _oops_count, mtGC);
     for (int c = 0; c < _oops_count; c++) {
@@ -42,24 +43,36 @@
     }
   }
   _has_non_immed_oops = non_immediate_oops;
 
   assert_same_oops();
+
+  if (!barriers.is_empty()) {
+    _barriers_count = barriers.length();
+    _barriers = NEW_C_HEAP_ARRAY(ShenandoahNMethodBarrier, _barriers_count, mtGC);
+    for (int c = 0; c < _barriers_count; c++) {
+      _barriers[c] = barriers.at(c);
+    }
+  }
 }
 
 ShenandoahNMethod::~ShenandoahNMethod() {
   if (_oops != nullptr) {
     FREE_C_HEAP_ARRAY(oop*, _oops);
   }
+  if (_barriers != nullptr) {
+    FREE_C_HEAP_ARRAY(ShenandoahNMethodBarrier, _barriers);
+  }
 }
 
 void ShenandoahNMethod::update() {
   ResourceMark rm;
   bool non_immediate_oops = false;
   GrowableArray<oop*> oops;
+  GrowableArray<ShenandoahNMethodBarrier> barriers;
 
-  detect_reloc_oops(nm(), oops, non_immediate_oops);
+  parse(nm(), oops, non_immediate_oops, barriers);
   if (oops.length() != _oops_count) {
     if (_oops != nullptr) {
       FREE_C_HEAP_ARRAY(oop*, _oops);
       _oops = nullptr;
     }
@@ -76,48 +89,65 @@
   _has_non_immed_oops = non_immediate_oops;
 
   assert_same_oops();
 }
 
-void ShenandoahNMethod::detect_reloc_oops(nmethod* nm, GrowableArray<oop*>& oops, bool& has_non_immed_oops) {
+void ShenandoahNMethod::parse(nmethod* nm, GrowableArray<oop*>& oops, bool& has_non_immed_oops, GrowableArray<ShenandoahNMethodBarrier>& barriers) {
   has_non_immed_oops = false;
-  // Find all oops relocations
   RelocIterator iter(nm);
   while (iter.next()) {
-    if (iter.type() != relocInfo::oop_type) {
-      // Not an oop
-      continue;
-    }
-
-    oop_Relocation* r = iter.oop_reloc();
-    if (!r->oop_is_immediate()) {
-      // Non-immediate oop found
-      has_non_immed_oops = true;
-      continue;
-    }
-
-    oop value = r->oop_value();
-    if (value != nullptr) {
-      oop* addr = r->oop_addr();
-      shenandoah_assert_correct(addr, value);
-      shenandoah_assert_not_in_cset_except(addr, value, ShenandoahHeap::heap()->cancelled_gc());
-      shenandoah_assert_not_forwarded(addr, value);
-      // Non-null immediate oop found. null oops can safely be
-      // ignored since the method will be re-registered if they
-      // are later patched to be non-null.
-      oops.push(addr);
+    switch (iter.type()) {
+      case relocInfo::oop_type: {
+        oop_Relocation* r = iter.oop_reloc();
+        if (!r->oop_is_immediate()) {
+          // Non-immediate oop found
+          has_non_immed_oops = true;
+          break;
+        }
+
+        oop value = r->oop_value();
+        if (value != nullptr) {
+          oop* addr = r->oop_addr();
+          shenandoah_assert_correct(addr, value);
+          shenandoah_assert_not_in_cset_except(addr, value, ShenandoahHeap::heap()->cancelled_gc());
+          shenandoah_assert_not_forwarded(addr, value);
+          // Non-null immediate oop found. null oops can safely be
+          // ignored since the method will be re-registered if they
+          // are later patched to be non-null.
+          oops.push(addr);
+        }
+        break;
+      }
+#ifdef COMPILER2
+      case relocInfo::barrier_type: {
+        assert(ShenandoahGCStateCheckHotpatch, "Who emits these?");
+        barrier_Relocation* r = iter.barrier_reloc();
+
+        ShenandoahNMethodBarrier b;
+        b._pc = r->addr();
+        b._stub_addr = ShenandoahBarrierSetAssembler::parse_stub_address(b._pc);
+        // TODO: Can technically figure out which GC state we care about in this reloc.
+        // b._gc_state_fast_bit = r->format();
+        barriers.push(b);
+        break;
+      }
+#endif
+      default:
+        // We do not care about other relocations.
+        break;
     }
   }
 }
 
 ShenandoahNMethod* ShenandoahNMethod::for_nmethod(nmethod* nm) {
   ResourceMark rm;
   bool non_immediate_oops = false;
   GrowableArray<oop*> oops;
+  GrowableArray<ShenandoahNMethodBarrier> barriers;
 
-  detect_reloc_oops(nm, oops, non_immediate_oops);
-  return new ShenandoahNMethod(nm, oops, non_immediate_oops);
+  parse(nm, oops, non_immediate_oops, barriers);
+  return new ShenandoahNMethod(nm, oops, non_immediate_oops, barriers);
 }
 
 void ShenandoahNMethod::heal_nmethod(nmethod* nm) {
   ShenandoahNMethod* data = gc_data(nm);
   assert(data != nullptr, "Sanity");
@@ -136,10 +166,30 @@
     // In this case, concurrent root phase is skipped and degenerated GC should be
     // followed, where nmethods are disarmed.
   }
 }
 
+void ShenandoahNMethod::update_barriers() {
+#ifdef COMPILER2
+  if (!ShenandoahGCStateCheckHotpatch) {
+    return;
+  }
+
+  ShenandoahHeap* heap = ShenandoahHeap::heap();
+
+  for (int c = 0; c < _barriers_count; c++) {
+    address pc = _barriers[c]._pc;
+    address stub_addr = _barriers[c]._stub_addr;
+    if (heap->is_idle()) {
+      ShenandoahBarrierSetAssembler::patch_branch_to_nop(pc);
+    } else {
+      ShenandoahBarrierSetAssembler::patch_nop_to_branch(pc, stub_addr);
+    }
+  }
+#endif
+}
+
 #ifdef ASSERT
 void ShenandoahNMethod::assert_correct() {
   ShenandoahHeap* heap = ShenandoahHeap::heap();
   for (int c = 0; c < _oops_count; c++) {
     oop *loc = _oops[c];
@@ -204,12 +254,13 @@
     debug_stream.print_cr("recorded oops: %d", _oops_count);
     for (int i = 0; i < _oops_count; i++) {
       debug_stream.print_cr("-> " PTR_FORMAT, p2i(_oops[i]));
     }
     GrowableArray<oop*> check;
+    GrowableArray<ShenandoahNMethodBarrier> barriers;
     bool non_immed;
-    detect_reloc_oops(nm(), check, non_immed);
+    parse(nm(), check, non_immed, barriers);
     debug_stream.print_cr("check oops: %d", check.length());
     for (int i = 0; i < check.length(); i++) {
       debug_stream.print_cr("-> " PTR_FORMAT, p2i(check.at(i)));
     }
     fatal("Must match #detected: %d, #recorded: %d, #total: %d, begin: " PTR_FORMAT ", end: " PTR_FORMAT "\n%s",
@@ -241,19 +292,21 @@
     assert(nm == data->nm(), "Must be same nmethod");
     // Prevent updating a nmethod while concurrent iteration is in progress.
     wait_until_concurrent_iteration_done();
     ShenandoahNMethodLocker data_locker(data->lock());
     data->update();
+    data->update_barriers();
   } else {
     // For a new nmethod, we can safely append it to the list, because
     // concurrent iteration will not touch it.
     data = ShenandoahNMethod::for_nmethod(nm);
     assert(data != nullptr, "Sanity");
     ShenandoahNMethod::attach_gc_data(nm, data);
     ShenandoahLocker locker(&_lock);
     log_register_nmethod(nm);
     append(data);
+    data->update_barriers();
   }
   // Disarm new nmethod
   ShenandoahNMethod::disarm_nmethod(nm);
 }
 
