pub trait ObjectModel<VM: VMBinding> {
    const GLOBAL_LOG_BIT_SPEC: VMGlobalLogBitSpec;
    const LOCAL_FORWARDING_POINTER_SPEC: VMLocalForwardingPointerSpec;
    const LOCAL_FORWARDING_BITS_SPEC: VMLocalForwardingBitsSpec;
    const LOCAL_MARK_BIT_SPEC: VMLocalMarkBitSpec;
    const LOCAL_PINNING_BIT_SPEC: VMLocalPinningBitSpec;
    const LOCAL_LOS_MARK_NURSERY_SPEC: VMLocalLOSMarkNurserySpec;
    const OBJECT_REF_OFFSET_LOWER_BOUND: isize;
    const NEED_VO_BITS_DURING_TRACING: bool = false;
    const VM_WORST_CASE_COPY_EXPANSION: f64 = 1.5f64;
    const UNIFIED_OBJECT_REFERENCE_ADDRESS: bool = false;
Show 22 methods // Required methods fn copy( from: ObjectReference, semantics: CopySemantics, copy_context: &mut GCWorkerCopyContext<VM> ) -> ObjectReference; fn copy_to( from: ObjectReference, to: ObjectReference, region: Address ) -> Address; fn get_reference_when_copied_to( from: ObjectReference, to: Address ) -> ObjectReference; fn get_current_size(object: ObjectReference) -> usize; fn get_size_when_copied(object: ObjectReference) -> usize; fn get_align_when_copied(object: ObjectReference) -> usize; fn get_align_offset_when_copied(object: ObjectReference) -> usize; fn get_type_descriptor(reference: ObjectReference) -> &'static [i8]; fn ref_to_object_start(object: ObjectReference) -> Address; fn ref_to_header(object: ObjectReference) -> Address; fn dump_object(object: ObjectReference); // Provided methods unsafe fn load_metadata<T: MetadataValue>( metadata_spec: &HeaderMetadataSpec, object: ObjectReference, mask: Option<T> ) -> T { ... } fn load_metadata_atomic<T: MetadataValue>( metadata_spec: &HeaderMetadataSpec, object: ObjectReference, mask: Option<T>, ordering: Ordering ) -> T { ... } unsafe fn store_metadata<T: MetadataValue>( metadata_spec: &HeaderMetadataSpec, object: ObjectReference, val: T, mask: Option<T> ) { ... } fn store_metadata_atomic<T: MetadataValue>( metadata_spec: &HeaderMetadataSpec, object: ObjectReference, val: T, mask: Option<T>, ordering: Ordering ) { ... } fn compare_exchange_metadata<T: MetadataValue>( metadata_spec: &HeaderMetadataSpec, object: ObjectReference, old_val: T, new_val: T, mask: Option<T>, success_order: Ordering, failure_order: Ordering ) -> Result<T, T> { ... } fn fetch_add_metadata<T: MetadataValue>( metadata_spec: &HeaderMetadataSpec, object: ObjectReference, val: T, order: Ordering ) -> T { ... } fn fetch_sub_metadata<T: MetadataValue>( metadata_spec: &HeaderMetadataSpec, object: ObjectReference, val: T, order: Ordering ) -> T { ... } fn fetch_and_metadata<T: MetadataValue>( metadata_spec: &HeaderMetadataSpec, object: ObjectReference, val: T, order: Ordering ) -> T { ... } fn fetch_or_metadata<T: MetadataValue>( metadata_spec: &HeaderMetadataSpec, object: ObjectReference, val: T, order: Ordering ) -> T { ... } fn fetch_update_metadata<T: MetadataValue, F: FnMut(T) -> Option<T> + Copy>( metadata_spec: &HeaderMetadataSpec, object: ObjectReference, set_order: Ordering, fetch_order: Ordering, f: F ) -> Result<T, T> { ... } fn is_object_sane(_object: ObjectReference) -> bool { ... }
}
Expand description

VM-specific methods for object model.

This trait includes 3 parts:

  1. Specifications for per object metadata: a binding needs to specify the location for each per object metadata spec. A binding can choose between in_header() or side(), e.g. VMGlobalLogBitSpec::side().
    • in_header: a binding needs to specify the bit offset to an object reference that can be used for the per object metadata spec. The actual number of bits required for a spec can be obtained from the num_bits() method of the spec type.
    • side: a binding does not need to provide any specific storage for metadata in the header. Instead, MMTk will use side tables to store the metadata. The following section Side Specs Layout will discuss how to correctly create side metadata specs.
  2. In header metadata access: A binding need to further define the functions with suffix _metadata about how to access the bits in the header. We provide default implementations for those methods, assuming the bits in the spec are always available to MMTk. A binding could implement their own routines to access the bits if VM specific treatment is needed (e.g. some bits are not always available to MMTk).
  3. VM-specific object info needed by MMTk: MMTk does not know object info as it is VM specific. However, MMTk needs some object information for GC. A binding needs to implement them correctly.

Note that depending on the selected GC plan, only a subset of the methods provided here will be used.

§Side Specs Layout

§Short version

  • For global side metadata:
    • The first spec: VMGlobalXXXSpec::side_first()
    • The following specs: VMGlobalXXXSpec::side_after(FIRST_GLOAL.as_spec())
  • For local side metadata:
    • The first spec: VMLocalXXXSpec::side_first()
    • The following specs: VMLocalXXXSpec::side_after(FIRST_LOCAL.as_spec())

§Detailed explanation

There are two types of side metadata layout in MMTk:

  1. Contiguous layout: is the layout in which the whole metadata space for a SideMetadataSpec is contiguous.
  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 SideMetadataSpecs which apply to a source-data chunk.

In 64-bits targets, both Global and PolicySpecific side metadata are contiguous. Also, in 32-bits targets, the Global side metadata is contiguous. 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. 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.

In 32-bits targets, the PolicySpecific side metadata is chunked. 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. This means if a policy has one SideMetadataSpec (LS1), the offset of that spec will be 0 (= at the start of a metadata chunk). 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), and for a third SideMetadataSpec (LS3), the offset will be BASE(LS2) + required_metadata_space_per_chunk(LS2).

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.

§Object Layout Addresses

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. 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 or engage with MMTk team on Zulip to disucss further.

§(Raw) Object Reference

See crate::util::address::ObjectReference. This is a special address that represents the object. MMTk refers to an object by its object reference. An object reference cannot be NULL, must be inside the address range of the object, and must be word aligned (crate::util::address::ObjectReference::ALIGNMENT).

§Object Start Address

This address is returned by an allocation call crate::memory_manager::alloc. This is the start of the address range of the allocation. ObjectModel::ref_to_object_start should return this address for a given object.

§Object header address

If a binding allows MMTk to use its header bits for object metadata, it needs to supply an object header address (ObjectModel::ref_to_header). MMTk will access header bits using this address.

Required Associated Constants§

source

const GLOBAL_LOG_BIT_SPEC: VMGlobalLogBitSpec

A global 1-bit metadata used by generational plans to track cross-generational pointers. It is generally located in side metadata.

Note that for this bit, 0 represents logged (default), and 1 represents unlogged. This bit is also referred to as unlogged bit in Java MMTk for this reason.

source

const LOCAL_FORWARDING_POINTER_SPEC: VMLocalForwardingPointerSpec

A local word-size metadata for the forwarding pointer, used by copying plans. It is almost always located in the object header as it is fine to destroy an object header in order to copy it.

source

const LOCAL_FORWARDING_BITS_SPEC: VMLocalForwardingBitsSpec

A local 2-bit metadata for the forwarding status bits, used by copying plans. If your runtime requires word-aligned addresses (i.e. 4- or 8-bytes), you can use the last two bits in the object header to store the forwarding bits. Note that you must be careful if you place this in the header as the runtime may be using those bits for some other reason.

source

const LOCAL_MARK_BIT_SPEC: VMLocalMarkBitSpec

A local 1-bit metadata for the mark bit, used by most plans that need to mark live objects. Like with the forwarding bits, you can often steal the last bit in the object header (due to alignment requirements) for the mark bit. Though some bindings such as the OpenJDK binding prefer to have the mark bits in side metadata to allow for bulk operations.

source

const LOCAL_PINNING_BIT_SPEC: VMLocalPinningBitSpec

A local 1-bit metadata specification for the pinning bit, used by plans that need to pin objects. It is generally in side metadata.

source

const LOCAL_LOS_MARK_NURSERY_SPEC: VMLocalLOSMarkNurserySpec

A local 2-bit metadata used by the large object space to mark objects and set objects as “newly allocated”. Used by any plan with large object allocation. It is generally in the header as we can add an extra word before the large object to store this metadata. This is fine as the metadata size is insignificant in comparison to the object size.

source

const OBJECT_REF_OFFSET_LOWER_BOUND: isize

For our allocation result (object_start), the binding may have an offset between the allocation result and the raw address of their object reference, i.e. object ref’s raw address = object_start + offset. The offset could be zero. The offset is not necessary to be constant for all the objects. This constant defines the smallest possible offset.

This is used as an indication for MMTk to predict where object references may point to in some algorithms.

We should have the invariant:

  • object ref >= object_start + OBJECT_REF_OFFSET_LOWER_BOUND

Provided Associated Constants§

source

const NEED_VO_BITS_DURING_TRACING: bool = false

Set this to true if the VM binding requires the valid object (VO) bits to be available during tracing. If this constant is set to false, it is undefined behavior if the binding attempts to access VO bits during tracing.

Note that the VO bits is always available during root scanning even if this flag is false, which is suitable for using VO bits (and the is_mmtk_object() method) for conservative stack scanning. However, if a binding is also conservative in finding references during object scanning, they need to set this constant to true. See the comments of individual methods in the Scanning trait.

Depending on the internal implementation of mmtk-core, different strategies for handling VO bits have different time/space overhead. mmtk-core will choose the best strategy according to the configuration of the VM binding, including this flag. Currently, setting this flag to true does not impose any additional overhead.

source

const VM_WORST_CASE_COPY_EXPANSION: f64 = 1.5f64

This is the worst case expansion that can occur due to object size increasing while copying. This constant is used to calculate whether a nursery has grown larger than the mature space for generational plans.

source

const UNIFIED_OBJECT_REFERENCE_ADDRESS: bool = false

If this is true, the binding guarantees that the object reference’s raw address and the object start are always the same address. In other words, an object reference’s raw address is always equal to the return value of the ref_to_object_start method,

This is a very strong guarantee, but it is also helpful for MMTk to make some assumptions and optimize for this case. If a binding sets this to true, and the related methods return inconsistent results, this is an undefined behavior. MMTk may panic if any assertion catches this error, but may also fail silently.

Required Methods§

source

fn copy( from: ObjectReference, semantics: CopySemantics, copy_context: &mut GCWorkerCopyContext<VM> ) -> ObjectReference

Copy an object and return the address of the new object. Usually in the implementation of this method, alloc_copy() and post_copy() from GCWorkerCopyContext are used for copying.

Arguments:

  • from: The address of the object to be copied.
  • semantics: The copy semantic to use.
  • copy_context: The GCWorkerCopyContext for the GC thread.
source

fn copy_to( from: ObjectReference, to: ObjectReference, region: Address ) -> Address

Copy an object. This is required for delayed-copy collectors such as compacting collectors. During the collection, MMTk reserves a region in the heap for an object as per requirements found from ObjectModel and then asks ObjectModel to determine what the object’s reference will be post-copy. Return the address past the end of the copied object.

Arguments:

  • from: The address of the object to be copied.
  • to: The target location.
  • `region: The start of the region that was reserved for this object.
source

fn get_reference_when_copied_to( from: ObjectReference, to: Address ) -> ObjectReference

Return the reference that an object will be referred to after it is copied to the specified region. Used in delayed-copy collectors such as compacting collectors.

Arguments:

  • from: The object to be copied.
  • to: The region to be copied to.
source

fn get_current_size(object: ObjectReference) -> usize

Return the size used by an object.

Arguments:

  • object: The object to be queried.
source

fn get_size_when_copied(object: ObjectReference) -> usize

Return the size when an object is copied.

Arguments:

  • object: The object to be queried.
source

fn get_align_when_copied(object: ObjectReference) -> usize

Return the alignment when an object is copied.

Arguments:

  • object: The object to be queried.
source

fn get_align_offset_when_copied(object: ObjectReference) -> usize

Return the alignment offset when an object is copied.

Arguments:

  • object: The object to be queried.
source

fn get_type_descriptor(reference: ObjectReference) -> &'static [i8]

Get the type descriptor for an object.

FIXME: Do we need this? If so, determine lifetime, return byte[]

Arguments:

  • reference: The object to be queried.
source

fn ref_to_object_start(object: ObjectReference) -> Address

Return the lowest address of the storage associated with an object. This should be the address that a binding gets by an allocation call (crate::memory_manager::alloc).

Note that the return value needs to satisfy the invariant mentioned in the doc comment of Self::OBJECT_REF_OFFSET_LOWER_BOUND.

Arguments:

  • object: The object to be queried.
source

fn ref_to_header(object: ObjectReference) -> Address

Return the header base address from an object reference. Any object header metadata in the crate::vm::ObjectModel declares a piece of header metadata with an offset from this address. If a binding does not use any header metadata for MMTk, this method will not be called, and the binding can simply use unreachable!() for the method.

Arguments:

  • object: The object to be queried.
source

fn dump_object(object: ObjectReference)

Dump debugging information for an object.

Arguments:

  • object: The object to be dumped.

Provided Methods§

source

unsafe fn load_metadata<T: MetadataValue>( metadata_spec: &HeaderMetadataSpec, object: ObjectReference, mask: Option<T> ) -> T

A function to non-atomically load the specified per-object metadata’s content. 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. Returns the metadata value.

§Arguments:
  • metadata_spec: is the header metadata spec that tries to perform the operation.
  • object: is a reference to the target object.
  • 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.
§Safety

This is a non-atomic load, thus not thread-safe.

source

fn load_metadata_atomic<T: MetadataValue>( metadata_spec: &HeaderMetadataSpec, object: ObjectReference, mask: Option<T>, ordering: Ordering ) -> T

A function to atomically load the specified per-object metadata’s content. 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. Returns the metadata value.

§Arguments:
  • metadata_spec: is the header metadata spec that tries to perform the operation.
  • object: is a reference to the target object.
  • 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.
  • atomic_ordering: is the atomic ordering for the load operation.
source

unsafe fn store_metadata<T: MetadataValue>( metadata_spec: &HeaderMetadataSpec, object: ObjectReference, val: T, mask: Option<T> )

A function to non-atomically store a value to the specified per-object metadata. 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.

§Arguments:
  • metadata_spec: is the header metadata spec that tries to perform the operation.
  • object: is a reference to the target object.
  • val: is the new metadata value to be stored.
  • 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.
§Safety

This is a non-atomic store, thus not thread-safe.

source

fn store_metadata_atomic<T: MetadataValue>( metadata_spec: &HeaderMetadataSpec, object: ObjectReference, val: T, mask: Option<T>, ordering: Ordering )

A function to atomically store a value to the specified per-object metadata. 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.

§Arguments:
  • metadata_spec: is the header metadata spec that tries to perform the operation.
  • object: is a reference to the target object.
  • val: is the new metadata value to be stored.
  • 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.
  • atomic_ordering: is the optional atomic ordering for the store operation.
source

fn compare_exchange_metadata<T: MetadataValue>( metadata_spec: &HeaderMetadataSpec, object: ObjectReference, old_val: T, new_val: T, mask: Option<T>, success_order: Ordering, failure_order: Ordering ) -> Result<T, T>

A function to atomically compare-and-exchange the specified per-object metadata’s content. 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. Returns true if the operation is successful, and false otherwise.

§Arguments:
  • metadata_spec: is the header metadata spec that tries to perform the operation.
  • object: is a reference to the target object.
  • old_val: is the expected current value of the metadata.
  • new_val: is the new metadata value to be stored if the compare-and-exchange operation is successful.
  • 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.
  • success_order: is the atomic ordering used if the operation is successful.
  • failure_order: is the atomic ordering used if the operation fails.
source

fn fetch_add_metadata<T: MetadataValue>( metadata_spec: &HeaderMetadataSpec, object: ObjectReference, val: T, order: Ordering ) -> T

A function to atomically perform an add operation on the specified per-object metadata’s content. 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. This is a wrapping add.

§Returns the old metadata value.
§Arguments:
  • metadata_spec: is the header metadata spec that tries to perform the operation.
  • object: is a reference to the target object.
  • val: is the value to be added to the current value of the metadata.
  • order: is the atomic ordering of the fetch-and-add operation.
source

fn fetch_sub_metadata<T: MetadataValue>( metadata_spec: &HeaderMetadataSpec, object: ObjectReference, val: T, order: Ordering ) -> T

A function to atomically perform a subtract operation on the specified per-object metadata’s content. 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. This is a wrapping sub. Returns the old metadata value.

§Arguments:
  • metadata_spec: is the header metadata spec that tries to perform the operation.
  • object: is a reference to the target object.
  • val: is the value to be subtracted from the current value of the metadata.
  • order: is the atomic ordering of the fetch-and-add operation.
source

fn fetch_and_metadata<T: MetadataValue>( metadata_spec: &HeaderMetadataSpec, object: ObjectReference, val: T, order: Ordering ) -> T

A function to atomically perform a bit-and operation on the specified per-object metadata’s content. 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. Returns the old metadata value.

§Arguments:
  • metadata_spec: is the header metadata spec that tries to perform the operation.
  • object: is a reference to the target object.
  • val: is the value to bit-and with the current value of the metadata.
  • order: is the atomic ordering of the fetch-and-add operation.
source

fn fetch_or_metadata<T: MetadataValue>( metadata_spec: &HeaderMetadataSpec, object: ObjectReference, val: T, order: Ordering ) -> T

A function to atomically perform a bit-or operation on the specified per-object metadata’s content. 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. Returns the old metadata value.

§Arguments:
  • metadata_spec: is the header metadata spec that tries to perform the operation.
  • object: is a reference to the target object.
  • val: is the value to bit-or with the current value of the metadata.
  • order: is the atomic ordering of the fetch-and-add operation.
source

fn fetch_update_metadata<T: MetadataValue, F: FnMut(T) -> Option<T> + Copy>( metadata_spec: &HeaderMetadataSpec, object: ObjectReference, set_order: Ordering, fetch_order: Ordering, f: F ) -> Result<T, T>

A function to atomically perform an update operation on the specified per-object metadata’s content. 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. The semantics of this method are the same as the fetch_update() on Rust atomic types.

§Arguments:
  • metadata_spec: is the header metadata spec that tries to perform the operation.
  • object: is a reference to the target object.
  • val: is the value to bit-and with the current value of the metadata.
  • order: is the atomic ordering of the fetch-and-add operation.
§Returns the old metadata value.
source

fn is_object_sane(_object: ObjectReference) -> bool

Return if an object is valid from the runtime point of view. This is used to debug MMTk.

Object Safety§

This trait is not object safe.

Implementors§