mmtk/util/metadata/
log_bit.rs

1use crate::util::constants::LOG_BITS_IN_BYTE;
2use crate::util::Address;
3use crate::util::ObjectReference;
4use crate::vm::ObjectModel;
5use crate::vm::VMBinding;
6use crate::vm::VMGlobalFieldUnlogBitSpec;
7use crate::vm::VMGlobalLogBitSpec;
8use std::sync::atomic::Ordering;
9
10use super::MetadataSpec;
11
12/// The value stored in the log bit/byte indicating that the object or field is unlogged, i.e. it
13/// has not yet been recorded in the remembered set and the write barrier should still take its slow path.
14pub const UNLOGGED_VALUE: u8 = 0b1;
15
16/// The value stored in the log bit/byte indicating that the object or field is logged, i.e. it
17/// has already been recorded in the remembered set and the write barrier can skip its slow path.
18pub const LOGGED_VALUE: u8 = 0b0;
19
20impl VMGlobalLogBitSpec {
21    /// Clear the unlog bit to log object (0 means logged)
22    pub fn clear<VM: VMBinding>(&self, object: ObjectReference, order: Ordering) {
23        self.store_atomic::<VM, u8>(object, LOGGED_VALUE, None, order)
24    }
25
26    /// Bulk clear the unlog bits for a memory range
27    pub fn bulk_mark_as_logged(&self, start: Address, size: usize) {
28        if let MetadataSpec::OnSide(side) = self.as_spec() {
29            side.bzero_metadata(start, size);
30        }
31    }
32
33    /// Mark the log bit as unlogged (1 means unlogged)
34    pub fn mark_as_unlogged<VM: VMBinding>(&self, object: ObjectReference, order: Ordering) {
35        self.store_atomic::<VM, u8>(object, UNLOGGED_VALUE, None, order)
36    }
37
38    /// Mark the entire byte as unlogged if the log bit is in the side metadata. As it marks the entire byte,
39    /// it may unlog adjacent objects. This method should only be used
40    /// when adjacent objects are also in the mature space, and there is no harm if we also unlog them.
41    /// This method is meant to be an optimization, and can always be replaced with `mark_as_unlogged`.
42    pub fn mark_byte_as_unlogged<VM: VMBinding>(&self, object: ObjectReference, order: Ordering) {
43        match self.as_spec() {
44            // If the log bit is in the header, there is nothing we can do. We just call `mark_as_unlogged`.
45            MetadataSpec::InHeader(_) => self.mark_as_unlogged::<VM>(object, order),
46            // If the log bit is in the side metadata, we can simply set the entire byte to 0xff. Because we
47            // know we are setting log bit for mature space, and every object in the space should have log
48            // bit as 1.
49            MetadataSpec::OnSide(spec) => unsafe {
50                spec.set_raw_byte_atomic(object.to_raw_address(), order)
51            },
52        }
53    }
54
55    /// Check if the log bit represents the unlogged state.
56    pub fn is_unlogged<VM: VMBinding>(&self, object: ObjectReference, order: Ordering) -> bool {
57        self.load_atomic::<VM, u8>(object, None, order) == UNLOGGED_VALUE
58    }
59}
60
61impl VMGlobalFieldUnlogBitSpec {
62    /// The number of heap bytes (in log2) covered by one byte of the field unlog side metadata.
63    pub(crate) const fn log_heap_bytes_per_unlog_byte(&self) -> usize {
64        let spec = self.as_spec().extract_side_spec();
65        spec.log_bytes_in_region + LOG_BITS_IN_BYTE as usize - spec.log_num_of_bits
66    }
67
68    /// The number of heap bytes covered by one byte of the field unlog side metadata.
69    pub(crate) const fn heap_bytes_per_unlog_byte(&self) -> usize {
70        1 << self.log_heap_bytes_per_unlog_byte()
71    }
72}
73
74impl MetadataSpec {
75    /// Mark the log bit as unlogged (1 means unlogged)
76    pub fn mark_as_unlogged<VM: VMBinding>(&self, object: ObjectReference, order: Ordering) {
77        self.store_atomic::<VM, u8>(object, UNLOGGED_VALUE, None, order)
78    }
79}
80
81/// This specifies what to do to the global side unlog bits in various functions or work packets.
82#[derive(Clone, Copy, PartialEq, Eq)]
83pub(crate) enum UnlogBitsOperation {
84    /// Do nothing.
85    NoOp,
86    /// Bulk set unlog bits to all 1s.
87    BulkSet,
88    /// Bulk clear unlog bits to all 0s.
89    BulkClear,
90}
91
92impl UnlogBitsOperation {
93    /// Run the specified operation on the address range from `start` to `start + size`.
94    pub(crate) fn execute<VM: VMBinding>(&self, start: Address, size: usize) {
95        if let MetadataSpec::OnSide(ref unlog_bits) = *VM::VMObjectModel::GLOBAL_LOG_BIT_SPEC {
96            match self {
97                UnlogBitsOperation::NoOp => {}
98                UnlogBitsOperation::BulkSet => {
99                    unlog_bits.bset_metadata(start, size);
100                }
101                UnlogBitsOperation::BulkClear => {
102                    unlog_bits.bzero_metadata(start, size);
103                }
104            }
105        }
106    }
107}