Skip to main content

InstanceHandle

Struct InstanceHandle 

Source
pub struct InstanceHandle {
    pub base: InstanceBase,
    pub template: TemplateKey,
    /* private fields */
}
Expand description

The concrete type this plan’s header design decision makes SimHandle point at (Task 8 adds the SimHandle conversion). layout/arena are private raw pointers; they stay valid for the life of this handle (never merely for the life of the StateEngine that minted them — see below) for two independent reasons (review fix, Task 7 r1 — the original comment here conflated them and was wrong about arena):

  • arena points at the Arena struct itself, inside the heap allocation arena_owner below (an owned Rc<Arena> clone) keeps alive. That alone is not sufficient for soundness, though: Arena’s own backing storage is UnsafeCell-wrapped and every mutating accessor takes &self, specifically so that no code in this module ever needs to form a fresh &mut Arena after this pointer is minted — under Rust’s Stacked/Tree Borrows aliasing model, forming a &mut Arena at all (regardless of whether it is used to write) invalidates every previously-derived raw pointer’s borrow-stack tag on Arena’s own field memory. See state::arena’s module doc comment for the full argument and the cargo +nightly miri failure this fixes.
  • layout points into the heap allocation a Box<StateLayout> owns inside the TemplateRegistry heap allocation templates_owner below (an owned Rc<TemplateRegistry> clone) keeps alive, at the specific Box<StateLayout> slot for this handle’s template — see TemplateRegistry’s doc comment — so it stays valid even if that registry’s backing Vec reallocates from a later register call.

Review fix (Task 7 r2): arena_owner/templates_owner are this handle’s own Rc clones, taken at the moment [StateEngine:: allocate_instance] mints the handle — not merely raw pointers derived from the minting StateEngine’s Rc<Arena>/Rc<TemplateRegistry> with no owned stake in them. allocate_instance’s signature (&mut self -> Option<Box<InstanceHandle>>) returns a fully owned value with no borrow-checked connection back to self — a helper function that builds a StateEngine, calls allocate_instance, and returns just the handle is completely ordinary code, and previously, once that StateEngine (and therefore its Rcs) dropped, arena/layout above would dangle: cargo +nightly miri test -p sv-sim-sim instance:: reported “Undefined Behavior: constructing invalid value of type &state::arena::Arena: encountered a dangling reference (use-after-free)” at exactly that read site before this fix. Cloning an Rc bumps its strong count, so as long as any InstanceHandle referencing a given Arena/TemplateRegistry is alive, that allocation’s refcount cannot reach zero — independent of whether the StateEngine that minted the handle is itself still alive. See dropping_the_state_engine_after_allocating_an_instance_leaves_the_handle_valid below for the Miri-checked regression test.

Task 10 (ST-027): base/template stay pub (CODEGEN needs base to mint a SimHandle at instantiation time, per this plan’s header design decision), but this type never hands a caller a raw pointer it could add base/a SlotOffset to itself — layout/arena are private, and the only way to actually reach a signal’s storage through this handle is the accessor fns (accessor_impl::sv_get_scalar/sv_set_scalar/_wide) or arena()/layout()’s own pub(crate)-scoped, already-safe accessors, never a pub fn returning *mut/*const for external base+offset arithmetic. See super::SlotOffset’s own doc comment for the superseded-design context this resolves.

Fields§

§base: InstanceBase§template: TemplateKey

Implementations§

Source§

impl InstanceHandle

Source

pub fn into_sim_handle(self: Box<Self>) -> SimHandle

Box::into_raw leak — the handle’s lifetime is the simulation run’s, matching how sim_init/sim_final bracket it per ARCHITECTURE §5.

Source

pub unsafe fn from_sim_handle<'a>(h: SimHandle) -> &'a InstanceHandle

§Safety

h must be a SimHandle previously produced by Self::into_sim_handle on an InstanceHandle that has not since been passed to a reclaiming function (no such function exists this wave — every handle this crate mints lives for the simulation run’s duration, per ARCHITECTURE §5, so this precondition is trivially satisfied by every caller in this wave), and no other thread is concurrently reclaiming/freeing it.

Auto Trait Implementations§

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