291 lines
12 KiB
Diff
291 lines
12 KiB
Diff
|
|
diff --git a/hotspot/src/share/vm/code/nmethod.cpp b/hotspot/src/share/vm/code/nmethod.cpp
|
||
|
|
index 175c195c6..01e878022 100644
|
||
|
|
--- a/hotspot/src/share/vm/code/nmethod.cpp
|
||
|
|
+++ b/hotspot/src/share/vm/code/nmethod.cpp
|
||
|
|
@@ -1656,24 +1656,28 @@ bool nmethod::can_unload(BoolObjectClosure* is_alive, oop* root, bool unloading_
|
||
|
|
// Transfer information from compilation to jvmti
|
||
|
|
void nmethod::post_compiled_method_load_event() {
|
||
|
|
|
||
|
|
- Method* moop = method();
|
||
|
|
+ // This is a bad time for a safepoint. We don't want
|
||
|
|
+ // this nmethod to get unloaded while we're queueing the event.
|
||
|
|
+ No_Safepoint_Verifier nsv;
|
||
|
|
+
|
||
|
|
+ Method* m = method();
|
||
|
|
#ifndef USDT2
|
||
|
|
HS_DTRACE_PROBE8(hotspot, compiled__method__load,
|
||
|
|
- moop->klass_name()->bytes(),
|
||
|
|
- moop->klass_name()->utf8_length(),
|
||
|
|
- moop->name()->bytes(),
|
||
|
|
- moop->name()->utf8_length(),
|
||
|
|
- moop->signature()->bytes(),
|
||
|
|
- moop->signature()->utf8_length(),
|
||
|
|
+ m->klass_name()->bytes(),
|
||
|
|
+ m->klass_name()->utf8_length(),
|
||
|
|
+ m->name()->bytes(),
|
||
|
|
+ m->name()->utf8_length(),
|
||
|
|
+ m->signature()->bytes(),
|
||
|
|
+ m->signature()->utf8_length(),
|
||
|
|
insts_begin(), insts_size());
|
||
|
|
#else /* USDT2 */
|
||
|
|
HOTSPOT_COMPILED_METHOD_LOAD(
|
||
|
|
- (char *) moop->klass_name()->bytes(),
|
||
|
|
- moop->klass_name()->utf8_length(),
|
||
|
|
- (char *) moop->name()->bytes(),
|
||
|
|
- moop->name()->utf8_length(),
|
||
|
|
- (char *) moop->signature()->bytes(),
|
||
|
|
- moop->signature()->utf8_length(),
|
||
|
|
+ (char *) m->klass_name()->bytes(),
|
||
|
|
+ m->klass_name()->utf8_length(),
|
||
|
|
+ (char *) m->name()->bytes(),
|
||
|
|
+ m->name()->utf8_length(),
|
||
|
|
+ (char *) m->signature()->bytes(),
|
||
|
|
+ m->signature()->utf8_length(),
|
||
|
|
insts_begin(), insts_size());
|
||
|
|
#endif /* USDT2 */
|
||
|
|
|
||
|
|
diff --git a/hotspot/src/share/vm/oops/instanceKlass.cpp b/hotspot/src/share/vm/oops/instanceKlass.cpp
|
||
|
|
index 895fbbf07..367c9a09d 100644
|
||
|
|
--- a/hotspot/src/share/vm/oops/instanceKlass.cpp
|
||
|
|
+++ b/hotspot/src/share/vm/oops/instanceKlass.cpp
|
||
|
|
@@ -1786,7 +1786,7 @@ jmethodID InstanceKlass::get_jmethod_id(instanceKlassHandle ik_h, methodHandle m
|
||
|
|
// we're single threaded or at a safepoint - no locking needed
|
||
|
|
get_jmethod_id_length_value(jmeths, idnum, &length, &id);
|
||
|
|
} else {
|
||
|
|
- MutexLocker ml(JmethodIdCreation_lock);
|
||
|
|
+ MutexLockerEx ml(JmethodIdCreation_lock, Mutex::_no_safepoint_check_flag);
|
||
|
|
get_jmethod_id_length_value(jmeths, idnum, &length, &id);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
@@ -1836,7 +1836,7 @@ jmethodID InstanceKlass::get_jmethod_id(instanceKlassHandle ik_h, methodHandle m
|
||
|
|
id = get_jmethod_id_fetch_or_update(ik_h, idnum, new_id, new_jmeths,
|
||
|
|
&to_dealloc_id, &to_dealloc_jmeths);
|
||
|
|
} else {
|
||
|
|
- MutexLocker ml(JmethodIdCreation_lock);
|
||
|
|
+ MutexLockerEx ml(JmethodIdCreation_lock, Mutex::_no_safepoint_check_flag);
|
||
|
|
id = get_jmethod_id_fetch_or_update(ik_h, idnum, new_id, new_jmeths,
|
||
|
|
&to_dealloc_id, &to_dealloc_jmeths);
|
||
|
|
}
|
||
|
|
diff --git a/hotspot/src/share/vm/prims/jvmtiExport.cpp b/hotspot/src/share/vm/prims/jvmtiExport.cpp
|
||
|
|
index 9b612598f..967ed200d 100644
|
||
|
|
--- a/hotspot/src/share/vm/prims/jvmtiExport.cpp
|
||
|
|
+++ b/hotspot/src/share/vm/prims/jvmtiExport.cpp
|
||
|
|
@@ -1754,7 +1754,7 @@ jvmtiCompiledMethodLoadInlineRecord* create_inline_record(nmethod* nm) {
|
||
|
|
int stackframe = 0;
|
||
|
|
for(ScopeDesc* sd = nm->scope_desc_at(p->real_pc(nm));sd != NULL;sd = sd->sender()) {
|
||
|
|
// sd->method() can be NULL for stubs but not for nmethods. To be completely robust, include an assert that we should never see a null sd->method()
|
||
|
|
- assert(sd->method() != NULL, "sd->method() cannot be null.");
|
||
|
|
+ guarantee(sd->method() != NULL, "sd->method() cannot be null.");
|
||
|
|
record->pcinfo[scope].methods[stackframe] = sd->method()->jmethod_id();
|
||
|
|
record->pcinfo[scope].bcis[stackframe] = sd->bci();
|
||
|
|
stackframe++;
|
||
|
|
diff --git a/hotspot/src/share/vm/prims/jvmtiImpl.cpp b/hotspot/src/share/vm/prims/jvmtiImpl.cpp
|
||
|
|
index 3c66b1671..3bcd15ed6 100644
|
||
|
|
--- a/hotspot/src/share/vm/prims/jvmtiImpl.cpp
|
||
|
|
+++ b/hotspot/src/share/vm/prims/jvmtiImpl.cpp
|
||
|
|
@@ -897,9 +897,6 @@ JvmtiDeferredEvent JvmtiDeferredEvent::compiled_method_load_event(
|
||
|
|
nmethod* nm) {
|
||
|
|
JvmtiDeferredEvent event = JvmtiDeferredEvent(TYPE_COMPILED_METHOD_LOAD);
|
||
|
|
event._event_data.compiled_method_load = nm;
|
||
|
|
- // Keep the nmethod alive until the ServiceThread can process
|
||
|
|
- // this deferred event.
|
||
|
|
- nmethodLocker::lock_nmethod(nm);
|
||
|
|
return event;
|
||
|
|
}
|
||
|
|
|
||
|
|
@@ -932,14 +929,12 @@ JvmtiDeferredEvent JvmtiDeferredEvent::dynamic_code_generated_event(
|
||
|
|
}
|
||
|
|
|
||
|
|
void JvmtiDeferredEvent::post() {
|
||
|
|
- assert(ServiceThread::is_service_thread(Thread::current()),
|
||
|
|
+ assert(Thread::current()->is_service_thread(),
|
||
|
|
"Service thread must post enqueued events");
|
||
|
|
switch(_type) {
|
||
|
|
case TYPE_COMPILED_METHOD_LOAD: {
|
||
|
|
nmethod* nm = _event_data.compiled_method_load;
|
||
|
|
JvmtiExport::post_compiled_method_load(nm);
|
||
|
|
- // done with the deferred event so unlock the nmethod
|
||
|
|
- nmethodLocker::unlock_nmethod(nm);
|
||
|
|
break;
|
||
|
|
}
|
||
|
|
case TYPE_COMPILED_METHOD_UNLOAD: {
|
||
|
|
@@ -969,6 +964,21 @@ void JvmtiDeferredEvent::post() {
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
+// Keep the nmethod for compiled_method_load from being unloaded.
|
||
|
|
+void JvmtiDeferredEvent::oops_do(OopClosure* f, CodeBlobClosure* cf) {
|
||
|
|
+ if (cf != NULL && _type == TYPE_COMPILED_METHOD_LOAD) {
|
||
|
|
+ cf->do_code_blob(_event_data.compiled_method_load);
|
||
|
|
+ }
|
||
|
|
+}
|
||
|
|
+
|
||
|
|
+// The sweeper calls this and marks the nmethods here on the stack so that
|
||
|
|
+// they cannot be turned into zombies while in the queue.
|
||
|
|
+void JvmtiDeferredEvent::nmethods_do(CodeBlobClosure* cf) {
|
||
|
|
+ if (cf != NULL && _type == TYPE_COMPILED_METHOD_LOAD) {
|
||
|
|
+ cf->do_code_blob(_event_data.compiled_method_load);
|
||
|
|
+ } // May add UNLOAD event but it doesn't work yet.
|
||
|
|
+}
|
||
|
|
+
|
||
|
|
JvmtiDeferredEventQueue::QueueNode* JvmtiDeferredEventQueue::_queue_tail = NULL;
|
||
|
|
JvmtiDeferredEventQueue::QueueNode* JvmtiDeferredEventQueue::_queue_head = NULL;
|
||
|
|
|
||
|
|
@@ -1084,3 +1094,15 @@ void JvmtiDeferredEventQueue::process_pending_events() {
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
+
|
||
|
|
+void JvmtiDeferredEventQueue::oops_do(OopClosure* f, CodeBlobClosure* cf) {
|
||
|
|
+ for(QueueNode* node = _queue_head; node != NULL; node = node->next()) {
|
||
|
|
+ node->event().oops_do(f, cf);
|
||
|
|
+ }
|
||
|
|
+}
|
||
|
|
+
|
||
|
|
+void JvmtiDeferredEventQueue::nmethods_do(CodeBlobClosure* cf) {
|
||
|
|
+ for(QueueNode* node = _queue_head; node != NULL; node = node->next()) {
|
||
|
|
+ node->event().nmethods_do(cf);
|
||
|
|
+ }
|
||
|
|
+}
|
||
|
|
diff --git a/hotspot/src/share/vm/prims/jvmtiImpl.hpp b/hotspot/src/share/vm/prims/jvmtiImpl.hpp
|
||
|
|
index 9f36f28fb..d74789451 100644
|
||
|
|
--- a/hotspot/src/share/vm/prims/jvmtiImpl.hpp
|
||
|
|
+++ b/hotspot/src/share/vm/prims/jvmtiImpl.hpp
|
||
|
|
@@ -492,6 +492,10 @@ class JvmtiDeferredEvent VALUE_OBJ_CLASS_SPEC {
|
||
|
|
|
||
|
|
// Actually posts the event.
|
||
|
|
void post() NOT_JVMTI_RETURN;
|
||
|
|
+ // Sweeper support to keep nmethods from being zombied while in the queue.
|
||
|
|
+ void nmethods_do(CodeBlobClosure* cf);
|
||
|
|
+ // GC support to keep nmethod from being unloaded while in the queue.
|
||
|
|
+ void oops_do(OopClosure* f, CodeBlobClosure* cf);
|
||
|
|
};
|
||
|
|
|
||
|
|
/**
|
||
|
|
@@ -511,7 +515,7 @@ class JvmtiDeferredEventQueue : AllStatic {
|
||
|
|
QueueNode(const JvmtiDeferredEvent& event)
|
||
|
|
: _event(event), _next(NULL) {}
|
||
|
|
|
||
|
|
- const JvmtiDeferredEvent& event() const { return _event; }
|
||
|
|
+ JvmtiDeferredEvent& event() { return _event; }
|
||
|
|
QueueNode* next() const { return _next; }
|
||
|
|
|
||
|
|
void set_next(QueueNode* next) { _next = next; }
|
||
|
|
@@ -529,6 +533,10 @@ class JvmtiDeferredEventQueue : AllStatic {
|
||
|
|
static bool has_events() NOT_JVMTI_RETURN_(false);
|
||
|
|
static void enqueue(const JvmtiDeferredEvent& event) NOT_JVMTI_RETURN;
|
||
|
|
static JvmtiDeferredEvent dequeue() NOT_JVMTI_RETURN_(JvmtiDeferredEvent());
|
||
|
|
+ // Sweeper support to keep nmethods from being zombied while in the queue.
|
||
|
|
+ static void nmethods_do(CodeBlobClosure* cf);
|
||
|
|
+ // GC support to keep nmethod from being unloaded while in the queue.
|
||
|
|
+ static void oops_do(OopClosure* f, CodeBlobClosure* cf);
|
||
|
|
|
||
|
|
// Used to enqueue events without using a lock, for times (such as during
|
||
|
|
// safepoint) when we can't or don't want to lock the Service_lock.
|
||
|
|
diff --git a/hotspot/src/share/vm/runtime/serviceThread.cpp b/hotspot/src/share/vm/runtime/serviceThread.cpp
|
||
|
|
index c3a2b88a5..a2a32ad2b 100644
|
||
|
|
--- a/hotspot/src/share/vm/runtime/serviceThread.cpp
|
||
|
|
+++ b/hotspot/src/share/vm/runtime/serviceThread.cpp
|
||
|
|
@@ -34,6 +34,7 @@
|
||
|
|
#include "services/diagnosticFramework.hpp"
|
||
|
|
|
||
|
|
ServiceThread* ServiceThread::_instance = NULL;
|
||
|
|
+JvmtiDeferredEvent* ServiceThread::_jvmti_event = NULL;
|
||
|
|
|
||
|
|
void ServiceThread::initialize() {
|
||
|
|
EXCEPTION_MARK;
|
||
|
|
@@ -112,12 +113,15 @@ void ServiceThread::service_thread_entry(JavaThread* jt, TRAPS) {
|
||
|
|
}
|
||
|
|
|
||
|
|
if (has_jvmti_events) {
|
||
|
|
+ // Get the event under the Service_lock
|
||
|
|
jvmti_event = JvmtiDeferredEventQueue::dequeue();
|
||
|
|
+ _jvmti_event = &jvmti_event;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
if (has_jvmti_events) {
|
||
|
|
- jvmti_event.post();
|
||
|
|
+ _jvmti_event->post();
|
||
|
|
+ _jvmti_event = NULL; // reset
|
||
|
|
}
|
||
|
|
|
||
|
|
if (sensors_changed) {
|
||
|
|
@@ -138,6 +142,26 @@ void ServiceThread::service_thread_entry(JavaThread* jt, TRAPS) {
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
-bool ServiceThread::is_service_thread(Thread* thread) {
|
||
|
|
- return thread == _instance;
|
||
|
|
+void ServiceThread::oops_do(OopClosure* f, CLDClosure* cld_f, CodeBlobClosure* cf) {
|
||
|
|
+ JavaThread::oops_do(f, cld_f, cf);
|
||
|
|
+ // The ServiceThread "owns" the JVMTI Deferred events, scan them here
|
||
|
|
+ // to keep them alive until they are processed.
|
||
|
|
+ if (cf != NULL) {
|
||
|
|
+ if (_jvmti_event != NULL) {
|
||
|
|
+ _jvmti_event->oops_do(f, cf);
|
||
|
|
+ }
|
||
|
|
+ MutexLockerEx ml(Service_lock, Mutex::_no_safepoint_check_flag);
|
||
|
|
+ JvmtiDeferredEventQueue::oops_do(f, cf);
|
||
|
|
+ }
|
||
|
|
+}
|
||
|
|
+
|
||
|
|
+void ServiceThread::nmethods_do(CodeBlobClosure* cf) {
|
||
|
|
+ JavaThread::nmethods_do(cf);
|
||
|
|
+ if (cf != NULL) {
|
||
|
|
+ if (_jvmti_event != NULL) {
|
||
|
|
+ _jvmti_event->nmethods_do(cf);
|
||
|
|
+ }
|
||
|
|
+ MutexLockerEx ml(Service_lock, Mutex::_no_safepoint_check_flag);
|
||
|
|
+ JvmtiDeferredEventQueue::nmethods_do(cf);
|
||
|
|
+ }
|
||
|
|
}
|
||
|
|
diff --git a/hotspot/src/share/vm/runtime/serviceThread.hpp b/hotspot/src/share/vm/runtime/serviceThread.hpp
|
||
|
|
index 42373e6f7..a9c219580 100644
|
||
|
|
--- a/hotspot/src/share/vm/runtime/serviceThread.hpp
|
||
|
|
+++ b/hotspot/src/share/vm/runtime/serviceThread.hpp
|
||
|
|
@@ -29,11 +29,13 @@
|
||
|
|
|
||
|
|
// A JavaThread for low memory detection support and JVMTI
|
||
|
|
// compiled-method-load events.
|
||
|
|
+class JvmtiDeferredEvent;
|
||
|
|
+
|
||
|
|
class ServiceThread : public JavaThread {
|
||
|
|
friend class VMStructs;
|
||
|
|
private:
|
||
|
|
-
|
||
|
|
static ServiceThread* _instance;
|
||
|
|
+ static JvmtiDeferredEvent* _jvmti_event;
|
||
|
|
|
||
|
|
static void service_thread_entry(JavaThread* thread, TRAPS);
|
||
|
|
ServiceThread(ThreadFunction entry_point) : JavaThread(entry_point) {};
|
||
|
|
@@ -43,9 +45,11 @@ class ServiceThread : public JavaThread {
|
||
|
|
|
||
|
|
// Hide this thread from external view.
|
||
|
|
bool is_hidden_from_external_view() const { return true; }
|
||
|
|
+ bool is_service_thread() const { return true; }
|
||
|
|
|
||
|
|
- // Returns true if the passed thread is the service thread.
|
||
|
|
- static bool is_service_thread(Thread* thread);
|
||
|
|
+ // GC support
|
||
|
|
+ void oops_do(OopClosure* f, CLDClosure* cld_f, CodeBlobClosure* cf);
|
||
|
|
+ void nmethods_do(CodeBlobClosure* cf);
|
||
|
|
};
|
||
|
|
|
||
|
|
#endif // SHARE_VM_RUNTIME_SERVICETHREAD_HPP
|
||
|
|
diff --git a/hotspot/src/share/vm/runtime/thread.hpp b/hotspot/src/share/vm/runtime/thread.hpp
|
||
|
|
index cc976182d..950c1b4fa 100644
|
||
|
|
--- a/hotspot/src/share/vm/runtime/thread.hpp
|
||
|
|
+++ b/hotspot/src/share/vm/runtime/thread.hpp
|
||
|
|
@@ -313,6 +313,7 @@ class Thread: public ThreadShadow {
|
||
|
|
virtual bool is_VM_thread() const { return false; }
|
||
|
|
virtual bool is_Java_thread() const { return false; }
|
||
|
|
virtual bool is_Compiler_thread() const { return false; }
|
||
|
|
+ virtual bool is_service_thread() const { return false; }
|
||
|
|
virtual bool is_hidden_from_external_view() const { return false; }
|
||
|
|
virtual bool is_jvmti_agent_thread() const { return false; }
|
||
|
|
// True iff the thread can perform GC operations at a safepoint.
|
||
|
|
--
|
||
|
|
2.22.0
|
||
|
|
|