Skip to content

Commit 4a29049

Browse files
committed
Only reset unlog bits of objects in modbuf for nursery GCs
This fixes a bug wherein we were erroneously resetting the unlog bits for objects in the modbuf for full-heap GCs. If we reset the unlog bits in a full-heap GC, we may end up setting the unlog bit for an object that actually died which may cause issues for future allocations. We now set the unlog bits for mature objects when tracing for VM space (if compiled with `set_unlog_bits_vm_space`), immortal space, and large object space. This PR also adds debug assertions checking that any object that has been added to the modbuf is considered "live" by MMTk, or in other words, it is a mature object.
1 parent b8355f8 commit 4a29049

File tree

5 files changed

+37
-11
lines changed

5 files changed

+37
-11
lines changed

src/plan/barriers.rs

+1
Original file line numberDiff line numberDiff line change
@@ -231,6 +231,7 @@ impl<S: BarrierSemantics> Barrier<S::VM> for ObjectBarrier<S> {
231231
target: Option<ObjectReference>,
232232
) {
233233
if self.log_object(src) {
234+
debug_assert!(src.is_live::<S::VM>(), "{} was logged but is not live", src);
234235
self.semantics
235236
.object_reference_write_slow(src, slot, target);
236237
}

src/plan/generational/gc_work.rs

+16-10
Original file line numberDiff line numberDiff line change
@@ -108,22 +108,28 @@ impl<E: ProcessEdgesWork> ProcessModBuf<E> {
108108

109109
impl<E: ProcessEdgesWork> GCWork<E::VM> for ProcessModBuf<E> {
110110
fn do_work(&mut self, worker: &mut GCWorker<E::VM>, mmtk: &'static MMTK<E::VM>) {
111-
// Flip the per-object unlogged bits to "unlogged" state.
112-
for obj in &self.modbuf {
113-
<E::VM as VMBinding>::VMObjectModel::GLOBAL_LOG_BIT_SPEC.store_atomic::<E::VM, u8>(
114-
*obj,
115-
1,
116-
None,
117-
Ordering::SeqCst,
118-
);
119-
}
120-
// scan modbuf only if the current GC is a nursery GC
111+
// Process and scan modbuf only if the current GC is a nursery GC
121112
if mmtk
122113
.get_plan()
123114
.generational()
124115
.unwrap()
125116
.is_current_gc_nursery()
126117
{
118+
// Flip the per-object unlogged bits to "unlogged" state.
119+
for obj in &self.modbuf {
120+
debug_assert!(
121+
(*obj).is_live::<E::VM>(),
122+
"{} was logged but is not live",
123+
*obj
124+
);
125+
126+
<E::VM as VMBinding>::VMObjectModel::GLOBAL_LOG_BIT_SPEC.store_atomic::<E::VM, u8>(
127+
*obj,
128+
1,
129+
None,
130+
Ordering::SeqCst,
131+
);
132+
}
127133
// Scan objects in the modbuf and forward pointers
128134
let modbuf = std::mem::take(&mut self.modbuf);
129135
GCWork::do_work(

src/policy/immortalspace.rs

+5
Original file line numberDiff line numberDiff line change
@@ -197,6 +197,11 @@ impl<VM: VMBinding> ImmortalSpace<VM> {
197197
object
198198
);
199199
if self.mark_state.test_and_mark::<VM>(object) {
200+
// Set the unlog bit if required
201+
if self.common.needs_log_bit {
202+
<E::VM as VMBinding>::VMObjectModel::GLOBAL_LOG_BIT_SPEC
203+
.store_atomic::<E::VM, u8>(object, 1, None, Ordering::SeqCst);
204+
}
200205
queue.enqueue(object);
201206
}
202207
object

src/policy/largeobjectspace.rs

+8-1
Original file line numberDiff line numberDiff line change
@@ -211,7 +211,9 @@ impl<VM: VMBinding> LargeObjectSpace<VM> {
211211
trace!("LOS object {} is being marked now", object);
212212
self.treadmill.copy(object, nursery_object);
213213
// We just moved the object out of the logical nursery, mark it as unlogged.
214-
if nursery_object && self.common.needs_log_bit {
214+
// We also unlog mature objects as their unlog bit may have been unset before the
215+
// full-heap GC
216+
if self.common.needs_log_bit {
215217
VM::VMObjectModel::GLOBAL_LOG_BIT_SPEC
216218
.mark_as_unlogged::<VM>(object, Ordering::SeqCst);
217219
}
@@ -230,6 +232,11 @@ impl<VM: VMBinding> LargeObjectSpace<VM> {
230232
let sweep = |object: ObjectReference| {
231233
#[cfg(feature = "vo_bit")]
232234
crate::util::metadata::vo_bit::unset_vo_bit::<VM>(object);
235+
// Clear log bits for dead objects to prevent a new nursery object having the unlog bit set
236+
if self.common.needs_log_bit {
237+
<E::VM as VMBinding>::VMObjectModel::GLOBAL_LOG_BIT_SPEC
238+
.store_atomic::<E::VM, u8>(object, 0, None, Ordering::SeqCst);
239+
}
233240
self.pr
234241
.release_pages(get_super_page(object.to_object_start::<VM>()));
235242
};

src/policy/vmspace.rs

+7
Original file line numberDiff line numberDiff line change
@@ -253,6 +253,13 @@ impl<VM: VMBinding> VMSpace<VM> {
253253
);
254254
debug_assert!(self.in_space(object));
255255
if self.mark_state.test_and_mark::<VM>(object) {
256+
// Flip the per-object unlogged bits to "unlogged" state for objects inside the
257+
// bootimage
258+
#[cfg(set_unlog_bits_vm_space)]
259+
if self.common.needs_log_bit {
260+
<E::VM as VMBinding>::VMObjectModel::GLOBAL_LOG_BIT_SPEC
261+
.store_atomic::<E::VM, u8>(object, 1, None, Ordering::SeqCst);
262+
}
256263
queue.enqueue(object);
257264
}
258265
object

0 commit comments

Comments
 (0)