mirror of
https://github.com/fluencelabs/wasmer
synced 2025-06-21 04:31:33 +00:00
Redesign the interface between the runtime and the backends.
This removes the ProtectedCaller and FuncResolver traits, simplifying call implementations and improving dynamic call throughput.
This commit is contained in:
1
Cargo.lock
generated
1
Cargo.lock
generated
@ -2363,6 +2363,7 @@ dependencies = [
|
|||||||
"serde-bench 0.0.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
"serde-bench 0.0.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"serde_bytes 0.10.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
"serde_bytes 0.10.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"serde_derive 1.0.90 (registry+https://github.com/rust-lang/crates.io-index)",
|
"serde_derive 1.0.90 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
|
"smallvec 0.6.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"wasmparser 0.29.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
"wasmparser 0.29.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
"winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
"winapi 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||||
]
|
]
|
||||||
|
@ -17,6 +17,7 @@ indexmap = "1.0.2"
|
|||||||
errno = "0.2.4"
|
errno = "0.2.4"
|
||||||
libc = "0.2.49"
|
libc = "0.2.49"
|
||||||
hex = "0.3.2"
|
hex = "0.3.2"
|
||||||
|
smallvec = "0.6.9"
|
||||||
|
|
||||||
# Dependencies for caching.
|
# Dependencies for caching.
|
||||||
[dependencies.serde]
|
[dependencies.serde]
|
||||||
|
@ -1,10 +1,8 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
backing::ImportBacking,
|
|
||||||
error::CompileResult,
|
error::CompileResult,
|
||||||
error::RuntimeResult,
|
|
||||||
module::ModuleInner,
|
module::ModuleInner,
|
||||||
typed_func::Wasm,
|
typed_func::Wasm,
|
||||||
types::{FuncIndex, LocalFuncIndex, SigIndex, Value},
|
types::{LocalFuncIndex, SigIndex},
|
||||||
vm,
|
vm,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -67,59 +65,25 @@ pub trait Compiler {
|
|||||||
unsafe fn from_cache(&self, cache: Artifact, _: Token) -> Result<ModuleInner, CacheError>;
|
unsafe fn from_cache(&self, cache: Artifact, _: Token) -> Result<ModuleInner, CacheError>;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// The functionality exposed by this trait is expected to be used
|
|
||||||
/// for calling functions exported by a webassembly module from
|
|
||||||
/// host code only.
|
|
||||||
pub trait ProtectedCaller: Send + Sync {
|
|
||||||
/// This calls the exported function designated by `local_func_index`.
|
|
||||||
/// Important to note, this supports calling imported functions that are
|
|
||||||
/// then exported.
|
|
||||||
///
|
|
||||||
/// It's invalid to attempt to call a local function that isn't exported and
|
|
||||||
/// the implementation is expected to check for that. The implementation
|
|
||||||
/// is also expected to check for correct parameter types and correct
|
|
||||||
/// parameter number.
|
|
||||||
///
|
|
||||||
/// The `returns` parameter is filled with dummy values when passed in and upon function
|
|
||||||
/// return, will be filled with the return values of the wasm function, as long as the
|
|
||||||
/// call completed successfully.
|
|
||||||
///
|
|
||||||
/// The existance of the Token parameter ensures that this can only be called from
|
|
||||||
/// within the runtime crate.
|
|
||||||
///
|
|
||||||
/// TODO(lachlan): Now that `get_wasm_trampoline` exists, `ProtectedCaller::call`
|
|
||||||
/// can be removed. That should speed up calls a little bit, since sanity checks
|
|
||||||
/// would only occur once.
|
|
||||||
fn call(
|
|
||||||
&self,
|
|
||||||
module: &ModuleInner,
|
|
||||||
func_index: FuncIndex,
|
|
||||||
params: &[Value],
|
|
||||||
import_backing: &ImportBacking,
|
|
||||||
vmctx: *mut vm::Ctx,
|
|
||||||
_: Token,
|
|
||||||
) -> RuntimeResult<Vec<Value>>;
|
|
||||||
|
|
||||||
/// A wasm trampoline contains the necesarry data to dynamically call an exported wasm function.
|
|
||||||
/// Given a particular signature index, we are returned a trampoline that is matched with that
|
|
||||||
/// signature and an invoke function that can call the trampoline.
|
|
||||||
fn get_wasm_trampoline(&self, module: &ModuleInner, sig_index: SigIndex) -> Option<Wasm>;
|
|
||||||
|
|
||||||
fn get_early_trapper(&self) -> Box<dyn UserTrapper>;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub trait UserTrapper {
|
pub trait UserTrapper {
|
||||||
unsafe fn do_early_trap(&self, data: Box<dyn Any>) -> !;
|
unsafe fn do_early_trap(&self, data: Box<dyn Any>) -> !;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait FuncResolver: Send + Sync {
|
pub trait RunnableModule: Send + Sync {
|
||||||
/// This returns a pointer to the function designated by the `local_func_index`
|
/// This returns a pointer to the function designated by the `local_func_index`
|
||||||
/// parameter.
|
/// parameter.
|
||||||
fn get(
|
fn get_func(
|
||||||
&self,
|
&self,
|
||||||
module: &ModuleInner,
|
info: &ModuleInfo,
|
||||||
local_func_index: LocalFuncIndex,
|
local_func_index: LocalFuncIndex,
|
||||||
) -> Option<NonNull<vm::Func>>;
|
) -> Option<NonNull<vm::Func>>;
|
||||||
|
|
||||||
|
/// A wasm trampoline contains the necesarry data to dynamically call an exported wasm function.
|
||||||
|
/// Given a particular signature index, we are returned a trampoline that is matched with that
|
||||||
|
/// signature and an invoke function that can call the trampoline.
|
||||||
|
fn get_trampoline(&self, info: &ModuleInfo, sig_index: SigIndex) -> Option<Wasm>;
|
||||||
|
|
||||||
|
fn get_early_trapper(&self) -> Box<dyn UserTrapper>;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait CacheGen: Send + Sync {
|
pub trait CacheGen: Send + Sync {
|
||||||
|
@ -72,8 +72,8 @@ impl LocalBacking {
|
|||||||
(0..module.info.func_assoc.len() - module.info.imported_functions.len())
|
(0..module.info.func_assoc.len() - module.info.imported_functions.len())
|
||||||
.map(|index| {
|
.map(|index| {
|
||||||
module
|
module
|
||||||
.func_resolver
|
.runnable_module
|
||||||
.get(module, LocalFuncIndex::new(index))
|
.get_func(&module.info, LocalFuncIndex::new(index))
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.as_ptr() as *const _
|
.as_ptr() as *const _
|
||||||
})
|
})
|
||||||
@ -216,8 +216,8 @@ impl LocalBacking {
|
|||||||
let (func, ctx) = match func_index.local_or_import(&module.info) {
|
let (func, ctx) = match func_index.local_or_import(&module.info) {
|
||||||
LocalOrImport::Local(local_func_index) => (
|
LocalOrImport::Local(local_func_index) => (
|
||||||
module
|
module
|
||||||
.func_resolver
|
.runnable_module
|
||||||
.get(module, local_func_index)
|
.get_func(&module.info, local_func_index)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.as_ptr()
|
.as_ptr()
|
||||||
as *const vm::Func,
|
as *const vm::Func,
|
||||||
@ -255,8 +255,8 @@ impl LocalBacking {
|
|||||||
let (func, ctx) = match func_index.local_or_import(&module.info) {
|
let (func, ctx) = match func_index.local_or_import(&module.info) {
|
||||||
LocalOrImport::Local(local_func_index) => (
|
LocalOrImport::Local(local_func_index) => (
|
||||||
module
|
module
|
||||||
.func_resolver
|
.runnable_module
|
||||||
.get(module, local_func_index)
|
.get_func(&module.info, local_func_index)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.as_ptr()
|
.as_ptr()
|
||||||
as *const vm::Func,
|
as *const vm::Func,
|
||||||
|
@ -1,18 +1,19 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
backend::Token,
|
backend::{RunnableModule, Token},
|
||||||
backing::{ImportBacking, LocalBacking},
|
backing::{ImportBacking, LocalBacking},
|
||||||
error::{CallError, CallResult, ResolveError, ResolveResult, Result},
|
error::{CallError, CallResult, ResolveError, ResolveResult, Result, RuntimeError},
|
||||||
export::{Context, Export, ExportIter, FuncPointer},
|
export::{Context, Export, ExportIter, FuncPointer},
|
||||||
global::Global,
|
global::Global,
|
||||||
import::{ImportObject, LikeNamespace},
|
import::{ImportObject, LikeNamespace},
|
||||||
memory::Memory,
|
memory::Memory,
|
||||||
module::{ExportIndex, Module, ModuleInner},
|
module::{ExportIndex, Module, ModuleInfo, ModuleInner},
|
||||||
sig_registry::SigRegistry,
|
sig_registry::SigRegistry,
|
||||||
table::Table,
|
table::Table,
|
||||||
typed_func::{Func, Wasm, WasmTypeList},
|
typed_func::{Func, Wasm, WasmTrapInfo, WasmTypeList},
|
||||||
types::{FuncIndex, FuncSig, GlobalIndex, LocalOrImport, MemoryIndex, TableIndex, Value},
|
types::{FuncIndex, FuncSig, GlobalIndex, LocalOrImport, MemoryIndex, TableIndex, Type, Value},
|
||||||
vm,
|
vm,
|
||||||
};
|
};
|
||||||
|
use smallvec::{smallvec, SmallVec};
|
||||||
use std::{mem, ptr::NonNull, sync::Arc};
|
use std::{mem, ptr::NonNull, sync::Arc};
|
||||||
|
|
||||||
pub(crate) struct InstanceInner {
|
pub(crate) struct InstanceInner {
|
||||||
@ -82,7 +83,45 @@ impl Instance {
|
|||||||
};
|
};
|
||||||
|
|
||||||
if let Some(start_index) = instance.module.info.start_func {
|
if let Some(start_index) = instance.module.info.start_func {
|
||||||
instance.call_with_index(start_index, &[])?;
|
// We know that the start function takes no arguments and returns no values.
|
||||||
|
// Therefore, we can call it without doing any signature checking, etc.
|
||||||
|
|
||||||
|
let func_ptr = match start_index.local_or_import(&instance.module.info) {
|
||||||
|
LocalOrImport::Local(local_func_index) => instance
|
||||||
|
.module
|
||||||
|
.runnable_module
|
||||||
|
.get_func(&instance.module.info, local_func_index)
|
||||||
|
.unwrap(),
|
||||||
|
LocalOrImport::Import(import_func_index) => NonNull::new(
|
||||||
|
instance.inner.import_backing.vm_functions[import_func_index].func as *mut _,
|
||||||
|
)
|
||||||
|
.unwrap(),
|
||||||
|
};
|
||||||
|
|
||||||
|
let ctx_ptr = match start_index.local_or_import(&instance.module.info) {
|
||||||
|
LocalOrImport::Local(_) => instance.inner.vmctx,
|
||||||
|
LocalOrImport::Import(imported_func_index) => {
|
||||||
|
instance.inner.import_backing.vm_functions[imported_func_index].vmctx
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let sig_index = *instance
|
||||||
|
.module
|
||||||
|
.info
|
||||||
|
.func_assoc
|
||||||
|
.get(start_index)
|
||||||
|
.expect("broken invariant, incorrect func index");
|
||||||
|
|
||||||
|
let wasm_trampoline = instance
|
||||||
|
.module
|
||||||
|
.runnable_module
|
||||||
|
.get_trampoline(&instance.module.info, sig_index)
|
||||||
|
.expect("wasm trampoline");
|
||||||
|
|
||||||
|
let start_func: Func<(), (), Wasm> =
|
||||||
|
unsafe { Func::from_raw_parts(wasm_trampoline, func_ptr, ctx_ptr) };
|
||||||
|
|
||||||
|
start_func.call()?;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(instance)
|
Ok(instance)
|
||||||
@ -147,15 +186,15 @@ impl Instance {
|
|||||||
|
|
||||||
let func_wasm_inner = self
|
let func_wasm_inner = self
|
||||||
.module
|
.module
|
||||||
.protected_caller
|
.runnable_module
|
||||||
.get_wasm_trampoline(&self.module, sig_index)
|
.get_trampoline(&self.module.info, sig_index)
|
||||||
.unwrap();
|
.unwrap();
|
||||||
|
|
||||||
let func_ptr = match func_index.local_or_import(&self.module.info) {
|
let func_ptr = match func_index.local_or_import(&self.module.info) {
|
||||||
LocalOrImport::Local(local_func_index) => self
|
LocalOrImport::Local(local_func_index) => self
|
||||||
.module
|
.module
|
||||||
.func_resolver
|
.runnable_module
|
||||||
.get(&self.module, local_func_index)
|
.get_func(&self.module.info, local_func_index)
|
||||||
.unwrap(),
|
.unwrap(),
|
||||||
LocalOrImport::Import(import_func_index) => NonNull::new(
|
LocalOrImport::Import(import_func_index) => NonNull::new(
|
||||||
self.inner.import_backing.vm_functions[import_func_index].func as *mut _,
|
self.inner.import_backing.vm_functions[import_func_index].func as *mut _,
|
||||||
@ -245,7 +284,7 @@ impl Instance {
|
|||||||
/// # Ok(())
|
/// # Ok(())
|
||||||
/// # }
|
/// # }
|
||||||
/// ```
|
/// ```
|
||||||
pub fn call(&self, name: &str, args: &[Value]) -> CallResult<Vec<Value>> {
|
pub fn call(&self, name: &str, params: &[Value]) -> CallResult<Vec<Value>> {
|
||||||
let export_index =
|
let export_index =
|
||||||
self.module
|
self.module
|
||||||
.info
|
.info
|
||||||
@ -264,7 +303,19 @@ impl Instance {
|
|||||||
.into());
|
.into());
|
||||||
};
|
};
|
||||||
|
|
||||||
self.call_with_index(func_index, args)
|
let mut results = Vec::new();
|
||||||
|
|
||||||
|
call_func_with_index(
|
||||||
|
&self.module.info,
|
||||||
|
&*self.module.runnable_module,
|
||||||
|
&self.inner.import_backing,
|
||||||
|
self.inner.vmctx,
|
||||||
|
func_index,
|
||||||
|
params,
|
||||||
|
&mut results,
|
||||||
|
)?;
|
||||||
|
|
||||||
|
Ok(results)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns an immutable reference to the
|
/// Returns an immutable reference to the
|
||||||
@ -295,45 +346,6 @@ impl Instance {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Instance {
|
|
||||||
fn call_with_index(&self, func_index: FuncIndex, args: &[Value]) -> CallResult<Vec<Value>> {
|
|
||||||
let sig_index = *self
|
|
||||||
.module
|
|
||||||
.info
|
|
||||||
.func_assoc
|
|
||||||
.get(func_index)
|
|
||||||
.expect("broken invariant, incorrect func index");
|
|
||||||
let signature = &self.module.info.signatures[sig_index];
|
|
||||||
|
|
||||||
if !signature.check_param_value_types(args) {
|
|
||||||
Err(ResolveError::Signature {
|
|
||||||
expected: signature.clone(),
|
|
||||||
found: args.iter().map(|val| val.ty()).collect(),
|
|
||||||
})?
|
|
||||||
}
|
|
||||||
|
|
||||||
let vmctx = match func_index.local_or_import(&self.module.info) {
|
|
||||||
LocalOrImport::Local(_) => self.inner.vmctx,
|
|
||||||
LocalOrImport::Import(imported_func_index) => {
|
|
||||||
self.inner.import_backing.vm_functions[imported_func_index].vmctx
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
let token = Token::generate();
|
|
||||||
|
|
||||||
let returns = self.module.protected_caller.call(
|
|
||||||
&self.module,
|
|
||||||
func_index,
|
|
||||||
args,
|
|
||||||
&self.inner.import_backing,
|
|
||||||
vmctx,
|
|
||||||
token,
|
|
||||||
)?;
|
|
||||||
|
|
||||||
Ok(returns)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl InstanceInner {
|
impl InstanceInner {
|
||||||
pub(crate) fn get_export_from_index(
|
pub(crate) fn get_export_from_index(
|
||||||
&self,
|
&self,
|
||||||
@ -382,8 +394,8 @@ impl InstanceInner {
|
|||||||
let (func_ptr, ctx) = match func_index.local_or_import(&module.info) {
|
let (func_ptr, ctx) = match func_index.local_or_import(&module.info) {
|
||||||
LocalOrImport::Local(local_func_index) => (
|
LocalOrImport::Local(local_func_index) => (
|
||||||
module
|
module
|
||||||
.func_resolver
|
.runnable_module
|
||||||
.get(&module, local_func_index)
|
.get_func(&module.info, local_func_index)
|
||||||
.expect("broken invariant, func resolver not synced with module.exports")
|
.expect("broken invariant, func resolver not synced with module.exports")
|
||||||
.cast()
|
.cast()
|
||||||
.as_ptr() as *const _,
|
.as_ptr() as *const _,
|
||||||
@ -452,6 +464,128 @@ impl LikeNamespace for Instance {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
|
fn call_func_with_index(
|
||||||
|
info: &ModuleInfo,
|
||||||
|
runnable: &dyn RunnableModule,
|
||||||
|
import_backing: &ImportBacking,
|
||||||
|
local_ctx: *mut vm::Ctx,
|
||||||
|
func_index: FuncIndex,
|
||||||
|
args: &[Value],
|
||||||
|
rets: &mut Vec<Value>,
|
||||||
|
) -> CallResult<()> {
|
||||||
|
rets.clear();
|
||||||
|
|
||||||
|
let sig_index = *info
|
||||||
|
.func_assoc
|
||||||
|
.get(func_index)
|
||||||
|
.expect("broken invariant, incorrect func index");
|
||||||
|
|
||||||
|
let signature = &info.signatures[sig_index];
|
||||||
|
let num_results = signature.returns().len();
|
||||||
|
rets.reserve(num_results);
|
||||||
|
|
||||||
|
if !signature.check_param_value_types(args) {
|
||||||
|
Err(ResolveError::Signature {
|
||||||
|
expected: signature.clone(),
|
||||||
|
found: args.iter().map(|val| val.ty()).collect(),
|
||||||
|
})?
|
||||||
|
}
|
||||||
|
|
||||||
|
let func_ptr = match func_index.local_or_import(info) {
|
||||||
|
LocalOrImport::Local(local_func_index) => {
|
||||||
|
runnable.get_func(info, local_func_index).unwrap()
|
||||||
|
}
|
||||||
|
LocalOrImport::Import(import_func_index) => {
|
||||||
|
NonNull::new(import_backing.vm_functions[import_func_index].func as *mut _).unwrap()
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let ctx_ptr = match func_index.local_or_import(info) {
|
||||||
|
LocalOrImport::Local(_) => local_ctx,
|
||||||
|
LocalOrImport::Import(imported_func_index) => {
|
||||||
|
import_backing.vm_functions[imported_func_index].vmctx
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let raw_args: SmallVec<[u64; 8]> = args
|
||||||
|
.iter()
|
||||||
|
.map(|v| match v {
|
||||||
|
Value::I32(i) => *i as u64,
|
||||||
|
Value::I64(i) => *i as u64,
|
||||||
|
Value::F32(f) => f.to_bits() as u64,
|
||||||
|
Value::F64(f) => f.to_bits(),
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
|
||||||
|
let Wasm {
|
||||||
|
trampoline,
|
||||||
|
invoke,
|
||||||
|
invoke_env,
|
||||||
|
} = runnable
|
||||||
|
.get_trampoline(info, sig_index)
|
||||||
|
.expect("wasm trampoline");
|
||||||
|
|
||||||
|
let run_wasm = |result_space: *mut u64| unsafe {
|
||||||
|
let mut trap_info = WasmTrapInfo::Unknown;
|
||||||
|
|
||||||
|
let success = invoke(
|
||||||
|
trampoline,
|
||||||
|
ctx_ptr,
|
||||||
|
func_ptr,
|
||||||
|
raw_args.as_ptr(),
|
||||||
|
result_space,
|
||||||
|
&mut trap_info,
|
||||||
|
invoke_env,
|
||||||
|
);
|
||||||
|
|
||||||
|
if success {
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
Err(RuntimeError::Trap {
|
||||||
|
msg: trap_info.to_string().into(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let raw_to_value = |raw, ty| match ty {
|
||||||
|
Type::I32 => Value::I32(raw as i32),
|
||||||
|
Type::I64 => Value::I64(raw as i64),
|
||||||
|
Type::F32 => Value::F32(f32::from_bits(raw as u32)),
|
||||||
|
Type::F64 => Value::F64(f64::from_bits(raw)),
|
||||||
|
};
|
||||||
|
|
||||||
|
match signature.returns() {
|
||||||
|
&[] => {
|
||||||
|
run_wasm(0 as *mut u64)?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
&[ty] => {
|
||||||
|
let mut result = 0u64;
|
||||||
|
|
||||||
|
run_wasm(&mut result)?;
|
||||||
|
|
||||||
|
rets.push(raw_to_value(result, ty));
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
result_tys @ _ => {
|
||||||
|
let mut results: SmallVec<[u64; 8]> = smallvec![0; num_results];
|
||||||
|
|
||||||
|
run_wasm(results.as_mut_ptr())?;
|
||||||
|
|
||||||
|
rets.extend(
|
||||||
|
results
|
||||||
|
.iter()
|
||||||
|
.zip(result_tys.iter())
|
||||||
|
.map(|(&raw, &ty)| raw_to_value(raw, ty)),
|
||||||
|
);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// A representation of an exported WebAssembly function.
|
/// A representation of an exported WebAssembly function.
|
||||||
pub struct DynFunc<'a> {
|
pub struct DynFunc<'a> {
|
||||||
pub(crate) signature: Arc<FuncSig>,
|
pub(crate) signature: Arc<FuncSig>,
|
||||||
@ -484,32 +618,19 @@ impl<'a> DynFunc<'a> {
|
|||||||
/// # }
|
/// # }
|
||||||
/// ```
|
/// ```
|
||||||
pub fn call(&self, params: &[Value]) -> CallResult<Vec<Value>> {
|
pub fn call(&self, params: &[Value]) -> CallResult<Vec<Value>> {
|
||||||
if !self.signature.check_param_value_types(params) {
|
let mut results = Vec::new();
|
||||||
Err(ResolveError::Signature {
|
|
||||||
expected: (*self.signature).clone(),
|
|
||||||
found: params.iter().map(|val| val.ty()).collect(),
|
|
||||||
})?
|
|
||||||
}
|
|
||||||
|
|
||||||
let vmctx = match self.func_index.local_or_import(&self.module.info) {
|
call_func_with_index(
|
||||||
LocalOrImport::Local(_) => self.instance_inner.vmctx,
|
&self.module.info,
|
||||||
LocalOrImport::Import(imported_func_index) => {
|
&*self.module.runnable_module,
|
||||||
self.instance_inner.import_backing.vm_functions[imported_func_index].vmctx
|
&self.instance_inner.import_backing,
|
||||||
}
|
self.instance_inner.vmctx,
|
||||||
};
|
|
||||||
|
|
||||||
let token = Token::generate();
|
|
||||||
|
|
||||||
let returns = self.module.protected_caller.call(
|
|
||||||
&self.module,
|
|
||||||
self.func_index,
|
self.func_index,
|
||||||
params,
|
params,
|
||||||
&self.instance_inner.import_backing,
|
&mut results,
|
||||||
vmctx,
|
|
||||||
token,
|
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
Ok(returns)
|
Ok(results)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn signature(&self) -> &FuncSig {
|
pub fn signature(&self) -> &FuncSig {
|
||||||
@ -520,8 +641,8 @@ impl<'a> DynFunc<'a> {
|
|||||||
match self.func_index.local_or_import(&self.module.info) {
|
match self.func_index.local_or_import(&self.module.info) {
|
||||||
LocalOrImport::Local(local_func_index) => self
|
LocalOrImport::Local(local_func_index) => self
|
||||||
.module
|
.module
|
||||||
.func_resolver
|
.runnable_module
|
||||||
.get(self.module, local_func_index)
|
.get_func(&self.module.info, local_func_index)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.as_ptr(),
|
.as_ptr(),
|
||||||
LocalOrImport::Import(import_func_index) => {
|
LocalOrImport::Import(import_func_index) => {
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
backend::{Backend, FuncResolver, ProtectedCaller},
|
backend::{Backend, RunnableModule},
|
||||||
cache::{Artifact, Error as CacheError},
|
cache::{Artifact, Error as CacheError},
|
||||||
error,
|
error,
|
||||||
import::ImportObject,
|
import::ImportObject,
|
||||||
@ -22,9 +22,7 @@ use std::sync::Arc;
|
|||||||
/// This is used to instantiate a new WebAssembly module.
|
/// This is used to instantiate a new WebAssembly module.
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
pub struct ModuleInner {
|
pub struct ModuleInner {
|
||||||
pub func_resolver: Box<dyn FuncResolver>,
|
pub runnable_module: Box<dyn RunnableModule>,
|
||||||
pub protected_caller: Box<dyn ProtectedCaller>,
|
|
||||||
|
|
||||||
pub cache_gen: Box<dyn CacheGen>,
|
pub cache_gen: Box<dyn CacheGen>,
|
||||||
|
|
||||||
pub info: ModuleInfo,
|
pub info: ModuleInfo,
|
||||||
@ -96,7 +94,7 @@ impl Module {
|
|||||||
pub(crate) fn new(inner: Arc<ModuleInner>) -> Self {
|
pub(crate) fn new(inner: Arc<ModuleInner>) -> Self {
|
||||||
unsafe {
|
unsafe {
|
||||||
EARLY_TRAPPER
|
EARLY_TRAPPER
|
||||||
.with(|ucell| *ucell.get() = Some(inner.protected_caller.get_early_trapper()));
|
.with(|ucell| *ucell.get() = Some(inner.runnable_module.get_early_trapper()));
|
||||||
}
|
}
|
||||||
Module { inner }
|
Module { inner }
|
||||||
}
|
}
|
||||||
|
@ -71,9 +71,9 @@ pub type Invoke = unsafe extern "C" fn(
|
|||||||
/// as well as the environment that the invoke function may or may not require.
|
/// as well as the environment that the invoke function may or may not require.
|
||||||
#[derive(Copy, Clone)]
|
#[derive(Copy, Clone)]
|
||||||
pub struct Wasm {
|
pub struct Wasm {
|
||||||
trampoline: Trampoline,
|
pub(crate) trampoline: Trampoline,
|
||||||
invoke: Invoke,
|
pub(crate) invoke: Invoke,
|
||||||
invoke_env: Option<NonNull<c_void>>,
|
pub(crate) invoke_env: Option<NonNull<c_void>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Wasm {
|
impl Wasm {
|
||||||
|
@ -544,42 +544,23 @@ mod vm_ctx_tests {
|
|||||||
|
|
||||||
fn generate_module() -> ModuleInner {
|
fn generate_module() -> ModuleInner {
|
||||||
use super::Func;
|
use super::Func;
|
||||||
use crate::backend::{
|
use crate::backend::{sys::Memory, Backend, CacheGen, RunnableModule, UserTrapper};
|
||||||
sys::Memory, Backend, CacheGen, FuncResolver, ProtectedCaller, Token, UserTrapper,
|
|
||||||
};
|
|
||||||
use crate::cache::Error as CacheError;
|
use crate::cache::Error as CacheError;
|
||||||
use crate::error::RuntimeResult;
|
|
||||||
use crate::typed_func::Wasm;
|
use crate::typed_func::Wasm;
|
||||||
use crate::types::{FuncIndex, LocalFuncIndex, SigIndex, Value};
|
use crate::types::{LocalFuncIndex, SigIndex};
|
||||||
use hashbrown::HashMap;
|
use hashbrown::HashMap;
|
||||||
use std::ptr::NonNull;
|
use std::ptr::NonNull;
|
||||||
struct Placeholder;
|
struct Placeholder;
|
||||||
impl FuncResolver for Placeholder {
|
impl RunnableModule for Placeholder {
|
||||||
fn get(
|
fn get_func(
|
||||||
&self,
|
&self,
|
||||||
_module: &ModuleInner,
|
_module: &ModuleInfo,
|
||||||
_local_func_index: LocalFuncIndex,
|
_local_func_index: LocalFuncIndex,
|
||||||
) -> Option<NonNull<Func>> {
|
) -> Option<NonNull<Func>> {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
}
|
|
||||||
impl ProtectedCaller for Placeholder {
|
fn get_trampoline(&self, _module: &ModuleInfo, _sig_index: SigIndex) -> Option<Wasm> {
|
||||||
fn call(
|
|
||||||
&self,
|
|
||||||
_module: &ModuleInner,
|
|
||||||
_func_index: FuncIndex,
|
|
||||||
_params: &[Value],
|
|
||||||
_import_backing: &ImportBacking,
|
|
||||||
_vmctx: *mut Ctx,
|
|
||||||
_: Token,
|
|
||||||
) -> RuntimeResult<Vec<Value>> {
|
|
||||||
Ok(vec![])
|
|
||||||
}
|
|
||||||
fn get_wasm_trampoline(
|
|
||||||
&self,
|
|
||||||
_module: &ModuleInner,
|
|
||||||
_sig_index: SigIndex,
|
|
||||||
) -> Option<Wasm> {
|
|
||||||
unimplemented!()
|
unimplemented!()
|
||||||
}
|
}
|
||||||
fn get_early_trapper(&self) -> Box<dyn UserTrapper> {
|
fn get_early_trapper(&self) -> Box<dyn UserTrapper> {
|
||||||
@ -596,8 +577,7 @@ mod vm_ctx_tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ModuleInner {
|
ModuleInner {
|
||||||
func_resolver: Box::new(Placeholder),
|
runnable_module: Box::new(Placeholder),
|
||||||
protected_caller: Box::new(Placeholder),
|
|
||||||
cache_gen: Box::new(Placeholder),
|
cache_gen: Box::new(Placeholder),
|
||||||
info: ModuleInfo {
|
info: ModuleInfo {
|
||||||
memories: Map::new(),
|
memories: Map::new(),
|
||||||
|
Reference in New Issue
Block a user