RFR: 8373367: interp-only mechanism fails to work for carrier threads in a corner case [v6]

Serguei Spitsyn sspitsyn at openjdk.org
Wed Feb 18 12:26:20 UTC 2026


On Wed, 18 Feb 2026 11:50:47 GMT, Serguei Spitsyn <sspitsyn at openjdk.org> wrote:

>> The `interp-only` mechanism is based on the `JavaThread` objects. Carrier and virtual threads can temporary share the same `JavaThread`. The `java_thread->jvmti_thread_state()` is re-linked to a virtual thread at `mount` and to the carrier thread at `unmount`. The `JvmtiThreadState` has a back link to the `JavaThread` which is also set for virtual thread at a `mount` and carrier thread at an `unmount`. Just one of these two links at the same time is set to the `JavaThread`, the other one has to be set to `nullptr`. The `interp-only` mechanism needs this invariant.
>> However, there is a corner case when this invariant is broken. It happens when the `JvmtiThreadState` for carrier thread has just been created. In such case, the link to `JavaThread` is always `non-nullptr` even though a virtual thread is currently mounted on a carrier thread. This simple update fixes the issue in the  `JvmtiThreadState` ctor.
>> 
>> Testing:
>>  - TBD: Mach5 tiers 1-6
>
> Serguei Spitsyn has updated the pull request incrementally with one additional commit since the last revision:
> 
>   review: simplify interp-only; remove _thread_saved; add more asserts

I've pushed an update with the `interp_only` simplifications and dependent changes and added more assert in the most important places. So this PR is ready for re-review now. Will need to update the PR description and bug description accordingly. The main simplification is removal of the field `JvmtiThreadState:_thread_saved`.
The change includes:
 - the field `JvmtiThreadState::_thread_saved` field has been removed
 - the function `JvmtiThreadState::get_thread_or_saved()` has also been removed
 - now the function `JvmtiThreadState:get_thread()` is semantically equal to the former `get_thread_or_saved()`
 - now the function `JvmtiThreadState::set_thread()` is used for virtual threads only
 - the function `JvmtiThreadState::is_interp_only_mode()` has been simplified to always return `_saved_interp_only_mode` which means interp_only_mode for specific  `JvmtiThreadState`
 - the function `JvmtiEnvBase::is_thread_carrying_vthread()` is used to identify the cases when the carrier thread is not active (a virtual thread has been mounted and executed at the top). Before the fix, the function `get_thread()` was returning `nullptr` in such cases.
 - the comment at start of `JvmtiThreadState` constructor has been updated with the simplifications
 - added more assert in the most important places
 - one incorrect assert (overly strong) has been removed
 
Testing:
 - mach5 tiers 1-6 were good but submitted again after cleanup

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

PR Comment: https://git.openjdk.org/jdk/pull/29436#issuecomment-3920539655


More information about the serviceability-dev mailing list