Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make Engine's executor use &mut StoreInner (making it non-generic) #611

Merged
merged 10 commits into from
Jan 15, 2023
152 changes: 152 additions & 0 deletions crates/arena/src/component_vec.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
use crate::ArenaIndex;
use alloc::vec::Vec;
use core::{
fmt::{self, Debug},
marker::PhantomData,
ops::{Index, IndexMut},
};

/// Stores components for entities backed by a [`Vec`].
pub struct ComponentVec<Idx, T> {
components: Vec<Option<T>>,
marker: PhantomData<fn() -> Idx>,
}

/// [`ComponentVec`] does not store `Idx` therefore it is `Send` without its bound.
unsafe impl<Idx, T> Send for ComponentVec<Idx, T> where T: Send {}

/// [`ComponentVec`] does not store `Idx` therefore it is `Sync` without its bound.
unsafe impl<Idx, T> Sync for ComponentVec<Idx, T> where T: Send {}

impl<Idx, T> Debug for ComponentVec<Idx, T>
where
T: Debug,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("ComponentVec")
.field("components", &DebugComponents(&self.components))
.field("marker", &self.marker)
.finish()
}
}

struct DebugComponents<'a, T>(&'a [Option<T>]);

impl<'a, T> Debug for DebugComponents<'a, T>
where
T: Debug,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let mut map = f.debug_map();
let components = self
.0
.iter()
.enumerate()
.filter_map(|(n, component)| component.as_ref().map(|c| (n, c)));
for (idx, component) in components {
map.entry(&idx, component);
}
map.finish()
}
}

impl<Idx, T> Default for ComponentVec<Idx, T> {
fn default() -> Self {
Self::new()
}
}

impl<Idx, T> PartialEq for ComponentVec<Idx, T>
where
T: PartialEq,
{
fn eq(&self, other: &Self) -> bool {
self.components.eq(&other.components)
}
}

impl<Idx, T> Eq for ComponentVec<Idx, T> where T: Eq {}

impl<Idx, T> ComponentVec<Idx, T> {
/// Creates a new empty [`ComponentVec`].
pub fn new() -> Self {
Self {
components: Vec::new(),
marker: PhantomData,
}
}

/// Clears all components from the [`ComponentVec`].
pub fn clear(&mut self) {
self.components.clear();
}
}

impl<Idx, T> ComponentVec<Idx, T>
where
Idx: ArenaIndex,
{
/// Sets the `component` for the entity at `index`.
///
/// Returns the old component of the same entity if any.
pub fn set(&mut self, index: Idx, component: T) -> Option<T> {
let index = index.into_usize();
if index >= self.components.len() {
// The underlying vector does not have enough capacity
// and is required to be enlarged.
self.components.resize_with(index + 1, || None);
}
self.components[index].replace(component)
}

/// Unsets the component for the entity at `index` and returns it if any.
pub fn unset(&mut self, index: Idx) -> Option<T> {
self.components
.get_mut(index.into_usize())
.and_then(Option::take)
}

/// Returns a shared reference to the component at the `index` if any.
///
/// Returns `None` if no component is stored under the `index`.
#[inline]
pub fn get(&self, index: Idx) -> Option<&T> {
self.components
.get(index.into_usize())
.and_then(Option::as_ref)
}

/// Returns an exclusive reference to the component at the `index` if any.
///
/// Returns `None` if no component is stored under the `index`.
#[inline]
pub fn get_mut(&mut self, index: Idx) -> Option<&mut T> {
self.components
.get_mut(index.into_usize())
.and_then(Option::as_mut)
}
}

impl<Idx, T> Index<Idx> for ComponentVec<Idx, T>
where
Idx: ArenaIndex,
{
type Output = T;

#[inline]
fn index(&self, index: Idx) -> &Self::Output {
self.get(index)
.unwrap_or_else(|| panic!("missing component at index: {}", index.into_usize()))
}
}

impl<Idx, T> IndexMut<Idx> for ComponentVec<Idx, T>
where
Idx: ArenaIndex,
{
#[inline]
fn index_mut(&mut self, index: Idx) -> &mut Self::Output {
self.get_mut(index)
.unwrap_or_else(|| panic!("missing component at index: {}", index.into_usize()))
}
}
3 changes: 2 additions & 1 deletion crates/arena/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,13 +22,14 @@ extern crate alloc;
#[cfg(feature = "std")]
extern crate std as alloc;

mod component_vec;
mod dedup;
mod guarded;

#[cfg(test)]
mod tests;

pub use self::{dedup::DedupArena, guarded::GuardedEntity};
pub use self::{component_vec::ComponentVec, dedup::DedupArena, guarded::GuardedEntity};
use alloc::vec::Vec;
use core::{
iter::{DoubleEndedIterator, Enumerate, ExactSizeIterator},
Expand Down
75 changes: 39 additions & 36 deletions crates/wasmi/src/engine/cache.rs
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
use crate::{
module::{DEFAULT_MEMORY_INDEX, DEFAULT_TABLE_INDEX},
AsContext,
AsContextMut,
Func,
Instance,
Memory,
StoreInner,
Table,
};
use core::ptr::NonNull;
Expand Down Expand Up @@ -69,10 +68,10 @@ impl InstanceCache {
/// # Panics
///
/// If the currently used [`Instance`] does not have a default linear memory.
fn load_default_memory(&mut self, ctx: impl AsContext) -> Memory {
let default_memory = self
.instance()
.get_memory(ctx.as_context(), DEFAULT_MEMORY_INDEX)
fn load_default_memory(&mut self, ctx: &StoreInner) -> Memory {
let default_memory = ctx
.resolve_instance(self.instance())
.get_memory(DEFAULT_MEMORY_INDEX)
.unwrap_or_else(|| {
panic!(
"missing default linear memory for instance: {:?}",
Expand All @@ -88,10 +87,10 @@ impl InstanceCache {
/// # Panics
///
/// If the currently used [`Instance`] does not have a default table.
fn load_default_table(&mut self, ctx: impl AsContext) -> Table {
let default_table = self
.instance()
.get_table(ctx.as_context(), DEFAULT_TABLE_INDEX)
fn load_default_table(&mut self, ctx: &StoreInner) -> Table {
let default_table = ctx
.resolve_instance(self.instance())
.get_table(DEFAULT_TABLE_INDEX)
.unwrap_or_else(|| panic!("missing default table for instance: {:?}", self.instance));
self.default_table = Some(default_table);
default_table
Expand All @@ -102,7 +101,8 @@ impl InstanceCache {
/// # Panics
///
/// If the currently used [`Instance`] does not have a default linear memory.
pub fn default_memory(&mut self, ctx: impl AsContext) -> Memory {
#[inline]
pub fn default_memory(&mut self, ctx: &StoreInner) -> Memory {
match self.default_memory {
Some(default_memory) => default_memory,
None => self.load_default_memory(ctx),
Expand All @@ -114,7 +114,8 @@ impl InstanceCache {
/// # Note
///
/// This avoids one indirection compared to using the `default_memory`.
pub fn default_memory_bytes(&mut self, ctx: impl AsContextMut) -> &mut CachedMemoryBytes {
#[inline]
pub fn default_memory_bytes(&mut self, ctx: &mut StoreInner) -> &mut CachedMemoryBytes {
match self.default_memory_bytes {
Some(ref mut cached) => cached,
None => self.load_default_memory_bytes(ctx),
Expand All @@ -124,8 +125,8 @@ impl InstanceCache {
/// Loads and populates the cached default memory instance.
///
/// Returns an exclusive reference to the cached default memory.
fn load_default_memory_bytes(&mut self, ctx: impl AsContextMut) -> &mut CachedMemoryBytes {
let memory = self.default_memory(&ctx);
fn load_default_memory_bytes(&mut self, ctx: &mut StoreInner) -> &mut CachedMemoryBytes {
let memory = self.default_memory(ctx);
self.default_memory_bytes = Some(CachedMemoryBytes::new(ctx, memory));
self.default_memory_bytes
.as_mut()
Expand All @@ -141,6 +142,7 @@ impl InstanceCache {
/// - Conservatively it is also recommended to reset default memory bytes
/// when calling a host function since that might invalidate linear memory
/// without the Wasm engine knowing.
#[inline]
pub fn reset_default_memory_bytes(&mut self) {
self.default_memory_bytes = None;
}
Expand All @@ -150,7 +152,8 @@ impl InstanceCache {
/// # Panics
///
/// If the currently used [`Instance`] does not have a default table.
pub fn default_table(&mut self, ctx: impl AsContext) -> Table {
#[inline]
pub fn default_table(&mut self, ctx: &StoreInner) -> Table {
match self.default_table {
Some(default_table) => default_table,
None => self.load_default_table(ctx),
Expand All @@ -162,10 +165,10 @@ impl InstanceCache {
/// # Panics
///
/// If the currently used [`Instance`] does not have a default table.
fn load_func_at(&mut self, ctx: impl AsContext, index: u32) -> Func {
let func = self
.instance()
.get_func(ctx.as_context(), index)
fn load_func_at(&mut self, ctx: &StoreInner, index: u32) -> Func {
let func = ctx
.resolve_instance(self.instance())
.get_func(index)
.unwrap_or_else(|| {
panic!(
"missing func at index {index} for instance: {:?}",
Expand All @@ -181,7 +184,8 @@ impl InstanceCache {
/// # Panics
///
/// If the currently used [`Instance`] does not have a [`Func`] at the index.
pub fn get_func(&mut self, ctx: impl AsContext, func_idx: u32) -> Func {
#[inline]
pub fn get_func(&mut self, ctx: &StoreInner, func_idx: u32) -> Func {
match self.last_func {
Some((index, func)) if index == func_idx => func,
_ => self.load_func_at(ctx, func_idx),
Expand All @@ -194,19 +198,17 @@ impl InstanceCache {
/// # Panics
///
/// If the currently used [`Instance`] does not have a default table.
fn load_global_at(&mut self, ctx: impl AsContextMut, index: u32) -> NonNull<UntypedValue> {
let global = self
.instance()
.get_global(ctx.as_context(), index)
.map_or_else(
|| {
panic!(
"missing global variable at index {index} for instance: {:?}",
self.instance
)
},
|g| g.get_untyped_ptr(ctx),
);
fn load_global_at(&mut self, ctx: &mut StoreInner, index: u32) -> NonNull<UntypedValue> {
let global = ctx
.resolve_instance(self.instance())
.get_global(index)
.map(|global| ctx.resolve_global_mut(global).get_untyped_ptr())
.unwrap_or_else(|| {
panic!(
"missing global variable at index {index} for instance: {:?}",
self.instance
)
});
self.last_global = Some((index, global));
global
}
Expand All @@ -217,7 +219,8 @@ impl InstanceCache {
/// # Panics
///
/// If the currently used [`Instance`] does not have a [`Func`] at the index.
pub fn get_global(&mut self, ctx: impl AsContextMut, global_idx: u32) -> &mut UntypedValue {
#[inline]
pub fn get_global(&mut self, ctx: &mut StoreInner, global_idx: u32) -> &mut UntypedValue {
let mut ptr = match self.last_global {
Some((index, global)) if index == global_idx => global,
_ => self.load_global_at(ctx, global_idx),
Expand All @@ -239,9 +242,9 @@ pub struct CachedMemoryBytes {
impl CachedMemoryBytes {
/// Creates a new [`CachedMemoryBytes`] from the given [`Memory`].
#[inline]
pub fn new(mut ctx: impl AsContextMut, memory: Memory) -> Self {
pub fn new(ctx: &mut StoreInner, memory: Memory) -> Self {
Self {
data: memory.data_mut(&mut ctx).into(),
data: ctx.resolve_memory_mut(memory).data().into(),
}
}

Expand Down
Loading