pub trait Slot:
Copy
+ Send
+ Debug
+ PartialEq
+ Eq
+ Hash {
// Required methods
fn load(&self) -> Option<ObjectReference>;
fn store(&self, object: ObjectReference);
// Provided methods
fn prefetch_load(&self) { ... }
fn prefetch_store(&self) { ... }
}Expand description
Slot is an abstraction for MMTk to load and update object references in memory.
§Slots and the Slot trait
In a VM, a slot can contain an object reference or a non-reference value. It can be in an
object (a.k.a. a field), on the stack (i.e. a local variable) or in any other places (such as
global variables). It may have different representations in different VMs. Some VMs put a
direct pointer to an object into a slot, while others may use compressed pointers, tagged
pointers, offsetted pointers, etc. Some VMs (such as JVM) have null references, and others
(such as CRuby and JavaScript engines) can also use tagged bits to represent non-reference
values such as small integers, true, false, null (a.k.a. “none”, “nil”, etc.),
undefined, etc.
In MMTk, the Slot trait is intended to abstract out such different representations of
reference fields (compressed, tagged, offsetted, etc.) among different VMs. From MMTk’s point
of view, MMTk only cares about the object reference held inside the slot, but not
non-reference values, such as null, true, etc. When the slot is holding an object
reference, we can load the object reference from it, and we can update the object reference in
it after the GC moves the object.
§The Slot trait has pointer semantics
A Slot value points to a slot, and is not the slot itself. In fact, the simplest
implementation of the Slot trait (SimpleSlot, see below) can simply contain the address of
the slot.
A Slot can be copied, and the copied Slot instance points to the same
slot.
§How to implement Slot?
If a reference field of a VM is word-sized and holds the raw pointer to an object, and uses the
0 word as the null pointer, it can use the default SimpleSlot we provide. It simply
contains a pointer to a memory location that holds an address.
pub struct SimpleSlot {
slot_addr: *mut Atomic<Address>,
}In other cases, the VM need to implement its own Slot instances.
For example:
- The VM uses compressed pointers (Compressed OOPs in OpenJDK’s terminology), where the heap size is limited, and a 64-bit pointer is stored in a 32-bit slot.
- The VM uses tagged pointers, where some bits of a word are used as metadata while the rest are used as pointer.
- The VM uses offsetted pointers, i.e. the value of the field is an address at an offset
from the
ObjectReferenceof the target object. Such offsetted pointers are usually used to represent interior pointers, i.e. pointers to an object field, an array element, etc.
If needed, the implementation of Slot can contain not only the pointer, but also additional
information. The OffsetSlot example below also contains an offset which can be used when
decoding the pointer. See src/vm/tests/mock_tests/mock_test_slots.rs for more concrete
examples, such as CompressedOopSlot and TaggedSlot.
pub struct OffsetSlot {
slot_addr: *mut Atomic<Address>,
offset: usize,
}When loading, Slot::load shall load the value from the slot and decode the value into a
regular ObjectReference (note that MMTk has specific requirements for ObjectReference, such
as being aligned, pointing inside an object, and cannot be null. Please read the doc comments
of ObjectReference for details). The decoding is VM-specific, but usually involves removing
tag bits and/or adding an offset to the word, and (in the case of compressed pointers) extending
the word size. By doing this conversion, MMTk can implement GC algorithms in a VM-neutral way,
knowing only ObjectReference.
When GC moves object, Slot::store shall convert the updated ObjectReference back to the
slot-specific representation. Compressed pointers remain compressed; tagged pointers preserve
their tag bits; and offsetted pointers keep their offsets.
§Performance notes
The methods of this trait are called on hot paths. Please ensure they have high performance.
The size of the data structure of the Slot implementation may affect the performance as well.
During GC, MMTk enqueues Slot instances, and its size affects the overhead of copying. If
your Slot implementation has multiple fields or uses enum for multiple kinds of slots, it
may have extra cost when copying or decoding. You should measure it. If the cost is too much,
you can implement Slot with a tagged word. For example, the mmtk-openjdk binding uses the
low order bit to encode whether the slot is compressed or not.
§About weak references
This trait only concerns the representation (i.e. the shape) of the slot, not its semantics,
such as whether it holds strong or weak references. Therefore, one Slot implementation can be
used for both slots that hold strong references and slots that hold weak references.
Required Methods§
sourcefn load(&self) -> Option<ObjectReference>
fn load(&self) -> Option<ObjectReference>
Load object reference from the slot.
If the slot is not holding an object reference (For example, if it is holding NULL or a
tagged non-reference value. See trait-level doc comment.), this method should return
None.
If the slot holds an object reference with tag bits, the returned value shall be the object reference with the tag bits removed.
sourcefn store(&self, object: ObjectReference)
fn store(&self, object: ObjectReference)
Store the object reference object into the slot.
If the slot holds an object reference with tag bits, this method must preserve the tag
bits while updating the object reference so that it points to the forwarded object given by
the parameter object.
FIXME: This design is inefficient for handling object references with tag bits. Consider introducing a new updating function to do the load, trace and store in one function. See: https://github.com/mmtk/mmtk-core/issues/1033
FIXME: This method is currently used by both moving GC algorithms and the subsuming write
barrier (crate::memory_manager::object_reference_write). The two reference writing
operations have different semantics, and need to be implemented differently if the VM
supports offsetted or tagged references.
See: https://github.com/mmtk/mmtk-core/issues/1038
Provided Methods§
sourcefn prefetch_load(&self)
fn prefetch_load(&self)
Prefetch the slot so that a subsequent load will be faster.
sourcefn prefetch_store(&self)
fn prefetch_store(&self)
Prefetch the slot so that a subsequent store will be faster.
Object Safety§
Implementors§
impl Slot for Address
For backword compatibility, we let Address implement Slot with the same semantics as
SimpleSlot so that existing bindings that use Address as Slot can continue to work.
However, we should use SimpleSlot directly instead of using Address. The purpose of the
Address type is to represent an address in memory. It is not directly related to fields
that hold references to other objects. Calling load() and store() on an Address does
not indicate how many bytes to load or store, or how to interpret those bytes. On the other
hand, SimpleSlot is all about how to access a field that holds a reference represented
simply as an ObjectReference. The intention and the semantics are clearer with
SimpleSlot.