use super::{
arena::Arena,
engine::DedupFuncType,
Engine,
Func,
FuncEntity,
FuncIdx,
FuncType,
Global,
GlobalEntity,
GlobalIdx,
Instance,
InstanceEntity,
InstanceIdx,
Memory,
MemoryEntity,
MemoryIdx,
Table,
TableEntity,
TableIdx,
};
use crate::{GuardedEntity, Index};
use core::sync::atomic::{AtomicU32, Ordering};
pub trait StepMeter: core::fmt::Debug {
fn max_insn_step(&self) -> u64 {
256
}
fn charge_cpu(&self, _insns: u64) -> Result<(), crate::core::TrapCode> {
Ok(())
}
fn charge_mem(&self, _bytes: u64) -> Result<(), crate::core::TrapCode> {
Ok(())
}
}
#[derive(Debug)]
struct NullStepMeter;
impl StepMeter for NullStepMeter {}
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub struct StoreIdx(u32);
impl Index for StoreIdx {
fn into_usize(self) -> usize {
self.0 as usize
}
fn from_usize(value: usize) -> Self {
let value = value.try_into().unwrap_or_else(|error| {
panic!("index {value} is out of bounds as store index: {error}")
});
Self(value)
}
}
impl StoreIdx {
fn new() -> Self {
static CURRENT_STORE_IDX: AtomicU32 = AtomicU32::new(0);
let next_idx = CURRENT_STORE_IDX.fetch_add(1, Ordering::AcqRel);
Self(next_idx)
}
}
pub type Stored<Idx> = GuardedEntity<StoreIdx, Idx>;
#[derive(Debug)]
pub struct Store<T> {
store_idx: StoreIdx,
memories: Arena<MemoryIdx, MemoryEntity>,
tables: Arena<TableIdx, TableEntity>,
globals: Arena<GlobalIdx, GlobalEntity>,
funcs: Arena<FuncIdx, FuncEntity<T>>,
instances: Arena<InstanceIdx, InstanceEntity>,
engine: Engine,
user_state: T,
step_meter: std::rc::Rc<dyn StepMeter>,
}
impl<T> Store<T> {
pub fn new(engine: &Engine, user_state: T) -> Self {
Self {
store_idx: StoreIdx::new(),
memories: Arena::new(),
tables: Arena::new(),
globals: Arena::new(),
funcs: Arena::new(),
instances: Arena::new(),
engine: engine.clone(),
user_state,
step_meter: std::rc::Rc::new(NullStepMeter),
}
}
pub fn engine(&self) -> &Engine {
&self.engine
}
pub fn state(&self) -> &T {
&self.user_state
}
pub fn state_mut(&mut self) -> &mut T {
&mut self.user_state
}
pub fn into_state(self) -> T {
self.user_state
}
pub fn get_step_meter(&self) -> std::rc::Rc<dyn StepMeter> {
self.step_meter.clone()
}
pub fn set_step_meter(&mut self, step_meter: std::rc::Rc<dyn StepMeter>) {
self.step_meter = step_meter
}
pub(super) fn alloc_func_type(&mut self, func_type: FuncType) -> DedupFuncType {
self.engine.alloc_func_type(func_type)
}
pub(super) fn alloc_global(&mut self, global: GlobalEntity) -> Global {
Global::from_inner(Stored::new(self.store_idx, self.globals.alloc(global)))
}
pub(super) fn alloc_table(&mut self, table: TableEntity) -> Table {
Table::from_inner(Stored::new(self.store_idx, self.tables.alloc(table)))
}
pub(super) fn alloc_memory(&mut self, memory: MemoryEntity) -> Memory {
Memory::from_inner(Stored::new(self.store_idx, self.memories.alloc(memory)))
}
pub(super) fn alloc_func(&mut self, func: FuncEntity<T>) -> Func {
Func::from_inner(Stored::new(self.store_idx, self.funcs.alloc(func)))
}
pub(super) fn alloc_instance(&mut self) -> Instance {
Instance::from_inner(Stored::new(
self.store_idx,
self.instances.alloc(InstanceEntity::uninitialized()),
))
}
pub(super) fn initialize_instance(&mut self, instance: Instance, initialized: InstanceEntity) {
let entity_index = self.unwrap_index(instance.into_inner());
let entity = self.instances.get_mut(entity_index).unwrap_or_else(|| {
panic!(
"the store has no reference to the given instance: {:?}",
instance,
)
});
assert!(
!entity.is_initialized(),
"encountered an already initialized instance: {:?}",
entity
);
assert!(
initialized.is_initialized(),
"encountered an uninitialized new instance entity: {:?}",
initialized,
);
*entity = initialized;
}
fn unwrap_index<Idx>(&self, stored: Stored<Idx>) -> Idx
where
Idx: Index,
{
stored.entity_index(self.store_idx).unwrap_or_else(|| {
panic!(
"encountered foreign entity in store: {}",
self.store_idx.into_usize()
)
})
}
pub(super) fn resolve_func_type(&self, func_type: DedupFuncType) -> FuncType {
self.engine.resolve_func_type(func_type, Clone::clone)
}
pub(super) fn resolve_global(&self, global: Global) -> &GlobalEntity {
let entity_index = self.unwrap_index(global.into_inner());
self.globals.get(entity_index).unwrap_or_else(|| {
panic!(
"failed to resolve stored global variable: {:?}",
entity_index,
)
})
}
pub(super) fn resolve_global_mut(&mut self, global: Global) -> &mut GlobalEntity {
let entity_index = self.unwrap_index(global.into_inner());
self.globals.get_mut(entity_index).unwrap_or_else(|| {
panic!(
"failed to resolve stored global variable: {:?}",
entity_index,
)
})
}
pub(super) fn resolve_table(&self, table: Table) -> &TableEntity {
let entity_index = self.unwrap_index(table.into_inner());
self.tables
.get(entity_index)
.unwrap_or_else(|| panic!("failed to resolve stored table: {:?}", entity_index))
}
pub(super) fn resolve_table_mut(&mut self, table: Table) -> &mut TableEntity {
let entity_index = self.unwrap_index(table.into_inner());
self.tables
.get_mut(entity_index)
.unwrap_or_else(|| panic!("failed to resolve stored table: {:?}", entity_index))
}
pub(super) fn resolve_memory(&self, memory: Memory) -> &MemoryEntity {
let entity_index = self.unwrap_index(memory.into_inner());
self.memories
.get(entity_index)
.unwrap_or_else(|| panic!("failed to resolve stored linear memory: {:?}", entity_index))
}
pub(super) fn resolve_memory_mut(&mut self, memory: Memory) -> &mut MemoryEntity {
let entity_index = self.unwrap_index(memory.into_inner());
self.memories
.get_mut(entity_index)
.unwrap_or_else(|| panic!("failed to resolve stored linear memory: {:?}", entity_index))
}
pub(super) fn resolve_func(&self, func: Func) -> &FuncEntity<T> {
let entity_index = self.unwrap_index(func.into_inner());
self.funcs.get(entity_index).unwrap_or_else(|| {
panic!(
"failed to resolve stored Wasm or host function: {:?}",
entity_index
)
})
}
pub(super) fn resolve_instance(&self, instance: Instance) -> &InstanceEntity {
let entity_index = self.unwrap_index(instance.into_inner());
self.instances.get(entity_index).unwrap_or_else(|| {
panic!(
"failed to resolve stored module instance: {:?}",
entity_index
)
})
}
}
pub trait AsContext {
type UserState;
fn as_context(&self) -> StoreContext<Self::UserState>;
}
pub trait AsContextMut: AsContext {
fn as_context_mut(&mut self) -> StoreContextMut<Self::UserState>;
}
#[derive(Debug, Copy, Clone)]
#[repr(transparent)]
pub struct StoreContext<'a, T> {
pub(super) store: &'a Store<T>,
}
impl<'a, T: AsContext> From<&'a T> for StoreContext<'a, T::UserState> {
fn from(ctx: &'a T) -> Self {
ctx.as_context()
}
}
impl<'a, T: AsContext> From<&'a mut T> for StoreContext<'a, T::UserState> {
fn from(ctx: &'a mut T) -> Self {
T::as_context(ctx)
}
}
impl<'a, T: AsContextMut> From<&'a mut T> for StoreContextMut<'a, T::UserState> {
fn from(ctx: &'a mut T) -> Self {
ctx.as_context_mut()
}
}
#[derive(Debug)]
#[repr(transparent)]
pub struct StoreContextMut<'a, T> {
pub(super) store: &'a mut Store<T>,
}
impl<T> AsContext for &'_ T
where
T: AsContext,
{
type UserState = T::UserState;
#[inline]
fn as_context(&self) -> StoreContext<'_, T::UserState> {
T::as_context(*self)
}
}
impl<T> AsContext for &'_ mut T
where
T: AsContext,
{
type UserState = T::UserState;
#[inline]
fn as_context(&self) -> StoreContext<'_, T::UserState> {
T::as_context(*self)
}
}
impl<T> AsContextMut for &'_ mut T
where
T: AsContextMut,
{
#[inline]
fn as_context_mut(&mut self) -> StoreContextMut<'_, T::UserState> {
T::as_context_mut(*self)
}
}
impl<T> AsContext for StoreContext<'_, T> {
type UserState = T;
fn as_context(&self) -> StoreContext<'_, Self::UserState> {
StoreContext { store: self.store }
}
}
impl<T> AsContext for StoreContextMut<'_, T> {
type UserState = T;
fn as_context(&self) -> StoreContext<'_, Self::UserState> {
StoreContext { store: self.store }
}
}
impl<T> AsContextMut for StoreContextMut<'_, T> {
fn as_context_mut(&mut self) -> StoreContextMut<'_, Self::UserState> {
StoreContextMut {
store: &mut *self.store,
}
}
}
impl<T> AsContext for Store<T> {
type UserState = T;
fn as_context(&self) -> StoreContext<'_, Self::UserState> {
StoreContext { store: self }
}
}
impl<T> AsContextMut for Store<T> {
fn as_context_mut(&mut self) -> StoreContextMut<'_, Self::UserState> {
StoreContextMut { store: self }
}
}