changeset 1790:852d0157c696

6956931: assert(SafepointSynchronize::is_at_safepoint()) failed: must be executed at a safepoint Reviewed-by: kvn, dcubed
author never
date Wed, 02 Jun 2010 14:23:23 -0700
parents 4a2e260bb13a
children ca3dceda776c
files src/share/vm/code/nmethod.cpp src/share/vm/prims/jvmtiExport.cpp src/share/vm/prims/jvmtiExport.hpp
diffstat 3 files changed, 58 insertions(+), 47 deletions(-) [+]
line wrap: on
line diff
--- a/src/share/vm/code/nmethod.cpp	Wed Jun 02 12:02:49 2010 -0700
+++ b/src/share/vm/code/nmethod.cpp	Wed Jun 02 14:23:23 2010 -0700
@@ -1342,19 +1342,7 @@
   // and it hasn't already been reported for this nmethod then report it now.
   // (the event may have been reported earilier if the GC marked it for unloading).
   if (state == zombie) {
-
-    DTRACE_METHOD_UNLOAD_PROBE(method());
-
-    if (JvmtiExport::should_post_compiled_method_unload() &&
-        !unload_reported()) {
-      assert(method() != NULL, "checking");
-      {
-        HandleMark hm;
-        JvmtiExport::post_compiled_method_unload_at_safepoint(
-            method()->jmethod_id(), code_begin());
-      }
-      set_unload_reported();
-    }
+    post_compiled_method_unload();
   }
 
 
@@ -1506,6 +1494,12 @@
 }
 
 void nmethod::post_compiled_method_unload() {
+  if (unload_reported()) {
+    // During unloading we transition to unloaded and then to zombie
+    // and the unloading is reported during the first transition.
+    return;
+  }
+
   assert(_method != NULL && !is_unloaded(), "just checking");
   DTRACE_METHOD_UNLOAD_PROBE(method());
 
@@ -1515,8 +1509,7 @@
   if (JvmtiExport::should_post_compiled_method_unload()) {
     assert(!unload_reported(), "already unloaded");
     HandleMark hm;
-    JvmtiExport::post_compiled_method_unload_at_safepoint(
-                      method()->jmethod_id(), code_begin());
+    JvmtiExport::post_compiled_method_unload(method()->jmethod_id(), code_begin());
   }
 
   // The JVMTI CompiledMethodUnload event can be enabled or disabled at
--- a/src/share/vm/prims/jvmtiExport.cpp	Wed Jun 02 12:02:49 2010 -0700
+++ b/src/share/vm/prims/jvmtiExport.cpp	Wed Jun 02 14:23:23 2010 -0700
@@ -726,6 +726,32 @@
 GrowableArray<const void *>* JvmtiExport::_pending_compiled_method_unload_code_begins;
 JavaThread* JvmtiExport::_current_poster;
 
+void JvmtiExport::post_compiled_method_unload_internal(JavaThread* self, jmethodID method, const void *code_begin) {
+  EVT_TRIG_TRACE(JVMTI_EVENT_COMPILED_METHOD_UNLOAD,
+                 ("JVMTI [%s] method compile unload event triggered",
+                  JvmtiTrace::safe_get_thread_name(self)));
+
+  // post the event for each environment that has this event enabled.
+  JvmtiEnvIterator it;
+  for (JvmtiEnv* env = it.first(); env != NULL; env = it.next(env)) {
+    if (env->is_enabled(JVMTI_EVENT_COMPILED_METHOD_UNLOAD)) {
+
+      EVT_TRACE(JVMTI_EVENT_COMPILED_METHOD_UNLOAD,
+                ("JVMTI [%s] class compile method unload event sent jmethodID " PTR_FORMAT,
+                 JvmtiTrace::safe_get_thread_name(self), method));
+
+      ResourceMark rm(self);
+
+      JvmtiEventMark jem(self);
+      JvmtiJavaThreadEventTransition jet(self);
+      jvmtiEventCompiledMethodUnload callback = env->callbacks()->CompiledMethodUnload;
+      if (callback != NULL) {
+        (*callback)(env->jvmti_external(), method, code_begin);
+      }
+    }
+  }
+}
+
 // post any pending CompiledMethodUnload events
 
 void JvmtiExport::post_pending_compiled_method_unload_events() {
@@ -788,26 +814,7 @@
   // flag, cleanup _current_poster to indicate that no thread is now servicing the
   // pending events list, and finally notify any thread that might be waiting.
   for (;;) {
-    EVT_TRIG_TRACE(JVMTI_EVENT_COMPILED_METHOD_UNLOAD,
-                   ("JVMTI [%s] method compile unload event triggered",
-                   JvmtiTrace::safe_get_thread_name(self)));
-
-    // post the event for each environment that has this event enabled.
-    JvmtiEnvIterator it;
-    for (JvmtiEnv* env = it.first(); env != NULL; env = it.next(env)) {
-      if (env->is_enabled(JVMTI_EVENT_COMPILED_METHOD_UNLOAD)) {
-        EVT_TRACE(JVMTI_EVENT_COMPILED_METHOD_UNLOAD,
-                  ("JVMTI [%s] class compile method unload event sent jmethodID " PTR_FORMAT,
-                  JvmtiTrace::safe_get_thread_name(self), method));
-
-        JvmtiEventMark jem(self);
-        JvmtiJavaThreadEventTransition jet(self);
-        jvmtiEventCompiledMethodUnload callback = env->callbacks()->CompiledMethodUnload;
-        if (callback != NULL) {
-          (*callback)(env->jvmti_external(), method, code_begin);
-        }
-      }
-    }
+    post_compiled_method_unload_internal(self, method, code_begin);
 
     // event posted, now re-grab monitor and get the next event
     // If there's no next event then we are done. If this is the first
@@ -1864,17 +1871,25 @@
 }
 
 // used at a safepoint to post a CompiledMethodUnload event
-void JvmtiExport::post_compiled_method_unload_at_safepoint(jmethodID mid, const void *code_begin) {
-  assert(SafepointSynchronize::is_at_safepoint(), "must be executed at a safepoint");
-
-  // create list lazily
-  if (_pending_compiled_method_unload_method_ids == NULL) {
-    _pending_compiled_method_unload_method_ids = new (ResourceObj::C_HEAP) GrowableArray<jmethodID>(10,true);
-    _pending_compiled_method_unload_code_begins = new (ResourceObj::C_HEAP) GrowableArray<const void *>(10,true);
+void JvmtiExport::post_compiled_method_unload(jmethodID mid, const void *code_begin) {
+  if (SafepointSynchronize::is_at_safepoint()) {
+    // Class unloading can cause nmethod unloading which is reported
+    // by the VMThread.  These must be batched to be processed later.
+    if (_pending_compiled_method_unload_method_ids == NULL) {
+      // create list lazily
+      _pending_compiled_method_unload_method_ids = new (ResourceObj::C_HEAP) GrowableArray<jmethodID>(10,true);
+      _pending_compiled_method_unload_code_begins = new (ResourceObj::C_HEAP) GrowableArray<const void *>(10,true);
+    }
+    _pending_compiled_method_unload_method_ids->append(mid);
+    _pending_compiled_method_unload_code_begins->append(code_begin);
+    _have_pending_compiled_method_unload_events = true;
+  } else {
+    // Unloading caused by the sweeper can be reported synchronously.
+    if (have_pending_compiled_method_unload_events()) {
+      post_pending_compiled_method_unload_events();
+    }
+    post_compiled_method_unload_internal(JavaThread::current(), mid, code_begin);
   }
-  _pending_compiled_method_unload_method_ids->append(mid);
-  _pending_compiled_method_unload_code_begins->append(code_begin);
-  _have_pending_compiled_method_unload_events = true;
 }
 
 void JvmtiExport::post_dynamic_code_generated_internal(const char *name, const void *code_begin, const void *code_end) {
--- a/src/share/vm/prims/jvmtiExport.hpp	Wed Jun 02 12:02:49 2010 -0700
+++ b/src/share/vm/prims/jvmtiExport.hpp	Wed Jun 02 14:23:23 2010 -0700
@@ -144,6 +144,9 @@
   // posts any pending CompiledMethodUnload events.
   static void post_pending_compiled_method_unload_events();
 
+  // Perform the actual notification to interested JvmtiEnvs.
+  static void post_compiled_method_unload_internal(JavaThread* self, jmethodID mid, const void* code_begin);
+
   // posts a DynamicCodeGenerated event (internal/private implementation).
   // The public post_dynamic_code_generated* functions make use of the
   // internal implementation.
@@ -299,8 +302,8 @@
   static void post_compiled_method_load(nmethod *nm) KERNEL_RETURN;
   static void post_dynamic_code_generated(const char *name, const void *code_begin, const void *code_end) KERNEL_RETURN;
 
-  // used at a safepoint to post a CompiledMethodUnload event
-  static void post_compiled_method_unload_at_safepoint(jmethodID mid, const void *code_begin) KERNEL_RETURN;
+  // used to post a CompiledMethodUnload event
+  static void post_compiled_method_unload(jmethodID mid, const void *code_begin) KERNEL_RETURN;
 
   // similiar to post_dynamic_code_generated except that it can be used to
   // post a DynamicCodeGenerated event while holding locks in the VM. Any event