Skip to content

Commit 3a02578

Browse files
committed
8255452: Doing GC during JVMTI MethodExit event posting breaks return oop
Reviewed-by: coleenp, dlong, rrich, sspitsyn
1 parent ba2ff3a commit 3a02578

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
@@ -1269,7 +1269,10 @@ JRT_ENTRY(void, InterpreterRuntime::post_method_entry(JavaThread *thread))
12691269
JRT_END
12701270

12711271

1272-
JRT_ENTRY(void, InterpreterRuntime::post_method_exit(JavaThread *thread))
1272+
// This is a JRT_BLOCK_ENTRY because we have to stash away the return oop
1273+
// before transitioning to VM, and restore it after transitioning back
1274+
// to Java. The return oop at the top-of-stack, is not walked by the GC.
1275+
JRT_BLOCK_ENTRY(void, InterpreterRuntime::post_method_exit(JavaThread *thread))
12731276
LastFrameAccessor last_frame(thread);
12741277
JvmtiExport::post_method_exit(thread, last_frame.method(), last_frame.get_frame());
12751278
JRT_END

src/hotspot/share/prims/jvmtiExport.cpp

Lines changed: 35 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1560,16 +1560,12 @@ void JvmtiExport::post_method_entry(JavaThread *thread, Method* method, frame cu
15601560
}
15611561
}
15621562

1563-
void JvmtiExport::post_method_exit(JavaThread *thread, Method* method, frame current_frame) {
1563+
void JvmtiExport::post_method_exit(JavaThread* thread, Method* method, frame current_frame) {
15641564
HandleMark hm(thread);
15651565
methodHandle mh(thread, method);
15661566

1567-
EVT_TRIG_TRACE(JVMTI_EVENT_METHOD_EXIT, ("[%s] Trg Method Exit triggered %s.%s",
1568-
JvmtiTrace::safe_get_thread_name(thread),
1569-
(mh() == NULL) ? "NULL" : mh()->klass_name()->as_C_string(),
1570-
(mh() == NULL) ? "NULL" : mh()->name()->as_C_string() ));
1571-
15721567
JvmtiThreadState *state = thread->jvmti_thread_state();
1568+
15731569
if (state == NULL || !state->is_interp_only_mode()) {
15741570
// for any thread that actually wants method exit, interp_only_mode is set
15751571
return;
@@ -1578,13 +1574,11 @@ void JvmtiExport::post_method_exit(JavaThread *thread, Method* method, frame cur
15781574
// return a flag when a method terminates by throwing an exception
15791575
// i.e. if an exception is thrown and it's not caught by the current method
15801576
bool exception_exit = state->is_exception_detected() && !state->is_exception_caught();
1581-
1577+
Handle result;
1578+
jvalue value;
1579+
value.j = 0L;
15821580

15831581
if (state->is_enabled(JVMTI_EVENT_METHOD_EXIT)) {
1584-
Handle result;
1585-
jvalue value;
1586-
value.j = 0L;
1587-
15881582
// if the method hasn't been popped because of an exception then we populate
15891583
// the return_value parameter for the callback. At this point we only have
15901584
// the address of a "raw result" and we just call into the interpreter to
@@ -1594,9 +1588,36 @@ void JvmtiExport::post_method_exit(JavaThread *thread, Method* method, frame cur
15941588
BasicType type = current_frame.interpreter_frame_result(&oop_result, &value);
15951589
if (is_reference_type(type)) {
15961590
result = Handle(thread, oop_result);
1591+
value.l = JNIHandles::make_local(thread, result());
15971592
}
15981593
}
1594+
}
15991595

1596+
// Deferred transition to VM, so we can stash away the return oop before GC
1597+
// Note that this transition is not needed when throwing an exception, because
1598+
// there is no oop to retain.
1599+
JRT_BLOCK
1600+
post_method_exit_inner(thread, mh, state, exception_exit, current_frame, value);
1601+
JRT_BLOCK_END
1602+
1603+
if (result.not_null() && !mh->is_native()) {
1604+
// We have to restore the oop on the stack for interpreter frames
1605+
*(oop*)current_frame.interpreter_frame_tos_address() = result();
1606+
}
1607+
}
1608+
1609+
void JvmtiExport::post_method_exit_inner(JavaThread* thread,
1610+
methodHandle& mh,
1611+
JvmtiThreadState *state,
1612+
bool exception_exit,
1613+
frame current_frame,
1614+
jvalue& value) {
1615+
EVT_TRIG_TRACE(JVMTI_EVENT_METHOD_EXIT, ("[%s] Trg Method Exit triggered %s.%s",
1616+
JvmtiTrace::safe_get_thread_name(thread),
1617+
(mh() == NULL) ? "NULL" : mh()->klass_name()->as_C_string(),
1618+
(mh() == NULL) ? "NULL" : mh()->name()->as_C_string() ));
1619+
1620+
if (state->is_enabled(JVMTI_EVENT_METHOD_EXIT)) {
16001621
JvmtiEnvThreadStateIterator it(state);
16011622
for (JvmtiEnvThreadState* ets = it.first(); ets != NULL; ets = it.next(ets)) {
16021623
if (ets->is_enabled(JVMTI_EVENT_METHOD_EXIT)) {
@@ -1607,9 +1628,6 @@ void JvmtiExport::post_method_exit(JavaThread *thread, Method* method, frame cur
16071628

16081629
JvmtiEnv *env = ets->get_env();
16091630
JvmtiMethodEventMark jem(thread, mh);
1610-
if (result.not_null()) {
1611-
value.l = JNIHandles::make_local(thread, result());
1612-
}
16131631
JvmtiJavaThreadEventTransition jet(thread);
16141632
jvmtiEventMethodExit callback = env->callbacks()->MethodExit;
16151633
if (callback != NULL) {
@@ -1801,7 +1819,9 @@ void JvmtiExport::notice_unwind_due_to_exception(JavaThread *thread, Method* met
18011819
if(state->is_interp_only_mode()) {
18021820
// method exit and frame pop events are posted only in interp mode.
18031821
// When these events are enabled code should be in running in interp mode.
1804-
JvmtiExport::post_method_exit(thread, method, thread->last_frame());
1822+
jvalue no_value;
1823+
no_value.j = 0L;
1824+
JvmtiExport::post_method_exit_inner(thread, mh, state, true, thread->last_frame(), no_value);
18051825
// The cached cur_stack_depth might have changed from the
18061826
// operations of frame pop or method exit. We are not 100% sure
18071827
// 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
@@ -193,6 +193,13 @@ class JvmtiExport : public AllStatic {
193193
// dependency information is complete or not.
194194
static bool _all_dependencies_are_recorded;
195195

196+
static void post_method_exit_inner(JavaThread* thread,
197+
methodHandle& mh,
198+
JvmtiThreadState *state,
199+
bool exception_exit,
200+
frame current_frame,
201+
jvalue& value);
202+
196203
public:
197204
inline static bool has_redefined_a_class() {
198205
JVMTI_ONLY(return _redefinition_count != 0);

0 commit comments

Comments
 (0)