mirror of
https://github.com/fluencelabs/wasmer
synced 2025-06-19 20:01:20 +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,18 +1,19 @@
|
||||
use crate::{
|
||||
backend::Token,
|
||||
backend::{RunnableModule, Token},
|
||||
backing::{ImportBacking, LocalBacking},
|
||||
error::{CallError, CallResult, ResolveError, ResolveResult, Result},
|
||||
error::{CallError, CallResult, ResolveError, ResolveResult, Result, RuntimeError},
|
||||
export::{Context, Export, ExportIter, FuncPointer},
|
||||
global::Global,
|
||||
import::{ImportObject, LikeNamespace},
|
||||
memory::Memory,
|
||||
module::{ExportIndex, Module, ModuleInner},
|
||||
module::{ExportIndex, Module, ModuleInfo, ModuleInner},
|
||||
sig_registry::SigRegistry,
|
||||
table::Table,
|
||||
typed_func::{Func, Wasm, WasmTypeList},
|
||||
types::{FuncIndex, FuncSig, GlobalIndex, LocalOrImport, MemoryIndex, TableIndex, Value},
|
||||
typed_func::{Func, Wasm, WasmTrapInfo, WasmTypeList},
|
||||
types::{FuncIndex, FuncSig, GlobalIndex, LocalOrImport, MemoryIndex, TableIndex, Type, Value},
|
||||
vm,
|
||||
};
|
||||
use smallvec::{smallvec, SmallVec};
|
||||
use std::{mem, ptr::NonNull, sync::Arc};
|
||||
|
||||
pub(crate) struct InstanceInner {
|
||||
@ -82,7 +83,45 @@ impl Instance {
|
||||
};
|
||||
|
||||
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)
|
||||
@ -147,15 +186,15 @@ impl Instance {
|
||||
|
||||
let func_wasm_inner = self
|
||||
.module
|
||||
.protected_caller
|
||||
.get_wasm_trampoline(&self.module, sig_index)
|
||||
.runnable_module
|
||||
.get_trampoline(&self.module.info, sig_index)
|
||||
.unwrap();
|
||||
|
||||
let func_ptr = match func_index.local_or_import(&self.module.info) {
|
||||
LocalOrImport::Local(local_func_index) => self
|
||||
.module
|
||||
.func_resolver
|
||||
.get(&self.module, local_func_index)
|
||||
.runnable_module
|
||||
.get_func(&self.module.info, local_func_index)
|
||||
.unwrap(),
|
||||
LocalOrImport::Import(import_func_index) => NonNull::new(
|
||||
self.inner.import_backing.vm_functions[import_func_index].func as *mut _,
|
||||
@ -245,7 +284,7 @@ impl Instance {
|
||||
/// # 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 =
|
||||
self.module
|
||||
.info
|
||||
@ -264,7 +303,19 @@ impl Instance {
|
||||
.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
|
||||
@ -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 {
|
||||
pub(crate) fn get_export_from_index(
|
||||
&self,
|
||||
@ -382,8 +394,8 @@ impl InstanceInner {
|
||||
let (func_ptr, ctx) = match func_index.local_or_import(&module.info) {
|
||||
LocalOrImport::Local(local_func_index) => (
|
||||
module
|
||||
.func_resolver
|
||||
.get(&module, local_func_index)
|
||||
.runnable_module
|
||||
.get_func(&module.info, local_func_index)
|
||||
.expect("broken invariant, func resolver not synced with module.exports")
|
||||
.cast()
|
||||
.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.
|
||||
pub struct DynFunc<'a> {
|
||||
pub(crate) signature: Arc<FuncSig>,
|
||||
@ -484,32 +618,19 @@ impl<'a> DynFunc<'a> {
|
||||
/// # }
|
||||
/// ```
|
||||
pub fn call(&self, params: &[Value]) -> CallResult<Vec<Value>> {
|
||||
if !self.signature.check_param_value_types(params) {
|
||||
Err(ResolveError::Signature {
|
||||
expected: (*self.signature).clone(),
|
||||
found: params.iter().map(|val| val.ty()).collect(),
|
||||
})?
|
||||
}
|
||||
let mut results = Vec::new();
|
||||
|
||||
let vmctx = match self.func_index.local_or_import(&self.module.info) {
|
||||
LocalOrImport::Local(_) => self.instance_inner.vmctx,
|
||||
LocalOrImport::Import(imported_func_index) => {
|
||||
self.instance_inner.import_backing.vm_functions[imported_func_index].vmctx
|
||||
}
|
||||
};
|
||||
|
||||
let token = Token::generate();
|
||||
|
||||
let returns = self.module.protected_caller.call(
|
||||
&self.module,
|
||||
call_func_with_index(
|
||||
&self.module.info,
|
||||
&*self.module.runnable_module,
|
||||
&self.instance_inner.import_backing,
|
||||
self.instance_inner.vmctx,
|
||||
self.func_index,
|
||||
params,
|
||||
&self.instance_inner.import_backing,
|
||||
vmctx,
|
||||
token,
|
||||
&mut results,
|
||||
)?;
|
||||
|
||||
Ok(returns)
|
||||
Ok(results)
|
||||
}
|
||||
|
||||
pub fn signature(&self) -> &FuncSig {
|
||||
@ -520,8 +641,8 @@ impl<'a> DynFunc<'a> {
|
||||
match self.func_index.local_or_import(&self.module.info) {
|
||||
LocalOrImport::Local(local_func_index) => self
|
||||
.module
|
||||
.func_resolver
|
||||
.get(self.module, local_func_index)
|
||||
.runnable_module
|
||||
.get_func(&self.module.info, local_func_index)
|
||||
.unwrap()
|
||||
.as_ptr(),
|
||||
LocalOrImport::Import(import_func_index) => {
|
||||
|
Reference in New Issue
Block a user