mmtk/vm/object_model.rs
1use atomic::Ordering;
2
3use self::specs::*;
4use crate::util::copy::*;
5use crate::util::metadata::header_metadata::HeaderMetadataSpec;
6use crate::util::metadata::MetadataValue;
7use crate::util::{Address, ObjectReference};
8use crate::vm::VMBinding;
9
10/// Default for [`ObjectModel::COMPRESSED_PTR_ENABLED`]
11pub(crate) const DEFAULT_COMPRESSED_PTR_ENABLED: bool = false;
12/// Default for [`ObjectModel::NEED_VO_BITS_DURING_TRACING`]
13#[cfg(feature = "vo_bit")]
14pub(crate) const DEFAULT_NEED_VO_BITS_DURING_TRACING: bool = false;
15/// Default for [`ObjectModel::VM_WORST_CASE_COPY_EXPANSION`]
16pub(crate) const DEFAULT_VM_WORST_CASE_COPY_EXPANSION: f64 = 1.5;
17/// Default for [`ObjectModel::UNIFIED_OBJECT_REFERENCE_ADDRESS`]
18pub(crate) const DEFAULT_UNIFIED_OBJECT_REFERENCE_ADDRESS: bool = false;
19
20/// VM-specific methods for object model.
21///
22/// This trait includes 3 parts:
23///
24/// 1. Specifications for per object metadata: a binding needs to specify the location for each per object metadata spec.
25/// A binding can choose between `in_header()` or `side()`, e.g. `VMGlobalLogBitSpec::side()`.
26/// * in_header: a binding needs to specify the bit offset to an object reference that can be used for the per object metadata spec.
27/// The actual number of bits required for a spec can be obtained from the `num_bits()` method of the spec type.
28/// * side: a binding does not need to provide any specific storage for metadata in the header. Instead, MMTk
29/// will use side tables to store the metadata. The following section Side Specs Layout will discuss how to correctly create
30/// side metadata specs.
31/// 2. In header metadata access: A binding
32/// need to further define the functions with suffix _metadata about how to access the bits in the header. We provide default implementations
33/// for those methods, assuming the bits in the spec are always available to MMTk. A binding could implement their
34/// own routines to access the bits if VM specific treatment is needed (e.g. some bits are not always available to MMTk).
35/// 3. VM-specific object info needed by MMTk: MMTk does not know object info as it is VM specific. However, MMTk needs
36/// some object information for GC. A binding needs to implement them correctly.
37///
38/// Note that depending on the selected GC plan, only a subset of the methods provided here will be used.
39///
40/// # Side Specs Layout
41///
42/// ## Short version
43///
44/// * For *global* side metadata:
45/// * The first spec: VMGlobalXXXSpec::side_first()
46/// * The following specs: VMGlobalXXXSpec::side_after(FIRST_GLOAL.as_spec())
47/// * For *local* side metadata:
48/// * The first spec: VMLocalXXXSpec::side_first()
49/// * The following specs: VMLocalXXXSpec::side_after(FIRST_LOCAL.as_spec())
50///
51/// ## Detailed explanation
52///
53/// There are two types of side metadata layout in MMTk:
54///
55/// 1. Contiguous layout: is the layout in which the whole metadata space for a SideMetadataSpec is contiguous.
56/// 2. Chunked layout: is the layout in which the whole metadata memory space, that is shared between MMTk policies, is divided into metadata-chunks. Each metadata-chunk stores all of the metadata for all `SideMetadataSpec`s which apply to a source-data chunk.
57///
58/// In 64-bits targets, both Global and PolicySpecific side metadata are contiguous.
59/// Also, in 32-bits targets, the Global side metadata is contiguous.
60/// This means if the starting address (variable named `offset`) of the metadata space for a SideMetadataSpec (`SPEC1`) is `BASE1`, the starting address (`offset`) of the next SideMetadataSpec (`SPEC2`) will be `BASE1 + total_metadata_space_size(SPEC1)`, which is located immediately after the end of the whole metadata space of `SPEC1`.
61/// Now, if we add a third SideMetadataSpec (`SPEC3`), its starting address (`offset`) will be `BASE2 + total_metadata_space_size(SPEC2)`, which is located immediately after the end of the whole metadata space of `SPEC2`.
62///
63/// In 32-bits targets, the PolicySpecific side metadata is chunked.
64/// This means for each chunk (2^22 Bytes) of data, which, by definition, is managed by exactly one MMTk policy, there is a metadata chunk (2^22 * some_fixed_ratio Bytes) that contains all of its PolicySpecific metadata.
65/// This means if a policy has one SideMetadataSpec (`LS1`), the `offset` of that spec will be `0` (= at the start of a metadata chunk).
66/// If there is a second SideMetadataSpec (`LS2`) for this specific policy, the `offset` for that spec will be `0 + required_metadata_space_per_chunk(LS1)`,
67/// and for a third SideMetadataSpec (`LS3`), the `offset` will be `BASE(LS2) + required_metadata_space_per_chunk(LS2)`.
68///
69/// For all other policies, the `offset` starts from zero. This is safe because no two policies ever manage one chunk, so there will be no overlap.
70///
71/// # Object Layout Addresses
72///
73/// MMTk tries to be general to cope with different language implementations and different object models. Thus it does not assume the internal of the object model.
74/// Instead, MMTk only uses the following addresses for an object. If you find the MMTk's approach does not work for your language in practice, you are welcome to submit an issue
75/// or engage with MMTk team on Zulip to disucss further.
76///
77/// ## (Raw) Object Reference
78///
79/// See [`crate::util::address::ObjectReference`]. This is a special address that represents the
80/// object. MMTk refers to an object by its object reference. An object reference cannot be NULL,
81/// must be inside the address range of the object, and must be word aligned
82/// ([`crate::util::address::ObjectReference::ALIGNMENT`]).
83///
84/// ## Object Start Address
85///
86/// This address is returned by an allocation call [`crate::memory_manager::alloc`]. This is the start of the address range of the allocation.
87/// [`ObjectModel::ref_to_object_start`] should return this address for a given object.
88///
89/// ## Object header address
90///
91/// If a binding allows MMTk to use its header bits for object metadata, it needs to supply an object header
92/// address ([`ObjectModel::ref_to_header`]). MMTk will access header bits using this address.
93pub trait ObjectModel<VM: VMBinding> {
94 // Per-object Metadata Spec definitions go here
95 //
96 // Note a number of Global and PolicySpecific side metadata specifications are already reserved by mmtk-core.
97 // Any side metadata offset calculation must consider these to prevent overlaps. A binding should start their
98 // side metadata from global_side_metadata_vm_base_address() or LOCAL_SIDE_METADATA_VM_BASE_OFFSET.
99
100 /// A global 1-bit metadata used by generational plans to track cross-generational pointers. It is generally
101 /// located in side metadata.
102 ///
103 /// Note that for this bit, 0 represents logged (default), and 1 represents unlogged.
104 /// This bit is also referred to as unlogged bit in Java MMTk for this reason.
105 const GLOBAL_LOG_BIT_SPEC: VMGlobalLogBitSpec;
106
107 /// A global per-field 1-bit metadata used by LXR's field barrier to record whether a field has
108 /// already been logged (recorded) for the current GC. It is generally located in side metadata,
109 /// with one bit per field-sized slot rather than one bit per object as with
110 /// [`GLOBAL_LOG_BIT_SPEC`](crate::vm::ObjectModel::GLOBAL_LOG_BIT_SPEC).
111 const GLOBAL_FIELD_UNLOG_BIT_SPEC: VMGlobalFieldUnlogBitSpec;
112
113 /// A local word-size metadata for the forwarding pointer, used by copying plans. It is almost always
114 /// located in the object header as it is fine to destroy an object header in order to copy it.
115 const LOCAL_FORWARDING_POINTER_SPEC: VMLocalForwardingPointerSpec;
116
117 /// A local 2-bit metadata for the forwarding status bits, used by copying plans. If your runtime requires
118 /// word-aligned addresses (i.e. 4- or 8-bytes), you can use the last two bits in the object header to store
119 /// the forwarding bits. Note that you must be careful if you place this in the header as the runtime may
120 /// be using those bits for some other reason.
121 const LOCAL_FORWARDING_BITS_SPEC: VMLocalForwardingBitsSpec;
122
123 /// A local 1-bit metadata for the mark bit, used by most plans that need to mark live objects. Like with the
124 /// [forwarding bits](crate::vm::ObjectModel::LOCAL_FORWARDING_BITS_SPEC), you can often steal the last bit in
125 /// the object header (due to alignment requirements) for the mark bit. Though some bindings such as the
126 /// OpenJDK binding prefer to have the mark bits in side metadata to allow for bulk operations.
127 const LOCAL_MARK_BIT_SPEC: VMLocalMarkBitSpec;
128
129 #[cfg(feature = "object_pinning")]
130 /// A local 1-bit metadata specification for the pinning bit, used by plans that need to pin objects. It is
131 /// generally in side metadata.
132 const LOCAL_PINNING_BIT_SPEC: VMLocalPinningBitSpec;
133
134 /// A local 2-bit metadata used by the large object space to mark objects and set objects as "newly allocated".
135 /// Used by any plan with large object allocation. It is generally in the header as we can add an extra word
136 /// before the large object to store this metadata. This is fine as the metadata size is insignificant in
137 /// comparison to the object size.
138 //
139 // TODO: Cleanup and place the LOS mark and nursery bits in the header. See here: https://github.com/mmtk/mmtk-core/issues/847
140 const LOCAL_LOS_MARK_NURSERY_SPEC: VMLocalLOSMarkNurserySpec;
141
142 /// Set this to true if the VM binding uses compressed (narrow) object pointers, e.g. compressed
143 /// oops on a 64-bit heap. When enabled, MMTk adjusts the size of certain per-object and per-field
144 /// side metadata (such as the field unlog bits) to match the narrower pointer/field width.
145 const COMPRESSED_PTR_ENABLED: bool = DEFAULT_COMPRESSED_PTR_ENABLED;
146
147 /// Set this to true if the VM binding requires the valid object (VO) bits to be available
148 /// during tracing. If this constant is set to `false`, it is undefined behavior if the binding
149 /// attempts to access VO bits during tracing.
150 ///
151 /// Note that the VO bits is always available during root scanning even if this flag is false,
152 /// which is suitable for using VO bits (and the `is_mmtk_object()` method) for conservative
153 /// stack scanning. However, if a binding is also conservative in finding references during
154 /// object scanning, they need to set this constant to `true`. See the comments of individual
155 /// methods in the `Scanning` trait.
156 ///
157 /// Depending on the internal implementation of mmtk-core, different strategies for handling
158 /// VO bits have different time/space overhead. mmtk-core will choose the best strategy
159 /// according to the configuration of the VM binding, including this flag. Currently, setting
160 /// this flag to true does not impose any additional overhead.
161 #[cfg(feature = "vo_bit")]
162 const NEED_VO_BITS_DURING_TRACING: bool = DEFAULT_NEED_VO_BITS_DURING_TRACING;
163
164 /// A function to non-atomically load the specified per-object metadata's content.
165 /// The default implementation assumes the bits defined by the spec are always avilable for MMTk to use. If that is not the case, a binding should override this method, and provide their implementation.
166 /// Returns the metadata value.
167 ///
168 /// # Arguments:
169 ///
170 /// * `metadata_spec`: is the header metadata spec that tries to perform the operation.
171 /// * `object`: is a reference to the target object.
172 /// * `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.
173 ///
174 /// # Safety
175 /// This is a non-atomic load, thus not thread-safe.
176 unsafe fn load_metadata<T: MetadataValue>(
177 metadata_spec: &HeaderMetadataSpec,
178 object: ObjectReference,
179 mask: Option<T>,
180 ) -> T {
181 metadata_spec.load::<T>(object.to_header::<VM>(), mask)
182 }
183
184 /// A function to atomically load the specified per-object metadata's content.
185 /// The default implementation assumes the bits defined by the spec are always avilable for MMTk to use. If that is not the case, a binding should override this method, and provide their implementation.
186 /// Returns the metadata value.
187 ///
188 /// # Arguments:
189 ///
190 /// * `metadata_spec`: is the header metadata spec that tries to perform the operation.
191 /// * `object`: is a reference to the target object.
192 /// * `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.
193 /// * `atomic_ordering`: is the atomic ordering for the load operation.
194 fn load_metadata_atomic<T: MetadataValue>(
195 metadata_spec: &HeaderMetadataSpec,
196 object: ObjectReference,
197 mask: Option<T>,
198 ordering: Ordering,
199 ) -> T {
200 metadata_spec.load_atomic::<T>(object.to_header::<VM>(), mask, ordering)
201 }
202
203 /// A function to non-atomically store a value to the specified per-object metadata.
204 /// The default implementation assumes the bits defined by the spec are always avilable for MMTk to use. If that is not the case, a binding should override this method, and provide their implementation.
205 ///
206 /// # Arguments:
207 ///
208 /// * `metadata_spec`: is the header metadata spec that tries to perform the operation.
209 /// * `object`: is a reference to the target object.
210 /// * `val`: is the new metadata value to be stored.
211 /// * `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.
212 ///
213 /// # Safety
214 /// This is a non-atomic store, thus not thread-safe.
215 unsafe fn store_metadata<T: MetadataValue>(
216 metadata_spec: &HeaderMetadataSpec,
217 object: ObjectReference,
218 val: T,
219 mask: Option<T>,
220 ) {
221 metadata_spec.store::<T>(object.to_header::<VM>(), val, mask)
222 }
223
224 /// A function to atomically store a value to the specified per-object metadata.
225 /// The default implementation assumes the bits defined by the spec are always avilable for MMTk to use. If that is not the case, a binding should override this method, and provide their implementation.
226 ///
227 /// # Arguments:
228 ///
229 /// * `metadata_spec`: is the header metadata spec that tries to perform the operation.
230 /// * `object`: is a reference to the target object.
231 /// * `val`: is the new metadata value to be stored.
232 /// * `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.
233 /// * `atomic_ordering`: is the optional atomic ordering for the store operation.
234 fn store_metadata_atomic<T: MetadataValue>(
235 metadata_spec: &HeaderMetadataSpec,
236 object: ObjectReference,
237 val: T,
238 mask: Option<T>,
239 ordering: Ordering,
240 ) {
241 metadata_spec.store_atomic::<T>(object.to_header::<VM>(), val, mask, ordering)
242 }
243
244 /// A function to atomically compare-and-exchange the specified per-object metadata's content.
245 /// The default implementation assumes the bits defined by the spec are always avilable for MMTk to use. If that is not the case, a binding should override this method, and provide their implementation.
246 /// Returns `true` if the operation is successful, and `false` otherwise.
247 ///
248 /// # Arguments:
249 ///
250 /// * `metadata_spec`: is the header metadata spec that tries to perform the operation.
251 /// * `object`: is a reference to the target object.
252 /// * `old_val`: is the expected current value of the metadata.
253 /// * `new_val`: is the new metadata value to be stored if the compare-and-exchange operation is successful.
254 /// * `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.
255 /// * `success_order`: is the atomic ordering used if the operation is successful.
256 /// * `failure_order`: is the atomic ordering used if the operation fails.
257 fn compare_exchange_metadata<T: MetadataValue>(
258 metadata_spec: &HeaderMetadataSpec,
259 object: ObjectReference,
260 old_val: T,
261 new_val: T,
262 mask: Option<T>,
263 success_order: Ordering,
264 failure_order: Ordering,
265 ) -> std::result::Result<T, T> {
266 metadata_spec.compare_exchange::<T>(
267 object.to_header::<VM>(),
268 old_val,
269 new_val,
270 mask,
271 success_order,
272 failure_order,
273 )
274 }
275
276 /// A function to atomically perform an add operation on the specified per-object metadata's content.
277 /// The default implementation assumes the bits defined by the spec are always avilable for MMTk to use. If that is not the case, a binding should override this method, and provide their implementation.
278 /// This is a wrapping add.
279 /// # Returns the old metadata value.
280 ///
281 /// # Arguments:
282 ///
283 /// * `metadata_spec`: is the header metadata spec that tries to perform the operation.
284 /// * `object`: is a reference to the target object.
285 /// * `val`: is the value to be added to the current value of the metadata.
286 /// * `order`: is the atomic ordering of the fetch-and-add operation.
287 fn fetch_add_metadata<T: MetadataValue>(
288 metadata_spec: &HeaderMetadataSpec,
289 object: ObjectReference,
290 val: T,
291 order: Ordering,
292 ) -> T {
293 metadata_spec.fetch_add::<T>(object.to_header::<VM>(), val, order)
294 }
295
296 /// A function to atomically perform a subtract operation on the specified per-object metadata's content.
297 /// The default implementation assumes the bits defined by the spec are always avilable for MMTk to use. If that is not the case, a binding should override this method, and provide their implementation.
298 /// This is a wrapping sub.
299 /// Returns the old metadata value.
300 ///
301 /// # Arguments:
302 ///
303 /// * `metadata_spec`: is the header metadata spec that tries to perform the operation.
304 /// * `object`: is a reference to the target object.
305 /// * `val`: is the value to be subtracted from the current value of the metadata.
306 /// * `order`: is the atomic ordering of the fetch-and-add operation.
307 fn fetch_sub_metadata<T: MetadataValue>(
308 metadata_spec: &HeaderMetadataSpec,
309 object: ObjectReference,
310 val: T,
311 order: Ordering,
312 ) -> T {
313 metadata_spec.fetch_sub::<T>(object.to_header::<VM>(), val, order)
314 }
315
316 /// A function to atomically perform a bit-and operation on the specified per-object metadata's content.
317 /// The default implementation assumes the bits defined by the spec are always avilable for MMTk to use. If that is not the case, a binding should override this method, and provide their implementation.
318 /// Returns the old metadata value.
319 ///
320 /// # Arguments:
321 ///
322 /// * `metadata_spec`: is the header metadata spec that tries to perform the operation.
323 /// * `object`: is a reference to the target object.
324 /// * `val`: is the value to bit-and with the current value of the metadata.
325 /// * `order`: is the atomic ordering of the fetch-and-add operation.
326 fn fetch_and_metadata<T: MetadataValue>(
327 metadata_spec: &HeaderMetadataSpec,
328 object: ObjectReference,
329 val: T,
330 order: Ordering,
331 ) -> T {
332 metadata_spec.fetch_and::<T>(object.to_header::<VM>(), val, order)
333 }
334
335 /// A function to atomically perform a bit-or operation on the specified per-object metadata's content.
336 /// The default implementation assumes the bits defined by the spec are always avilable for MMTk to use. If that is not the case, a binding should override this method, and provide their implementation.
337 /// Returns the old metadata value.
338 ///
339 /// # Arguments:
340 ///
341 /// * `metadata_spec`: is the header metadata spec that tries to perform the operation.
342 /// * `object`: is a reference to the target object.
343 /// * `val`: is the value to bit-or with the current value of the metadata.
344 /// * `order`: is the atomic ordering of the fetch-and-add operation.
345 fn fetch_or_metadata<T: MetadataValue>(
346 metadata_spec: &HeaderMetadataSpec,
347 object: ObjectReference,
348 val: T,
349 order: Ordering,
350 ) -> T {
351 metadata_spec.fetch_or::<T>(object.to_header::<VM>(), val, order)
352 }
353
354 /// A function to atomically perform an update operation on the specified per-object metadata's content.
355 /// The default implementation assumes the bits defined by the spec are always avilable for MMTk to use. If that is not the case, a binding should override this method, and provide their implementation.
356 /// The semantics of this method are the same as the `fetch_update()` on Rust atomic types.
357 ///
358 /// # Arguments:
359 ///
360 /// * `metadata_spec`: is the header metadata spec that tries to perform the operation.
361 /// * `object`: is a reference to the target object.
362 /// * `val`: is the value to bit-and with the current value of the metadata.
363 /// * `order`: is the atomic ordering of the fetch-and-add operation.
364 ///
365 /// # Returns the old metadata value.
366 fn fetch_update_metadata<T: MetadataValue, F: FnMut(T) -> Option<T> + Copy>(
367 metadata_spec: &HeaderMetadataSpec,
368 object: ObjectReference,
369 set_order: Ordering,
370 fetch_order: Ordering,
371 f: F,
372 ) -> std::result::Result<T, T> {
373 metadata_spec.fetch_update::<T, F>(object.to_header::<VM>(), set_order, fetch_order, f)
374 }
375
376 /// Copy an object and return the address of the new object. Usually in the implementation of this method,
377 /// `alloc_copy()` and `post_copy()` from [`GCWorkerCopyContext`](util/copy/struct.GCWorkerCopyContext.html)
378 /// are used for copying.
379 ///
380 /// Arguments:
381 /// * `from`: The address of the object to be copied.
382 /// * `semantics`: The copy semantic to use.
383 /// * `copy_context`: The `GCWorkerCopyContext` for the GC thread.
384 fn copy(
385 from: ObjectReference,
386 semantics: CopySemantics,
387 copy_context: &mut GCWorkerCopyContext<VM>,
388 ) -> ObjectReference;
389
390 /// Attempt to copy an object, allowing the copy to fail (e.g. under concurrent copying, where
391 /// another GC worker may already be copying the same object). Returns the address of the new
392 /// object on success, or `None` if the copy could not be performed.
393 ///
394 /// Arguments:
395 /// * `from`: The address of the object to be copied.
396 /// * `semantics`: The copy semantic to use.
397 /// * `copy_context`: The `GCWorkerCopyContext` for the GC thread.
398 fn try_copy(
399 from: ObjectReference,
400 semantics: CopySemantics,
401 copy_context: &mut GCWorkerCopyContext<VM>,
402 ) -> Option<ObjectReference>;
403
404 /// Copy an object. This is required
405 /// for delayed-copy collectors such as compacting collectors. During the
406 /// collection, MMTk reserves a region in the heap for an object as per
407 /// requirements found from `ObjectModel` and then asks `ObjectModel` to
408 /// determine what the object's reference will be post-copy. Return the address
409 /// past the end of the copied object.
410 ///
411 /// Arguments:
412 /// * `from`: The address of the object to be copied.
413 /// * `to`: The target location.
414 /// * `region: The start of the region that was reserved for this object.
415 fn copy_to(from: ObjectReference, to: ObjectReference, region: Address) -> Address;
416
417 /// Return the reference that an object will be referred to after it is copied
418 /// to the specified region. Used in delayed-copy collectors such as compacting
419 /// collectors.
420 ///
421 /// Arguments:
422 /// * `from`: The object to be copied.
423 /// * `to`: The start of the region to be copied to.
424 fn get_reference_when_copied_to(from: ObjectReference, to: Address) -> ObjectReference;
425
426 /// Return the size used by an object.
427 ///
428 /// Arguments:
429 /// * `object`: The object to be queried.
430 fn get_current_size(object: ObjectReference) -> usize;
431
432 /// Return the size when an object is copied.
433 ///
434 /// Arguments:
435 /// * `object`: The object to be queried.
436 fn get_size_when_copied(object: ObjectReference) -> usize;
437
438 /// Return the alignment when an object is copied.
439 ///
440 /// Arguments:
441 /// * `object`: The object to be queried.
442 fn get_align_when_copied(object: ObjectReference) -> usize;
443
444 /// Return the alignment offset when an object is copied.
445 ///
446 /// Arguments:
447 /// * `object`: The object to be queried.
448 fn get_align_offset_when_copied(object: ObjectReference) -> usize;
449
450 /// Get the type descriptor for an object.
451 ///
452 /// FIXME: Do we need this? If so, determine lifetime, return byte[]
453 ///
454 /// Arguments:
455 /// * `reference`: The object to be queried.
456 fn get_type_descriptor(reference: ObjectReference) -> &'static [i8];
457
458 /// This is the worst case expansion that can occur due to object size increasing while
459 /// copying. This constant is used to calculate whether a nursery has grown larger than the
460 /// mature space for generational plans.
461 const VM_WORST_CASE_COPY_EXPANSION: f64 = DEFAULT_VM_WORST_CASE_COPY_EXPANSION;
462
463 /// If this is true, the binding guarantees that the object reference's raw address and the
464 /// object start are always the same address. In other words, an object reference's raw
465 /// address is always equal to the return value of the `ref_to_object_start` method,
466 ///
467 /// This is a very strong guarantee, but it is also helpful for MMTk to
468 /// make some assumptions and optimize for this case.
469 /// If a binding sets this to true, and the related methods return inconsistent results, this is an undefined behavior. MMTk may panic
470 /// if any assertion catches this error, but may also fail silently.
471 const UNIFIED_OBJECT_REFERENCE_ADDRESS: bool = DEFAULT_UNIFIED_OBJECT_REFERENCE_ADDRESS;
472
473 /// For our allocation result (object_start), the binding may have an offset between the allocation result
474 /// and the raw address of their object reference, i.e. object ref's raw address = object_start + offset.
475 /// The offset could be zero. The offset is not necessary to be
476 /// constant for all the objects. This constant defines the smallest possible offset.
477 ///
478 /// This is used as an indication for MMTk to predict where object references may point to in some algorithms.
479 ///
480 /// We should have the invariant:
481 /// * object ref >= object_start + OBJECT_REF_OFFSET_LOWER_BOUND
482 const OBJECT_REF_OFFSET_LOWER_BOUND: isize;
483
484 /// Return the lowest address of the storage associated with an object. This should be
485 /// the address that a binding gets by an allocation call ([`crate::memory_manager::alloc`]).
486 ///
487 /// Note that the return value needs to satisfy the invariant mentioned in the doc comment of
488 /// [`Self::OBJECT_REF_OFFSET_LOWER_BOUND`].
489 ///
490 /// Arguments:
491 /// * `object`: The object to be queried.
492 fn ref_to_object_start(object: ObjectReference) -> Address;
493
494 /// Return the header base address from an object reference. Any object header metadata
495 /// in the [`crate::vm::ObjectModel`] declares a piece of header metadata with an offset
496 /// from this address. If a binding does not use any header metadata for MMTk, this method
497 /// will not be called, and the binding can simply use `unreachable!()` for the method.
498 ///
499 /// Arguments:
500 /// * `object`: The object to be queried.
501 fn ref_to_header(object: ObjectReference) -> Address;
502
503 /// Dump debugging information for an object.
504 ///
505 /// Arguments:
506 /// * `object`: The object to be dumped.
507 fn dump_object(object: ObjectReference);
508
509 /// Return if an object is valid from the runtime point of view. This is used
510 /// to debug MMTk.
511 fn is_object_sane(_object: ObjectReference) -> bool {
512 true
513 }
514}
515
516pub mod specs {
517 use crate::util::constants::LOG_BITS_IN_WORD;
518 use crate::util::constants::LOG_BYTES_IN_ADDRESS;
519 use crate::util::constants::LOG_BYTES_IN_PAGE;
520 use crate::util::constants::LOG_MIN_OBJECT_SIZE;
521 use crate::util::metadata::side_metadata::*;
522 use crate::util::metadata::{
523 header_metadata::HeaderMetadataSpec,
524 side_metadata::{side_metadata_offset_after, SideMetadataSpec},
525 MetadataSpec,
526 };
527
528 // This macro is invoked in define_vm_metadata_global_spec or define_vm_metadata_local_spec.
529 // Use those two to define a new VM metadata spec.
530 macro_rules! define_vm_metadata_spec {
531 ($(#[$outer:meta])*$spec_name: ident, $is_global: expr, $log_num_bits: expr, $side_min_obj_size: expr) => {
532 $(#[$outer])*
533 /// A newtype wrapper around [`MetadataSpec`] that identifies this particular per-object
534 /// metadata (e.g. whether it is in the header or on the side, and where). Generated by the
535 /// `define_vm_metadata_spec` macro for each metadata kind declared on
536 /// [`crate::vm::ObjectModel`].
537 pub struct $spec_name(MetadataSpec);
538 impl $spec_name {
539 /// The number of bits (in log2) that are needed for the spec.
540 pub const LOG_NUM_BITS: usize = $log_num_bits;
541
542 /// Whether this spec is global or local. For side metadata, the binding needs to make sure
543 /// global specs are laid out after another global spec, and local specs are laid
544 /// out after another local spec. Otherwise, there will be an assertion failure.
545 pub const IS_GLOBAL: bool = $is_global;
546
547 /// Declare that the VM uses in-header metadata for this metadata type.
548 /// For the specification of the `bit_offset` argument, please refer to
549 /// the document of `[crate::util::metadata::header_metadata::HeaderMetadataSpec.bit_offset]`.
550 /// The binding needs to make sure that the bits used for a spec in the header do not conflict with
551 /// the bits of another spec (unless it is specified that some bits may be reused).
552 pub const fn in_header(bit_offset: isize) -> Self {
553 Self(MetadataSpec::InHeader(HeaderMetadataSpec {
554 bit_offset,
555 num_of_bits: 1 << Self::LOG_NUM_BITS,
556 }))
557 }
558
559 /// Declare that the VM uses side metadata for this metadata type,
560 /// and the side metadata is the first of its kind (global or local).
561 /// The first global or local side metadata should be declared with `side_first()`,
562 /// and the rest side metadata should be declared with `side_after()` after a defined
563 /// side metadata of the same kind (global or local). Logically, all the declarations
564 /// create two list of side metadata, one for global, and one for local.
565 pub const fn side_first() -> Self {
566 if Self::IS_GLOBAL {
567 Self(MetadataSpec::OnSide(SideMetadataSpec {
568 name: stringify!($spec_name),
569 is_global: Self::IS_GLOBAL,
570 offset: GLOBAL_SIDE_METADATA_VM_BASE_OFFSET,
571 log_num_of_bits: Self::LOG_NUM_BITS,
572 log_bytes_in_region: $side_min_obj_size as usize,
573 }))
574 } else {
575 Self(MetadataSpec::OnSide(SideMetadataSpec {
576 name: stringify!($spec_name),
577 is_global: Self::IS_GLOBAL,
578 offset: LOCAL_SIDE_METADATA_VM_BASE_OFFSET,
579 log_num_of_bits: Self::LOG_NUM_BITS,
580 log_bytes_in_region: $side_min_obj_size as usize,
581 }))
582 }
583 }
584 /// Like [`side_first`](Self::side_first), but for use with compressed pointers
585 /// ([`crate::vm::ObjectModel::COMPRESSED_PTR_ENABLED`]): the region size is one bit
586 /// narrower to match the reduced field/pointer width, so this declares the first side
587 /// metadata of its kind (global or local) sized for a compressed-pointer heap.
588 pub const fn side_first_compressed() -> Self {
589 if Self::IS_GLOBAL {
590 Self(MetadataSpec::OnSide(SideMetadataSpec {
591 name: stringify!($spec_name),
592 is_global: Self::IS_GLOBAL,
593 offset: GLOBAL_SIDE_METADATA_VM_BASE_OFFSET,
594 log_num_of_bits: Self::LOG_NUM_BITS,
595 log_bytes_in_region: $side_min_obj_size as usize - 1,
596 }))
597 } else {
598 Self(MetadataSpec::OnSide(SideMetadataSpec {
599 name: stringify!($spec_name),
600 is_global: Self::IS_GLOBAL,
601 offset: LOCAL_SIDE_METADATA_VM_BASE_OFFSET,
602 log_num_of_bits: Self::LOG_NUM_BITS,
603 log_bytes_in_region: $side_min_obj_size as usize - 1,
604 }))
605 }
606 }
607
608 /// Declare that the VM uses side metadata for this metadata type,
609 /// and the side metadata should be laid out after the given side metadata spec.
610 /// The first global or local side metadata should be declared with `side_first()`,
611 /// and the rest side metadata should be declared with `side_after()` after a defined
612 /// side metadata of the same kind (global or local). Logically, all the declarations
613 /// create two list of side metadata, one for global, and one for local.
614 pub const fn side_after(spec: &MetadataSpec) -> Self {
615 assert!(spec.is_on_side());
616 let side_spec = spec.extract_side_spec();
617 assert!(side_spec.is_global == Self::IS_GLOBAL);
618 Self(MetadataSpec::OnSide(SideMetadataSpec {
619 name: stringify!($spec_name),
620 is_global: Self::IS_GLOBAL,
621 offset: side_metadata_offset_after(side_spec),
622 log_num_of_bits: Self::LOG_NUM_BITS,
623 log_bytes_in_region: $side_min_obj_size as usize,
624 }))
625 }
626
627 /// Return the inner `[crate::util::metadata::MetadataSpec]` for the metadata type.
628 pub const fn as_spec(&self) -> &MetadataSpec {
629 &self.0
630 }
631
632 /// Return the number of bits for the metadata type.
633 pub const fn num_bits(&self) -> usize {
634 1 << $log_num_bits
635 }
636 }
637 impl std::ops::Deref for $spec_name {
638 type Target = MetadataSpec;
639 fn deref(&self) -> &Self::Target {
640 self.as_spec()
641 }
642 }
643 };
644 }
645
646 // Log bit: 1 bit per object, global
647 define_vm_metadata_spec!(
648 /// 1-bit global metadata to log an object.
649 VMGlobalLogBitSpec,
650 true,
651 0,
652 LOG_MIN_OBJECT_SIZE
653 );
654 define_vm_metadata_spec!(VMGlobalFieldUnlogBitSpec, true, 0, LOG_BYTES_IN_ADDRESS);
655 // Forwarding pointer: word size per object, local
656 define_vm_metadata_spec!(
657 /// 1-word local metadata for spaces that may copy objects.
658 /// This metadata has to be stored in the header.
659 /// This metadata can be defined at a position within the object payload.
660 /// As a forwarding pointer is only stored in dead objects which is not
661 /// accessible by the language, it is okay that store a forwarding pointer overwrites object payload
662 VMLocalForwardingPointerSpec,
663 false,
664 LOG_BITS_IN_WORD,
665 LOG_MIN_OBJECT_SIZE
666 );
667 // Forwarding bits: 2 bits per object, local
668 define_vm_metadata_spec!(
669 /// 2-bit local metadata for spaces that store a forwarding state for objects.
670 /// If this spec is defined in the header, it can be defined with a position of the lowest 2 bits in the forwarding pointer.
671 VMLocalForwardingBitsSpec,
672 false,
673 1,
674 LOG_MIN_OBJECT_SIZE
675 );
676 // Mark bit: 1 bit per object, local
677 define_vm_metadata_spec!(
678 /// 1-bit local metadata for spaces that need to mark an object.
679 VMLocalMarkBitSpec,
680 false,
681 0,
682 LOG_MIN_OBJECT_SIZE
683 );
684 // Pinning bit: 1 bit per object, local
685 define_vm_metadata_spec!(
686 /// 1-bit local metadata for spaces that support pinning.
687 VMLocalPinningBitSpec,
688 false,
689 0,
690 LOG_MIN_OBJECT_SIZE
691 );
692 // Mark&nursery bits for LOS: 2 bit per page, local
693 define_vm_metadata_spec!(
694 /// 2-bits local metadata for the large object space. The two bits serve as
695 /// the mark bit and the nursery bit.
696 VMLocalLOSMarkNurserySpec,
697 false,
698 1,
699 LOG_BYTES_IN_PAGE
700 );
701}