Skip to content

Should we rename the Edge trait? #687

@wks

Description

@wks

I am not planning to rename it now. I would like to discuss two things before we change the code.

  • What is the proper name for that trait currently named "Edge"?
  • Is that trait the right abstraction the API should provide?

The Edge trait

The Edge trait was introduced in #606

The purpose is to support different VMs that store object references in fields differently, giving the VM a place to customise. It is defined as:

pub trait Edge: Copy + Send + Debug + PartialEq + Eq + Hash {
    /// Load object reference from the edge.
    fn load(&self) -> ObjectReference;

    /// Store the object reference `object` into the edge.
    fn store(&self, object: ObjectReference);

    /// Prefetch the edge so that a subsequent `load` will be faster.
    #[inline(always)]
    fn prefetch_load(&self) {
        // no-op by default
    }

    /// Prefetch the edge so that a subsequent `store` will be faster.
    #[inline(always)]
    fn prefetch_store(&self) {
        // no-op by default
    }
}

An edge can be anything that supports the following operations:

  • load: load an object reference from it. Used to support any GC.
  • store: store an updated object reference back to it. Used to support copying GC.
  • prefetching: as a way of optimisation.

And it needs to support Copy + Send in order to be transferred between work packets, and Debug + PartialEq + Eq + Hash to support sanity GC.

So an implementation of the Edge trait could be

  • a field that holds an ordinary (uncompressed, unoffsetted, untagged) pointer,
  • a field that holds compressed pointer (so it can re-compress it when stored back),
  • a field that holds pointer with an offset (so it can re-apply the offset when stored back),
  • a field that holds tagged pointer (so it can restore the tag bits when stored back),
  • a local variable on the stack,
  • a memory location considered as global root,
  • an entry of a HashSet (when updated, needs to be stored to a different bucket)
  • etc.

A ProcessEdgesWork should hold a list of Edge instances, and process each of them. I am open to the idea of specialising work packets for each different kind of edges. I do not know whether it is more efficient to use enum to make a union type of different kinds of edges in a VM (such as OpenJDK) and put all of them into a Vec<OpenJDKEdge>, or scatter different edges into different work packets.

What's the right name?

But recently, debates around the meaning of "object reference" let us rethink whether "edge" is the proper name of this thing.

The GC Handbook does not define "edge" in its glossary, but mentioned "edge" when defining object graph. An edge (an object graph) is "a reference from a source node or a root to a destination node".

The GC Handbook defines "field" as "a component of an object holding a reference or scalar value", and "slot" as a synonym of "field".

According to these definitions, what I defined as the trait Edge satisfies the definition of "edge" of the GC handbook. But a trait Edge instance does not have to be a field or slot, because it may be used to represent a local variable root from the stack or a global root.

Do we need a Slot or Field trait?

Recently, @wenyuzhao mentioned the need to get the address of a field in order to implement field-remembering barriers. If a trait Edge instance is always a field, then it is easy to just add a get_address() method so the barrier can use that to access the metadata.

However, a trait Edge instance doesn't have to be a field, and the field-remembering barrier doesn't make sense for roots. So although we can let Edge::get_address() return an address on the stack, it still looks out of place.

Currently (even before I introduced the Edge trait), the ProcessEdgesWork work packet does not distinguish between object field edges and root edges. Before the introduction of the Edge trait, ProcessEdgesWork holds a Vec<Address> where the Address can point to anywhere, including object fields, stack variables and global variables. With trait Edge introduced, it is now a Vec<VM::VMEdgeType>, but still doesn't differentiate root edges and field edges. I am not sure if that is a problem if we merge LXR into MMTk core. It looks like as long as we have the Edge::load(), Edge::store() and Edge::prefetch_xxx() methods, we can update any edge for copying GC, regardless of whether those edges are from roots or from fields.

Correction: Currently, the boolean field ProcessEdgesBase::root is set to true if the current work packet holds root edges instead of field edges.

Metadata

Metadata

Assignees

No one assigned

    Labels

    P-highPriority: High. A high-priority issue should be fixed as soon as possible.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions