mmtk/policy/immix/
line.rs

1use std::ops::Range;
2
3use super::block::Block;
4use crate::util::linear_scan::{Region, RegionIterator};
5use crate::util::metadata::side_metadata::SideMetadataSpec;
6use crate::{
7    util::{Address, ObjectReference},
8    vm::*,
9};
10
11/// Data structure to reference a line within an immix block.
12#[repr(transparent)]
13#[derive(Debug, Clone, Copy, PartialOrd, PartialEq, Eq)]
14pub struct Line(Address);
15
16impl Region for Line {
17    const LOG_BYTES: usize = 8;
18
19    #[allow(clippy::assertions_on_constants)] // make sure line is not used when BLOCK_ONLY is turned on.
20    fn from_aligned_address(address: Address) -> Self {
21        debug_assert!(!super::BLOCK_ONLY);
22        debug_assert!(address.is_aligned_to(Self::BYTES));
23        Self(address)
24    }
25
26    fn start(&self) -> Address {
27        self.0
28    }
29}
30
31#[allow(clippy::assertions_on_constants)]
32impl Line {
33    pub const RESET_MARK_STATE: u8 = 1;
34    pub const MAX_MARK_STATE: u8 = 127;
35
36    /// Line mark table (side)
37    pub const MARK_TABLE: SideMetadataSpec =
38        crate::util::metadata::side_metadata::spec_defs::IX_LINE_MARK;
39
40    /// Get the block containing the line.
41    pub fn block(&self) -> Block {
42        debug_assert!(!super::BLOCK_ONLY);
43        Block::from_unaligned_address(self.0)
44    }
45
46    /// Get line index within its containing block.
47    pub fn get_index_within_block(&self) -> usize {
48        let addr = self.start();
49        addr.get_extent(Block::align(addr)) >> Line::LOG_BYTES
50    }
51
52    /// Mark the line. This will update the side line mark table.
53    pub fn mark(&self, state: u8) {
54        debug_assert!(!super::BLOCK_ONLY);
55        unsafe {
56            Self::MARK_TABLE.store::<u8>(self.start(), state);
57        }
58    }
59
60    /// Test line mark state.
61    pub fn is_marked(&self, state: u8) -> bool {
62        debug_assert!(!super::BLOCK_ONLY);
63        unsafe { Self::MARK_TABLE.load::<u8>(self.start()) == state }
64    }
65
66    /// Mark all lines the object is spanned to.
67    pub fn mark_lines_for_object<VM: VMBinding>(object: ObjectReference, state: u8) -> usize {
68        debug_assert!(!super::BLOCK_ONLY);
69        let start = object.to_object_start::<VM>();
70        let end = start + VM::VMObjectModel::get_current_size(object);
71        let start_line = Line::from_unaligned_address(start);
72        let mut end_line = Line::from_unaligned_address(end);
73        if !Line::is_aligned(end) {
74            end_line = end_line.next();
75        }
76        let mut marked_lines = 0;
77        let iter = RegionIterator::<Line>::new(start_line, end_line);
78        for line in iter {
79            if !line.is_marked(state) {
80                marked_lines += 1;
81            }
82            line.mark(state)
83        }
84        marked_lines
85    }
86
87    /// Bulk set the local mark bits of a line range.
88    ///
89    /// This is useful during concurrent marking. By doing this, concurrent marking will
90    /// conservatively consider all objects allocated in the line range as live, and the mutator
91    /// doesn't need to explicitly mark bump-allocated objects in the fast path.
92    pub fn initialize_mark_table_as_marked<VM: VMBinding>(lines: Range<Line>) {
93        let meta = VM::VMObjectModel::LOCAL_MARK_BIT_SPEC.extract_side_spec();
94        let start = lines.start.start();
95        let limit = lines.end.start();
96        let size = limit - start;
97        meta.bset_metadata(start, size);
98    }
99
100    /// Bulk set line mark states.
101    pub fn bulk_set_line_mark_states(line_mark_state: u8, lines: Range<Line>) {
102        for line in RegionIterator::<Line>::new(lines.start, lines.end) {
103            line.mark(line_mark_state);
104        }
105    }
106
107    /// Eagerly mark all line mark states and all side mark bits in the gap.
108    ///
109    /// Useful during concurrent marking.
110    pub fn eager_mark_lines<VM: VMBinding>(line_mark_state: u8, lines: Range<Line>) {
111        Self::bulk_set_line_mark_states(line_mark_state, lines.clone());
112        Self::initialize_mark_table_as_marked::<VM>(lines);
113    }
114}