Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
38 changes: 10 additions & 28 deletions src/policy/largeobjectspace.rs
Original file line number Diff line number Diff line change
Expand Up @@ -251,37 +251,19 @@ impl<VM: VMBinding> LargeObjectSpace<VM> {
/// succeeds, the method will return true, meaning the object is marked by this invocation.
/// Otherwise, it returns false.
fn test_and_mark(&self, object: ObjectReference, value: u8) -> bool {
loop {
let mask = if self.in_nursery_gc {
LOS_BIT_MASK
} else {
MARK_BIT
};
let old_value = VM::VMObjectModel::LOCAL_LOS_MARK_NURSERY_SPEC.load_atomic::<VM, u8>(
let mask = if self.in_nursery_gc {
LOS_BIT_MASK
} else {
MARK_BIT
};
let result = VM::VMObjectModel::LOCAL_LOS_MARK_NURSERY_SPEC
.fetch_update_metadata::<VM, u8, _>(
object,
None,
Ordering::SeqCst,
Ordering::SeqCst,
|old_value| (old_value & mask != value).then(|| old_value & !LOS_BIT_MASK | value),
);
let mark_bit = old_value & mask;
if mark_bit == value {
return false;
}
// using LOS_BIT_MASK have side effects of clearing nursery bit
if VM::VMObjectModel::LOCAL_LOS_MARK_NURSERY_SPEC
.compare_exchange_metadata::<VM, u8>(
object,
old_value,
old_value & !LOS_BIT_MASK | value,
None,
Ordering::SeqCst,
Ordering::SeqCst,
)
.is_ok()
{
break;
}
}
true
result.is_ok()
}

fn test_mark_bit(&self, object: ObjectReference, value: u8) -> bool {
Expand Down
63 changes: 12 additions & 51 deletions src/policy/markcompactspace.rs
Original file line number Diff line number Diff line change
Expand Up @@ -248,60 +248,21 @@ impl<VM: VMBinding> MarkCompactSpace<VM> {
}

pub fn test_and_mark(object: ObjectReference) -> bool {
loop {
let old_value = VM::VMObjectModel::LOCAL_MARK_BIT_SPEC.load_atomic::<VM, u8>(
object,
None,
Ordering::SeqCst,
);
let mark_bit = old_value & GC_MARK_BIT_MASK;
if mark_bit != 0 {
return false;
}
if VM::VMObjectModel::LOCAL_MARK_BIT_SPEC
.compare_exchange_metadata::<VM, u8>(
object,
old_value,
1,
None,
Ordering::SeqCst,
Ordering::SeqCst,
)
.is_ok()
{
break;
}
}
true
let old_value = VM::VMObjectModel::LOCAL_MARK_BIT_SPEC.fetch_or_metadata::<VM, u8>(
object,
GC_MARK_BIT_MASK,
Ordering::SeqCst,
);
old_value == 0
}

pub fn test_and_clear_mark(object: ObjectReference) -> bool {
loop {
let old_value = VM::VMObjectModel::LOCAL_MARK_BIT_SPEC.load_atomic::<VM, u8>(
object,
None,
Ordering::SeqCst,
);
let mark_bit = old_value & GC_MARK_BIT_MASK;
if mark_bit == 0 {
return false;
}

if VM::VMObjectModel::LOCAL_MARK_BIT_SPEC
.compare_exchange_metadata::<VM, u8>(
object,
old_value,
0,
None,
Ordering::SeqCst,
Ordering::SeqCst,
)
.is_ok()
{
break;
}
}
true
let old_value = VM::VMObjectModel::LOCAL_MARK_BIT_SPEC.fetch_and_metadata::<VM, u8>(
object,
!GC_MARK_BIT_MASK,
Ordering::SeqCst,
);
old_value == 1
}

pub fn is_marked(object: ObjectReference) -> bool {
Expand Down
50 changes: 20 additions & 30 deletions src/util/metadata/mark_bit.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ use std::sync::atomic::Ordering;
impl VMLocalMarkBitSpec {
/// Set the mark bit for the object to 1
pub fn mark<VM: VMBinding>(&self, object: ObjectReference, ordering: Ordering) {
self.store_atomic::<VM, u8>(object, 1, None, ordering);
self.fetch_or_metadata::<VM, u8>(object, 1, ordering);
}

/// Test if the mark bit for the object is set (1)
Expand Down Expand Up @@ -63,43 +63,33 @@ impl MarkState {
/// Attempt to mark an object. If the object is marked by this invocation, return true.
/// Otherwise return false -- the object was marked by others.
pub fn test_and_mark<VM: VMBinding>(&self, object: ObjectReference) -> bool {
loop {
let old_value = VM::VMObjectModel::LOCAL_MARK_BIT_SPEC.load_atomic::<VM, u8>(
let old_value = match self.state {
0 => VM::VMObjectModel::LOCAL_MARK_BIT_SPEC.fetch_and_metadata::<VM, u8>(
object,
None,
0,
Ordering::SeqCst,
);
if old_value == self.state {
return false;
}

if VM::VMObjectModel::LOCAL_MARK_BIT_SPEC
.compare_exchange_metadata::<VM, u8>(
object,
old_value,
self.state,
None,
Ordering::SeqCst,
Ordering::SeqCst,
)
.is_ok()
{
break;
}
}
true
),
1 => VM::VMObjectModel::LOCAL_MARK_BIT_SPEC.fetch_or_metadata::<VM, u8>(
object,
1,
Ordering::SeqCst,
),
_ => unreachable!(),
};
old_value == self.state
}

/// This has to be called during object initialization.
pub fn on_object_metadata_initialization<VM: VMBinding>(&self, object: ObjectReference) {
// If it is in header, we have to set the mark bit for every newly allocated object
if VM::VMObjectModel::LOCAL_MARK_BIT_SPEC.is_in_header() {
VM::VMObjectModel::LOCAL_MARK_BIT_SPEC.store_atomic::<VM, u8>(
object,
self.unmarked_state(),
None,
Ordering::SeqCst,
);
unsafe {
VM::VMObjectModel::LOCAL_MARK_BIT_SPEC.store::<VM, u8>(
object,
self.unmarked_state(),
None,
);
}
}
}

Expand Down
31 changes: 11 additions & 20 deletions src/util/object_forwarding.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,23 +22,15 @@ const FORWARDING_POINTER_MASK: usize = 0xffff_fffc;
/// Attempt to become the worker thread who will forward the object.
/// The successful worker will set the object forwarding bits to BEING_FORWARDED, preventing other workers from forwarding the same object.
pub fn attempt_to_forward<VM: VMBinding>(object: ObjectReference) -> u8 {
loop {
let old_value = get_forwarding_status::<VM>(object);
if old_value != FORWARDING_NOT_TRIGGERED_YET
|| VM::VMObjectModel::LOCAL_FORWARDING_BITS_SPEC
.compare_exchange_metadata::<VM, u8>(
object,
old_value,
BEING_FORWARDED,
None,
Ordering::SeqCst,
Ordering::Relaxed,
)
.is_ok()
{
return old_value;
}
}
// We simply "or" the current value with `BEING_FORWARDED` and return the old value.
// If the old value was 00 (`FORWARDING_NOT_TRIGGERED_YET`),
// it will be changed to 10 (`BEING_FORWARDED`);
// otherwise (the old value would be 10 or 11) it will be a no-op.
VM::VMObjectModel::LOCAL_FORWARDING_BITS_SPEC.fetch_or_metadata::<VM, u8>(
object,
BEING_FORWARDED,
Ordering::SeqCst,
)
}

/// Spin-wait for the object's forwarding to become complete and then read the forwarding pointer to the new object.
Expand Down Expand Up @@ -132,12 +124,11 @@ pub fn state_is_being_forwarded(forwarding_bits: u8) -> bool {
/// Zero the forwarding bits of an object.
/// This function is used on new objects.
pub fn clear_forwarding_bits<VM: VMBinding>(object: ObjectReference) {
VM::VMObjectModel::LOCAL_FORWARDING_BITS_SPEC.store_atomic::<VM, u8>(
VM::VMObjectModel::LOCAL_FORWARDING_BITS_SPEC.fetch_and_metadata::<VM, u8>(
object,
0,
None,
Ordering::SeqCst,
)
);
}

/// Read the forwarding pointer of an object.
Expand Down