On Tue, 22 Oct 2024 02:14:23 GMT, Patricio Chilano Mateo <pchilanom...@openjdk.org> wrote:
>> This is the implementation of JEP 491: Synchronize Virtual Threads without >> Pinning. See [JEP 491](https://bugs.openjdk.org/browse/JDK-8337395) for >> further details. >> >> In order to make the code review easier the changes have been split into the >> following initial 4 commits: >> >> - Changes to allow unmounting a virtual thread that is currently holding >> monitors. >> - Changes to allow unmounting a virtual thread blocked on synchronized >> trying to acquire the monitor. >> - Changes to allow unmounting a virtual thread blocked in `Object.wait()` >> and its timed-wait variants. >> - Changes to tests, JFR pinned event, and other changes in the JDK libraries. >> >> The changes fix pinning issues for all 4 ports that currently implement >> continuations: x64, aarch64, riscv and ppc. Note: ppc changes were added >> recently and stand in its own commit after the initial ones. >> >> The changes fix pinning issues when using `LM_LIGHTWEIGHT`, i.e. the default >> locking mode, (and `LM_MONITOR` which comes for free), but not when using >> `LM_LEGACY` mode. Note that the `LockingMode` flag has already been >> deprecated ([JDK-8334299](https://bugs.openjdk.org/browse/JDK-8334299)), >> with the intention to remove `LM_LEGACY` code in future releases. >> >> >> ## Summary of changes >> >> ### Unmount virtual thread while holding monitors >> >> As stated in the JEP, currently when a virtual thread enters a synchronized >> method or block, the JVM records the virtual thread's carrier platform >> thread as holding the monitor, not the virtual thread itself. This prevents >> the virtual thread from being unmounted from its carrier, as ownership >> information would otherwise go wrong. In order to fix this limitation we >> will do two things: >> >> - We copy the oops stored in the LockStack of the carrier to the stackChunk >> when freezing (and clear the LockStack). We copy the oops back to the >> LockStack of the next carrier when thawing for the first time (and clear >> them from the stackChunk). Note that we currently assume carriers don't hold >> monitors while mounting virtual threads. >> >> - For inflated monitors we now record the `java.lang.Thread.tid` of the >> owner in the ObjectMonitor's `_owner` field instead of a JavaThread*. This >> allows us to tie the owner of the monitor to a `java.lang.Thread` instance, >> rather than to a JavaThread which is only created per platform thread. The >> tid is already a 64 bit field so we can ignore issues of the counter >> wrapping around. >> >> #### General notes about this part: >> >> - Since virtual th... > > Patricio Chilano Mateo has updated the pull request incrementally with six > additional commits since the last revision: > > - Fix comments in objectMonitor.hpp > - Move frame::saved_thread_address() to platform dependent files > - Fix typo in jvmtiExport.cpp > - remove usage of frame::metadata_words in possibly_adjust_frame() > - Fix comments in c2 locking paths > - Revert and simplify changes to c1_Runtime1 on aarch64 and riscv src/hotspot/share/runtime/continuationFreezeThaw.cpp line 2247: > 2245: _thread->lock_stack().move_from_address(tmp_lockstack, > lockStackSize); > 2246: > 2247: chunk->set_lockstack_size(0); After some discussion here at the office we think there might be an issue here with simply hiding the oops without clearing them. Below in `recurse_thaw` we `do_barriers`. But it does not touch these lockstack. Missing the SATB store barrier is probably fine from a liveness perspective, because the oops in the lockstack must also be in the frames. But removing the oops without a barrier and clear will probably lead to problems down the line. Something like the following would probably handle this. Or even fuse the `copy_lockstack` and `clear_lockstack` together into some kind of `transfer_lockstack` which both loads and clears the oops. diff --git a/src/hotspot/share/oops/stackChunkOop.cpp b/src/hotspot/share/oops/stackChunkOop.cpp index d3d63533eed..f737bd2db71 100644 --- a/src/hotspot/share/oops/stackChunkOop.cpp +++ b/src/hotspot/share/oops/stackChunkOop.cpp @@ -470,6 +470,28 @@ void stackChunkOopDesc::copy_lockstack(oop* dst) { } } +void stackChunkOopDesc::clear_lockstack() { + const int cnt = lockstack_size(); + const bool requires_gc_barriers = is_gc_mode() || requires_barriers(); + const bool requires_uncompress = has_bitmap() && UseCompressedOops; + const auto clear_obj = [&](intptr_t* at) { + if (requires_uncompress) { + HeapAccess<>::oop_store(reinterpret_cast<narrowOop*>(at), nullptr); + } else { + HeapAccess<>::oop_store(reinterpret_cast<oop*>(at), nullptr); + } + }; + + if (requires_gc_barriers) { + intptr_t* lockstack_start = start_address(); + for (int i = 0; i < cnt; i++) { + clear_obj(&lockstack_start[i]); + } + } + set_lockstack_size(0); + set_has_lockstack(false); +} + void stackChunkOopDesc::print_on(bool verbose, outputStream* st) const { if (*((juint*)this) == badHeapWordVal) { st->print_cr("BAD WORD"); diff --git a/src/hotspot/share/oops/stackChunkOop.hpp b/src/hotspot/share/oops/stackChunkOop.hpp index 28e0576801e..928e94dd695 100644 --- a/src/hotspot/share/oops/stackChunkOop.hpp +++ b/src/hotspot/share/oops/stackChunkOop.hpp @@ -167,6 +167,7 @@ class stackChunkOopDesc : public instanceOopDesc { void fix_thawed_frame(const frame& f, const RegisterMapT* map); void copy_lockstack(oop* start); + void clear_lockstack(); template <typename OopT, class StackChunkLockStackClosureType> inline void iterate_lockstack(StackChunkLockStackClosureType* closure); diff --git a/src/hotspot/share/runtime/continuationFreezeThaw.cpp b/src/hotspot/share/runtime/continuationFreezeThaw.cpp index 5b6e48a02f3..e7d505bb9b1 100644 --- a/src/hotspot/share/runtime/continuationFreezeThaw.cpp +++ b/src/hotspot/share/runtime/continuationFreezeThaw.cpp @@ -2244,8 +2244,7 @@ NOINLINE intptr_t* Thaw<ConfigT>::thaw_slow(stackChunkOop chunk, Continuation::t chunk->copy_lockstack(tmp_lockstack); _thread->lock_stack().move_from_address(tmp_lockstack, lockStackSize); - chunk->set_lockstack_size(0); - chunk->set_has_lockstack(false); + chunk->clear_lockstack(); retry_fast_path = true; } ``` ------------- PR Review Comment: https://git.openjdk.org/jdk/pull/21565#discussion_r1810764911