mmtk/util/metadata/mod.rs
1//! This is a generic module to work with metadata including side metadata and in-object metadata.
2//!
3//! This module is designed to enable the implementation of a wide range of GC algorithms for VMs with various combinations of in-object and on-side space for GC-specific metadata (e.g. forwarding bits, marking bit, logging bit, etc.).
4//!
5//! The new metadata design differentiates per-object metadata (e.g. forwarding-bits and marking-bit) from other types of metadata including per-address (e.g. VO bit) and per-X (where X != object size), because the per-object metadata can optionally be kept in the object headers.
6//!
7//! MMTk acknowledges the VM-dependant nature of the in-object metadata, and asks the VM bindings to contribute by implementing the related parts in the ['ObjectModel'](crate::vm::ObjectModel).
8//!
9//!
10//! # Side Metadata
11//!
12//! ## Design
13//!
14//! MMTk side metadata is designed to be **generic**, and **space-** and **time-** efficient.
15//!
16//! It aims to support two categories of metadata:
17//!
18//! 1. **Global** metadata bits which are plan-specific but common to all policies, and
19//! 2. **Policy-specific** bits which are only used exclusively by certain policies.
20//!
21//! To support these categories, MMTk metadata provides the following features:
22//!
23//! 1. The granularity of the source data (minimum data size) is configurable to $2^n$ bytes, where $n >= 0$.
24//! 2. The number of metadata bits per source data unit is configurable to $2^m$ bits, where $m >= 0$.
25//! 3. The total number of metadata bit-sets is constrained by the worst-case ratio of global and policy-specific metadata.
26//! 4. Metadata space is only allocated on demand.
27//! 5. Bulk-zeroing of metadata bits should be possible. For this, the memory space for each metadata bit-set is contiguous per chunk.
28//!
29//! ### 64-bits targets
30//!
31//! In 64-bits targets, each MMTk side metadata bit-set is organized as a contiguous space.
32//! The base address for both the global and the local side metadata are constants (e.g. `GLOBAL_SIDE_METADATA_BASE_ADDRESS` and `LOCAL_SIDE_METADATA_BASE_ADDRESS`).
33//!
34//! In this case, a schematic of the local and global side metadata looks like:
35//!
36//! _______________________________ <= global-1 = GLOBAL_SIDE_METADATA_BASE_ADDRESS
37//! | |
38//! | Global-1 |
39//! |_____________________________| <= global-2 = global-1 +
40//! | | metadata_address_range_size(global-1)
41//! | Global-2 |
42//! | |
43//! |_____________________________| <= global-3 = global-2 +
44//! | | metadata_address_range_size(global-2)
45//! | Not Mapped |
46//! | |
47//! |_____________________________| <= global-end = GLOBAL_SIDE_METADATA_BASE_ADDRESS +
48//! | | MAX_HEAP_SIZE * Global_WCR
49//! | |
50//! | |
51//! |_____________________________| <= local-1 = LOCAL_SIDE_METADATA_BASE_ADDRESS
52//! | |
53//! | PolicySpecific-1 |
54//! | |
55//! |_____________________________| <= local-2 = local-1 + metadata_address_range_size(local-1)
56//! | |
57//! | PolicySpecific-2 |
58//! | |
59//! |_____________________________| <= local-3 = local-2 + metadata_address_range_size(local-2)
60//! | |
61//! | Not Mapped |
62//! | |
63//! | |
64//! |_____________________________| <= local-end = LOCAL_SIDE_METADATA_BASE_ADDRESS +
65//! MAX_HEAP_SIZE * PolicySpecific_WCR
66//!
67//! ### 32-bits targets
68//!
69//! In 32-bits targets, the global side metadata is organized the same way as 64-bits, but the policy-specific side metadata is organized per chunk of data (each chunk is managed exclusively by one policy).
70//! This means, when a new chunk is mapped, the policy-specific side metadata for the whole chunk is also mapped.
71//!
72//! In this case, a schematic of the local and global side metadata looks like:
73//!
74//! _______________________________ <= global-1 = GLOBAL_SIDE_METADATA_BASE_ADDRESS(e.g. 0x1000_0000)
75//! | |
76//! | Global-1 |
77//! |_____________________________| <= global-2 = global-1 +
78//! | | metadata_address_range_size(global-1)
79//! | Global-2 |
80//! | |
81//! |_____________________________| <= global-3 = global-2 +
82//! | | metadata_address_range_size(global-2)
83//! | Not Mapped |
84//! | |
85//! |_____________________________| <= global-end = GLOBAL_SIDE_METADATA_BASE_ADDRESS +
86//! | | MAX_HEAP_SIZE * Global_WCR
87//! | |
88//! | |
89//! |_____________________________| <= LOCAL_SIDE_METADATA_BASE_ADDRESS
90//! | |
91//! | PolicySpecific |
92//! | |
93//! | |
94//! | |
95//! |_____________________________| <= local-end = LOCAL_SIDE_METADATA_BASE_ADDRESS +
96//! MAX_HEAP_SIZE * PolicySpecific_WCR
97//!
98//!
99//! And inside the PolicySpecific space, each per chunk policy-specific side metadata looks like:
100//!
101//! _______________________________ <= offset-1 = 0x0
102//! | |
103//! | Local-1 |
104//! |_____________________________| <= offset-2 = metadata_bytes_per_chunk(Local-1)
105//! | |
106//! | Local-2 |
107//! | |
108//! |_____________________________| <= offset-g3 = offset-g2 + metadata_bytes_per_chunk(Local-2)
109//! | |
110//! | Not Mapped |
111//! | |
112//! |_____________________________| <= 4MB * PolicySpecific_WCR
113//!
114//!
115//!
116//!
117//! # How to Use
118//!
119//! ## Declare metadata specs
120//!
121//! For each global metadata bit-set, a constant instance of the `MetadataSpec` struct should be created.
122//!
123//! If the metadata is per-object and may possibly reside in objects, the constant instance should be created in the VM's ObjectModel.
124//! For instance, the forwarding-bits metadata spec should be assigned to `LOCAL_FORWARDING_BITS_SPEC` in [`ObjectModel`](crate::vm::ObjectModel).
125//! The VM binding decides whether to put these metadata bit-sets in-objects or on-side.
126//!
127//! For other metadata bit-sets, constant `MetadataSpec` instances, created inside MMTk by plans/policies, are used in conjunction with the access functions from the current module.
128//!
129//! Example:
130//!
131//! For the first global side metadata bit-set:
132//!
133//! ```
134//! const GLOBAL_META_1: MetadataSpec = MetadataSpec {
135//! is_side_metadata: true,
136//! is_global: true,
137//! offset: GLOBAL_SIDE_METADATA_BASE_ADDRESS,
138//! log_num_of_bits: b1,
139//! log_bytes_in_region: s1,
140//! };
141//! ```
142//!
143//! Here, the number of bits per data is $2^b1$, and the minimum object size is $2^s1$.
144//! The `offset` is actually the base address for a global side metadata bit-set.
145//! For the first bit-set, `offset` is `GLOBAL_SIDE_METADATA_BASE_ADDRESS`.
146//!
147//! Now, to add a second side metadata bit-set, offset needs to be calculated based-on the first global bit-set:
148//!
149//! ```
150//! const GLOBAL_META_2: MetadataSpec = MetadataSpec {
151//! is_side_metadata: true,
152//! is_global: true,
153//! offset: GLOBAL_META_1.offset + metadata_address_range_size(GLOBAL_META_1)
154//! log_num_of_bits: b2,
155//! log_bytes_in_region: s2,
156//! };
157//! ```
158//!
159//! where `metadata_address_range_size` is a const function which calculates the total metadata space size of a contiguous side metadata bit-set based-on `s` and `b`.
160//!
161//! The policy-specific side metadata for 64-bits targets, and the global side metadata for 32-bits targets are used on the same way, except that their base addresses are different.
162//!
163//! Policy-specific side metadata for 32-bits target is slightly different, because it is chunk-based.
164//!
165//! For the first local side metadata bit-set:
166//!
167//! ```
168//! const LOCAL_META_1: MetadataSpec = MetadataSpec {
169//! is_side_metadata: true,
170//! is_global: false,
171//! offset: 0,
172//! log_num_of_bits: b1,
173//! log_bytes_in_region: s1,
174//! };
175//! ```
176//!
177//! Here, the `offset` is actually the inter-chunk offset of the side metadata from the start of the current side metadata chunk.
178//!
179//! Now, to add a second side metadata bit-set, offset needs to be calculated based-on the first global bit-set:
180//!
181//! ```
182//! const LOCAL_META_2: MetadataSpec = MetadataSpec {
183//! is_side_metadata: true,
184//! is_global: false,
185//! offset: LOCAL_META_1.offset + metadata_bytes_per_chunk(LOCAL_META_1)
186//! log_num_of_bits: b2,
187//! log_bytes_in_region: s2,
188//! };
189//! ```
190//!
191//! So far, we declared each metadata specs.
192//! We can now use the in-object metadata through the access functions in the VM bindings ObjectModel.
193//! For side metadata, the next step is to allocate metadata space.
194//!
195//!
196//! ## Create and allocate side metadata for spaces
197//!
198//! A space needs to know all global metadata specs and its own policy-specific/local metadata specs in order to calculate and allocate metadata space.
199//! When a space is created by a plan (e.g. SemiSpace::new), the plan can create its global specs by `MetadataContext::new_global_specs(&[GLOBAL_META_1, GLOBAL_META_2])`. Then,
200//! the global specs are passed to each space that the plan creates.
201//!
202//! Each space will then combine the global specs and its own local specs to create a SideMetadataContext.
203//! Allocating side metadata space and accounting its memory usage is done by `SideMetadata`. If a space uses `CommonSpace`, `CommonSpace` will create `SideMetadata` and manage
204//! reserving and allocating metadata space when necessary. If a space does not use `CommonSpace`, it should create `SideMetadata` itself and manage allocating metadata space
205//! as its own responsibility.
206//!
207//! ## Access side metadata
208//!
209//! After mapping the metadata space, the following operations can be performed with a specific metadata spec:
210//!
211//! 1. atomic load
212//! 2. atomic store
213//! 3. atomic compare-and-exchange
214//! 4. atomic fetch-and-add
215//! 5. atomic fetch-and-sub
216//! 6. load (non-atomic)
217//! 7. store (non-atomic)
218//! 8. bulk zeroing
219//!
220
221mod global;
222pub mod header_metadata;
223mod metadata_val_traits;
224pub mod side_metadata;
225pub mod vo_bit;
226pub use metadata_val_traits::*;
227
228pub(crate) mod log_bit;
229pub(crate) mod mark_bit;
230pub(crate) mod pin_bit;
231
232pub use global::*;