RFR: 8288129: Shenandoah: Skynet test crashed with iu + aggressive
Erik Österlund
eosterlund at openjdk.org
Mon Aug 29 16:13:11 UTC 2022
On Mon, 29 Aug 2022 06:58:37 GMT, Stefan Karlsson <stefank at openjdk.org> wrote:
> > @stefank @fisk I see this code [1] which indicates ZGC does not require barriers at all. I would appreciate if either of you can provide inputs on how does ZGC handles the scenario where the previously reachable object O1 is now reachable only from another object O2 allocated after marking has started. How would O1 be marked by ZGC in such case? This seems to be the scenario we are hitting in the context of loom code during the freeze process and shenandoah IU mode fails to handle it.
>
> >
>
> > [1]
>
> >
>
> > https://github.com/openjdk/jdk/blob/9a0d1e7ce86368cdcade713a9e220604f7d77ecf/src/hotspot/share/runtime/continuationFreezeThaw.cpp#L1299
>
>
>
> This is our thinking w.r.t ZGC:
>
> 1) ZGC only returns memory from what we call "allocating" ZPages. Such pages are never part of an on-going marking cycle, and therefore don't need any barriers.
>
> 2) There's no safepoint *after* the memory has been allocated via `chunk_oop = allocator.allocate(); // can safepoint`
>
>
>
> So, when we reach the line you linked to, we are guaranteed that we don't need to perform any GC barriers on that object.
>
>
>
> Now, for Shenandoah IU mode, AFAIU (drawing parallels to CMS), the raw initializing stores are problematic, because you don't register those oops anywhere:
>
> ```
>
> // fields are uninitialized
>
> chunk->set_parent_raw<typename ConfigT::OopT>(_cont.last_nonempty_chunk());
>
> chunk->set_cont_raw<typename ConfigT::OopT>(_cont.continuation());
>
> ```
>
>
>
> You can also see how that comment about the fields are uninitialized, refers to SATB marking, and most-likely uses that as a rationale for skipping store barriers.
>
>
>
> In Generational ZGC, we also introduced store barriers. It's not similar to IU, but you can see how we had to changed from a raw store, to a store with a barrier:
>
> https://github.com/openjdk/zgc/blob/f0b25d9339104a80f903d889a7939dd623c76867/src/hotspot/share/runtime/continuationFreezeThaw.cpp
>
>
>
> ```
>
> // Allocate the chunk.
>
> //
>
> // This might safepoint while allocating, but all safepointing due to
>
> // instrumentation have been deferred. This property is important for
>
> // some GCs, as this ensures that the allocated object is in the young
>
> // generation / newly allocated memory.
>
> StackChunkAllocator allocator(klass, size_in_words, current, stack_size, _cont, _jvmti_event_collector);
>
> stackChunkOop chunk = allocator.allocate();
>
>
>
> if (chunk == nullptr) {
>
> return nullptr; // OOME
>
> }
>
> ...
>
> #if INCLUDE_ZGC
>
> if (UseZGC) {
>
> // fields are uninitialized
>
> chunk->set_parent_access<IS_DEST_UNINITIALIZED>(_cont.last_nonempty_chunk());
>
> chunk->set_cont_access<IS_DEST_UNINITIALIZED>(_cont.continuation());
>
> ZStackChunkGCData::initialize(chunk);
>
>
>
> assert(!chunk->requires_barriers(), "ZGC always allocates in the young generation");
>
> _barriers = false;
>
> } else
>
> #endif
>
> ```
The neat thing with using the right Access API stores instead of an ad hoc barrier, is that it works for both shenandoah IU mode, and generational ZGC, while the ad hoc barrier does not.
-------------
PR: https://git.openjdk.org/jdk/pull/9982
More information about the shenandoah-dev
mailing list