use atomic::Ordering;
use crate::{
util::{
linear_scan::Region,
metadata::{vo_bit, MetadataSpec},
ObjectReference,
},
vm::{ObjectModel, VMBinding},
};
#[derive(Debug)]
enum VOBitUpdateStrategy {
ClearAndReconstruct,
CopyFromMarkBits,
}
impl VOBitUpdateStrategy {
pub fn vo_bit_available_during_tracing(&self) -> bool {
match *self {
VOBitUpdateStrategy::ClearAndReconstruct => false,
VOBitUpdateStrategy::CopyFromMarkBits => true,
}
}
}
const fn strategy<VM: VMBinding>() -> VOBitUpdateStrategy {
match VM::VMObjectModel::LOCAL_MARK_BIT_SPEC.as_spec() {
MetadataSpec::InHeader(_) => VOBitUpdateStrategy::ClearAndReconstruct,
MetadataSpec::OnSide(_) => VOBitUpdateStrategy::CopyFromMarkBits,
}
}
pub(crate) fn validate_config<VM: VMBinding>() {
assert!(
!(VM::VMObjectModel::NEED_VO_BITS_DURING_TRACING
&& VM::VMObjectModel::LOCAL_MARK_BIT_SPEC
.as_spec()
.is_in_header()),
"The VM binding needs VO bits during tracing but also has in-header mark bits. \
We currently don't have an appropriate strategy for this case."
);
let s = strategy::<VM>();
match s {
VOBitUpdateStrategy::ClearAndReconstruct => {
}
VOBitUpdateStrategy::CopyFromMarkBits => {
let mark_bit_spec = VM::VMObjectModel::LOCAL_MARK_BIT_SPEC;
assert!(
mark_bit_spec.is_on_side(),
"The {s:?} strategy requires the mark bits to be on the side."
);
let mark_bit_meta = mark_bit_spec.extract_side_spec();
let vo_bit_meta = vo_bit::VO_BIT_SIDE_METADATA_SPEC;
assert_eq!(
mark_bit_meta.log_bytes_in_region,
vo_bit_meta.log_bytes_in_region,
"The {s:?} strategy requires the mark bits to have the same granularity as the VO bits."
);
assert_eq!(mark_bit_meta.log_num_of_bits, vo_bit_meta.log_num_of_bits,
"The {s:?} strategy requires the mark bits to have the same number of bits per object as the VO bits.");
}
}
}
pub(crate) fn need_to_clear_vo_bits_before_tracing<VM: VMBinding>() -> bool {
match strategy::<VM>() {
VOBitUpdateStrategy::ClearAndReconstruct => true,
VOBitUpdateStrategy::CopyFromMarkBits => false,
}
}
pub(crate) fn on_trace_object<VM: VMBinding>(object: ObjectReference) {
if strategy::<VM>().vo_bit_available_during_tracing() {
debug_assert!(
vo_bit::is_vo_bit_set(object),
"{:x}: VO bit not set",
object
);
}
}
pub(crate) fn on_object_marked<VM: VMBinding>(object: ObjectReference) {
match strategy::<VM>() {
VOBitUpdateStrategy::ClearAndReconstruct => {
vo_bit::set_vo_bit(object);
}
VOBitUpdateStrategy::CopyFromMarkBits => {
}
}
}
pub(crate) fn on_object_forwarded<VM: VMBinding>(new_object: ObjectReference) {
match strategy::<VM>() {
VOBitUpdateStrategy::ClearAndReconstruct => {
vo_bit::set_vo_bit(new_object);
}
VOBitUpdateStrategy::CopyFromMarkBits => {
VM::VMObjectModel::LOCAL_MARK_BIT_SPEC.store_atomic::<VM, u8>(
new_object,
1,
None,
Ordering::SeqCst,
);
vo_bit::set_vo_bit(new_object);
}
}
}
pub(crate) fn on_region_swept<VM: VMBinding, R: Region>(region: &R, is_occupied: bool) {
match strategy::<VM>() {
VOBitUpdateStrategy::ClearAndReconstruct => {
}
VOBitUpdateStrategy::CopyFromMarkBits => {
if is_occupied {
vo_bit::bcopy_vo_bit_from_mark_bit::<VM>(region.start(), R::BYTES);
} else {
vo_bit::bzero_vo_bit(region.start(), R::BYTES);
}
}
}
}