#[cfg(feature = "vo_bit")]
pub(crate) mod helper;
use atomic::Ordering;
use crate::util::metadata::side_metadata::SideMetadataSpec;
use crate::util::Address;
use crate::util::ObjectReference;
use crate::vm::object_model::ObjectModel;
use crate::vm::VMBinding;
cfg_if::cfg_if! {
if #[cfg(feature = "vo_bit_access")] {
pub const VO_BIT_SIDE_METADATA_SPEC: SideMetadataSpec =
crate::util::metadata::side_metadata::spec_defs::VO_BIT;
} else {
pub(crate) const VO_BIT_SIDE_METADATA_SPEC: SideMetadataSpec =
crate::util::metadata::side_metadata::spec_defs::VO_BIT;
}
}
#[cfg(target_pointer_width = "64")]
pub const VO_BIT_SIDE_METADATA_ADDR: Address = VO_BIT_SIDE_METADATA_SPEC.get_absolute_offset();
pub(crate) fn set_vo_bit(object: ObjectReference) {
debug_assert!(!is_vo_bit_set(object), "{:x}: VO bit already set", object);
VO_BIT_SIDE_METADATA_SPEC.store_atomic::<u8>(object.to_raw_address(), 1, Ordering::SeqCst);
}
pub(crate) fn unset_vo_bit(object: ObjectReference) {
debug_assert!(is_vo_bit_set(object), "{:x}: VO bit not set", object);
VO_BIT_SIDE_METADATA_SPEC.store_atomic::<u8>(object.to_raw_address(), 0, Ordering::SeqCst);
}
pub(crate) fn unset_vo_bit_nocheck(object: ObjectReference) {
VO_BIT_SIDE_METADATA_SPEC.store_atomic::<u8>(object.to_raw_address(), 0, Ordering::SeqCst);
}
pub(crate) unsafe fn unset_vo_bit_unsafe(object: ObjectReference) {
debug_assert!(is_vo_bit_set(object), "{:x}: VO bit not set", object);
VO_BIT_SIDE_METADATA_SPEC.store::<u8>(object.to_raw_address(), 0);
}
pub(crate) fn is_vo_bit_set(object: ObjectReference) -> bool {
VO_BIT_SIDE_METADATA_SPEC.load_atomic::<u8>(object.to_raw_address(), Ordering::SeqCst) == 1
}
pub(crate) fn is_vo_bit_set_for_addr(address: Address) -> Option<ObjectReference> {
is_vo_bit_set_inner::<true>(address)
}
pub(crate) unsafe fn is_vo_bit_set_unsafe(address: Address) -> Option<ObjectReference> {
is_vo_bit_set_inner::<false>(address)
}
fn is_vo_bit_set_inner<const ATOMIC: bool>(addr: Address) -> Option<ObjectReference> {
debug_assert!(
addr.is_aligned_to(ObjectReference::ALIGNMENT),
"Address is not word-aligned: {addr}"
);
if !VO_BIT_SIDE_METADATA_SPEC.is_mapped(addr) {
return None;
}
let vo_bit = if ATOMIC {
VO_BIT_SIDE_METADATA_SPEC.load_atomic::<u8>(addr, Ordering::SeqCst)
} else {
unsafe { VO_BIT_SIDE_METADATA_SPEC.load::<u8>(addr) }
};
(vo_bit == 1).then(|| get_object_ref_for_vo_addr(addr))
}
pub(crate) fn bzero_vo_bit(start: Address, size: usize) {
VO_BIT_SIDE_METADATA_SPEC.bzero_metadata(start, size);
}
pub(crate) fn bcopy_vo_bit_from_mark_bit<VM: VMBinding>(start: Address, size: usize) {
let mark_bit_spec = VM::VMObjectModel::LOCAL_MARK_BIT_SPEC;
debug_assert!(
mark_bit_spec.is_on_side(),
"bcopy_vo_bit_from_mark_bits can only be used with on-the-side mark bits."
);
let side_mark_bit_spec = mark_bit_spec.extract_side_spec();
VO_BIT_SIDE_METADATA_SPEC.bcopy_metadata_contiguous(start, size, side_mark_bit_spec);
}
use crate::util::constants::{LOG_BITS_IN_BYTE, LOG_BYTES_IN_ADDRESS};
pub(crate) const VO_BIT_WORD_TO_REGION: usize = 1
<< (VO_BIT_SIDE_METADATA_SPEC.log_bytes_in_region
+ LOG_BITS_IN_BYTE as usize
+ LOG_BYTES_IN_ADDRESS as usize
- VO_BIT_SIDE_METADATA_SPEC.log_num_of_bits);
pub(crate) fn get_raw_vo_bit_word(addr: Address) -> usize {
unsafe { VO_BIT_SIDE_METADATA_SPEC.load_raw_word(addr) }
}
pub(crate) fn find_object_from_internal_pointer<VM: VMBinding>(
start: Address,
search_limit_bytes: usize,
) -> Option<ObjectReference> {
if !start.is_mapped() {
return None;
}
if let Some(vo_addr) = unsafe {
VO_BIT_SIDE_METADATA_SPEC.find_prev_non_zero_value::<u8>(start, search_limit_bytes)
} {
is_internal_ptr_from_vo_bit::<VM>(vo_addr, start)
} else {
None
}
}
pub(crate) fn get_object_ref_for_vo_addr(vo_addr: Address) -> ObjectReference {
debug_assert!(vo_addr.is_aligned_to(ObjectReference::ALIGNMENT));
debug_assert!(unsafe { is_vo_addr(vo_addr) });
unsafe { ObjectReference::from_raw_address_unchecked(vo_addr) }
}
fn is_internal_ptr<VM: VMBinding>(obj: ObjectReference, internal_ptr: Address) -> bool {
let obj_start = obj.to_object_start::<VM>();
let obj_size = VM::VMObjectModel::get_current_size(obj);
internal_ptr < obj_start + obj_size
}
pub(crate) fn is_internal_ptr_from_vo_bit<VM: VMBinding>(
vo_addr: Address,
internal_ptr: Address,
) -> Option<ObjectReference> {
let obj = get_object_ref_for_vo_addr(vo_addr);
if is_internal_ptr::<VM>(obj, internal_ptr) {
Some(obj)
} else {
None
}
}
pub(crate) unsafe fn is_vo_addr(addr: Address) -> bool {
VO_BIT_SIDE_METADATA_SPEC.load::<u8>(addr) != 0
}