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::*;