mmtk/util/metadata/vo_bit/
mod.rs

1//! Valid object bit (VO bit)
2//!
3//! The valid object bit, or "VO bit" for short", is a global per-address metadata.  It is set at
4//! the address of the `ObjectReference` of an object when the object is allocated, and cleared
5//! when the object is determined to be dead by the GC.
6//!
7//! The VO bit metadata serves multiple purposes, including but not limited to:
8//!
9//! | purpose                                     | happens when                                  |
10//! |---------------------------------------------|-----------------------------------------------|
11//! | conservative stack scanning                 | stack scanning                                |
12//! | conservative object scanning                | tracing                                       |
13//! | supporting interior pointers                | tracing                                       |
14//! | heap dumping (by tracing)                   | tracing                                       |
15//! | heap dumping (by iteration)                 | before or after tracing                       |
16//! | heap iteration (for GC algorithm)           | depending on algorithm                        |
17//! | heap iteration (for VM API, e.g. JVM-TI)    | during mutator time                           |
18//! | sanity checking                             | any time in GC                                |
19//!
20//! Among the listed purposes, conservative stack scanning and conservative objects scanning are
21//! visible to the VM binding.  By default, if the "vo_bit" cargo feature is enabled, the VO bits
22//! metadata will be available to the VM binding during stack scanning time.  The VM binding can
23//! further require the VO bits to be available during tracing (for object scanning) by setting
24//! [`crate::vm::ObjectModel::NEED_VO_BITS_DURING_TRACING`] to `true`.  mmtk-core does not
25//! guarantee the VO bits are available to the VM binding during other time.
26//!
27//! Internally, mmtk-core will also make the VO bits available when necessary if mmtk-core needs to
28//! implement features that needs VO bits.
29//!
30//! When the VO bits are available during tracing, if a plan uses evacuation to reclaim space, then
31//! both the from-space copy and the to-space copy of an object will have the VO-bit set.
32//!
33//! *(Note: There are several reasons behind this semantics.  One reason is that a slot may be
34//! visited multiple times during GC.  If a slot is visited twice, we will see the object reference
35//! in the slot pointing to the from-space copy during the first visit, but pointing to the to-space
36//! copy during the second visit.  We consider an object reference valid if it points to either the
37//! from-space or the to-space copy.  If each slot is visited only once, and we see a slot happen to
38//! hold a pointer into the to-space during its only visit, that must be a dangling pointer, and
39//! error should be reported.  However, it is hard to guarantee each slot is only visited once
40//! during tracing because both the VM and the GC algorithm may break this guarantee.  See:
41//! [`crate::plan::PlanConstraints::may_trace_duplicate_edges`])*
42
43// FIXME: The entire vo_bit module should only be available if the "vo_bit" feature is enabled.
44// However, the malloc-based MarkSweepSpace and MarkCompactSpace depends on the VO bits regardless
45// of the "vo_bit" feature.
46#[cfg(feature = "vo_bit")]
47pub(crate) mod helper;
48
49use atomic::Ordering;
50
51use crate::util::metadata::side_metadata::SideMetadataSpec;
52use crate::util::Address;
53use crate::util::ObjectReference;
54use crate::vm::object_model::ObjectModel;
55use crate::vm::VMBinding;
56
57cfg_if::cfg_if! {
58    if #[cfg(feature = "vo_bit_access")] {
59        /// A VO bit is required per min-object-size aligned address, rather than per object, and can only exist as side metadata.
60        /// This is only publicly available when the feature "vo_bit_access" is enabled.
61        /// Check the comments on "vo_bit_access" in `Cargo.toml` before use. Use at your own risk.
62        pub const VO_BIT_SIDE_METADATA_SPEC: SideMetadataSpec =
63        crate::util::metadata::side_metadata::spec_defs::VO_BIT;
64    } else {
65        /// A VO bit is required per min-object-size aligned address, rather than per object, and can only exist as side metadata.
66        pub(crate) const VO_BIT_SIDE_METADATA_SPEC: SideMetadataSpec =
67            crate::util::metadata::side_metadata::spec_defs::VO_BIT;
68    }
69}
70
71/// The base address for VO bit side metadata on 64 bits platforms.
72#[cfg(target_pointer_width = "64")]
73pub fn vo_bit_side_metadata_addr() -> Address {
74    VO_BIT_SIDE_METADATA_SPEC.get_starting_address()
75}
76
77/// Atomically set the VO bit for an object.
78pub(crate) fn set_vo_bit(object: ObjectReference) {
79    debug_assert!(!is_vo_bit_set(object), "{:x}: VO bit already set", object);
80    VO_BIT_SIDE_METADATA_SPEC.store_atomic::<u8>(object.to_raw_address(), 1, Ordering::SeqCst);
81}
82
83/// Atomically unset the VO bit for an object.
84pub(crate) fn unset_vo_bit(object: ObjectReference) {
85    debug_assert!(is_vo_bit_set(object), "{:x}: VO bit not set", object);
86    VO_BIT_SIDE_METADATA_SPEC.store_atomic::<u8>(object.to_raw_address(), 0, Ordering::SeqCst);
87}
88
89/// Atomically unset the VO bit for an object, regardless whether the bit is set or not.
90pub(crate) fn unset_vo_bit_nocheck(object: ObjectReference) {
91    VO_BIT_SIDE_METADATA_SPEC.store_atomic::<u8>(object.to_raw_address(), 0, Ordering::SeqCst);
92}
93
94/// Non-atomically unset the VO bit for an object. The caller needs to ensure the side
95/// metadata for the VO bit for the object is accessed by only one thread.
96///
97/// # Safety
98///
99/// This is unsafe: check the comment on `side_metadata::store`
100pub(crate) unsafe fn unset_vo_bit_unsafe(object: ObjectReference) {
101    debug_assert!(is_vo_bit_set(object), "{:x}: VO bit not set", object);
102    VO_BIT_SIDE_METADATA_SPEC.store::<u8>(object.to_raw_address(), 0);
103}
104
105/// Check if the VO bit is set for an object.
106pub(crate) fn is_vo_bit_set(object: ObjectReference) -> bool {
107    VO_BIT_SIDE_METADATA_SPEC.load_atomic::<u8>(object.to_raw_address(), Ordering::SeqCst) == 1
108}
109
110/// Check if an address can be turned directly into an object reference using the VO bit.
111/// If so, return `Some(object)`. Otherwise return `None`.
112///
113/// The `address` must be word-aligned.
114pub(crate) fn is_vo_bit_set_for_addr(address: Address) -> Option<ObjectReference> {
115    is_vo_bit_set_inner::<true>(address)
116}
117
118/// Check if an address can be turned directly into an object reference using the VO bit.
119/// If so, return `Some(object)`. Otherwise return `None`. The caller needs to ensure the side
120/// metadata for the VO bit for the object is accessed by only one thread.
121///
122/// The `address` must be word-aligned.
123///
124/// # Safety
125///
126/// This is unsafe: check the comment on `side_metadata::load`
127pub(crate) unsafe fn is_vo_bit_set_unsafe(address: Address) -> Option<ObjectReference> {
128    is_vo_bit_set_inner::<false>(address)
129}
130
131fn is_vo_bit_set_inner<const ATOMIC: bool>(addr: Address) -> Option<ObjectReference> {
132    debug_assert!(
133        addr.is_aligned_to(ObjectReference::ALIGNMENT),
134        "Address is not word-aligned: {addr}"
135    );
136
137    // If we haven't mapped VO bit for the address, it cannot be an object
138    if !VO_BIT_SIDE_METADATA_SPEC.is_mapped(addr) {
139        return None;
140    }
141
142    let vo_bit = if ATOMIC {
143        VO_BIT_SIDE_METADATA_SPEC.load_atomic::<u8>(addr, Ordering::SeqCst)
144    } else {
145        unsafe { VO_BIT_SIDE_METADATA_SPEC.load::<u8>(addr) }
146    };
147
148    (vo_bit == 1).then(|| get_object_ref_for_vo_addr(addr))
149}
150
151/// Bulk zero the VO bit.
152pub(crate) fn bzero_vo_bit(start: Address, size: usize) {
153    VO_BIT_SIDE_METADATA_SPEC.bzero_metadata(start, size);
154}
155
156/// Bulk copy VO bits from side mark bits.
157/// Some VMs require the VO bits to be available during tracing.
158/// However, some GC algorithms (such as Immix) cannot clear VO bits for dead objects only.
159/// As an alternative, this function copies the mark bits metadata to VO bits.
160/// The caller needs to ensure the mark bits are set exactly wherever VO bits need to be set before
161/// calling this function.
162pub(crate) fn bcopy_vo_bit_from_mark_bit<VM: VMBinding>(start: Address, size: usize) {
163    let mark_bit_spec = VM::VMObjectModel::LOCAL_MARK_BIT_SPEC;
164    debug_assert!(
165        mark_bit_spec.is_on_side(),
166        "bcopy_vo_bit_from_mark_bits can only be used with on-the-side mark bits."
167    );
168    let side_mark_bit_spec = mark_bit_spec.extract_side_spec();
169    VO_BIT_SIDE_METADATA_SPEC.bcopy_metadata_contiguous(start, size, side_mark_bit_spec);
170}
171
172use crate::util::constants::{LOG_BITS_IN_BYTE, LOG_BYTES_IN_ADDRESS};
173
174/// How many data memory bytes does 1 word in the VO bit side metadata represents?
175pub(crate) const VO_BIT_WORD_TO_REGION: usize = 1
176    << (VO_BIT_SIDE_METADATA_SPEC.log_bytes_in_region
177        + LOG_BITS_IN_BYTE as usize
178        + LOG_BYTES_IN_ADDRESS as usize
179        - VO_BIT_SIDE_METADATA_SPEC.log_num_of_bits);
180
181/// Bulk check if a VO bit word. Return true if there is any bit set in the word.
182pub(crate) fn get_raw_vo_bit_word(addr: Address) -> usize {
183    unsafe { VO_BIT_SIDE_METADATA_SPEC.load_raw_word(addr) }
184}
185
186/// Find the base reference to the object from a potential internal pointer.
187pub(crate) fn find_object_from_internal_pointer<VM: VMBinding>(
188    start: Address,
189    search_limit_bytes: usize,
190) -> Option<ObjectReference> {
191    if !start.is_mapped() {
192        return None;
193    }
194
195    if let Some(vo_addr) = unsafe {
196        VO_BIT_SIDE_METADATA_SPEC.find_prev_non_zero_value::<u8>(start, search_limit_bytes)
197    } {
198        is_internal_ptr_from_vo_bit::<VM>(vo_addr, start)
199    } else {
200        None
201    }
202}
203
204/// Get the object reference from an aligned address where VO bit is set.
205pub(crate) fn get_object_ref_for_vo_addr(vo_addr: Address) -> ObjectReference {
206    // VO bit should be set on the address.
207    debug_assert!(vo_addr.is_aligned_to(ObjectReference::ALIGNMENT));
208    debug_assert!(unsafe { is_vo_addr(vo_addr) });
209    unsafe { ObjectReference::from_raw_address_unchecked(vo_addr) }
210}
211
212/// Check if the address could be an internal pointer in the object.
213fn is_internal_ptr<VM: VMBinding>(obj: ObjectReference, internal_ptr: Address) -> bool {
214    let obj_start = obj.to_object_start::<VM>();
215    let obj_size = VM::VMObjectModel::get_current_size(obj);
216    internal_ptr < obj_start + obj_size
217}
218
219/// Check if the address could be an internal pointer based on where VO bit is set.
220pub(crate) fn is_internal_ptr_from_vo_bit<VM: VMBinding>(
221    vo_addr: Address,
222    internal_ptr: Address,
223) -> Option<ObjectReference> {
224    let obj = get_object_ref_for_vo_addr(vo_addr);
225    if is_internal_ptr::<VM>(obj, internal_ptr) {
226        Some(obj)
227    } else {
228        None
229    }
230}
231
232/// Non-atomically check if the VO bit is set for this address.
233///
234/// # Safety
235/// The caller needs to make sure that no one is modifying VO bit.
236pub(crate) unsafe fn is_vo_addr(addr: Address) -> bool {
237    VO_BIT_SIDE_METADATA_SPEC.load::<u8>(addr) != 0
238}