From 9ec7180f1ebf2ff19b0735f7b1c4fc9b97d632be Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Erik=20=C3=96sterlund?= <eosterlund@openjdk.org>
Date: Tue, 22 Jun 2021 15:20:10 +0000
Subject: [PATCH] 8268524: nmethod::post_compiled_method_load_event racingly
 called on zombie

Reviewed-by: kvn, neliasso, coleenp
---
 src/hotspot/share/code/nmethod.cpp              | 14 ++++++++++++--
 src/hotspot/share/prims/jvmtiCodeBlobEvents.cpp |  6 ++++--
 2 files changed, 16 insertions(+), 4 deletions(-)

diff --git a/src/hotspot/share/code/nmethod.cpp b/src/hotspot/share/code/nmethod.cpp
index de4c93438b4..e2b27e5f4f0 100644
--- a/src/hotspot/share/code/nmethod.cpp
+++ b/src/hotspot/share/code/nmethod.cpp
@@ -1596,8 +1596,18 @@ void nmethod::post_compiled_method_load_event(JvmtiThreadState* state) {
 
   // Don't post this nmethod load event if it is already dying
   // because the sweeper might already be deleting this nmethod.
-  if (is_not_entrant() && can_convert_to_zombie()) {
-    return;
+  {
+    MutexLocker ml(CompiledMethod_lock, Mutex::_no_safepoint_check_flag);
+    // When the nmethod is acquired from the CodeCache iterator, it can racingly become zombie
+    // before this code is called. Filter them out here under the CompiledMethod_lock.
+    if (!is_alive()) {
+      return;
+    }
+    // As for is_alive() nmethods, we also don't want them to racingly become zombie once we
+    // release this lock, so we check that this is not going to be the case.
+    if (is_not_entrant() && can_convert_to_zombie()) {
+      return;
+    }
   }
 
   // This is a bad time for a safepoint.  We don't want
diff --git a/src/hotspot/share/prims/jvmtiCodeBlobEvents.cpp b/src/hotspot/share/prims/jvmtiCodeBlobEvents.cpp
index 7c5138fedbd..8d433ea5dc7 100644
--- a/src/hotspot/share/prims/jvmtiCodeBlobEvents.cpp
+++ b/src/hotspot/share/prims/jvmtiCodeBlobEvents.cpp
@@ -227,8 +227,10 @@ jvmtiError JvmtiCodeBlobEvents::generate_compiled_method_load_events(JvmtiEnv* e
   {
     NoSafepointVerifier nsv;  // safepoints are not safe while collecting methods to post.
     {
-      // Walk the CodeCache notifying for live nmethods, don't release the CodeCache_lock
-      // because the sweeper may be running concurrently.
+      // Walk the CodeCache notifying for live nmethods. We hold the CodeCache_lock
+      // to ensure the iteration is safe and nmethods are not concurrently freed.
+      // However, they may still change states and become !is_alive(). Filtering
+      // those out is done inside of nmethod::post_compiled_method_load_event().
       // Save events to the queue for posting outside the CodeCache_lock.
       MutexLocker mu(java_thread, CodeCache_lock, Mutex::_no_safepoint_check_flag);
       // Iterate over non-profiled and profiled nmethods