Skip to content

Commit 509170c

Browse files
committed
8255452: Doing GC during JVMTI MethodExit event posting breaks return oop
Reviewed-by: rrich, mbaesken Backport-of: 3a02578
1 parent c44da65 commit 509170c

File tree

3 files changed

+46
-16
lines changed

3 files changed

+46
-16
lines changed

src/hotspot/share/interpreter/interpreterRuntime.cpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1282,7 +1282,10 @@ IRT_ENTRY(void, InterpreterRuntime::post_method_entry(JavaThread *thread))
12821282
IRT_END
12831283

12841284

1285-
IRT_ENTRY(void, InterpreterRuntime::post_method_exit(JavaThread *thread))
1285+
// This is a JRT_BLOCK_ENTRY because we have to stash away the return oop
1286+
// before transitioning to VM, and restore it after transitioning back
1287+
// to Java. The return oop at the top-of-stack, is not walked by the GC.
1288+
JRT_BLOCK_ENTRY(void, InterpreterRuntime::post_method_exit(JavaThread *thread))
12861289
LastFrameAccessor last_frame(thread);
12871290
JvmtiExport::post_method_exit(thread, last_frame.method(), last_frame.get_frame());
12881291
IRT_END

src/hotspot/share/prims/jvmtiExport.cpp

Lines changed: 35 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1543,16 +1543,12 @@ void JvmtiExport::post_method_entry(JavaThread *thread, Method* method, frame cu
15431543
}
15441544
}
15451545

1546-
void JvmtiExport::post_method_exit(JavaThread *thread, Method* method, frame current_frame) {
1546+
void JvmtiExport::post_method_exit(JavaThread* thread, Method* method, frame current_frame) {
15471547
HandleMark hm(thread);
15481548
methodHandle mh(thread, method);
15491549

1550-
EVT_TRIG_TRACE(JVMTI_EVENT_METHOD_EXIT, ("[%s] Trg Method Exit triggered %s.%s",
1551-
JvmtiTrace::safe_get_thread_name(thread),
1552-
(mh() == NULL) ? "NULL" : mh()->klass_name()->as_C_string(),
1553-
(mh() == NULL) ? "NULL" : mh()->name()->as_C_string() ));
1554-
15551550
JvmtiThreadState *state = thread->jvmti_thread_state();
1551+
15561552
if (state == NULL || !state->is_interp_only_mode()) {
15571553
// for any thread that actually wants method exit, interp_only_mode is set
15581554
return;
@@ -1561,13 +1557,11 @@ void JvmtiExport::post_method_exit(JavaThread *thread, Method* method, frame cur
15611557
// return a flag when a method terminates by throwing an exception
15621558
// i.e. if an exception is thrown and it's not caught by the current method
15631559
bool exception_exit = state->is_exception_detected() && !state->is_exception_caught();
1564-
1560+
Handle result;
1561+
jvalue value;
1562+
value.j = 0L;
15651563

15661564
if (state->is_enabled(JVMTI_EVENT_METHOD_EXIT)) {
1567-
Handle result;
1568-
jvalue value;
1569-
value.j = 0L;
1570-
15711565
// if the method hasn't been popped because of an exception then we populate
15721566
// the return_value parameter for the callback. At this point we only have
15731567
// the address of a "raw result" and we just call into the interpreter to
@@ -1577,9 +1571,36 @@ void JvmtiExport::post_method_exit(JavaThread *thread, Method* method, frame cur
15771571
BasicType type = current_frame.interpreter_frame_result(&oop_result, &value);
15781572
if (type == T_OBJECT || type == T_ARRAY) {
15791573
result = Handle(thread, oop_result);
1574+
value.l = JNIHandles::make_local(thread, result());
15801575
}
15811576
}
1577+
}
15821578

1579+
// Deferred transition to VM, so we can stash away the return oop before GC
1580+
// Note that this transition is not needed when throwing an exception, because
1581+
// there is no oop to retain.
1582+
JRT_BLOCK
1583+
post_method_exit_inner(thread, mh, state, exception_exit, current_frame, value);
1584+
JRT_BLOCK_END
1585+
1586+
if (result.not_null() && !mh->is_native()) {
1587+
// We have to restore the oop on the stack for interpreter frames
1588+
*(oop*)current_frame.interpreter_frame_tos_address() = result();
1589+
}
1590+
}
1591+
1592+
void JvmtiExport::post_method_exit_inner(JavaThread* thread,
1593+
methodHandle& mh,
1594+
JvmtiThreadState *state,
1595+
bool exception_exit,
1596+
frame current_frame,
1597+
jvalue& value) {
1598+
EVT_TRIG_TRACE(JVMTI_EVENT_METHOD_EXIT, ("[%s] Trg Method Exit triggered %s.%s",
1599+
JvmtiTrace::safe_get_thread_name(thread),
1600+
(mh() == NULL) ? "NULL" : mh()->klass_name()->as_C_string(),
1601+
(mh() == NULL) ? "NULL" : mh()->name()->as_C_string() ));
1602+
1603+
if (state->is_enabled(JVMTI_EVENT_METHOD_EXIT)) {
15831604
JvmtiEnvThreadStateIterator it(state);
15841605
for (JvmtiEnvThreadState* ets = it.first(); ets != NULL; ets = it.next(ets)) {
15851606
if (ets->is_enabled(JVMTI_EVENT_METHOD_EXIT)) {
@@ -1590,9 +1611,6 @@ void JvmtiExport::post_method_exit(JavaThread *thread, Method* method, frame cur
15901611

15911612
JvmtiEnv *env = ets->get_env();
15921613
JvmtiMethodEventMark jem(thread, mh);
1593-
if (result.not_null()) {
1594-
value.l = JNIHandles::make_local(thread, result());
1595-
}
15961614
JvmtiJavaThreadEventTransition jet(thread);
15971615
jvmtiEventMethodExit callback = env->callbacks()->MethodExit;
15981616
if (callback != NULL) {
@@ -1781,7 +1799,9 @@ void JvmtiExport::notice_unwind_due_to_exception(JavaThread *thread, Method* met
17811799
if(state->is_interp_only_mode()) {
17821800
// method exit and frame pop events are posted only in interp mode.
17831801
// When these events are enabled code should be in running in interp mode.
1784-
JvmtiExport::post_method_exit(thread, method, thread->last_frame());
1802+
jvalue no_value;
1803+
no_value.j = 0L;
1804+
JvmtiExport::post_method_exit_inner(thread, mh, state, true, thread->last_frame(), no_value);
17851805
// The cached cur_stack_depth might have changed from the
17861806
// operations of frame pop or method exit. We are not 100% sure
17871807
// the cached cur_stack_depth is still valid depth so invalidate

src/hotspot/share/prims/jvmtiExport.hpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -187,6 +187,13 @@ class JvmtiExport : public AllStatic {
187187
// dependency information is complete or not.
188188
static bool _all_dependencies_are_recorded;
189189

190+
static void post_method_exit_inner(JavaThread* thread,
191+
methodHandle& mh,
192+
JvmtiThreadState *state,
193+
bool exception_exit,
194+
frame current_frame,
195+
jvalue& value);
196+
190197
public:
191198
inline static bool has_redefined_a_class() {
192199
JVMTI_ONLY(return _has_redefined_a_class);

0 commit comments

Comments
 (0)