RFR: 8373116: Genshen: arraycopy_work should be done unconditionally by arraycopy_marking if the array is in an old region [v5]

William Kemper wkemper at openjdk.org
Fri Dec 5 20:02:57 UTC 2025


On Fri, 5 Dec 2025 18:19:39 GMT, Xiaolong Peng <xpeng at openjdk.org> wrote:

>> Chasing the root cause of JDK-8372498, I have narrowed down root cause to the commit https://github.com/openjdk/jdk/commit/f8cf9ca69cfef286c80559bfe1d147b6303d10d2
>> 
>> It is caused by the behavior change from follow code:
>> 
>> Original:
>> 
>>   if (ShenandoahSATBBarrier) {
>>     T* array = dst;
>>     HeapWord* array_addr = reinterpret_cast<HeapWord*>(array);
>>     ShenandoahHeapRegion* r = _heap->heap_region_containing(array_addr);
>>     if (is_old_marking) {
>>       // Generational, old marking
>>       assert(_heap->mode()->is_generational(), "Invariant");
>>       if (r->is_old() && (array_addr < _heap->marking_context()->top_at_mark_start(r))) {
>>         arraycopy_work<T, false, false, true>(array, count);
>>       }
>>     } else if (_heap->mode()->is_generational()) {
>>       // Generational, young marking
>>       if (r->is_old() || (array_addr < _heap->marking_context()->top_at_mark_start(r))) {
>>         arraycopy_work<T, false, false, true>(array, count);
>>       }
>>     } else if (array_addr < _heap->marking_context()->top_at_mark_start(r)) {
>>       // Non-generational, marking
>>       arraycopy_work<T, false, false, true>(array, count);
>>     }
>>   }
>> 
>> New:
>> 
>>   if (ShenandoahSATBBarrier) {
>>     if (!_heap->marking_context()->allocated_after_mark_start(reinterpret_cast<HeapWord*>(dst))) {
>>       arraycopy_work<T, false, false, true>(dst, count);
>>     }
>>   }
>> 
>> 
>> 
>> With the new STAB barrier code for arraycopy_marking, if is it young GC and the array is in old region, but array is above TAMS, arraycopy_work won't be applied anymore, so we may have missed some pointers in SATB in such case.
>> 
>> ### Test
>> - [x] hotspot_gc_shenandoah
>> - [x] repeat gc/TestAllocHumongousFragment.java#generational and sure it won't crash with the fix
>> - [x] GHA
>
> Xiaolong Peng has updated the pull request incrementally with one additional commit since the last revision:
> 
>   Add include header shenandoahOldGeneration.hpp

The issue, as I understand it, is that mutators are racing with the concurrent remembered set scan. If a mutator changes a pointer covered by a dirty card, it could prevent the remembered set scan from tracing the original object that was reachable at the beginning of marking. Since we may not be marking old, we cannot rely on the TAMS for objects in old regions and must unconditionally enqueue all of the overwritten pointers in the old array. Should we only do this when young marking is in progress? Perhaps we should have a version of `arraycopy_work` that only enqueues young pointers here?

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

PR Review: https://git.openjdk.org/jdk/pull/28669#pullrequestreview-3546247628


More information about the shenandoah-dev mailing list