-
Notifications
You must be signed in to change notification settings - Fork 286
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* swap printing fields in Debug impl of ValueStack * move value_stack.rs into stack folder/module * move call_stack.rs into stack folder/module * merge ValueStack and CallStack into Stack Stack is still very transparent towards its users but this is going to change soon. * extract Config into its own submodule/file * remove unnecessary getters from Config Add a wasm_features constructor method instead to Config. * remove redundant stack limit constants * make Config fields private again * panic from ValueStack::new if initial_len > maximum_len * properly use stack limits from Config to initialize Stack * decrease default max recursion depth from 64k to 1024 This requires benchmarks to use a custom config. * rename FunctionFrame -> FuncFrame * fix small doc typo * mark error path as #[cold] in CallStack::push * move err_stack_overflow to stack/mod.rs * refactor ValueStack::reserve This also fixes a rare overflow bug. * use capacity method in debug_assert instead of duplicating code * apply rustfmt * improve encapsulation of Stack and change execution model around it * remove unnecessary #[inline(never)] annotation * remove pessimizing #[inline(always)] annotation * remove commented out code * rename EngineInner::execute_wasm_func2 -> execute_wasm_func * add docs to EngineInner::execute_wasm_func * rename FuncFrame::new2 -> new * use pub visibility instead of pub(crate) The type is non-pub anyways. * remove FuncFrameRef indirection Now the top most FuncFrame is always handled manually and passed around by value instead of indirectly via its FuncFrameRef. * only resolve FuncBody once and create Instructions abstraction * introduce lightweight InstructionsRef * introduce function headers to codemap While this introduces an indirection upon calling a function this also heavily simplifies code. * remove unsafe code since unneeded * removed commented out code * handle FuncFrame by reference instead of by value * remove unused ResolvedFuncFrame type * add docs to FuncFrame::iref method * make CallStack::len method private * remove Func field from FuncFrame This reduces call stack size during execution of many nested function calls. * add important #[inline] annotations This mostly pushes the branch on perf par with master. * remove unused where bound * cache instance related data in InstanceCache No longer store instance related data on the CallStack. An advantage of the InstanceCache is that it synchronizes across function calls. * apply clippy suggestions * fix docs
- Loading branch information
Showing
15 changed files
with
880 additions
and
775 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,143 @@ | ||
use crate::{ | ||
module::{DEFAULT_MEMORY_INDEX, DEFAULT_TABLE_INDEX}, | ||
AsContext, | ||
Func, | ||
Instance, | ||
Memory, | ||
Table, | ||
}; | ||
|
||
/// A cache for frequently used entities of an [`Instance`]. | ||
#[derive(Debug)] | ||
pub struct InstanceCache { | ||
/// The current instance in use. | ||
instance: Instance, | ||
/// The default linear memory of the currently used [`Instance`]. | ||
default_memory: Option<Memory>, | ||
/// The default table of the currently used [`Instance`]. | ||
default_table: Option<Table>, | ||
/// The last accessed function of the currently used [`Instance`]. | ||
last_func: Option<(u32, Func)>, | ||
} | ||
|
||
impl From<Instance> for InstanceCache { | ||
fn from(instance: Instance) -> Self { | ||
Self { | ||
instance, | ||
default_memory: None, | ||
default_table: None, | ||
last_func: None, | ||
} | ||
} | ||
} | ||
|
||
impl InstanceCache { | ||
/// Resolves the instances. | ||
fn instance(&self) -> Instance { | ||
self.instance | ||
} | ||
|
||
/// Updates the cached [`Instance`]. | ||
fn set_instance(&mut self, instance: Instance) { | ||
self.instance = instance; | ||
} | ||
|
||
/// Updates the currently used instance resetting all cached entities. | ||
pub fn update_instance(&mut self, instance: Instance) { | ||
if instance == self.instance() { | ||
return; | ||
} | ||
self.set_instance(instance); | ||
self.default_memory = None; | ||
self.default_table = None; | ||
self.last_func = None; | ||
} | ||
|
||
/// Loads the default [`Memory`] of the currently used [`Instance`]. | ||
/// | ||
/// # 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) | ||
.unwrap_or_else(|| { | ||
panic!( | ||
"missing default linear memory for instance: {:?}", | ||
self.instance | ||
) | ||
}); | ||
self.default_memory = Some(default_memory); | ||
default_memory | ||
} | ||
|
||
/// Loads the default [`Table`] of the currently used [`Instance`]. | ||
/// | ||
/// # 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) | ||
.unwrap_or_else(|| panic!("missing default table for instance: {:?}", self.instance)); | ||
self.default_table = Some(default_table); | ||
default_table | ||
} | ||
|
||
/// Returns the default [`Memory`] of the currently used [`Instance`]. | ||
/// | ||
/// # Panics | ||
/// | ||
/// If the currently used [`Instance`] does not have a default linear memory. | ||
pub fn default_memory(&mut self, ctx: impl AsContext, _instance: Instance) -> Memory { | ||
match self.default_memory { | ||
Some(default_memory) => default_memory, | ||
None => self.load_default_memory(ctx), | ||
} | ||
} | ||
|
||
/// Returns the default [`Table`] of the currently used [`Instance`]. | ||
/// | ||
/// # Panics | ||
/// | ||
/// If the currently used [`Instance`] does not have a default table. | ||
pub fn default_table(&mut self, ctx: impl AsContext, _instance: Instance) -> Table { | ||
match self.default_table { | ||
Some(default_table) => default_table, | ||
None => self.load_default_table(ctx), | ||
} | ||
} | ||
|
||
/// Loads the [`Func`] at `index` of the currently used [`Instance`]. | ||
/// | ||
/// # 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) | ||
.unwrap_or_else(|| { | ||
panic!( | ||
"missing func at index {index} for instance: {:?}", | ||
self.instance | ||
) | ||
}); | ||
self.last_func = Some((index, func)); | ||
func | ||
} | ||
|
||
/// Loads the [`Func`] at `index` of the currently used [`Instance`]. | ||
/// | ||
/// # Panics | ||
/// | ||
/// If the currently used [`Instance`] does not have a [`Func`] at the index. | ||
pub fn get_func(&mut self, ctx: impl AsContext, _instance: Instance, func_idx: u32) -> Func { | ||
match self.last_func { | ||
Some((index, func)) if index == func_idx => func, | ||
_ => self.load_func_at(ctx, func_idx), | ||
} | ||
} | ||
} |
Oops, something went wrong.