RFR: 8365192: post_meth_exit should be in vm state when calling get_jvmti_thread_state [v4]

Serguei Spitsyn sspitsyn at openjdk.org
Thu Aug 14 15:01:11 UTC 2025


On Thu, 14 Aug 2025 09:15:03 GMT, Serguei Spitsyn <sspitsyn at openjdk.org> wrote:

>> src/hotspot/share/prims/jvmtiExport.cpp line 1838:
>> 
>>> 1836:   {
>>> 1837:     ThreadInVMfromJava tiv(thread);
>>> 1838:     state = get_jvmti_thread_state(thread);
>> 
>> The issue I see is that `get_jvmti_thread_state()` can safepoint for virtual threads (and now also for platform threads because of `~ThreadInVMfromJava`), which brings us back to the bug 8255452 was trying to fix: if there is a return oop at the top of the stack, it could become invalid if a GC occurs. I think we will have to unconditionally save the return value in case it's an oop, before doing anything else.
>
> Thank you, Patricio! Good catch and suggestion.

This can be kind of intrusive, something like below (without changes from Leonid):

@@ -1830,6 +1830,16 @@ void JvmtiExport::post_method_entry(JavaThread *thread, Method* method, frame cu
 void JvmtiExport::post_method_exit(JavaThread* thread, Method* method, frame current_frame) {
   HandleMark hm(thread);
   methodHandle mh(thread, method);
+  Handle result;
+  jvalue value;
+  oop oop_result;
+  BasicType type = current_frame.interpreter_frame_result(&oop_result, &value);
+
+  value.j = 0L;
+  if (is_reference_type(type)) {
+    result = Handle(thread, oop_result);
+    value.l = JNIHandles::make_local(thread, result());
+  }
 
   JvmtiThreadState *state = get_jvmti_thread_state(thread);
 
@@ -1841,21 +1851,15 @@ void JvmtiExport::post_method_exit(JavaThread* thread, Method* method, frame cur
   // return a flag when a method terminates by throwing an exception
   // i.e. if an exception is thrown and it's not caught by the current method
   bool exception_exit = state->is_exception_detected() && !state->is_exception_caught();
-  Handle result;
-  jvalue value;
-  value.j = 0L;
 
   if (state->is_enabled(JVMTI_EVENT_METHOD_EXIT)) {
     // if the method hasn't been popped because of an exception then we populate
     // the return_value parameter for the callback. At this point we only have
     // the address of a "raw result" and we just call into the interpreter to
     // convert this into a jvalue.
-    if (!exception_exit) {
-      oop oop_result;
-      BasicType type = current_frame.interpreter_frame_result(&oop_result, &value);
+    if (exception_exit) {
       if (is_reference_type(type)) {
-        result = Handle(thread, oop_result);
-        value.l = JNIHandles::make_local(thread, result());
+        value.j = 0L;
       }
     }
   }

Not sure yet how to make it simpler.

-------------

PR Review Comment: https://git.openjdk.org/jdk/pull/26713#discussion_r2276882958


More information about the serviceability-dev mailing list