diff --git a/src/hotspot/share/gc/z/zHeapIterator.cpp b/src/hotspot/share/gc/z/zHeapIterator.cpp
index c5f3970ba118c..367e276a35aee 100644
--- a/src/hotspot/share/gc/z/zHeapIterator.cpp
+++ b/src/hotspot/share/gc/z/zHeapIterator.cpp
@@ -126,6 +126,17 @@ class ZHeapIteratorRootOopClosure : public ZRootsIteratorClosure {
     CodeBlobToOopClosure code_cl(this, false /* fix_oop_relocations */);
     thread->oops_do(this, &code_cl);
   }
+
+  virtual ZNMethodEntry nmethod_entry() const {
+    if (ClassUnloading) {
+      // All encountered nmethods should have been "entered" during stack walking
+      return ZNMethodEntry::VerifyDisarmed;
+    } else {
+      // All nmethods are considered roots and will be visited.
+      // Make sure that the unvisited gets fixed and disarmed before proceeding.
+      return ZNMethodEntry::PreBarrier;
+    }
+  }
 };
 
 template <bool VisitReferents>
diff --git a/src/hotspot/share/gc/z/zMark.cpp b/src/hotspot/share/gc/z/zMark.cpp
index 421dc28b348d6..df47f69022820 100644
--- a/src/hotspot/share/gc/z/zMark.cpp
+++ b/src/hotspot/share/gc/z/zMark.cpp
@@ -582,8 +582,9 @@ class ZMarkConcurrentRootsIteratorClosure : public ZRootsIteratorClosure {
     ZThreadLocalAllocBuffer::publish_statistics();
   }
 
-  virtual bool should_disarm_nmethods() const {
-    return true;
+  virtual ZNMethodEntry nmethod_entry() const {
+    // Only apply closure to armed nmethods, and then disarm them.
+    return ZNMethodEntry::Disarm;
   }
 
   virtual void do_thread(Thread* thread) {
diff --git a/src/hotspot/share/gc/z/zNMethod.cpp b/src/hotspot/share/gc/z/zNMethod.cpp
index 16c0ef15d4e8f..dfbf38d1dc0df 100644
--- a/src/hotspot/share/gc/z/zNMethod.cpp
+++ b/src/hotspot/share/gc/z/zNMethod.cpp
@@ -236,28 +236,42 @@ void ZNMethod::nmethod_oops_do(nmethod* nm, OopClosure* cl) {
 
 class ZNMethodToOopsDoClosure : public NMethodClosure {
 private:
-  OopClosure* const _cl;
-  const bool        _should_disarm_nmethods;
+  OopClosure* const        _cl;
+  const ZNMethodEntry      _entry;
+  BarrierSetNMethod* const _bs_nm;
 
 public:
-  ZNMethodToOopsDoClosure(OopClosure* cl, bool should_disarm_nmethods) :
+  ZNMethodToOopsDoClosure(OopClosure* cl, ZNMethodEntry entry) :
       _cl(cl),
-      _should_disarm_nmethods(should_disarm_nmethods) {}
+      _entry(entry),
+      _bs_nm(BarrierSet::barrier_set()->barrier_set_nmethod()) {}
 
   virtual void do_nmethod(nmethod* nm) {
+    if (_entry == ZNMethodEntry::PreBarrier) {
+      // Apply entry barrier before proceeding with closure
+      _bs_nm->nmethod_entry_barrier(nm);
+    }
+
     ZLocker<ZReentrantLock> locker(ZNMethod::lock_for_nmethod(nm));
     if (!nm->is_alive()) {
       return;
     }
 
-    if (_should_disarm_nmethods) {
+    if (_entry == ZNMethodEntry::Disarm) {
+      // Apply closure and disarm only armed nmethods
       if (ZNMethod::is_armed(nm)) {
         ZNMethod::nmethod_oops_do(nm, _cl);
         ZNMethod::disarm(nm);
       }
-    } else {
-      ZNMethod::nmethod_oops_do(nm, _cl);
+      return;
     }
+
+    if (_entry == ZNMethodEntry::VerifyDisarmed) {
+      // Only verify
+      assert(!ZNMethod::is_armed(nm), "Must be disarmed");
+    }
+
+    ZNMethod::nmethod_oops_do(nm, _cl);
   }
 };
 
@@ -269,8 +283,8 @@ void ZNMethod::oops_do_end() {
   ZNMethodTable::nmethods_do_end();
 }
 
-void ZNMethod::oops_do(OopClosure* cl, bool should_disarm_nmethods) {
-  ZNMethodToOopsDoClosure nmethod_cl(cl, should_disarm_nmethods);
+void ZNMethod::oops_do(OopClosure* cl, ZNMethodEntry entry) {
+  ZNMethodToOopsDoClosure nmethod_cl(cl, entry);
   ZNMethodTable::nmethods_do(&nmethod_cl);
 }
 
diff --git a/src/hotspot/share/gc/z/zNMethod.hpp b/src/hotspot/share/gc/z/zNMethod.hpp
index 1b6117b22c6e7..66914f1ff25d9 100644
--- a/src/hotspot/share/gc/z/zNMethod.hpp
+++ b/src/hotspot/share/gc/z/zNMethod.hpp
@@ -31,6 +31,13 @@ class OopClosure;
 class ZReentrantLock;
 class ZWorkers;
 
+enum class ZNMethodEntry {
+  PreBarrier,
+  Disarm,
+  VerifyDisarmed,
+  None
+};
+
 class ZNMethod : public AllStatic {
 private:
   static void attach_gc_data(nmethod* nm);
@@ -52,7 +59,7 @@ class ZNMethod : public AllStatic {
 
   static void oops_do_begin();
   static void oops_do_end();
-  static void oops_do(OopClosure* cl, bool should_disarm_nmethods);
+  static void oops_do(OopClosure* cl, ZNMethodEntry entry);
 
   static ZReentrantLock* lock_for_nmethod(nmethod* nm);
 
diff --git a/src/hotspot/share/gc/z/zOopClosures.hpp b/src/hotspot/share/gc/z/zOopClosures.hpp
index 25984b6cd6fc2..93aede74e5787 100644
--- a/src/hotspot/share/gc/z/zOopClosures.hpp
+++ b/src/hotspot/share/gc/z/zOopClosures.hpp
@@ -57,12 +57,16 @@ class ZPhantomKeepAliveOopClosure : public ZRootsIteratorClosure {
 public:
   virtual void do_oop(oop* p);
   virtual void do_oop(narrowOop* p);
+
+  virtual ZNMethodEntry nmethod_entry() const;
 };
 
 class ZPhantomCleanOopClosure : public ZRootsIteratorClosure {
 public:
   virtual void do_oop(oop* p);
   virtual void do_oop(narrowOop* p);
+
+  virtual ZNMethodEntry nmethod_entry() const;
 };
 
 #endif // SHARE_GC_Z_ZOOPCLOSURES_HPP
diff --git a/src/hotspot/share/gc/z/zOopClosures.inline.hpp b/src/hotspot/share/gc/z/zOopClosures.inline.hpp
index da8f22ff9d8e7..eb9c7ad92fa47 100644
--- a/src/hotspot/share/gc/z/zOopClosures.inline.hpp
+++ b/src/hotspot/share/gc/z/zOopClosures.inline.hpp
@@ -80,6 +80,11 @@ inline void ZPhantomKeepAliveOopClosure::do_oop(oop* p) {
   ZBarrier::keep_alive_barrier_on_phantom_oop_field(p);
 }
 
+inline ZNMethodEntry ZPhantomKeepAliveOopClosure::nmethod_entry() const {
+  ShouldNotReachHere();
+  return ZNMethodEntry::None;
+}
+
 inline void ZPhantomKeepAliveOopClosure::do_oop(narrowOop* p) {
   ShouldNotReachHere();
 }
@@ -104,4 +109,9 @@ inline void ZPhantomCleanOopClosure::do_oop(narrowOop* p) {
   ShouldNotReachHere();
 }
 
+inline ZNMethodEntry ZPhantomCleanOopClosure::nmethod_entry() const {
+  ShouldNotReachHere();
+  return ZNMethodEntry::None;
+}
+
 #endif // SHARE_GC_Z_ZOOPCLOSURES_INLINE_HPP
diff --git a/src/hotspot/share/gc/z/zRootsIterator.cpp b/src/hotspot/share/gc/z/zRootsIterator.cpp
index 5d5e7190c8a5a..3ddda27b8d51d 100644
--- a/src/hotspot/share/gc/z/zRootsIterator.cpp
+++ b/src/hotspot/share/gc/z/zRootsIterator.cpp
@@ -122,7 +122,7 @@ void ZConcurrentRootsIterator::do_class_loader_data_graph(ZRootsIteratorClosure*
 
 void ZConcurrentRootsIterator::do_code_cache(ZRootsIteratorClosure* cl) {
   ZStatTimer timer(ZSubPhaseConcurrentRootsCodeCache);
-  ZNMethod::oops_do(cl, cl->should_disarm_nmethods());
+  ZNMethod::oops_do(cl, cl->nmethod_entry());
 }
 
 class ZConcurrentRootsIteratorThreadClosure : public ThreadClosure {
diff --git a/src/hotspot/share/gc/z/zRootsIterator.hpp b/src/hotspot/share/gc/z/zRootsIterator.hpp
index 87626b09ab117..49e87cd9799dc 100644
--- a/src/hotspot/share/gc/z/zRootsIterator.hpp
+++ b/src/hotspot/share/gc/z/zRootsIterator.hpp
@@ -26,6 +26,7 @@
 
 #include "classfile/classLoaderDataGraph.hpp"
 #include "gc/shared/oopStorageSetParState.hpp"
+#include "gc/z/zNMethod.hpp"
 #include "memory/allocation.hpp"
 #include "memory/iterator.hpp"
 #include "runtime/threadSMR.hpp"
@@ -61,9 +62,7 @@ class ZRootsIteratorClosure : public OopClosure {
 public:
   virtual void do_thread(Thread* thread) {}
 
-  virtual bool should_disarm_nmethods() const {
-    return false;
-  }
+  virtual ZNMethodEntry nmethod_entry() const = 0;
 };
 
 class ZJavaThreadsIterator {
diff --git a/src/hotspot/share/gc/z/zVerify.cpp b/src/hotspot/share/gc/z/zVerify.cpp
index 841cd4cbeacc2..a10d64c1e873e 100644
--- a/src/hotspot/share/gc/z/zVerify.cpp
+++ b/src/hotspot/share/gc/z/zVerify.cpp
@@ -94,6 +94,11 @@ class ZVerifyRootClosure : public ZRootsIteratorClosure {
   bool verify_fixed() const {
     return _verify_fixed;
   }
+
+  virtual ZNMethodEntry nmethod_entry() const {
+    // Verification performs its own verification
+    return ZNMethodEntry::None;
+  }
 };
 
 class ZVerifyCodeBlobClosure : public CodeBlobToOopClosure {
@@ -188,7 +193,7 @@ void ZVerifyRootClosure::do_thread(Thread* thread) {
   verify_stack.verify_frames();
 }
 
-class ZVerifyOopClosure : public ClaimMetadataVisitingOopIterateClosure, public ZRootsIteratorClosure  {
+class ZVerifyOopClosure : public ClaimMetadataVisitingOopIterateClosure {
 private:
   const bool _verify_weaks;