Skip to content

Commit

Permalink
Add CachedMemory type (#1068)
Browse files Browse the repository at this point in the history
add CachedMemory type
  • Loading branch information
Robbepop committed Jun 14, 2024
1 parent 8a489cc commit 0627348
Show file tree
Hide file tree
Showing 8 changed files with 76 additions and 27 deletions.
64 changes: 64 additions & 0 deletions crates/wasmi/src/engine/executor/cache.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
use crate::{module::DEFAULT_MEMORY_INDEX, store::StoreInner, Instance};
use core::ptr::NonNull;

/// Cached default linear memory bytes.
#[derive(Debug, Copy, Clone)]
pub struct CachedMemory {
data: NonNull<[u8]>,
}

impl Default for CachedMemory {
#[inline]
fn default() -> Self {
Self {
data: NonNull::from(&mut []),
}
}
}

impl CachedMemory {
/// Updates the [`CachedMemory`]'s linear memory data pointer.
///
/// # Note
///
/// This needs to be called whenever the cached pointer might have changed.
///
/// The linear memory pointer might change when ...
///
/// - calling a host function
/// - successfully growing the default linear memory
/// - calling functions defined in other instances via imported or indirect calls
/// - returning from functions that changed the currently used instance
#[inline]
pub fn update(&mut self, ctx: &mut StoreInner, instance: &Instance) {
self.data = Self::load_default_memory(ctx, instance);
}

/// Loads the default [`Memory`] of the currently used [`Instance`].
///
/// # Panics
///
/// If the currently used [`Instance`] does not have a default linear memory.
///
/// [`Memory`]: crate::Memory
#[inline]
fn load_default_memory(ctx: &mut StoreInner, instance: &Instance) -> NonNull<[u8]> {
ctx.resolve_instance(instance)
.get_memory(DEFAULT_MEMORY_INDEX)
.map(|memory| ctx.resolve_memory_mut(&memory).data_mut())
.unwrap_or_else(|| &mut [])
.into()
}

/// Returns a shared slice to the bytes of the cached default linear memory.
#[inline]
pub unsafe fn data(&self) -> &[u8] {
unsafe { self.data.as_ref() }
}

/// Returns an exclusive slice to the bytes of the cached default linear memory.
#[inline]
pub unsafe fn data_mut(&mut self) -> &mut [u8] {
unsafe { self.data.as_mut() }
}
}
26 changes: 5 additions & 21 deletions crates/wasmi/src/engine/executor/instrs.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
use core::ptr::NonNull;

pub use self::call::{dispatch_host_func, ResumableHostError};
use self::return_::ReturnOutcome;
use super::cache::CachedMemory;
use crate::{
core::{TrapCode, UntypedVal},
engine::{
Expand All @@ -26,7 +25,6 @@ use crate::{
store::StoreInner,
Error,
FuncRef,
Instance,
Memory,
Store,
};
Expand Down Expand Up @@ -82,8 +80,8 @@ struct Executor<'engine> {
sp: FrameRegisters,
/// The pointer to the currently executed instruction.
ip: InstructionPtr,
/// The default memory byte buffer.
memory: NonNull<[u8]>,
/// The cached default memory bytes.
memory: CachedMemory,
/// Stores frequently used instance related data.
cache: &'engine mut InstanceCache,
/// The value stack.
Expand Down Expand Up @@ -134,7 +132,7 @@ impl<'engine> Executor<'engine> {
Self {
sp,
ip,
memory: NonNull::from(&mut []),
memory: CachedMemory::default(),
cache,
value_stack,
call_stack,
Expand All @@ -143,20 +141,6 @@ impl<'engine> Executor<'engine> {
}
}

/// Loads the default [`Memory`] of the currently used [`Instance`].
///
/// # Panics
///
/// If the currently used [`Instance`] does not have a default linear memory.
#[inline]
fn load_default_memory(ctx: &mut StoreInner, instance: &Instance) -> NonNull<[u8]> {
ctx.resolve_instance(instance)
.get_memory(DEFAULT_MEMORY_INDEX)
.map(|memory| ctx.resolve_memory_mut(&memory).data_mut())
.unwrap_or_else(|| &mut [])
.into()
}

#[inline]
fn default_memory(&self, ctx: &StoreInner) -> Memory {
let instance = self.cache.instance();
Expand All @@ -170,7 +154,7 @@ impl<'engine> Executor<'engine> {
fn execute<T>(mut self, store: &mut Store<T>) -> Result<(), Error> {
use Instruction as Instr;
let instance = self.cache.instance();
self.memory = Self::load_default_memory(&mut store.inner, instance);
self.memory.update(&mut store.inner, instance);
loop {
match *self.ip.get() {
Instr::Trap(trap_code) => self.execute_trap(trap_code)?,
Expand Down
4 changes: 2 additions & 2 deletions crates/wasmi/src/engine/executor/instrs/call.rs
Original file line number Diff line number Diff line change
Expand Up @@ -460,7 +460,7 @@ impl<'engine> Executor<'engine> {
let func_body = func.func_body();
self.prepare_compiled_func_call::<C>(&mut store.inner, results, func_body)?;
self.cache.update_instance(&instance);
self.memory = Self::load_default_memory(&mut store.inner, &instance);
self.memory.update(&mut store.inner, &instance);
Ok(())
}
FuncEntity::Host(host_func) => {
Expand Down Expand Up @@ -513,7 +513,7 @@ impl<'engine> Executor<'engine> {
false => ResumableHostError::new(error, *func, results).into(),
})?;
self.cache.reset_last_global();
self.memory = Self::load_default_memory(&mut store.inner, caller.instance());
self.memory.update(&mut store.inner, caller.instance());
let results = results.iter(len_results);
let returned = self.value_stack.drop_return(max_inout);
for (result, value) in results.zip(returned) {
Expand Down
2 changes: 1 addition & 1 deletion crates/wasmi/src/engine/executor/instrs/load.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ impl<'engine> Executor<'engine> {
) -> Result<(), Error> {
// Safety: `self.memory` is always re-loaded conservatively whenever
// the heap allocations and thus the pointer might have changed.
let memory = unsafe { self.memory.as_ref() };
let memory = unsafe { self.memory.data() };
let loaded_value = load_extend(memory, address, offset)?;
self.set_register(result, loaded_value);
Ok(())
Expand Down
2 changes: 1 addition & 1 deletion crates/wasmi/src/engine/executor/instrs/memory.rs
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@ impl<'engine> Executor<'engine> {
// linear memory so we need to reset it in order for the cache to
// reload in case it is used again.
let instance = self.cache.instance();
self.memory = Self::load_default_memory(store, instance);
self.memory.update(store, instance);
return_value
}
Err(EntityGrowError::InvalidGrow) => EntityGrowError::ERROR_CODE,
Expand Down
2 changes: 1 addition & 1 deletion crates/wasmi/src/engine/executor/instrs/return_.rs
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ impl<'engine> Executor<'engine> {
Self::init_call_frame_impl(self.value_stack, &mut self.sp, &mut self.ip, caller);
let instance = caller.instance();
self.cache.update_instance(instance);
self.memory = Self::load_default_memory(store, instance);
self.memory.update(store, instance);
ReturnOutcome::Wasm
}
None => ReturnOutcome::Host,
Expand Down
2 changes: 1 addition & 1 deletion crates/wasmi/src/engine/executor/instrs/store.rs
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ impl<'engine> Executor<'engine> {
) -> Result<(), Error> {
// Safety: `self.memory` is always re-loaded conservatively whenever
// the heap allocations and thus the pointer might have changed.
let memory = unsafe { self.memory.as_mut() };
let memory = unsafe { self.memory.data_mut() };
store_wrap(memory, address, offset, value)?;
Ok(())
}
Expand Down
1 change: 1 addition & 0 deletions crates/wasmi/src/engine/executor/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ use crate::{
#[cfg(doc)]
use crate::engine::StackLimits;

mod cache;
mod instrs;
mod stack;

Expand Down

0 comments on commit 0627348

Please sign in to comment.