Skip to main content

Arena

Struct Arena 

Source
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

Source

pub fn new(mode: BuildMode) -> Self

Source

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.

Source

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.

Source

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.

Source

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.

Source

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).

Source

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).

Source

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.

Source

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.

Source

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.

Source

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.

Source

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).

Source

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.

Source

pub fn wide_aval(&self) -> &[u64]

Safe: see Self::inline’s doc comment — the same reasoning applies to the wide aval plane.

Source

pub fn wide_bval(&self) -> &[u64]

Safe: see Self::inline’s doc comment — the same reasoning applies to the wide bval plane.

Source

pub unsafe fn wide_aval_mut(&self) -> &mut [u64]

§Safety

Same obligations as Self::inline_mut, applied to the wide aval plane.

Source

pub unsafe fn wide_bval_mut(&self) -> &mut [u64]

§Safety

Same obligations as Self::inline_mut, applied to the wide bval plane.

Source

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.

Source

pub unsafe fn inline_2s_mut(&self) -> &mut [u64]

§Safety

Same obligations as Self::inline_mut, applied to the inline_2s plane.

Source

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.

Source

pub unsafe fn wide_2s_mut(&self) -> &mut [u64]

§Safety

Same obligations as Self::inline_mut, applied to the wide_2s plane.

Source

pub fn mode(&self) -> BuildMode

Source

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.

Source

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.

Trait Implementations§

Source§

impl Debug for Arena

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more

Auto Trait Implementations§

§

impl !Freeze for Arena

§

impl !RefUnwindSafe for Arena

§

impl !Sync for Arena

§

impl Send for Arena

§

impl Unpin for Arena

§

impl UnsafeUnpin for Arena

§

impl UnwindSafe for Arena

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<ST, DT> CastableFrom<ST, Initialized, Initialized> for DT
where ST: ?Sized, DT: ?Sized,

Source§

impl<ST, DT> CastableFrom<ST, Uninit, Uninit> for DT
where ST: ?Sized, DT: ?Sized,

Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> Read<Exclusive, BecauseExclusive> for T
where T: ?Sized,

Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = !

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, !>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<V, T> VZip<V> for T
where V: MultiLane<T>,

Source§

fn vzip(self) -> V