mmtk/util/metadata/side_metadata/
spec_defs.rs

1use crate::util::constants::*;
2use crate::util::heap::layout::vm_layout::*;
3use crate::util::linear_scan::Region;
4use crate::util::metadata::side_metadata::layout::{
5    GLOBAL_SIDE_METADATA_BASE_OFFSET, LOCAL_SIDE_METADATA_BASE_OFFSET_FOR_LAYOUT,
6};
7use crate::util::metadata::side_metadata::side_metadata_offset_after;
8use crate::util::metadata::side_metadata::SideMetadataSpec;
9
10// This macro helps define side metadata specs, and layout their offsets one after another.
11// The macro is implemented with the incremental TT muncher pattern (see https://danielkeep.github.io/tlborm/book/pat-incremental-tt-munchers.html).
12// This should only be used twice within mmtk-core: one for global specs, and one for local specs.
13// This should not be used to layout VM specs (we have provided side_first()/side_after() for the VM side metadata specs).
14macro_rules! define_side_metadata_specs {
15    // Internal patterns
16
17// Define the first spec with the given base offset.
18    (@first_spec $base_offset: expr, $name: ident = (global: $is_global: expr, log_num_of_bits: $log_num_of_bits: expr, log_bytes_in_region: $log_bytes_in_region: expr)) => {
19        pub const $name: SideMetadataSpec = SideMetadataSpec {
20            name: stringify!($name),
21            is_global: $is_global,
22            offset: $base_offset,
23            log_num_of_bits: $log_num_of_bits,
24            log_bytes_in_region: $log_bytes_in_region,
25        };
26    };
27    // Define any spec that follows a previous spec. The new spec will be created and laid out after the previous spec.
28    (@prev_spec $last_spec: ident as $last_spec_ident: ident, $name: ident = (global: $is_global: expr, log_num_of_bits: $log_num_of_bits: expr, log_bytes_in_region: $log_bytes_in_region: expr), $($tail:tt)*) => {
29        pub const $name: SideMetadataSpec = SideMetadataSpec {
30            name: stringify!($name),
31            is_global: $is_global,
32            offset: side_metadata_offset_after(&$last_spec),
33            log_num_of_bits: $log_num_of_bits,
34            log_bytes_in_region: $log_bytes_in_region,
35        };
36        define_side_metadata_specs!(@prev_spec $name as $last_spec_ident, $($tail)*);
37    };
38    // Define the last spec with the given identifier.
39    (@prev_spec $last_spec: ident as $last_spec_ident: ident,) => {
40        pub const $last_spec_ident: SideMetadataSpec = $last_spec;
41    };
42
43    // The actual macro
44
45    // This is the pattern that should be used outside this macro.
46    (base_offset $base_offset: expr, last_spec_as $last_spec_ident: ident, $name0: ident = (global: $is_global0: expr, log_num_of_bits: $log_num_of_bits0: expr, log_bytes_in_region: $log_bytes_in_region0: expr), $($tail:tt)*) => {
47        // Defines the first spec
48        define_side_metadata_specs!(@first_spec $base_offset, $name0 = (global: $is_global0, log_num_of_bits: $log_num_of_bits0, log_bytes_in_region: $log_bytes_in_region0));
49        // The rest specs
50        define_side_metadata_specs!(@prev_spec $name0 as $last_spec_ident, $($tail)*);
51    };
52}
53
54// This defines all GLOBAL side metadata used by mmtk-core.
55define_side_metadata_specs!(
56    base_offset GLOBAL_SIDE_METADATA_BASE_OFFSET,
57    last_spec_as LAST_GLOBAL_SIDE_METADATA_SPEC,
58    // Mark the start of an object
59    VO_BIT       = (global: true, log_num_of_bits: 0, log_bytes_in_region: LOG_MIN_OBJECT_SIZE as usize),
60    // Track the index in SFT map for a chunk (only used for SFT sparse chunk map)
61    SFT_DENSE_CHUNK_MAP_INDEX   = (global: true, log_num_of_bits: 3, log_bytes_in_region: LOG_BYTES_IN_CHUNK),
62    // Mark chunks (any plan that uses the chunk map should include this spec in their global sidemetadata specs)
63    CHUNK_MARK   = (global: true, log_num_of_bits: 3, log_bytes_in_region: crate::util::heap::chunk_map::Chunk::LOG_BYTES),
64);
65
66// This defines all LOCAL side metadata used by mmtk-core.
67define_side_metadata_specs!(
68    base_offset LOCAL_SIDE_METADATA_BASE_OFFSET_FOR_LAYOUT,
69    last_spec_as LAST_LOCAL_SIDE_METADATA_SPEC,
70    // Mark pages by (malloc) marksweep
71    MALLOC_MS_ACTIVE_PAGE  = (global: false, log_num_of_bits: 3, log_bytes_in_region: crate::util::malloc::library::LOG_BYTES_IN_MALLOC_PAGE as usize),
72    // Record objects allocated with some offset
73    MS_OFFSET_MALLOC = (global: false, log_num_of_bits: 0, log_bytes_in_region: LOG_MIN_OBJECT_SIZE as usize),
74    // Mark lines by immix
75    IX_LINE_MARK    = (global: false, log_num_of_bits: 3, log_bytes_in_region: crate::policy::immix::line::Line::LOG_BYTES),
76    // Record defrag state for immix blocks
77    IX_BLOCK_DEFRAG = (global: false, log_num_of_bits: 3, log_bytes_in_region: crate::policy::immix::block::Block::LOG_BYTES),
78    // Mark blocks by immix
79    IX_BLOCK_MARK   = (global: false, log_num_of_bits: 3, log_bytes_in_region: crate::policy::immix::block::Block::LOG_BYTES),
80    // Mark blocks by (native mimalloc) marksweep
81    MS_BLOCK_MARK   = (global: false, log_num_of_bits: 3, log_bytes_in_region: crate::policy::marksweepspace::native_ms::Block::LOG_BYTES),
82    // Next block in list for native mimalloc
83    MS_BLOCK_NEXT   = (global: false, log_num_of_bits: LOG_BITS_IN_ADDRESS, log_bytes_in_region: crate::policy::marksweepspace::native_ms::Block::LOG_BYTES),
84    // Previous block in list for native mimalloc
85    MS_BLOCK_PREV   = (global: false, log_num_of_bits: LOG_BITS_IN_ADDRESS, log_bytes_in_region: crate::policy::marksweepspace::native_ms::Block::LOG_BYTES),
86    // Pointer to owning list for blocks for native mimalloc
87    MS_BLOCK_LIST   = (global: false, log_num_of_bits: LOG_BITS_IN_ADDRESS, log_bytes_in_region: crate::policy::marksweepspace::native_ms::Block::LOG_BYTES),
88    // Size of cells in block for native mimalloc FIXME: do we actually need usize?
89    MS_BLOCK_SIZE         = (global: false, log_num_of_bits: LOG_BITS_IN_ADDRESS, log_bytes_in_region: crate::policy::marksweepspace::native_ms::Block::LOG_BYTES),
90    // TLS of owning mutator of block for native mimalloc
91    MS_BLOCK_TLS    = (global: false, log_num_of_bits: LOG_BITS_IN_ADDRESS, log_bytes_in_region: crate::policy::marksweepspace::native_ms::Block::LOG_BYTES),
92    // First cell of free list in block for native mimalloc
93    MS_FREE         = (global: false, log_num_of_bits: LOG_BITS_IN_ADDRESS, log_bytes_in_region: crate::policy::marksweepspace::native_ms::Block::LOG_BYTES),
94    // The following specs are only used for manual malloc/free
95    // First cell of local free list in block for native mimalloc
96    MS_LOCAL_FREE   = (global: false, log_num_of_bits: LOG_BITS_IN_ADDRESS, log_bytes_in_region: crate::policy::marksweepspace::native_ms::Block::LOG_BYTES),
97    // First cell of thread free list in block for native mimalloc
98    MS_THREAD_FREE  = (global: false, log_num_of_bits: LOG_BITS_IN_ADDRESS, log_bytes_in_region: crate::policy::marksweepspace::native_ms::Block::LOG_BYTES),
99    // Start and end marks by Compressor
100    COMPRESSOR_MARK = (global: false, log_num_of_bits: 0, log_bytes_in_region: LOG_BYTES_IN_WORD as usize),
101    // Block offset vectors by Compressor
102    COMPRESSOR_OFFSET_VECTOR = (global: false, log_num_of_bits: LOG_BITS_IN_ADDRESS, log_bytes_in_region: crate::policy::compressor::forwarding::Block::LOG_BYTES),
103);
104
105#[cfg(test)]
106mod tests {
107    // We assert on constants to test if the macro is working properly.
108    #![allow(clippy::assertions_on_constants)]
109
110    use super::*;
111    #[test]
112    fn first_global_spec() {
113        define_side_metadata_specs!(
114            base_offset GLOBAL_SIDE_METADATA_BASE_OFFSET,
115            last_spec_as LAST_GLOBAL_SPEC,
116            TEST_SPEC = (global: true, log_num_of_bits: 0, log_bytes_in_region: 3),
117        );
118        assert!(TEST_SPEC.is_global);
119        assert!(TEST_SPEC.offset == GLOBAL_SIDE_METADATA_BASE_OFFSET);
120        assert_eq!(TEST_SPEC.log_num_of_bits, 0);
121        assert_eq!(TEST_SPEC.log_bytes_in_region, 3);
122        assert_eq!(TEST_SPEC, LAST_GLOBAL_SPEC);
123    }
124
125    #[test]
126    fn first_local_spec() {
127        define_side_metadata_specs!(
128            base_offset LOCAL_SIDE_METADATA_BASE_OFFSET_FOR_LAYOUT,
129            last_spec_as LAST_LOCAL_SPEC,
130            TEST_SPEC = (global: false, log_num_of_bits: 0, log_bytes_in_region: 3),
131        );
132        assert!(!TEST_SPEC.is_global);
133        assert!(TEST_SPEC.offset == LOCAL_SIDE_METADATA_BASE_OFFSET_FOR_LAYOUT);
134        assert_eq!(TEST_SPEC.log_num_of_bits, 0);
135        assert_eq!(TEST_SPEC.log_bytes_in_region, 3);
136        assert_eq!(TEST_SPEC, LAST_LOCAL_SPEC);
137    }
138
139    #[test]
140    fn two_global_specs() {
141        define_side_metadata_specs!(
142            base_offset GLOBAL_SIDE_METADATA_BASE_OFFSET,
143            last_spec_as LAST_GLOBAL_SPEC,
144            TEST_SPEC1 = (global: true, log_num_of_bits: 0, log_bytes_in_region: 3),
145            TEST_SPEC2 = (global: true, log_num_of_bits: 1, log_bytes_in_region: 4),
146        );
147
148        assert!(TEST_SPEC1.is_global);
149        assert!(TEST_SPEC1.offset == GLOBAL_SIDE_METADATA_BASE_OFFSET);
150        assert_eq!(TEST_SPEC1.log_num_of_bits, 0);
151        assert_eq!(TEST_SPEC1.log_bytes_in_region, 3);
152
153        assert!(TEST_SPEC2.is_global);
154        assert!(TEST_SPEC2.offset == side_metadata_offset_after(&TEST_SPEC1));
155        assert_eq!(TEST_SPEC2.log_num_of_bits, 1);
156        assert_eq!(TEST_SPEC2.log_bytes_in_region, 4);
157
158        assert_eq!(TEST_SPEC2, LAST_GLOBAL_SPEC);
159    }
160
161    #[test]
162    fn three_global_specs() {
163        define_side_metadata_specs!(
164            base_offset GLOBAL_SIDE_METADATA_BASE_OFFSET,
165            last_spec_as LAST_GLOBAL_SPEC,
166            TEST_SPEC1 = (global: true, log_num_of_bits: 0, log_bytes_in_region: 3),
167            TEST_SPEC2 = (global: true, log_num_of_bits: 1, log_bytes_in_region: 4),
168            TEST_SPEC3 = (global: true, log_num_of_bits: 2, log_bytes_in_region: 5),
169        );
170
171        assert!(TEST_SPEC1.is_global);
172        assert!(TEST_SPEC1.offset == GLOBAL_SIDE_METADATA_BASE_OFFSET);
173        assert_eq!(TEST_SPEC1.log_num_of_bits, 0);
174        assert_eq!(TEST_SPEC1.log_bytes_in_region, 3);
175
176        assert!(TEST_SPEC2.is_global);
177        assert!(TEST_SPEC2.offset == side_metadata_offset_after(&TEST_SPEC1));
178        assert_eq!(TEST_SPEC2.log_num_of_bits, 1);
179        assert_eq!(TEST_SPEC2.log_bytes_in_region, 4);
180
181        assert!(TEST_SPEC3.is_global);
182        assert!(TEST_SPEC3.offset == side_metadata_offset_after(&TEST_SPEC2));
183        assert_eq!(TEST_SPEC3.log_num_of_bits, 2);
184        assert_eq!(TEST_SPEC3.log_bytes_in_region, 5);
185
186        assert_eq!(TEST_SPEC3, LAST_GLOBAL_SPEC);
187    }
188
189    #[test]
190    fn both_global_and_local() {
191        define_side_metadata_specs!(
192            base_offset GLOBAL_SIDE_METADATA_BASE_OFFSET,
193            last_spec_as LAST_GLOBAL_SPEC,
194            TEST_GSPEC1 = (global: true, log_num_of_bits: 0, log_bytes_in_region: 3),
195            TEST_GSPEC2 = (global: true, log_num_of_bits: 1, log_bytes_in_region: 4),
196        );
197        define_side_metadata_specs!(
198            base_offset LOCAL_SIDE_METADATA_BASE_OFFSET_FOR_LAYOUT,
199            last_spec_as LAST_LOCAL_SPEC,
200            TEST_LSPEC1 = (global: false, log_num_of_bits: 2, log_bytes_in_region: 5),
201            TEST_LSPEC2 = (global: false, log_num_of_bits: 3, log_bytes_in_region: 6),
202        );
203
204        assert!(TEST_GSPEC1.is_global);
205        assert!(TEST_GSPEC1.offset == GLOBAL_SIDE_METADATA_BASE_OFFSET);
206        assert_eq!(TEST_GSPEC1.log_num_of_bits, 0);
207        assert_eq!(TEST_GSPEC1.log_bytes_in_region, 3);
208
209        assert!(TEST_GSPEC2.is_global);
210        assert!(TEST_GSPEC2.offset == side_metadata_offset_after(&TEST_GSPEC1));
211        assert_eq!(TEST_GSPEC2.log_num_of_bits, 1);
212        assert_eq!(TEST_GSPEC2.log_bytes_in_region, 4);
213
214        assert_eq!(TEST_GSPEC2, LAST_GLOBAL_SPEC);
215
216        assert!(!TEST_LSPEC1.is_global);
217        assert!(TEST_LSPEC1.offset == LOCAL_SIDE_METADATA_BASE_OFFSET_FOR_LAYOUT);
218        assert_eq!(TEST_LSPEC1.log_num_of_bits, 2);
219        assert_eq!(TEST_LSPEC1.log_bytes_in_region, 5);
220
221        assert!(!TEST_LSPEC2.is_global);
222        assert!(TEST_LSPEC2.offset == side_metadata_offset_after(&TEST_LSPEC1));
223        assert_eq!(TEST_LSPEC2.log_num_of_bits, 3);
224        assert_eq!(TEST_LSPEC2.log_bytes_in_region, 6);
225
226        assert_eq!(TEST_LSPEC2, LAST_LOCAL_SPEC);
227    }
228}