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    // Reference counts
63    RC_TABLE = (global: true, log_num_of_bits: crate::util::rc::LOG_REF_COUNT_BITS, log_bytes_in_region: crate::util::rc::LOG_MIN_OBJECT_SIZE),
64    // Mark chunks (any plan that uses the chunk map should include this spec in their global sidemetadata specs)
65    CHUNK_MARK   = (global: true, log_num_of_bits: 3, log_bytes_in_region: crate::util::heap::chunk_map::Chunk::LOG_BYTES),
66);
67
68// This defines all LOCAL side metadata used by mmtk-core.
69define_side_metadata_specs!(
70    base_offset LOCAL_SIDE_METADATA_BASE_OFFSET_FOR_LAYOUT,
71    last_spec_as LAST_LOCAL_SIDE_METADATA_SPEC,
72    // Mark pages by (malloc) marksweep
73    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),
74    // Record objects allocated with some offset
75    MS_OFFSET_MALLOC = (global: false, log_num_of_bits: 0, log_bytes_in_region: LOG_MIN_OBJECT_SIZE as usize),
76    // Mark lines by immix
77    IX_LINE_MARK    = (global: false, log_num_of_bits: 3, log_bytes_in_region: crate::policy::immix::line::Line::LOG_BYTES),
78    // Record defrag state for immix blocks
79    IX_BLOCK_DEFRAG = (global: false, log_num_of_bits: 3, log_bytes_in_region: crate::policy::immix::block::Block::LOG_BYTES),
80    // Mark blocks by immix
81    IX_BLOCK_MARK   = (global: false, log_num_of_bits: 3, log_bytes_in_region: crate::policy::immix::block::Block::LOG_BYTES),
82    // Straddle line marks
83    RC_STRADDLE_LINES = (global: false, log_num_of_bits: 3, log_bytes_in_region: crate::policy::immix::line::Line::LOG_BYTES),
84    // LXR Block logging bits
85    IX_BLOCK_LOG   = (global: false, log_num_of_bits: 0, log_bytes_in_region: crate::policy::immix::block::Block::LOG_BYTES),
86    NURSERY_PROMOTION_STATE   = (global: false, log_num_of_bits: 3, log_bytes_in_region: crate::policy::immix::block::Block::LOG_BYTES),
87    PHASE_EPOCH   = (global: false, log_num_of_bits: 3, log_bytes_in_region: crate::policy::immix::block::Block::LOG_BYTES),
88    IX_LINE_REUSE_COUNT   = (global: false, log_num_of_bits: 3, log_bytes_in_region: crate::policy::immix::line::Line::LOG_BYTES),
89    LOS_PAGE_REUSE_COUNT   = (global: false, log_num_of_bits: 3, log_bytes_in_region: LOG_BYTES_IN_PAGE as usize),
90    // Mark blocks by (native mimalloc) marksweep
91    MS_BLOCK_MARK   = (global: false, log_num_of_bits: 3, log_bytes_in_region: crate::policy::marksweepspace::native_ms::Block::LOG_BYTES),
92    // Next block in list for native mimalloc
93    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),
94    // Previous block in list for native mimalloc
95    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),
96    // Pointer to owning list for blocks for native mimalloc
97    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),
98    // Size of cells in block for native mimalloc FIXME: do we actually need usize?
99    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),
100    // TLS of owning mutator of block for native mimalloc
101    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),
102    // First cell of free list in block for native mimalloc
103    MS_FREE         = (global: false, log_num_of_bits: LOG_BITS_IN_ADDRESS, log_bytes_in_region: crate::policy::marksweepspace::native_ms::Block::LOG_BYTES),
104    // The following specs are only used for manual malloc/free
105    // First cell of local free list in block for native mimalloc
106    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),
107    // First cell of thread free list in block for native mimalloc
108    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),
109    // Start and end marks by OVC
110    OVC_MARK = (global: false, log_num_of_bits: 0, log_bytes_in_region: LOG_BYTES_IN_WORD as usize),
111    // Block offset vectors by OVC
112    OVC_OFFSET_VECTOR = (global: false, log_num_of_bits: LOG_BITS_IN_ADDRESS, log_bytes_in_region: crate::policy::ovc::forwarding::Block::LOG_BYTES),
113);
114
115#[cfg(test)]
116mod tests {
117    // We assert on constants to test if the macro is working properly.
118    #![allow(clippy::assertions_on_constants)]
119
120    use super::*;
121    #[test]
122    fn first_global_spec() {
123        define_side_metadata_specs!(
124            base_offset GLOBAL_SIDE_METADATA_BASE_OFFSET,
125            last_spec_as LAST_GLOBAL_SPEC,
126            TEST_SPEC = (global: true, log_num_of_bits: 0, log_bytes_in_region: 3),
127        );
128        assert!(TEST_SPEC.is_global);
129        assert!(TEST_SPEC.offset == GLOBAL_SIDE_METADATA_BASE_OFFSET);
130        assert_eq!(TEST_SPEC.log_num_of_bits, 0);
131        assert_eq!(TEST_SPEC.log_bytes_in_region, 3);
132        assert_eq!(TEST_SPEC, LAST_GLOBAL_SPEC);
133    }
134
135    #[test]
136    fn first_local_spec() {
137        define_side_metadata_specs!(
138            base_offset LOCAL_SIDE_METADATA_BASE_OFFSET_FOR_LAYOUT,
139            last_spec_as LAST_LOCAL_SPEC,
140            TEST_SPEC = (global: false, log_num_of_bits: 0, log_bytes_in_region: 3),
141        );
142        assert!(!TEST_SPEC.is_global);
143        assert!(TEST_SPEC.offset == LOCAL_SIDE_METADATA_BASE_OFFSET_FOR_LAYOUT);
144        assert_eq!(TEST_SPEC.log_num_of_bits, 0);
145        assert_eq!(TEST_SPEC.log_bytes_in_region, 3);
146        assert_eq!(TEST_SPEC, LAST_LOCAL_SPEC);
147    }
148
149    #[test]
150    fn two_global_specs() {
151        define_side_metadata_specs!(
152            base_offset GLOBAL_SIDE_METADATA_BASE_OFFSET,
153            last_spec_as LAST_GLOBAL_SPEC,
154            TEST_SPEC1 = (global: true, log_num_of_bits: 0, log_bytes_in_region: 3),
155            TEST_SPEC2 = (global: true, log_num_of_bits: 1, log_bytes_in_region: 4),
156        );
157
158        assert!(TEST_SPEC1.is_global);
159        assert!(TEST_SPEC1.offset == GLOBAL_SIDE_METADATA_BASE_OFFSET);
160        assert_eq!(TEST_SPEC1.log_num_of_bits, 0);
161        assert_eq!(TEST_SPEC1.log_bytes_in_region, 3);
162
163        assert!(TEST_SPEC2.is_global);
164        assert!(TEST_SPEC2.offset == side_metadata_offset_after(&TEST_SPEC1));
165        assert_eq!(TEST_SPEC2.log_num_of_bits, 1);
166        assert_eq!(TEST_SPEC2.log_bytes_in_region, 4);
167
168        assert_eq!(TEST_SPEC2, LAST_GLOBAL_SPEC);
169    }
170
171    #[test]
172    fn three_global_specs() {
173        define_side_metadata_specs!(
174            base_offset GLOBAL_SIDE_METADATA_BASE_OFFSET,
175            last_spec_as LAST_GLOBAL_SPEC,
176            TEST_SPEC1 = (global: true, log_num_of_bits: 0, log_bytes_in_region: 3),
177            TEST_SPEC2 = (global: true, log_num_of_bits: 1, log_bytes_in_region: 4),
178            TEST_SPEC3 = (global: true, log_num_of_bits: 2, log_bytes_in_region: 5),
179        );
180
181        assert!(TEST_SPEC1.is_global);
182        assert!(TEST_SPEC1.offset == GLOBAL_SIDE_METADATA_BASE_OFFSET);
183        assert_eq!(TEST_SPEC1.log_num_of_bits, 0);
184        assert_eq!(TEST_SPEC1.log_bytes_in_region, 3);
185
186        assert!(TEST_SPEC2.is_global);
187        assert!(TEST_SPEC2.offset == side_metadata_offset_after(&TEST_SPEC1));
188        assert_eq!(TEST_SPEC2.log_num_of_bits, 1);
189        assert_eq!(TEST_SPEC2.log_bytes_in_region, 4);
190
191        assert!(TEST_SPEC3.is_global);
192        assert!(TEST_SPEC3.offset == side_metadata_offset_after(&TEST_SPEC2));
193        assert_eq!(TEST_SPEC3.log_num_of_bits, 2);
194        assert_eq!(TEST_SPEC3.log_bytes_in_region, 5);
195
196        assert_eq!(TEST_SPEC3, LAST_GLOBAL_SPEC);
197    }
198
199    #[test]
200    fn both_global_and_local() {
201        define_side_metadata_specs!(
202            base_offset GLOBAL_SIDE_METADATA_BASE_OFFSET,
203            last_spec_as LAST_GLOBAL_SPEC,
204            TEST_GSPEC1 = (global: true, log_num_of_bits: 0, log_bytes_in_region: 3),
205            TEST_GSPEC2 = (global: true, log_num_of_bits: 1, log_bytes_in_region: 4),
206        );
207        define_side_metadata_specs!(
208            base_offset LOCAL_SIDE_METADATA_BASE_OFFSET_FOR_LAYOUT,
209            last_spec_as LAST_LOCAL_SPEC,
210            TEST_LSPEC1 = (global: false, log_num_of_bits: 2, log_bytes_in_region: 5),
211            TEST_LSPEC2 = (global: false, log_num_of_bits: 3, log_bytes_in_region: 6),
212        );
213
214        assert!(TEST_GSPEC1.is_global);
215        assert!(TEST_GSPEC1.offset == GLOBAL_SIDE_METADATA_BASE_OFFSET);
216        assert_eq!(TEST_GSPEC1.log_num_of_bits, 0);
217        assert_eq!(TEST_GSPEC1.log_bytes_in_region, 3);
218
219        assert!(TEST_GSPEC2.is_global);
220        assert!(TEST_GSPEC2.offset == side_metadata_offset_after(&TEST_GSPEC1));
221        assert_eq!(TEST_GSPEC2.log_num_of_bits, 1);
222        assert_eq!(TEST_GSPEC2.log_bytes_in_region, 4);
223
224        assert_eq!(TEST_GSPEC2, LAST_GLOBAL_SPEC);
225
226        assert!(!TEST_LSPEC1.is_global);
227        assert!(TEST_LSPEC1.offset == LOCAL_SIDE_METADATA_BASE_OFFSET_FOR_LAYOUT);
228        assert_eq!(TEST_LSPEC1.log_num_of_bits, 2);
229        assert_eq!(TEST_LSPEC1.log_bytes_in_region, 5);
230
231        assert!(!TEST_LSPEC2.is_global);
232        assert!(TEST_LSPEC2.offset == side_metadata_offset_after(&TEST_LSPEC1));
233        assert_eq!(TEST_LSPEC2.log_num_of_bits, 3);
234        assert_eq!(TEST_LSPEC2.log_bytes_in_region, 6);
235
236        assert_eq!(TEST_LSPEC2, LAST_LOCAL_SPEC);
237    }
238}