mmtk/util/metadata/global.rs
1use super::header_metadata::HeaderMetadataSpec;
2use crate::util::metadata::metadata_val_traits::*;
3use crate::util::metadata::side_metadata::SideMetadataSpec;
4use crate::util::ObjectReference;
5use crate::vm::ObjectModel;
6use crate::vm::VMBinding;
7use atomic::Ordering;
8
9/// This struct stores the specification of a metadata bit-set.
10/// It is used as an input to the (inline) functions provided by the side metadata module.
11///
12/// Each plan or policy which uses a metadata bit-set, needs to create an instance of this struct.
13///
14/// For performance reasons, objects of this struct should be constants.
15#[derive(Clone, Copy, Debug)]
16pub enum MetadataSpec {
17 /// In-header metadata uses bits from an object header.
18 InHeader(HeaderMetadataSpec),
19 /// On-side metadata uses a side table.
20 OnSide(SideMetadataSpec),
21}
22
23impl MetadataSpec {
24 /// Is this metadata stored in the side table?
25 pub const fn is_on_side(&self) -> bool {
26 matches!(self, &MetadataSpec::OnSide(_))
27 }
28
29 /// Is this metadata stored in the object header?
30 pub const fn is_in_header(&self) -> bool {
31 matches!(self, &MetadataSpec::InHeader(_))
32 }
33
34 /// Extract SideMetadataSpec from a MetadataSpec. Panics if this is not side metadata.
35 pub const fn extract_side_spec(&self) -> &SideMetadataSpec {
36 match self {
37 MetadataSpec::OnSide(spec) => spec,
38 MetadataSpec::InHeader(_) => panic!("Expect a side spec"),
39 }
40 }
41
42 /// A function to non-atomically load the specified metadata's content.
43 /// Returns the metadata value.
44 ///
45 /// # Arguments:
46 ///
47 /// * `object`: is a reference to the target object.
48 /// * `mask`: is an optional mask value for the metadata. This value is used in cases like the forwarding pointer metadata, where some of the bits are reused by other metadata such as the forwarding bits.
49 ///
50 /// # Safety
51 /// This is a non-atomic load, thus not thread-safe.
52 pub unsafe fn load<VM: VMBinding, T: MetadataValue>(
53 &self,
54 object: ObjectReference,
55 mask: Option<T>,
56 ) -> T {
57 match self {
58 MetadataSpec::OnSide(metadata_spec) => metadata_spec.load(object.to_raw_address()),
59 MetadataSpec::InHeader(metadata_spec) => {
60 VM::VMObjectModel::load_metadata::<T>(metadata_spec, object, mask)
61 }
62 }
63 }
64
65 /// A function to atomically load the specified metadata's content.
66 /// Returns the metadata value.
67 ///
68 /// # Arguments:
69 ///
70 /// * `object`: is a reference to the target object.
71 /// * `mask`: is an optional mask value for the metadata. This value is used in cases like the forwarding pointer metadata, where some of the bits are reused by other metadata such as the forwarding bits.
72 /// * `atomic_ordering`: is the ordering for the load operation.
73 ///
74 pub fn load_atomic<VM: VMBinding, T: MetadataValue>(
75 &self,
76 object: ObjectReference,
77 mask: Option<T>,
78 ordering: Ordering,
79 ) -> T {
80 match self {
81 MetadataSpec::OnSide(metadata_spec) => {
82 metadata_spec.load_atomic(object.to_raw_address(), ordering)
83 }
84 MetadataSpec::InHeader(metadata_spec) => {
85 VM::VMObjectModel::load_metadata_atomic::<T>(metadata_spec, object, mask, ordering)
86 }
87 }
88 }
89
90 /// A function to non-atomically store a value to the specified metadata.
91 ///
92 /// # Arguments:
93 ///
94 /// * `object`: is a reference to the target object.
95 /// * `val`: is the new metadata value to be stored.
96 /// * `mask`: is an optional mask value for the metadata. This value is used in cases like the forwarding pointer metadata, where some of the bits are reused by other metadata such as the forwarding bits.
97 ///
98 /// # Safety
99 /// This is a non-atomic store, thus not thread-safe.
100 pub unsafe fn store<VM: VMBinding, T: MetadataValue>(
101 &self,
102 object: ObjectReference,
103 val: T,
104 mask: Option<T>,
105 ) {
106 match self {
107 MetadataSpec::OnSide(metadata_spec) => {
108 metadata_spec.store(object.to_raw_address(), val);
109 }
110 MetadataSpec::InHeader(metadata_spec) => {
111 VM::VMObjectModel::store_metadata::<T>(metadata_spec, object, val, mask)
112 }
113 }
114 }
115
116 /// A function to atomically store a value to the specified metadata.
117 ///
118 /// # Arguments:
119 ///
120 /// * `object`: is a reference to the target object.
121 /// * `val`: is the new metadata value to be stored.
122 /// * `mask`: is an optional mask value for the metadata. This value is used in cases like the forwarding pointer metadata, where some of the bits are reused by other metadata such as the forwarding bits.
123 /// * `ordering`: is the ordering for the store operation.
124 pub fn store_atomic<VM: VMBinding, T: MetadataValue>(
125 &self,
126 object: ObjectReference,
127 val: T,
128 mask: Option<T>,
129 ordering: Ordering,
130 ) {
131 match self {
132 MetadataSpec::OnSide(metadata_spec) => {
133 metadata_spec.store_atomic(object.to_raw_address(), val, ordering);
134 }
135 MetadataSpec::InHeader(metadata_spec) => VM::VMObjectModel::store_metadata_atomic::<T>(
136 metadata_spec,
137 object,
138 val,
139 mask,
140 ordering,
141 ),
142 }
143 }
144
145 /// A function to atomically compare-and-exchange the specified metadata's content.
146 /// Returns `true` if the operation is successful, and `false` otherwise.
147 ///
148 /// # Arguments:
149 ///
150 /// * `object`: is a reference to the target object.
151 /// * `old_val`: is the expected current value of the metadata.
152 /// * `new_val`: is the new metadata value to be stored if the compare-and-exchange operation is successful.
153 /// * `mask`: is an optional mask value for the metadata. This value is used in cases like the forwarding pointer metadata, where some of the bits are reused by other metadata such as the forwarding bits.
154 /// * `success_order`: is the atomic ordering used if the operation is successful.
155 /// * `failure_order`: is the atomic ordering used if the operation fails.
156 ///
157 pub fn compare_exchange_metadata<VM: VMBinding, T: MetadataValue>(
158 &self,
159 object: ObjectReference,
160 old_val: T,
161 new_val: T,
162 mask: Option<T>,
163 success_order: Ordering,
164 failure_order: Ordering,
165 ) -> std::result::Result<T, T> {
166 match self {
167 MetadataSpec::OnSide(metadata_spec) => metadata_spec.compare_exchange_atomic(
168 object.to_raw_address(),
169 old_val,
170 new_val,
171 success_order,
172 failure_order,
173 ),
174 MetadataSpec::InHeader(metadata_spec) => {
175 VM::VMObjectModel::compare_exchange_metadata::<T>(
176 metadata_spec,
177 object,
178 old_val,
179 new_val,
180 mask,
181 success_order,
182 failure_order,
183 )
184 }
185 }
186 }
187
188 /// A function to atomically perform an add operation on the specified metadata's content.
189 /// Returns the old metadata value.
190 ///
191 /// # Arguments:
192 ///
193 /// * `object`: is a reference to the target object.
194 /// * `val`: is the value to be added to the current value of the metadata.
195 /// * `order`: is the atomic ordering of the fetch-and-add operation.
196 ///
197 pub fn fetch_add_metadata<VM: VMBinding, T: MetadataValue>(
198 &self,
199 object: ObjectReference,
200 val: T,
201 order: Ordering,
202 ) -> T {
203 match self {
204 MetadataSpec::OnSide(metadata_spec) => {
205 metadata_spec.fetch_add_atomic(object.to_raw_address(), val, order)
206 }
207 MetadataSpec::InHeader(metadata_spec) => {
208 VM::VMObjectModel::fetch_add_metadata::<T>(metadata_spec, object, val, order)
209 }
210 }
211 }
212
213 /// A function to atomically perform a subtract operation on the specified metadata's content.
214 /// Returns the old metadata value.
215 ///
216 /// # Arguments:
217 ///
218 /// * `object`: is a reference to the target object.
219 /// * `val`: is the value to be subtracted from the current value of the metadata.
220 /// * `order`: is the atomic ordering of the fetch-and-add operation.
221 ///
222 pub fn fetch_sub_metadata<VM: VMBinding, T: MetadataValue>(
223 &self,
224 object: ObjectReference,
225 val: T,
226 order: Ordering,
227 ) -> T {
228 match self {
229 MetadataSpec::OnSide(metadata_spec) => {
230 metadata_spec.fetch_sub_atomic(object.to_raw_address(), val, order)
231 }
232 MetadataSpec::InHeader(metadata_spec) => {
233 VM::VMObjectModel::fetch_sub_metadata::<T>(metadata_spec, object, val, order)
234 }
235 }
236 }
237
238 /// A function to atomically perform a bit-and operation on the specified metadata's content.
239 /// Returns the old metadata value.
240 ///
241 /// # Arguments:
242 ///
243 /// * `object`: is a reference to the target object.
244 /// * `val`: is the value to bit-and with the current value of the metadata.
245 /// * `order`: is the atomic ordering of the fetch-and-add operation.
246 ///
247 pub fn fetch_and_metadata<VM: VMBinding, T: MetadataValue>(
248 &self,
249 object: ObjectReference,
250 val: T,
251 order: Ordering,
252 ) -> T {
253 match self {
254 MetadataSpec::OnSide(metadata_spec) => {
255 metadata_spec.fetch_and_atomic(object.to_raw_address(), val, order)
256 }
257 MetadataSpec::InHeader(metadata_spec) => {
258 VM::VMObjectModel::fetch_and_metadata::<T>(metadata_spec, object, val, order)
259 }
260 }
261 }
262
263 /// A function to atomically perform a bit-or operation on the specified metadata's content.
264 /// Returns the old metadata value.
265 ///
266 /// # Arguments:
267 ///
268 /// * `object`: is a reference to the target object.
269 /// * `val`: is the value to bit-or with the current value of the metadata.
270 /// * `order`: is the atomic ordering of the fetch-and-add operation.
271 ///
272 pub fn fetch_or_metadata<VM: VMBinding, T: MetadataValue>(
273 &self,
274 object: ObjectReference,
275 val: T,
276 order: Ordering,
277 ) -> T {
278 match self {
279 MetadataSpec::OnSide(metadata_spec) => {
280 metadata_spec.fetch_or_atomic(object.to_raw_address(), val, order)
281 }
282 MetadataSpec::InHeader(metadata_spec) => {
283 VM::VMObjectModel::fetch_or_metadata::<T>(metadata_spec, object, val, order)
284 }
285 }
286 }
287
288 /// A function to atomically perform an update operation on the specified metadata's content. The semantics are the same as Rust's `fetch_update` on atomic types.
289 /// Returns a Result of Ok(previous_value) if the function returned Some(_), else Err(previous_value).
290 ///
291 /// # Arguments:
292 ///
293 /// * `object`: is a reference to the target object.
294 /// * `val`: is the value to bit-or with the current value of the metadata.
295 /// * `order`: is the atomic ordering of the fetch-and-add operation.
296 /// * `f`: the update function. The function may be called multiple times.
297 ///
298 pub fn fetch_update_metadata<
299 VM: VMBinding,
300 T: MetadataValue,
301 F: FnMut(T) -> Option<T> + Copy,
302 >(
303 &self,
304 object: ObjectReference,
305 set_order: Ordering,
306 fetch_order: Ordering,
307 f: F,
308 ) -> std::result::Result<T, T> {
309 match self {
310 MetadataSpec::OnSide(metadata_spec) => metadata_spec.fetch_update_atomic(
311 object.to_raw_address(),
312 set_order,
313 fetch_order,
314 f,
315 ),
316 MetadataSpec::InHeader(metadata_spec) => VM::VMObjectModel::fetch_update_metadata(
317 metadata_spec,
318 object,
319 set_order,
320 fetch_order,
321 f,
322 ),
323 }
324 }
325}
326
327/// Given a slice of metadata specifications, returns a vector of the specs which are on side.
328///
329/// # Arguments:
330/// * `specs` is the input slice of on-side and/or in-header metadata specifications.
331///
332pub(crate) fn extract_side_metadata(specs: &[MetadataSpec]) -> Vec<SideMetadataSpec> {
333 let mut side_specs = vec![];
334 for spec in specs {
335 if let MetadataSpec::OnSide(ss) = *spec {
336 side_specs.push(ss);
337 }
338 }
339
340 side_specs
341}