On Thu, 30 Oct 2025 15:54:18 GMT, Patricio Chilano Mateo
<[email protected]> wrote:
>> If a thread tries to initialize a class that is already being initialized by
>> another thread, it will block until notified. Since at this blocking point
>> there are native frames on the stack, a virtual thread cannot be unmounted
>> and is pinned to its carrier. Besides harming scalability, this can, in some
>> pathological cases, lead to a deadlock, for example, if the thread executing
>> the class initialization method is blocked waiting for some unmounted
>> virtual thread to run, but all carriers are blocked waiting for that class
>> to be initialized.
>>
>> As of JDK-8338383, virtual threads blocked in the VM on `ObjectMonitor`
>> operations can be unmounted. Since synchronization on class initialization
>> is implemented using `ObjectLocker`, we can reuse the same mechanism to
>> unmount virtual threads on these cases too.
>>
>> This patch adds support for unmounting virtual threads on some of the most
>> common class initialization paths, specifically when calling
>> `InterpreterRuntime::_new` (`new` bytecode), and
>> `InterpreterRuntime::resolve_from_cache` for `invokestatic`, `getstatic` or
>> `putstatic` bytecodes. In the future we might consider extending this
>> mechanism to include initialization calls originating from native methods
>> such as `Class.forName0`.
>>
>> ### Summary of implementation
>>
>> The ObjectLocker class was modified to not pin the continuation if we are
>> coming from a preemptable path, which will be the case when calling
>> `InstanceKlass::initialize_impl` from new method
>> `InstanceKlass::initialize_preemptable`. This means that for these cases, a
>> virtual thread can now be unmounted either when contending for the init_lock
>> in the `ObjectLocker` constructor, or in the call to `wait_uninterruptibly`.
>> Also, since the call to initialize a class includes a previous call to
>> `link_class` which also uses `ObjectLocker` to protect concurrent calls from
>> multiple threads, we will allow preemption there too.
>>
>> If preempted, we will throw a pre-allocated exception which will get
>> propagated with the `TRAPS/CHECK` macros all the way back to the VM entry
>> point. The exception will be cleared and on return back to Java the virtual
>> thread will go through the preempt stub and unmount. When running again, at
>> the end of the thaw call we will identify this preemption case and redo the
>> original VM call (either `InterpreterRuntime::_new` or
>> `InterpreterRuntime::resolve_from_cache`).
>>
>> ### Notes
>>
>> `InterpreterRuntime::call_VM_preemptable` used previously only for
>> `InterpreterRuntime::mon...
>
> Patricio Chilano Mateo has updated the pull request incrementally with one
> additional commit since the last revision:
>
> Improve comment and assert msg
A truly useful enhancement! Just had a few questions / suggestions.
src/hotspot/cpu/ppc/macroAssembler_ppc.cpp line 762:
> 760: load_const_optimized(bad, 0xbad0101babe00000);
> 761: for (uint32_t i = 1; i < (sizeof(regs) / sizeof(Register)); i++) {
> 762: addi(regs[i], regs[0], regs[i]->encoding());
Guess it's a question for @reinrich, but why set up `bad = regs[0]` and then
still use `regs[0]` instead of `bad`?
I think using `bad` would make the code easier to understand than using
`regs[0]`.
Suggestion:
addi(regs[i], bad, regs[i]->encoding());
src/hotspot/share/interpreter/linkResolver.cpp line 1689:
> 1687: EXCEPTION_MARK;
> 1688: CallInfo info;
> 1689: resolve_static_call(info, link_info, ClassInitMode::dont_init,
> THREAD);
Couldn't you just do `CHECK_AND_CLEAR_NULL` and skip the following `if
(HAS_PENDING_EXCEPTION)` statement?
Suggestion:
resolve_static_call(info, link_info, ClassInitMode::dont_init,
CHECK_AND_CLEAR_NULL);
I see the same in functions both above and below this one, is there any reason
for this?
-------------
Marked as reviewed by fbredberg (Reviewer).
PR Review: https://git.openjdk.org/jdk/pull/27802#pullrequestreview-3411212227
PR Review Comment: https://git.openjdk.org/jdk/pull/27802#discussion_r2487050754
PR Review Comment: https://git.openjdk.org/jdk/pull/27802#discussion_r2486618754