Description
We currently use TraceKind
(a u8
value) to decouple plan, work packets, and the tracing function in the policy. Basically, a plan creates work packets that carry TraceKind
const values. The policy trace objects according to the TraceKind
value.
The benefits from this design
- It decouples plan, work packets and policies. Work packets are general and can be used for multiple plans. Policies are unaware of the plan, and only trace objects according to the
TraceKind
. In Java MMTk, a plan directly calls to the tracing function in the policies, which no longer works for MMTk core. TraceKind
is a const generic parameter, and the Rust compiler can specialize code based on the const. Thus it introduces no overhead.
TraceKind
values
Global
255 - DEFAULT_TRACE
254 - TRACE_KIND_TRANSITIVE_PIN
Plan specific
Mark Compact: 0 - TRACE_KIND_MARK
, 1 - TRACE_KIND_FORWARD
Immix: 0 - TRACE_KIND_FAST
, 1 - TRACE_KIND_DEFRAG
Issues
Conflict of plan specific values
If we use mark compact along with an Immix space, the same TraceKind
value will be interpreted differently by each policy. E.g. 0 is marking trace for mark compact, and also the fast trace for Immix. This causes unintended behavior.
Cross product of TraceKind
among policies
To solve the previous issue, we could use different values for plan specific TraceKind
, such as 0 - TRACE_KIND_MC_MARK
, 1 - TRACE_KIND_MC_FORWARD
, 2 - TRACE_KIND_IX_FAST
, 3 - TRACE_KIND_IX_DEFRAG
. This leads to an unreasonable situation that Immix needs to know what to do in a mark compact marking trace.
TraceKind
is skipped in some cases
For sticky immix's nursery GC (GenNurseryProcessEdges
), we use DEFAULT_TRACE
, but Immix does not have code in its tracing function to deal with DEFAULT_TRACE
. Instead, GenNurseryProcessEdges
calls functions in the plan which specifically calls tracing functions in the policies. This causes confusion.
TraceKind
cannot not solely decide the tracing behavior.
The function may_move_objects<const KIND: TraceKind>() -> bool
is implemented for each policy, and only uses TraceKind
to determine whether the policy may move objects in a trace. When we have two Immix spaces, one for moving, and one for non moving, this function no longer works -- we need information from the space instance to know whether it will move objects or not. Though we can conservatively state that the policy may move objects even if the instance does not really move objects, this causes confusion as well.
Solution
We should remove plan-specific traces, and only have a few defined general TraceKind
, and each policy needs to know what to do for such cases. E.g.
TraceKind | Immix | MarkCompact |
---|---|---|
default | non moving | marking |
exhaustive | defrag/moving if the instance allows moving | fall back to default |
nursery | not reachable -- handled specifically | not reachable |
secondary | fall back to default | forwarding |
transitive pinning | non moving | panic |
may_move_objects
needs to take a self
paramter, or conservatively states that it may move objects if it is uncertain.