-
Bug
-
Resolution: Fixed
-
P3
-
11
-
b01
CMS precleaning is a phase where the card table is scanned for dirty cards. A
dirty card is an indication for GC that references in corresponding objects were
updated. In the precleaning phase the references of these objects are followed
and the objects reached are marked.
Precleaning is a concurrent phase therefore accesses to the card table need to
be ordered with corresponding accesses to references.
On mutator side storing references must preceed the stores for marking the
corresponding cards dirty.
This ordering is missing when copying object arrays in the interpreter or when
default versions of array copy routines like `StubRoutines::oop_copy()` are used.
This is the stack where cards are marked dirty after an arraycopy in the
interpreter. Copying array elements happens in `oop_arraycopy_in_heap()`[1]. The
card table is dirtied in `write_ref_array_work()`[2]. Between a storestore barrier
is missing.
```
CardTableBarrierSet::write_ref_array_work()
ModRefBarrierSet::write_ref_array()
ModRefBarrierSet::AccessBarrier<36225142ul, CardTableBarrierSet>::oop_arraycopy_in_heap<unsigned int>()
AccessInternal::PostRuntimeDispatch<CardTableBarrierSet::AccessBarrier<36225142ul, CardTableBarrierSet>,()
AccessInternal::RuntimeDispatch<36225110ul, HeapWord,()
AccessInternal::RuntimeDispatch<36225110ul, HeapWord,()
AccessInternal::PreRuntimeDispatch::arraycopy<36225110ul, HeapWord>()
AccessInternal::arraycopy_reduce_types<36225108ul>()
AccessInternal::arraycopy<36175876ul, HeapWord>()
Access<36175872ul>::oop_arraycopy<HeapWord>()
ArrayAccess<33554432ul>::oop_arraycopy()
ObjArrayKlass::do_copy()
ObjArrayKlass::copy_array()
JVM_ArrayCopy()
```
Note that in `CardTableBarrierSet::write_ref_field_post(T* field, oop newVal)` [3]
for example the card table store is given release semantics.
`CardTableBarrierSetAssembler::gen_write_ref_array_post_barrier()` on AARCH64[4]
and PPC64[5] issue a StoreStore barrier.
[1] Copying array elements in `oop_arraycopy_in_heap()`
https://github.com/openjdk/jdk11u/blob/73eef16128417f4a489c4dde47383bb4a00f39d4/src/hotspot/share/gc/shared/modRefBarrierSet.inline.hpp#L106
[2] Marking cards dirty for the updates of [1] in `write_ref_array_work()`
https://github.com/openjdk/jdk11u/blob/master/src/hotspot/share/gc/shared/cardTableBarrierSet.cpp#L82
[3] Card table store with release sematics in CardTableBarrierSet::write_ref_field_post(T* field, oop newVal)
https://github.com/openjdk/jdk11u/blob/73eef16128417f4a489c4dde47383bb4a00f39d4/src/hotspot/share/gc/shared/cardTableBarrierSet.inline.hpp#L36-L37
[4] StoreStore barrier in AARCH64 version of `CardTableBarrierSetAssembler::gen_write_ref_array_post_barrier()`
https://github.com/openjdk/jdk11u/blob/73eef16128417f4a489c4dde47383bb4a00f39d4/src/hotspot/cpu/aarch64/gc/shared/cardTableBarrierSetAssembler_aarch64.cpp#L86
[5] StoreStore barrier in PPC64 version of `CardTableBarrierSetAssembler::gen_write_ref_array_post_barrier()`
https://github.com/openjdk/jdk11u/blob/73eef16128417f4a489c4dde47383bb4a00f39d4/src/hotspot/cpu/ppc/gc/shared/cardTableBarrierSetAssembler_ppc.cpp#L53
dirty card is an indication for GC that references in corresponding objects were
updated. In the precleaning phase the references of these objects are followed
and the objects reached are marked.
Precleaning is a concurrent phase therefore accesses to the card table need to
be ordered with corresponding accesses to references.
On mutator side storing references must preceed the stores for marking the
corresponding cards dirty.
This ordering is missing when copying object arrays in the interpreter or when
default versions of array copy routines like `StubRoutines::oop_copy()` are used.
This is the stack where cards are marked dirty after an arraycopy in the
interpreter. Copying array elements happens in `oop_arraycopy_in_heap()`[1]. The
card table is dirtied in `write_ref_array_work()`[2]. Between a storestore barrier
is missing.
```
CardTableBarrierSet::write_ref_array_work()
ModRefBarrierSet::write_ref_array()
ModRefBarrierSet::AccessBarrier<36225142ul, CardTableBarrierSet>::oop_arraycopy_in_heap<unsigned int>()
AccessInternal::PostRuntimeDispatch<CardTableBarrierSet::AccessBarrier<36225142ul, CardTableBarrierSet>,()
AccessInternal::RuntimeDispatch<36225110ul, HeapWord,()
AccessInternal::RuntimeDispatch<36225110ul, HeapWord,()
AccessInternal::PreRuntimeDispatch::arraycopy<36225110ul, HeapWord>()
AccessInternal::arraycopy_reduce_types<36225108ul>()
AccessInternal::arraycopy<36175876ul, HeapWord>()
Access<36175872ul>::oop_arraycopy<HeapWord>()
ArrayAccess<33554432ul>::oop_arraycopy()
ObjArrayKlass::do_copy()
ObjArrayKlass::copy_array()
JVM_ArrayCopy()
```
Note that in `CardTableBarrierSet::write_ref_field_post(T* field, oop newVal)` [3]
for example the card table store is given release semantics.
`CardTableBarrierSetAssembler::gen_write_ref_array_post_barrier()` on AARCH64[4]
and PPC64[5] issue a StoreStore barrier.
[1] Copying array elements in `oop_arraycopy_in_heap()`
https://github.com/openjdk/jdk11u/blob/73eef16128417f4a489c4dde47383bb4a00f39d4/src/hotspot/share/gc/shared/modRefBarrierSet.inline.hpp#L106
[2] Marking cards dirty for the updates of [1] in `write_ref_array_work()`
https://github.com/openjdk/jdk11u/blob/master/src/hotspot/share/gc/shared/cardTableBarrierSet.cpp#L82
[3] Card table store with release sematics in CardTableBarrierSet::write_ref_field_post(T* field, oop newVal)
https://github.com/openjdk/jdk11u/blob/73eef16128417f4a489c4dde47383bb4a00f39d4/src/hotspot/share/gc/shared/cardTableBarrierSet.inline.hpp#L36-L37
[4] StoreStore barrier in AARCH64 version of `CardTableBarrierSetAssembler::gen_write_ref_array_post_barrier()`
https://github.com/openjdk/jdk11u/blob/73eef16128417f4a489c4dde47383bb4a00f39d4/src/hotspot/cpu/aarch64/gc/shared/cardTableBarrierSetAssembler_aarch64.cpp#L86
[5] StoreStore barrier in PPC64 version of `CardTableBarrierSetAssembler::gen_write_ref_array_post_barrier()`
https://github.com/openjdk/jdk11u/blob/73eef16128417f4a489c4dde47383bb4a00f39d4/src/hotspot/cpu/ppc/gc/shared/cardTableBarrierSetAssembler_ppc.cpp#L53