Skip to content

Forwarding pointer is not an object metadata #1030

Open
@wks

Description

@wks

Forwarding pointers are associated to dead memory instead of live objects.

Currently, forwarding pointers are implemented as an object metadata, namely const LOCAL_FORWARDING_POINTER_SPEC: VMLocalForwardingPointerSpec; in trait ObjectModel. Like other metadata, the forwarding pointer metadata can be defined as on the side. However,

  1. It is not practical to put it on the side. The forwarding pointer metadata is per (dead) object, and the size and granularity will be 'one word per word'. If we define it as on the side, it will consume a huge amount of memory (50%), making it impossible to run any copying GC with on-the-side forwarding pointers.
  2. It does not need to be put on the side. Forwarding pointers never needs to be set for live objects, so there is no need to reserve space for the forwarding pointers of live objects. Once an object is dead, we can use any part of the dead object to store the forwarding pointer.

There is a prior issue about putting all metadata on the side: #362 Forwarding pointer may be an exception. If the forwarding bits are on the side, we can simply use the first word of a dead object to store the forwarding pointer because it doesn't overlap with the forwarding bits which is on the side.

Even if the forwarding bits metadata is defined as in the header, we can make use of object alignment, and the reset of the word occupied by the forwarding bits to save the forwarding pointer.

What should we change?

We need to replace the const LOCAL_FORWARDING_POINTER_SPEC: VMLocalForwardingPointerSpec;

Offset

We can replace it with an offset:

pub trait ObjectModel<VM: VMBinding> {
    const FORWARDING_POINTER_OFFSET: isize = 0;
}

The unit of this offset will be bits, and it will be relative to the address returned by ref_to_header, or whatever is easy to compute.

Method to compute the address

Alternatively, we can let ObjectModel provide a method ref_to_forwarding_pointer:

pub trait ObjectModel<VM: VMBinding> {
    fn ref_to_forwarding_pointer(object: ObjectReference) -> Address {
        unimplemented!()
    }
}

One advantage of ref_to_forwarding_pointer is that it is always computed from the raw object reference. If both ref_to_header() and ref_to_address() needs some non-trivial computation, conditional branches or memory loading, this may outperform them.

Methods to access the forwarding pointer (and forwarding bits?)

Alternatively, we can let the VM binding implement methods for getting and setting the forwarding pointer of a given object, and provide a default implementation that loads/stores the first word relative to the raw address:

pub trait ObjectModel<VM: VMBinding> {
    fn get_forwarding_pointer(object: ObjectReference) -> ObjectReference {
        unsafe { object.to_raw_address().load::<ObjectReference>() }
    }

    fn set_forwarding_pointer(object: ObjectReference, forwarded: ObjectReference) {
        unsafe { object.to_raw_address().store::<ObjectReference>(forwarded) }
    }
}

We can let the binding implement forwarding states, too. In that case, it will be similar to what the PR #975 tries to implement.

pub trait ObjectModel<VM: VMBinding> {
    // ... other methods

    fn get_forwarding_state(object: ObjectReference) -> ForwardingState {
        unimplemented!()
    }

    fn set_forwarding_state(object: ObjectReference, state: ForwardingState) {
        unimplemented()
    }

    fn set_forwarding_state_and_forwarding_pointer(object: ObjectReference, forwarded: ObjectReference) {
        // The forwarding state should be set to `ForwardingState::Forwarded`
        unimplemented()
    }
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    P-normalPriority: Normal.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions