Skip to content

Commit 1b4f32d

Browse files
author
Dongbo He
committed
8173361: various crashes in JvmtiExport::post_compiled_method_load
Don't post information that uses metadata from unloaded nmethods Reviewed-by: andrew, sspitsyn Backport-of: b1d915ef80ebdf511dc2897b20ada78b3dc44241
1 parent cf6b628 commit 1b4f32d

File tree

8 files changed

+92
-29
lines changed

8 files changed

+92
-29
lines changed

hotspot/src/share/vm/code/nmethod.cpp

+17-13
Original file line numberDiff line numberDiff line change
@@ -1656,24 +1656,28 @@ bool nmethod::can_unload(BoolObjectClosure* is_alive, oop* root, bool unloading_
16561656
// Transfer information from compilation to jvmti
16571657
void nmethod::post_compiled_method_load_event() {
16581658

1659-
Method* moop = method();
1659+
// This is a bad time for a safepoint. We don't want
1660+
// this nmethod to get unloaded while we're queueing the event.
1661+
No_Safepoint_Verifier nsv;
1662+
1663+
Method* m = method();
16601664
#ifndef USDT2
16611665
HS_DTRACE_PROBE8(hotspot, compiled__method__load,
1662-
moop->klass_name()->bytes(),
1663-
moop->klass_name()->utf8_length(),
1664-
moop->name()->bytes(),
1665-
moop->name()->utf8_length(),
1666-
moop->signature()->bytes(),
1667-
moop->signature()->utf8_length(),
1666+
m->klass_name()->bytes(),
1667+
m->klass_name()->utf8_length(),
1668+
m->name()->bytes(),
1669+
m->name()->utf8_length(),
1670+
m->signature()->bytes(),
1671+
m->signature()->utf8_length(),
16681672
insts_begin(), insts_size());
16691673
#else /* USDT2 */
16701674
HOTSPOT_COMPILED_METHOD_LOAD(
1671-
(char *) moop->klass_name()->bytes(),
1672-
moop->klass_name()->utf8_length(),
1673-
(char *) moop->name()->bytes(),
1674-
moop->name()->utf8_length(),
1675-
(char *) moop->signature()->bytes(),
1676-
moop->signature()->utf8_length(),
1675+
(char *) m->klass_name()->bytes(),
1676+
m->klass_name()->utf8_length(),
1677+
(char *) m->name()->bytes(),
1678+
m->name()->utf8_length(),
1679+
(char *) m->signature()->bytes(),
1680+
m->signature()->utf8_length(),
16771681
insts_begin(), insts_size());
16781682
#endif /* USDT2 */
16791683

hotspot/src/share/vm/oops/instanceKlass.cpp

+2-2
Original file line numberDiff line numberDiff line change
@@ -1786,7 +1786,7 @@ jmethodID InstanceKlass::get_jmethod_id(instanceKlassHandle ik_h, methodHandle m
17861786
// we're single threaded or at a safepoint - no locking needed
17871787
get_jmethod_id_length_value(jmeths, idnum, &length, &id);
17881788
} else {
1789-
MutexLocker ml(JmethodIdCreation_lock);
1789+
MutexLockerEx ml(JmethodIdCreation_lock, Mutex::_no_safepoint_check_flag);
17901790
get_jmethod_id_length_value(jmeths, idnum, &length, &id);
17911791
}
17921792
}
@@ -1836,7 +1836,7 @@ jmethodID InstanceKlass::get_jmethod_id(instanceKlassHandle ik_h, methodHandle m
18361836
id = get_jmethod_id_fetch_or_update(ik_h, idnum, new_id, new_jmeths,
18371837
&to_dealloc_id, &to_dealloc_jmeths);
18381838
} else {
1839-
MutexLocker ml(JmethodIdCreation_lock);
1839+
MutexLockerEx ml(JmethodIdCreation_lock, Mutex::_no_safepoint_check_flag);
18401840
id = get_jmethod_id_fetch_or_update(ik_h, idnum, new_id, new_jmeths,
18411841
&to_dealloc_id, &to_dealloc_jmeths);
18421842
}

hotspot/src/share/vm/prims/jvmtiExport.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -1754,7 +1754,7 @@ jvmtiCompiledMethodLoadInlineRecord* create_inline_record(nmethod* nm) {
17541754
int stackframe = 0;
17551755
for(ScopeDesc* sd = nm->scope_desc_at(p->real_pc(nm));sd != NULL;sd = sd->sender()) {
17561756
// 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()
1757-
assert(sd->method() != NULL, "sd->method() cannot be null.");
1757+
guarantee(sd->method() != NULL, "sd->method() cannot be null.");
17581758
record->pcinfo[scope].methods[stackframe] = sd->method()->jmethod_id();
17591759
record->pcinfo[scope].bcis[stackframe] = sd->bci();
17601760
stackframe++;

hotspot/src/share/vm/prims/jvmtiImpl.cpp

+28-6
Original file line numberDiff line numberDiff line change
@@ -897,9 +897,6 @@ JvmtiDeferredEvent JvmtiDeferredEvent::compiled_method_load_event(
897897
nmethod* nm) {
898898
JvmtiDeferredEvent event = JvmtiDeferredEvent(TYPE_COMPILED_METHOD_LOAD);
899899
event._event_data.compiled_method_load = nm;
900-
// Keep the nmethod alive until the ServiceThread can process
901-
// this deferred event.
902-
nmethodLocker::lock_nmethod(nm);
903900
return event;
904901
}
905902

@@ -932,14 +929,12 @@ JvmtiDeferredEvent JvmtiDeferredEvent::dynamic_code_generated_event(
932929
}
933930

934931
void JvmtiDeferredEvent::post() {
935-
assert(ServiceThread::is_service_thread(Thread::current()),
932+
assert(Thread::current()->is_service_thread(),
936933
"Service thread must post enqueued events");
937934
switch(_type) {
938935
case TYPE_COMPILED_METHOD_LOAD: {
939936
nmethod* nm = _event_data.compiled_method_load;
940937
JvmtiExport::post_compiled_method_load(nm);
941-
// done with the deferred event so unlock the nmethod
942-
nmethodLocker::unlock_nmethod(nm);
943938
break;
944939
}
945940
case TYPE_COMPILED_METHOD_UNLOAD: {
@@ -969,6 +964,21 @@ void JvmtiDeferredEvent::post() {
969964
}
970965
}
971966

967+
// Keep the nmethod for compiled_method_load from being unloaded.
968+
void JvmtiDeferredEvent::oops_do(OopClosure* f, CodeBlobClosure* cf) {
969+
if (cf != NULL && _type == TYPE_COMPILED_METHOD_LOAD) {
970+
cf->do_code_blob(_event_data.compiled_method_load);
971+
}
972+
}
973+
974+
// The sweeper calls this and marks the nmethods here on the stack so that
975+
// they cannot be turned into zombies while in the queue.
976+
void JvmtiDeferredEvent::nmethods_do(CodeBlobClosure* cf) {
977+
if (cf != NULL && _type == TYPE_COMPILED_METHOD_LOAD) {
978+
cf->do_code_blob(_event_data.compiled_method_load);
979+
} // May add UNLOAD event but it doesn't work yet.
980+
}
981+
972982
JvmtiDeferredEventQueue::QueueNode* JvmtiDeferredEventQueue::_queue_tail = NULL;
973983
JvmtiDeferredEventQueue::QueueNode* JvmtiDeferredEventQueue::_queue_head = NULL;
974984

@@ -1084,3 +1094,15 @@ void JvmtiDeferredEventQueue::process_pending_events() {
10841094
}
10851095
}
10861096
}
1097+
1098+
void JvmtiDeferredEventQueue::oops_do(OopClosure* f, CodeBlobClosure* cf) {
1099+
for(QueueNode* node = _queue_head; node != NULL; node = node->next()) {
1100+
node->event().oops_do(f, cf);
1101+
}
1102+
}
1103+
1104+
void JvmtiDeferredEventQueue::nmethods_do(CodeBlobClosure* cf) {
1105+
for(QueueNode* node = _queue_head; node != NULL; node = node->next()) {
1106+
node->event().nmethods_do(cf);
1107+
}
1108+
}

hotspot/src/share/vm/prims/jvmtiImpl.hpp

+9-1
Original file line numberDiff line numberDiff line change
@@ -492,6 +492,10 @@ class JvmtiDeferredEvent VALUE_OBJ_CLASS_SPEC {
492492

493493
// Actually posts the event.
494494
void post() NOT_JVMTI_RETURN;
495+
// Sweeper support to keep nmethods from being zombied while in the queue.
496+
void nmethods_do(CodeBlobClosure* cf);
497+
// GC support to keep nmethod from being unloaded while in the queue.
498+
void oops_do(OopClosure* f, CodeBlobClosure* cf);
495499
};
496500

497501
/**
@@ -511,7 +515,7 @@ class JvmtiDeferredEventQueue : AllStatic {
511515
QueueNode(const JvmtiDeferredEvent& event)
512516
: _event(event), _next(NULL) {}
513517

514-
const JvmtiDeferredEvent& event() const { return _event; }
518+
JvmtiDeferredEvent& event() { return _event; }
515519
QueueNode* next() const { return _next; }
516520

517521
void set_next(QueueNode* next) { _next = next; }
@@ -529,6 +533,10 @@ class JvmtiDeferredEventQueue : AllStatic {
529533
static bool has_events() NOT_JVMTI_RETURN_(false);
530534
static void enqueue(const JvmtiDeferredEvent& event) NOT_JVMTI_RETURN;
531535
static JvmtiDeferredEvent dequeue() NOT_JVMTI_RETURN_(JvmtiDeferredEvent());
536+
// Sweeper support to keep nmethods from being zombied while in the queue.
537+
static void nmethods_do(CodeBlobClosure* cf);
538+
// GC support to keep nmethod from being unloaded while in the queue.
539+
static void oops_do(OopClosure* f, CodeBlobClosure* cf);
532540

533541
// Used to enqueue events without using a lock, for times (such as during
534542
// safepoint) when we can't or don't want to lock the Service_lock.

hotspot/src/share/vm/runtime/serviceThread.cpp

+27-3
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@
3434
#include "services/diagnosticFramework.hpp"
3535

3636
ServiceThread* ServiceThread::_instance = NULL;
37+
JvmtiDeferredEvent* ServiceThread::_jvmti_event = NULL;
3738

3839
void ServiceThread::initialize() {
3940
EXCEPTION_MARK;
@@ -112,12 +113,15 @@ void ServiceThread::service_thread_entry(JavaThread* jt, TRAPS) {
112113
}
113114

114115
if (has_jvmti_events) {
116+
// Get the event under the Service_lock
115117
jvmti_event = JvmtiDeferredEventQueue::dequeue();
118+
_jvmti_event = &jvmti_event;
116119
}
117120
}
118121

119122
if (has_jvmti_events) {
120-
jvmti_event.post();
123+
_jvmti_event->post();
124+
_jvmti_event = NULL; // reset
121125
}
122126

123127
if (sensors_changed) {
@@ -138,6 +142,26 @@ void ServiceThread::service_thread_entry(JavaThread* jt, TRAPS) {
138142
}
139143
}
140144

141-
bool ServiceThread::is_service_thread(Thread* thread) {
142-
return thread == _instance;
145+
void ServiceThread::oops_do(OopClosure* f, CLDClosure* cld_f, CodeBlobClosure* cf) {
146+
JavaThread::oops_do(f, cld_f, cf);
147+
// The ServiceThread "owns" the JVMTI Deferred events, scan them here
148+
// to keep them alive until they are processed.
149+
if (cf != NULL) {
150+
if (_jvmti_event != NULL) {
151+
_jvmti_event->oops_do(f, cf);
152+
}
153+
MutexLockerEx ml(Service_lock, Mutex::_no_safepoint_check_flag);
154+
JvmtiDeferredEventQueue::oops_do(f, cf);
155+
}
156+
}
157+
158+
void ServiceThread::nmethods_do(CodeBlobClosure* cf) {
159+
JavaThread::nmethods_do(cf);
160+
if (cf != NULL) {
161+
if (_jvmti_event != NULL) {
162+
_jvmti_event->nmethods_do(cf);
163+
}
164+
MutexLockerEx ml(Service_lock, Mutex::_no_safepoint_check_flag);
165+
JvmtiDeferredEventQueue::nmethods_do(cf);
166+
}
143167
}

hotspot/src/share/vm/runtime/serviceThread.hpp

+7-3
Original file line numberDiff line numberDiff line change
@@ -29,11 +29,13 @@
2929

3030
// A JavaThread for low memory detection support and JVMTI
3131
// compiled-method-load events.
32+
class JvmtiDeferredEvent;
33+
3234
class ServiceThread : public JavaThread {
3335
friend class VMStructs;
3436
private:
35-
3637
static ServiceThread* _instance;
38+
static JvmtiDeferredEvent* _jvmti_event;
3739

3840
static void service_thread_entry(JavaThread* thread, TRAPS);
3941
ServiceThread(ThreadFunction entry_point) : JavaThread(entry_point) {};
@@ -43,9 +45,11 @@ class ServiceThread : public JavaThread {
4345

4446
// Hide this thread from external view.
4547
bool is_hidden_from_external_view() const { return true; }
48+
bool is_service_thread() const { return true; }
4649

47-
// Returns true if the passed thread is the service thread.
48-
static bool is_service_thread(Thread* thread);
50+
// GC support
51+
void oops_do(OopClosure* f, CLDClosure* cld_f, CodeBlobClosure* cf);
52+
void nmethods_do(CodeBlobClosure* cf);
4953
};
5054

5155
#endif // SHARE_VM_RUNTIME_SERVICETHREAD_HPP

hotspot/src/share/vm/runtime/thread.hpp

+1
Original file line numberDiff line numberDiff line change
@@ -313,6 +313,7 @@ class Thread: public ThreadShadow {
313313
virtual bool is_VM_thread() const { return false; }
314314
virtual bool is_Java_thread() const { return false; }
315315
virtual bool is_Compiler_thread() const { return false; }
316+
virtual bool is_service_thread() const { return false; }
316317
virtual bool is_hidden_from_external_view() const { return false; }
317318
virtual bool is_jvmti_agent_thread() const { return false; }
318319
// True iff the thread can perform GC operations at a safepoint.

0 commit comments

Comments
 (0)