pub struct Arena { /* private fields */ }Expand description
The one design-wide flat SoA backing store (ST-007: grouped by storage
tier, not a per-signal heap object model). inline holds every
bit_width <= 64 signal as a packed u128 (val low 64 / xzmask high 64);
wide_aval/wide_bval hold every wider signal and every memory element,
word-aligned, at identical relative offsets in both planes (ST-009);
inline_2s/wide_2s are the 2-state-build counterparts (Task 10 exercises
them; this task only reserves the fields).
Each backing Vec is wrapped in UnsafeCell (review fix, Task 7 r1):
see the module-level doc comment for why growing/writing must never
require a fresh &mut Arena.
Task 20 (ST-040) — cross-signal bit-packing is out of scope for v1, by
deliberate decision, not a silently-dropped optimization. Every signal
gets a full u128 inline word or full word-aligned wide-plane slot (see
the module doc comment’s “no cross-signal bit-packing… even a 1-bit
wire gets a full u128”); nothing in this file ever packs two or more
narrow signals into one word’s spare bits. This is a tracked v2 scaling
risk for huge port-heavy designs (a design with millions of 1-bit
signals pays a full 16 bytes each rather than the theoretical 1 bit),
cross-referenced at docs/design/state.md §1/Risks and restated in
docs/CONTRACTS.md’s “Wave A — wA-state notes” section so it is
discoverable without reading this file.
Implementations§
Source§impl Arena
impl Arena
pub fn new(mode: BuildMode) -> Self
Sourcepub unsafe fn alloc_inline_words(&self, n: u32) -> u32
pub unsafe fn alloc_inline_words(&self, n: u32) -> u32
Appends n new inline u128 words in one call, returning the shared
start offset (Task 7, ST-067/ST-136’s bulk variant of
Self::alloc_inline_word — reserves a whole template instance’s
inline words in one bump, the same way Self::alloc_wide_words
already bulk-allocates the wide planes). n == 0 is a legal no-op
that still returns the current length (a template with zero inline
words gets a well-defined, if unused, base).
§Safety
The caller must ensure no other live &/&mut borrow of the inline
plane (from Self::inline, Self::inline_mut, or
Self::raw_inline_ptr) is held across this call, and that at most
one logical writer grows this Arena’s planes at a time (the same
single-logical-writer discipline Self::raw_inline_ptr documents).
This method takes &self, not &mut self, specifically so it can be
called through a *const Arena minted once (e.g.
InstanceHandle::arena) without ever forming a fresh &mut Arena —
see the module-level doc comment.
Sourcepub unsafe fn alloc_inline_word(&self) -> u32
pub unsafe fn alloc_inline_word(&self) -> u32
Appends one new inline u128 word, returning its word_offset
(always len-before-push — dense, order-preserving, never a reused or
coalesced gap: ST-038’s “even a single-bit wire gets a full word”).
Task 7: a thin wrapper over Self::alloc_inline_words(1).
§Safety
Same obligations as Self::alloc_inline_words.
Sourcepub unsafe fn alloc_wide_words(&self, words: u32) -> u32
pub unsafe fn alloc_wide_words(&self, words: u32) -> u32
Appends words new u64 slots to both wide planes in lockstep,
returning the shared start offset (ST-009: the same relative
addressing scheme in both planes).
§Panics
Review fix (Task 9 r3): if words > 0 and Self::seal_wide_plane
has already been called on this Arena (i.e. sv_get_wide has
already handed some caller a WideView aliasing these planes’ live
storage) — growing either Vec now could reallocate its backing
buffer and dangle that already-issued WideView, so this refuses
rather than silently doing it. See Self::wide_sealed’s doc
comment for the full hazard. words == 0 is exempt (it never
touches either Vec’s capacity, so it can never reallocate
anything) and stays the legal, always-safe no-op it already was.
§Safety
The caller must ensure no other live &/&mut borrow of either wide
plane (from Self::wide_aval/Self::wide_bval/
Self::wide_aval_mut/Self::wide_bval_mut) is held across this
call, and that at most one logical writer grows this Arena’s planes
at a time. &self, not &mut self, for the same reason as
Self::alloc_inline_words.
Sourcepub unsafe fn alloc_force_wide_words(&self, words: u32) -> u32
pub unsafe fn alloc_force_wide_words(&self, words: u32) -> u32
Review fix (Task 14 r2, blocking finding 2): the force_wide_aval/
force_wide_bval counterpart of Self::alloc_wide_words —
driver::force_driver’s Wide/Memory-class contribution-cell
allocator. Deliberately never consults Self::wide_sealed: that
flag exists only to protect WideViews sv_get_wide has handed out
aliasing wide_aval/wide_bval’s storage, and this method never
grows those planes at all — it grows a wholly separate pair that no
accessor-ABI function or ffi_view call ever exposes a pointer into
(see this field pair’s own doc comment on Arena). Growing/
reallocating it is therefore unconditionally safe, wide_sealed or
not, which is exactly what makes force/release real, always
-available runtime operations (ST-055) rather than ones that panic the
instant any wide signal has been read through sv_get_wide first —
the bug this fixes (Task 14 review finding: force_driver on a net
wider than 64 bits panicked via alloc_wide_words once the ordinary
wide plane had been sealed by an unrelated prior sv_get_wide call).
§Safety
Same obligations as Self::alloc_wide_words, applied to this
separate plane pair.
Sourcepub fn force_wide_aval(&self) -> &[u64]
pub fn force_wide_aval(&self) -> &[u64]
Safe: see Self::inline’s doc comment — the same reasoning applies
to the force-only wide aval plane (Self::alloc_force_wide_words’s
doc comment).
Sourcepub fn force_wide_bval(&self) -> &[u64]
pub fn force_wide_bval(&self) -> &[u64]
Safe: see Self::inline’s doc comment — the same reasoning applies
to the force-only wide bval plane (Self::alloc_force_wide_words’s
doc comment).
Sourcepub unsafe fn force_wide_aval_mut(&self) -> &mut [u64]
pub unsafe fn force_wide_aval_mut(&self) -> &mut [u64]
§Safety
Same obligations as Self::inline_mut, applied to the force-only
wide aval plane.
Sourcepub unsafe fn force_wide_bval_mut(&self) -> &mut [u64]
pub unsafe fn force_wide_bval_mut(&self) -> &mut [u64]
§Safety
Same obligations as Self::inline_mut, applied to the force-only
wide bval plane.
Sourcepub unsafe fn alloc_inline_2s_words(&self, n: u32) -> u32
pub unsafe fn alloc_inline_2s_words(&self, n: u32) -> u32
Task 13 (ST-100, ST-139): the 2-state-family name for the same bulk
growth Self::alloc_inline_words already performs on the
inline_2s plane. Deviation from the plan’s literal prose (“this
task adds their allocators”, implying a growth operation independent
of the 4-state family’s own bulk allocators): alloc_inline_words
already grows inline/inline_2s in lockstep (see its own body
above), which is load-bearing, not incidental – a SlotOffset‘s
word_offset is computed once by the mode-agnostic Task 4/6 layout
builder and must address the same position regardless of which
build mode the compiled binary ends up using, so the two planes’
offset spaces cannot be allowed to diverge. A genuinely independent
inline_2s-only counter would break that invariant the first time a
caller allocated through one family without the other. This method is
therefore a thin, same-offset forwarding wrapper – a 2-state-family
name for API discoverability/completeness, not a second allocator.
§Safety
Same obligations as Self::alloc_inline_words.
Sourcepub unsafe fn alloc_wide_2s_words(&self, n: u32) -> u32
pub unsafe fn alloc_wide_2s_words(&self, n: u32) -> u32
Task 13 (ST-100, ST-139): the wide-plane counterpart of
Self::alloc_inline_2s_words – see that method’s doc comment for
why this forwards to Self::alloc_wide_words rather than growing
wide_2s independently.
§Safety
Same obligations as Self::alloc_wide_words.
Sourcepub fn inline(&self) -> &[u128]
pub fn inline(&self) -> &[u128]
Read-only access to the inline plane (test/read helper — the hot path
is the FFI raw-pointer view below). Safe: any number of live &[T]
reads coexist without aliasing; the aliasing obligation is on the
unsafe mutating accessors instead (see their doc comments).
Sourcepub unsafe fn inline_mut(&self) -> &mut [u128]
pub unsafe fn inline_mut(&self) -> &mut [u128]
Mutable access to the inline plane.
§Safety
The caller must ensure no other live &/&mut borrow of the inline
plane exists for as long as the returned slice is used, and that no
other writer touches it concurrently (single-logical-writer, same as
Self::raw_inline_ptr). &self, not &mut self, for the same
reason as Self::alloc_inline_words — see the module-level doc
comment.
Sourcepub fn wide_aval(&self) -> &[u64]
pub fn wide_aval(&self) -> &[u64]
Safe: see Self::inline’s doc comment — the same reasoning applies
to the wide aval plane.
Sourcepub fn wide_bval(&self) -> &[u64]
pub fn wide_bval(&self) -> &[u64]
Safe: see Self::inline’s doc comment — the same reasoning applies
to the wide bval plane.
Sourcepub unsafe fn wide_aval_mut(&self) -> &mut [u64]
pub unsafe fn wide_aval_mut(&self) -> &mut [u64]
§Safety
Same obligations as Self::inline_mut, applied to the wide aval
plane.
Sourcepub unsafe fn wide_bval_mut(&self) -> &mut [u64]
pub unsafe fn wide_bval_mut(&self) -> &mut [u64]
§Safety
Same obligations as Self::inline_mut, applied to the wide bval
plane.
Sourcepub fn inline_2s(&self) -> &[u64]
pub fn inline_2s(&self) -> &[u64]
Task 13 (ST-100, ST-102, ST-139): read-only access to the 2-state
inline plane – see Self::inline’s doc comment, identical
reasoning.
Sourcepub unsafe fn inline_2s_mut(&self) -> &mut [u64]
pub unsafe fn inline_2s_mut(&self) -> &mut [u64]
§Safety
Same obligations as Self::inline_mut, applied to the inline_2s
plane.
Sourcepub fn wide_2s(&self) -> &[u64]
pub fn wide_2s(&self) -> &[u64]
Task 13 (ST-100, ST-102, ST-139): read-only access to the 2-state
wide plane – see Self::inline’s doc comment, identical
reasoning.
Sourcepub unsafe fn wide_2s_mut(&self) -> &mut [u64]
pub unsafe fn wide_2s_mut(&self) -> &mut [u64]
§Safety
Same obligations as Self::inline_mut, applied to the wide_2s
plane.
pub fn mode(&self) -> BuildMode
Sourcepub fn ffi_view(&mut self) -> StateArena
pub fn ffi_view(&mut self) -> StateArena
The FFI arena view (ST-145): raw pointers into the three planes a
compiled kernel indexes through the accessor ABI. wide_aval/
wide_bval are null when mode == TwoState — the 4-state planes
simply aren’t touched in a 2-state build. Takes &mut self: this is
Task 2’s original, not-yet-consumed-anywhere entry point (no Task 7
code path calls it against an Arena that already has live
InstanceHandles pointing at it), so it keeps requiring genuine
exclusive access rather than adopting Task 7’s &self/UnsafeCell
pattern; UnsafeCell::get_mut() is a safe way to reach the backing
Vecs given that exclusive access.
Sourcepub unsafe fn raw_inline_ptr(&mut self) -> *mut u128
pub unsafe fn raw_inline_ptr(&mut self) -> *mut u128
Raw pointer to the start of the inline plane, for callers that need to
hand out disjoint per-word pointers to multiple worker threads
(ST-039: word-aligned, non-packed slots enable lock-free writes across
worker threads with no per-write locking). Takes &mut self for the
same reason Self::ffi_view does — see its doc comment.
§Safety
The caller writes only through offsets it obtained from this Arena’s
own alloc_* calls, each offset written by at most one thread for the
duration of the unsafe scope, and must not alias with any &Arena/
&mut Arena use until the writer threads have joined.