mmtk/util/metadata/
log_bit.rs

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