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