Expand description
ARC reference counting FFI for JIT-compiled code.
§Route A close (ADR-006 §2.7.14 / W11-jit-new-array)
Both entry points operate on a JIT-emitted UnifiedValue<T> allocation
pointer (or, equivalently, a v2 *mut HeapHeader-prefixed allocation —
BOTH layouts carry a kind: u16 at offset 0 and a refcount at a
layout-fixed offset). The caller contract (post-W11) is that the MIR
emitter only emits these calls for slots whose NativeKind satisfies
[NativeKind::is_refcounted] — String (ArcPtr(HeapKind::*) (ArcUnifiedValue). Raw scalar slots (Int64, Float64, Bool, etc.)
never reach this FFI; the discrimination lives at the emitter side
in [crate::mir_compiler::ownership::refcount_disposition].
§Refcount layout
Two #[repr(C)] shapes flow through this FFI today:
-
JIT-emitted
UnifiedValue<T>(ffi/jit_kinds.rs):offset 0: kind: u16 offset 2: flags: u8 offset 3: _reserved: u8 offset 4: refcount: AtomicU32 ← retain/release target offset 8: data: TUsed by
box_string,box_typed_object,unified_box-family. -
v2
HeapHeader-prefixed allocations (shape_value::v2::heap_header):offset 0: refcount: AtomicU32 ← retain/release target offset 4: kind: u16 offset 6: flags: u8 offset 7: _pad: u8Used by
TypedArray<T>,TypedClosureHeader,v2_alloc_struct. These have their OWN dedicated FFI (jit_v2_retain/jit_v2_release) and the MIR emitter routes them viaSkip_TypedCellCarrier(v2_typed_array_elem_kind-guarded), so they do NOT reach this function in production. Disambiguating the two shapes fromptralone would require a tag-bit probe (CLAUDE.md “Forbidden Patterns” #4); the contract is “MIR emitter routes by kind”.
§Discriminator on release
When refcount reaches zero, the underlying Box::from_raw reclaim
needs to know the inner T of the UnifiedValue<T> (or the
HeapValue discriminant for the Ptr(HeapKind::*) arms). The
kind: u16 field at offset 0 of UnifiedValue IS the canonical
discriminator (§2.7.6 / Q8 single-discriminator — same field, same
semantics as HeapValue::kind()); reading it is NOT a tag-bit probe
because it’s a structural field on the heap object, not a bit-pack
on an inline value. The free path dispatches on this kind via
[shape_value::release::release_v2_heap_by_kind].
§Forbidden
- Bool-default fallback for unknown kind (CLAUDE.md “Forbidden rationalizations”).
tag_bitsdecode on theptrvalue (CLAUDE.md “Forbidden Patterns” #4).- Silent no-op’ing the body (the supervisor explicitly refused this shape during the W11 reopen — “Soft-fail counter for now” pattern).
- “ARC bridge” / “retain helper” / “kind-injection adapter” framing (CLAUDE.md “Renames to refuse on sight” — broader family rule).
Functions§
- jit_
arc_ release - Release a JIT-emitted refcounted heap value.
- jit_
arc_ retain - Retain a JIT-emitted refcounted heap value.