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}