pub use self::{
handler::{
Cell,
CellError,
CellsReader,
CellsWriter,
ExecutionOutcome,
Inst,
LiftFromCells,
LiftFromCellsByValue,
LoadByVal,
LoadFromCellsByValue,
LowerToCells,
Stack,
StoreToCells,
op_code_to_handler,
resume_wasm_func_call,
},
inout::{InOutParams, InOutResults},
};
use super::code_map::CodeMap;
use crate::{
Error,
Func,
FuncEntity,
Store,
StoreContextMut,
engine::{
EngineInner,
ResumableCallBase,
ResumableCallHostTrap,
ResumableCallOutOfFuel,
executor::handler::{init_host_func_call, init_wasm_func_call},
},
ir::SlotSpan,
};
mod handler;
mod inout;
impl EngineInner {
/// Executes the given [`Func`] with the given `params` and returns the `results`.
///
/// Uses the [`StoreContextMut`] for context information about the Wasm [`Store`].
///
/// # Errors
///
/// If the Wasm execution traps or runs out of resources.
pub fn execute_func<T, Params, Results>(
&self,
ctx: StoreContextMut<T>,
func: &Func,
params: Params,
results: Results,
) -> Result<Results::Value, Error>
where
Params: LowerToCells,
Results: LiftFromCells,
{
let mut stack = self.stacks.lock().reuse_or_new();
let value = EngineExecutor::new(&self.code_map, &mut stack)
.execute_root_func(ctx.store, func, params, results)
.map_err(ExecutionOutcome::into_non_resumable)?;
self.stacks.lock().recycle(stack);
Ok(value)
}
/// Executes the given [`Func`] resumably with the given `params` and returns the `results`.
///
/// Uses the [`StoreContextMut`] for context information about the Wasm [`Store`].
///
/// # Errors
///
/// If the Wasm execution traps or runs out of resources.
pub fn execute_func_resumable<T, Params, Results>(
&self,
ctx: StoreContextMut<T>,
func: &Func,
params: Params,
results: Results,
) -> Result<ResumableCallBase<Results::Value>, Error>
where
Params: LowerToCells,
Results: LiftFromCells,
{
let store = ctx.store;
let mut stack = self.stacks.lock().reuse_or_new();
let outcome = EngineExecutor::new(&self.code_map, &mut stack)
.execute_root_func(store, func, params, results);
let value = match outcome {
Ok(value) => value,
Err(ExecutionOutcome::Host(error)) => {
let host_func = *error.host_func();
let caller_results = *error.caller_results();
let host_error = error.into_error();
return Ok(ResumableCallBase::HostTrap(ResumableCallHostTrap::new(
store.engine().clone(),
stack,
*func,
host_func,
host_error,
caller_results,
)));
}
Err(ExecutionOutcome::OutOfFuel(error)) => {
let required_fuel = error.required_fuel();
return Ok(ResumableCallBase::OutOfFuel(ResumableCallOutOfFuel::new(
store.engine().clone(),
stack,
*func,
required_fuel,
)));
}
Err(ExecutionOutcome::Error(error)) => {
self.stacks.lock().recycle(stack);
return Err(error);
}
};
self.stacks.lock().recycle(stack);
Ok(ResumableCallBase::Finished(value))
}
/// Resumes the given [`Func`] with the given `params` and returns the `results`.
///
/// Uses the [`StoreContextMut`] for context information about the Wasm [`Store`].
///
/// # Errors
///
/// If the Wasm execution traps or runs out of resources.
pub fn resume_func_host_trap<T, Params, Results>(
&self,
ctx: StoreContextMut<T>,
mut invocation: ResumableCallHostTrap,
params: Params,
results: Results,
) -> Result<ResumableCallBase<Results::Value>, Error>
where
Params: LowerToCells,
Results: LiftFromCells,
{
let caller_results = invocation.caller_results();
let mut executor = EngineExecutor::new(&self.code_map, invocation.common.stack_mut());
let outcome = executor.resume_func_host_trap(ctx.store, params, caller_results, results);
let results = match outcome {
Ok(results) => results,
Err(ExecutionOutcome::Host(error)) => {
let host_func = *error.host_func();
let caller_results = *error.caller_results();
invocation.update(host_func, error.into_error(), caller_results);
return Ok(ResumableCallBase::HostTrap(invocation));
}
Err(ExecutionOutcome::OutOfFuel(error)) => {
let required_fuel = error.required_fuel();
let invocation = invocation.update_to_out_of_fuel(required_fuel);
return Ok(ResumableCallBase::OutOfFuel(invocation));
}
Err(ExecutionOutcome::Error(error)) => {
self.stacks.lock().recycle(invocation.common.take_stack());
return Err(error);
}
};
self.stacks.lock().recycle(invocation.common.take_stack());
Ok(ResumableCallBase::Finished(results))
}
/// Resumes the given [`Func`] after running out of fuel and returns the `results`.
///
/// Uses the [`StoreContextMut`] for context information about the Wasm [`Store`].
///
/// # Errors
///
/// If the Wasm execution traps or runs out of resources.
pub fn resume_func_out_of_fuel<T, Results>(
&self,
ctx: StoreContextMut<T>,
mut invocation: ResumableCallOutOfFuel,
results: Results,
) -> Result<ResumableCallBase<Results::Value>, Error>
where
Results: LiftFromCells,
{
let mut executor = EngineExecutor::new(&self.code_map, invocation.common.stack_mut());
let outcome = executor.resume_func_out_of_fuel(ctx.store, results);
let results = match outcome {
Ok(results) => results,
Err(ExecutionOutcome::Host(error)) => {
let host_func = *error.host_func();
let caller_results = *error.caller_results();
let invocation =
invocation.update_to_host_trap(host_func, error.into_error(), caller_results);
return Ok(ResumableCallBase::HostTrap(invocation));
}
Err(ExecutionOutcome::OutOfFuel(error)) => {
invocation.update(error.required_fuel());
return Ok(ResumableCallBase::OutOfFuel(invocation));
}
Err(ExecutionOutcome::Error(error)) => {
self.stacks.lock().recycle(invocation.common.take_stack());
return Err(error);
}
};
self.stacks.lock().recycle(invocation.common.take_stack());
Ok(ResumableCallBase::Finished(results))
}
}
/// The internal state of the Wasmi engine.
#[derive(Debug)]
pub struct EngineExecutor<'engine> {
/// Shared and reusable generic engine resources.
code_map: &'engine CodeMap,
/// The value and call stacks.
stack: &'engine mut Stack,
}
impl<'engine> EngineExecutor<'engine> {
/// Creates a new [`EngineExecutor`] for the given [`Stack`].
fn new(code_map: &'engine CodeMap, stack: &'engine mut Stack) -> Self {
Self { code_map, stack }
}
/// Executes the given [`Func`] using the given `params`.
///
/// Stores the execution result into `results` upon a successful execution.
///
/// # Errors
///
/// - If the given `params` do not match the expected parameters of `func`.
/// - If the given `results` do not match the length of the expected results of `func`.
/// - When encountering a Wasm or host trap during the execution of `func`.
fn execute_root_func<T, Params, Results>(
&mut self,
store: &mut Store<T>,
func: &Func,
params: Params,
results: Results,
) -> Result<Results::Value, ExecutionOutcome>
where
Params: LowerToCells,
Results: LiftFromCells,
{
self.stack.reset();
let results = match store.inner.resolve_func(func) {
FuncEntity::Wasm(wasm_func) => {
// We reserve space on the stack to write the results of the root function execution.
let instance = *wasm_func.instance();
let engine_func = wasm_func.func_body();
let call =
init_wasm_func_call(store, self.code_map, self.stack, engine_func, instance)?;
call.write_params(params).execute()?.write_results(results)
}
FuncEntity::Host(host_func) => {
// The host function signature is required for properly
// adjusting, inspecting and manipulating the value stack.
// In case the host function returns more values than it takes
// we are required to extend the value stack.
let host_func = *host_func;
let call = init_host_func_call(store, self.stack, host_func)?;
call.write_params(params).execute()?.write_results(results)
}
};
Ok(results)
}
/// Resumes the execution of the given [`Func`] using `params` after a host function trapped.
///
/// Stores the execution result into `results` upon a successful execution.
///
/// # Errors
///
/// - If the given `params` do not match the expected parameters of `func`.
/// - If the given `results` do not match the length of the expected results of `func`.
/// - When encountering a Wasm or host trap during the execution of `func`.
fn resume_func_host_trap<T, Params, Results>(
&mut self,
store: &mut Store<T>,
params: Params,
params_slots: SlotSpan,
results: Results,
) -> Result<Results::Value, ExecutionOutcome>
where
Params: LowerToCells,
Results: LiftFromCells,
{
let value = resume_wasm_func_call(store, self.code_map, self.stack)?
.provide_host_results(params, params_slots)
.execute()?
.write_results(results);
Ok(value)
}
/// Resumes the execution of the given [`Func`] using `params` after running out of fuel.
///
/// Stores the execution result into `results` upon a successful execution.
///
/// # Errors
///
/// - If the given `results` do not match the length of the expected results of `func`.
/// - When encountering a Wasm or host trap during the execution of `func`.
fn resume_func_out_of_fuel<T, Results>(
&mut self,
store: &mut Store<T>,
results: Results,
) -> Result<Results::Value, ExecutionOutcome>
where
Results: LiftFromCells,
{
let value = resume_wasm_func_call(store, self.code_map, self.stack)?
.execute()?
.write_results(results);
Ok(value)
}
}
pub use ;
use CodeMap;
use crate::;
/// The internal state of the Wasmi engine.
Homonyms
cyb/evy/forks/naga/src/back/hlsl/mod.rs
struct Baz { m: mat3x2, } struct Baz { float2 m_0; float2 m_1; float2 m_2; }; float3x2 GetMatmOnBaz(Baz obj) { return float3x2(obj.m_0, obj.m_1, obj.m_2); }