mirror of
https://github.com/fluencelabs/wasmer
synced 2025-03-16 08:10:49 +00:00
add 'ProtectedCaller' to runtime
This commit is contained in:
parent
ed87168c48
commit
705708cafe
@ -12,7 +12,7 @@ use cranelift_codegen::{
|
||||
};
|
||||
use target_lexicon::Triple;
|
||||
use wasmer_runtime::{
|
||||
backend::Compiler,
|
||||
backend::{Compiler, Token},
|
||||
error::{CompileError, CompileResult},
|
||||
module::ModuleInner,
|
||||
};
|
||||
@ -28,7 +28,7 @@ impl CraneliftCompiler {
|
||||
|
||||
impl Compiler for CraneliftCompiler {
|
||||
// Compiles wasm binary to a wasmer module.
|
||||
fn compile(&self, wasm: &[u8]) -> CompileResult<ModuleInner> {
|
||||
fn compile(&self, wasm: &[u8], _: Token) -> CompileResult<ModuleInner> {
|
||||
validate(wasm)?;
|
||||
|
||||
let isa = get_isa();
|
||||
|
@ -1,18 +1,74 @@
|
||||
use crate::{error::CompileResult, module::ModuleInner, types::LocalFuncIndex, vm};
|
||||
use crate::{
|
||||
error::CompileResult,
|
||||
error::RuntimeResult,
|
||||
module::ModuleInner,
|
||||
types::{FuncIndex, LocalFuncIndex, Value},
|
||||
vm,
|
||||
};
|
||||
use std::ptr::NonNull;
|
||||
|
||||
pub use crate::mmap::{Mmap, Protect};
|
||||
pub use crate::sig_registry::SigRegistry;
|
||||
|
||||
/// This type cannot be constructed from
|
||||
/// outside the runtime crate.
|
||||
pub struct Token {
|
||||
_private: (),
|
||||
}
|
||||
|
||||
impl Token {
|
||||
pub(crate) fn generate() -> Self {
|
||||
Self { _private: () }
|
||||
}
|
||||
}
|
||||
|
||||
pub trait Compiler {
|
||||
/// Compiles a `Module` from WebAssembly binary format
|
||||
fn compile(&self, wasm: &[u8]) -> CompileResult<ModuleInner>;
|
||||
/// Compiles a `Module` from WebAssembly binary format.
|
||||
/// The `CompileToken` parameter ensures that this can only
|
||||
/// be called from inside the runtime.
|
||||
fn compile(&self, wasm: &[u8], _: Token) -> CompileResult<ModuleInner>;
|
||||
}
|
||||
|
||||
/// 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 {
|
||||
/// 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.
|
||||
fn call(
|
||||
&self,
|
||||
module: &ModuleInner,
|
||||
func_index: FuncIndex,
|
||||
params: &[Value],
|
||||
returns: &mut [Value],
|
||||
vmctx: *mut vm::Ctx,
|
||||
_: Token,
|
||||
) -> RuntimeResult<()>;
|
||||
}
|
||||
|
||||
pub trait FuncResolver {
|
||||
/// This returns a pointer to the function designated by the `local_func_index`
|
||||
/// parameter.
|
||||
///
|
||||
/// The existance of the Token parameter ensures that this can only be called from
|
||||
/// within the runtime crate.
|
||||
fn get(
|
||||
&self,
|
||||
module: &ModuleInner,
|
||||
local_func_index: LocalFuncIndex,
|
||||
_: Token,
|
||||
) -> Option<NonNull<vm::Func>>;
|
||||
}
|
||||
|
@ -1,4 +1,5 @@
|
||||
use crate::{
|
||||
backend::Token,
|
||||
error::{LinkError, LinkResult},
|
||||
export::{Context, Export},
|
||||
import::Imports,
|
||||
@ -178,14 +179,17 @@ impl LocalBacking {
|
||||
let sig_id = vm::SigId(sig_index.index() as u32);
|
||||
|
||||
let func_data = match func_index.local_or_import(module) {
|
||||
LocalOrImport::Local(local_func_index) => vm::ImportedFunc {
|
||||
func: module
|
||||
.func_resolver
|
||||
.get(module, local_func_index)
|
||||
.unwrap()
|
||||
.as_ptr(),
|
||||
vmctx,
|
||||
},
|
||||
LocalOrImport::Local(local_func_index) => {
|
||||
let token = Token::generate();
|
||||
vm::ImportedFunc {
|
||||
func: module
|
||||
.func_resolver
|
||||
.get(module, local_func_index, token)
|
||||
.unwrap()
|
||||
.as_ptr(),
|
||||
vmctx,
|
||||
}
|
||||
}
|
||||
LocalOrImport::Import(imported_func_index) => {
|
||||
imports.functions[imported_func_index].clone()
|
||||
}
|
||||
@ -229,14 +233,17 @@ impl LocalBacking {
|
||||
let sig_id = vm::SigId(sig_index.index() as u32);
|
||||
|
||||
let func_data = match func_index.local_or_import(module) {
|
||||
LocalOrImport::Local(local_func_index) => vm::ImportedFunc {
|
||||
func: module
|
||||
.func_resolver
|
||||
.get(module, local_func_index)
|
||||
.unwrap()
|
||||
.as_ptr(),
|
||||
vmctx,
|
||||
},
|
||||
LocalOrImport::Local(local_func_index) => {
|
||||
let token = Token::generate();
|
||||
vm::ImportedFunc {
|
||||
func: module
|
||||
.func_resolver
|
||||
.get(module, local_func_index, token)
|
||||
.unwrap()
|
||||
.as_ptr(),
|
||||
vmctx,
|
||||
}
|
||||
}
|
||||
LocalOrImport::Import(imported_func_index) => {
|
||||
imports.functions[imported_func_index].clone()
|
||||
}
|
||||
|
@ -1,5 +1,6 @@
|
||||
use crate::recovery::call_protected;
|
||||
use crate::{
|
||||
backend::Token,
|
||||
backing::{ImportBacking, LocalBacking},
|
||||
error::{CallError, CallResult, Result},
|
||||
export::{
|
||||
@ -67,11 +68,11 @@ impl Instance {
|
||||
|
||||
/// Call an exported webassembly function given the export name.
|
||||
/// Pass arguments by wrapping each one in the `Value` enum.
|
||||
/// The returned value is also returned in a `Value`.
|
||||
/// The returned values are also each wrapped in a `Value`.
|
||||
///
|
||||
/// This will eventually return `Result<Option<Vec<Value>>, String>` in
|
||||
/// order to support multi-value returns.
|
||||
pub fn call(&mut self, name: &str, args: &[Value]) -> CallResult<Option<Value>> {
|
||||
/// This returns `CallResult<Vec<Value>>` in order to support
|
||||
/// the future multi-value returns webassembly feature.
|
||||
pub fn call(&mut self, name: &str, args: &[Value]) -> CallResult<Vec<Value>> {
|
||||
let export_index =
|
||||
self.module
|
||||
.exports
|
||||
@ -102,23 +103,13 @@ impl Instance {
|
||||
}
|
||||
|
||||
impl Instance {
|
||||
fn call_with_index(
|
||||
&mut self,
|
||||
func_index: FuncIndex,
|
||||
args: &[Value],
|
||||
) -> CallResult<Option<Value>> {
|
||||
let (func_ref, ctx, signature) = self.inner.get_func_from_index(&self.module, func_index);
|
||||
|
||||
let func_ptr = CodePtr::from_ptr(func_ref.inner() as _);
|
||||
let vmctx_ptr = match ctx {
|
||||
Context::External(vmctx) => vmctx,
|
||||
Context::Internal => &mut *self.inner.vmctx,
|
||||
};
|
||||
|
||||
assert!(
|
||||
signature.returns.len() <= 1,
|
||||
"multi-value returns not yet supported"
|
||||
);
|
||||
fn call_with_index(&mut self, func_index: FuncIndex, args: &[Value]) -> CallResult<Vec<Value>> {
|
||||
let sig_index = *self
|
||||
.module
|
||||
.func_assoc
|
||||
.get(func_index)
|
||||
.expect("broken invariant, incorrect func index");
|
||||
let signature = self.module.sig_registry.lookup_func_sig(sig_index);
|
||||
|
||||
if !signature.check_sig(args) {
|
||||
Err(CallError::Signature {
|
||||
@ -127,35 +118,78 @@ impl Instance {
|
||||
})?
|
||||
}
|
||||
|
||||
let libffi_args: Vec<_> = args
|
||||
.iter()
|
||||
.map(|val| match val {
|
||||
Value::I32(ref x) => libffi_arg(x),
|
||||
Value::I64(ref x) => libffi_arg(x),
|
||||
Value::F32(ref x) => libffi_arg(x),
|
||||
Value::F64(ref x) => libffi_arg(x),
|
||||
})
|
||||
.chain(iter::once(libffi_arg(&vmctx_ptr)))
|
||||
.collect();
|
||||
// Create an output vector that's full of dummy values.
|
||||
let mut returns = vec![Value::I32(0); signature.returns.len()];
|
||||
|
||||
Ok(call_protected(|| {
|
||||
signature
|
||||
.returns
|
||||
.first()
|
||||
.map(|ty| match ty {
|
||||
Type::I32 => Value::I32(unsafe { libffi_call(func_ptr, &libffi_args) }),
|
||||
Type::I64 => Value::I64(unsafe { libffi_call(func_ptr, &libffi_args) }),
|
||||
Type::F32 => Value::F32(unsafe { libffi_call(func_ptr, &libffi_args) }),
|
||||
Type::F64 => Value::F64(unsafe { libffi_call(func_ptr, &libffi_args) }),
|
||||
})
|
||||
.or_else(|| {
|
||||
// call with no returns
|
||||
unsafe {
|
||||
libffi_call::<()>(func_ptr, &libffi_args);
|
||||
}
|
||||
None
|
||||
})
|
||||
})?)
|
||||
let vmctx = match func_index.local_or_import(&self.module) {
|
||||
LocalOrImport::Local(local_func_index) => &mut *self.inner.vmctx,
|
||||
LocalOrImport::Import(imported_func_index) => {
|
||||
self.inner.import_backing.functions[imported_func_index].vmctx
|
||||
}
|
||||
};
|
||||
|
||||
let token = Token::generate();
|
||||
|
||||
self.module.protected_caller.call(
|
||||
&self.module,
|
||||
func_index,
|
||||
args,
|
||||
&mut returns,
|
||||
vmctx,
|
||||
token,
|
||||
)?;
|
||||
|
||||
Ok(returns)
|
||||
|
||||
// let (func_ref, ctx, signature) = self.inner.get_func_from_index(&self.module, func_index);
|
||||
|
||||
// let func_ptr = CodePtr::from_ptr(func_ref.inner() as _);
|
||||
// let vmctx_ptr = match ctx {
|
||||
// Context::External(vmctx) => vmctx,
|
||||
// Context::Internal => &mut *self.inner.vmctx,
|
||||
// };
|
||||
|
||||
// assert!(
|
||||
// signature.returns.len() <= 1,
|
||||
// "multi-value returns not yet supported"
|
||||
// );
|
||||
|
||||
// if !signature.check_sig(args) {
|
||||
// Err(CallError::Signature {
|
||||
// expected: signature.clone(),
|
||||
// found: args.iter().map(|val| val.ty()).collect(),
|
||||
// })?
|
||||
// }
|
||||
|
||||
// let libffi_args: Vec<_> = args
|
||||
// .iter()
|
||||
// .map(|val| match val {
|
||||
// Value::I32(ref x) => libffi_arg(x),
|
||||
// Value::I64(ref x) => libffi_arg(x),
|
||||
// Value::F32(ref x) => libffi_arg(x),
|
||||
// Value::F64(ref x) => libffi_arg(x),
|
||||
// })
|
||||
// .chain(iter::once(libffi_arg(&vmctx_ptr)))
|
||||
// .collect();
|
||||
|
||||
// Ok(call_protected(|| {
|
||||
// signature
|
||||
// .returns
|
||||
// .first()
|
||||
// .map(|ty| match ty {
|
||||
// Type::I32 => Value::I32(unsafe { libffi_call(func_ptr, &libffi_args) }),
|
||||
// Type::I64 => Value::I64(unsafe { libffi_call(func_ptr, &libffi_args) }),
|
||||
// Type::F32 => Value::F32(unsafe { libffi_call(func_ptr, &libffi_args) }),
|
||||
// Type::F64 => Value::F64(unsafe { libffi_call(func_ptr, &libffi_args) }),
|
||||
// })
|
||||
// .or_else(|| {
|
||||
// // call with no returns
|
||||
// unsafe {
|
||||
// libffi_call::<()>(func_ptr, &libffi_args);
|
||||
// }
|
||||
// None
|
||||
// })
|
||||
// })?)
|
||||
}
|
||||
}
|
||||
|
||||
@ -218,15 +252,18 @@ impl InstanceInner {
|
||||
.expect("broken invariant, incorrect func index");
|
||||
|
||||
let (func_ptr, ctx) = match func_index.local_or_import(module) {
|
||||
LocalOrImport::Local(local_func_index) => (
|
||||
module
|
||||
.func_resolver
|
||||
.get(&module, local_func_index)
|
||||
.expect("broken invariant, func resolver not synced with module.exports")
|
||||
.cast()
|
||||
.as_ptr() as *const _,
|
||||
Context::Internal,
|
||||
),
|
||||
LocalOrImport::Local(local_func_index) => {
|
||||
let token = Token::generate();
|
||||
(
|
||||
module
|
||||
.func_resolver
|
||||
.get(&module, local_func_index, token)
|
||||
.expect("broken invariant, func resolver not synced with module.exports")
|
||||
.cast()
|
||||
.as_ptr() as *const _,
|
||||
Context::Internal,
|
||||
)
|
||||
}
|
||||
LocalOrImport::Import(imported_func_index) => {
|
||||
let imported_func = &self.import_backing.functions[imported_func_index];
|
||||
(
|
||||
|
@ -32,7 +32,8 @@ use std::rc::Rc;
|
||||
|
||||
/// Compile a webassembly module using the provided compiler.
|
||||
pub fn compile(wasm: &[u8], compiler: &dyn backend::Compiler) -> CompileResult<module::Module> {
|
||||
let token = backend::Token::generate();
|
||||
compiler
|
||||
.compile(wasm)
|
||||
.compile(wasm, token)
|
||||
.map(|inner| module::Module::new(Rc::new(inner)))
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
use crate::{
|
||||
backend::FuncResolver,
|
||||
backend::{FuncResolver, ProtectedCaller},
|
||||
error::Result,
|
||||
import::Imports,
|
||||
sig_registry::SigRegistry,
|
||||
@ -18,6 +18,7 @@ use std::rc::Rc;
|
||||
#[doc(hidden)]
|
||||
pub struct ModuleInner {
|
||||
pub func_resolver: Box<dyn FuncResolver>,
|
||||
pub protected_caller: Box<dyn ProtectedCaller>,
|
||||
// This are strictly local and the typsystem ensures that.
|
||||
pub memories: Map<LocalMemoryIndex, Memory>,
|
||||
pub globals: Map<LocalGlobalIndex, Global>,
|
||||
|
Loading…
x
Reference in New Issue
Block a user