mirror of
https://github.com/fluencelabs/wasmer
synced 2025-03-30 22:41:03 +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 target_lexicon::Triple;
|
||||||
use wasmer_runtime::{
|
use wasmer_runtime::{
|
||||||
backend::Compiler,
|
backend::{Compiler, Token},
|
||||||
error::{CompileError, CompileResult},
|
error::{CompileError, CompileResult},
|
||||||
module::ModuleInner,
|
module::ModuleInner,
|
||||||
};
|
};
|
||||||
@ -28,7 +28,7 @@ impl CraneliftCompiler {
|
|||||||
|
|
||||||
impl Compiler for CraneliftCompiler {
|
impl Compiler for CraneliftCompiler {
|
||||||
// Compiles wasm binary to a wasmer module.
|
// Compiles wasm binary to a wasmer module.
|
||||||
fn compile(&self, wasm: &[u8]) -> CompileResult<ModuleInner> {
|
fn compile(&self, wasm: &[u8], _: Token) -> CompileResult<ModuleInner> {
|
||||||
validate(wasm)?;
|
validate(wasm)?;
|
||||||
|
|
||||||
let isa = get_isa();
|
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;
|
use std::ptr::NonNull;
|
||||||
|
|
||||||
pub use crate::mmap::{Mmap, Protect};
|
pub use crate::mmap::{Mmap, Protect};
|
||||||
pub use crate::sig_registry::SigRegistry;
|
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 {
|
pub trait Compiler {
|
||||||
/// Compiles a `Module` from WebAssembly binary format
|
/// Compiles a `Module` from WebAssembly binary format.
|
||||||
fn compile(&self, wasm: &[u8]) -> CompileResult<ModuleInner>;
|
/// 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 {
|
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(
|
fn get(
|
||||||
&self,
|
&self,
|
||||||
module: &ModuleInner,
|
module: &ModuleInner,
|
||||||
local_func_index: LocalFuncIndex,
|
local_func_index: LocalFuncIndex,
|
||||||
|
_: Token,
|
||||||
) -> Option<NonNull<vm::Func>>;
|
) -> Option<NonNull<vm::Func>>;
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
|
backend::Token,
|
||||||
error::{LinkError, LinkResult},
|
error::{LinkError, LinkResult},
|
||||||
export::{Context, Export},
|
export::{Context, Export},
|
||||||
import::Imports,
|
import::Imports,
|
||||||
@ -178,14 +179,17 @@ impl LocalBacking {
|
|||||||
let sig_id = vm::SigId(sig_index.index() as u32);
|
let sig_id = vm::SigId(sig_index.index() as u32);
|
||||||
|
|
||||||
let func_data = match func_index.local_or_import(module) {
|
let func_data = match func_index.local_or_import(module) {
|
||||||
LocalOrImport::Local(local_func_index) => vm::ImportedFunc {
|
LocalOrImport::Local(local_func_index) => {
|
||||||
func: module
|
let token = Token::generate();
|
||||||
.func_resolver
|
vm::ImportedFunc {
|
||||||
.get(module, local_func_index)
|
func: module
|
||||||
.unwrap()
|
.func_resolver
|
||||||
.as_ptr(),
|
.get(module, local_func_index, token)
|
||||||
vmctx,
|
.unwrap()
|
||||||
},
|
.as_ptr(),
|
||||||
|
vmctx,
|
||||||
|
}
|
||||||
|
}
|
||||||
LocalOrImport::Import(imported_func_index) => {
|
LocalOrImport::Import(imported_func_index) => {
|
||||||
imports.functions[imported_func_index].clone()
|
imports.functions[imported_func_index].clone()
|
||||||
}
|
}
|
||||||
@ -229,14 +233,17 @@ impl LocalBacking {
|
|||||||
let sig_id = vm::SigId(sig_index.index() as u32);
|
let sig_id = vm::SigId(sig_index.index() as u32);
|
||||||
|
|
||||||
let func_data = match func_index.local_or_import(module) {
|
let func_data = match func_index.local_or_import(module) {
|
||||||
LocalOrImport::Local(local_func_index) => vm::ImportedFunc {
|
LocalOrImport::Local(local_func_index) => {
|
||||||
func: module
|
let token = Token::generate();
|
||||||
.func_resolver
|
vm::ImportedFunc {
|
||||||
.get(module, local_func_index)
|
func: module
|
||||||
.unwrap()
|
.func_resolver
|
||||||
.as_ptr(),
|
.get(module, local_func_index, token)
|
||||||
vmctx,
|
.unwrap()
|
||||||
},
|
.as_ptr(),
|
||||||
|
vmctx,
|
||||||
|
}
|
||||||
|
}
|
||||||
LocalOrImport::Import(imported_func_index) => {
|
LocalOrImport::Import(imported_func_index) => {
|
||||||
imports.functions[imported_func_index].clone()
|
imports.functions[imported_func_index].clone()
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
use crate::recovery::call_protected;
|
use crate::recovery::call_protected;
|
||||||
use crate::{
|
use crate::{
|
||||||
|
backend::Token,
|
||||||
backing::{ImportBacking, LocalBacking},
|
backing::{ImportBacking, LocalBacking},
|
||||||
error::{CallError, CallResult, Result},
|
error::{CallError, CallResult, Result},
|
||||||
export::{
|
export::{
|
||||||
@ -67,11 +68,11 @@ impl Instance {
|
|||||||
|
|
||||||
/// Call an exported webassembly function given the export name.
|
/// Call an exported webassembly function given the export name.
|
||||||
/// Pass arguments by wrapping each one in the `Value` enum.
|
/// 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
|
/// This returns `CallResult<Vec<Value>>` in order to support
|
||||||
/// order to support multi-value returns.
|
/// the future multi-value returns webassembly feature.
|
||||||
pub fn call(&mut self, name: &str, args: &[Value]) -> CallResult<Option<Value>> {
|
pub fn call(&mut self, name: &str, args: &[Value]) -> CallResult<Vec<Value>> {
|
||||||
let export_index =
|
let export_index =
|
||||||
self.module
|
self.module
|
||||||
.exports
|
.exports
|
||||||
@ -102,23 +103,13 @@ impl Instance {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Instance {
|
impl Instance {
|
||||||
fn call_with_index(
|
fn call_with_index(&mut self, func_index: FuncIndex, args: &[Value]) -> CallResult<Vec<Value>> {
|
||||||
&mut self,
|
let sig_index = *self
|
||||||
func_index: FuncIndex,
|
.module
|
||||||
args: &[Value],
|
.func_assoc
|
||||||
) -> CallResult<Option<Value>> {
|
.get(func_index)
|
||||||
let (func_ref, ctx, signature) = self.inner.get_func_from_index(&self.module, func_index);
|
.expect("broken invariant, incorrect func index");
|
||||||
|
let signature = self.module.sig_registry.lookup_func_sig(sig_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) {
|
if !signature.check_sig(args) {
|
||||||
Err(CallError::Signature {
|
Err(CallError::Signature {
|
||||||
@ -127,35 +118,78 @@ impl Instance {
|
|||||||
})?
|
})?
|
||||||
}
|
}
|
||||||
|
|
||||||
let libffi_args: Vec<_> = args
|
// Create an output vector that's full of dummy values.
|
||||||
.iter()
|
let mut returns = vec![Value::I32(0); signature.returns.len()];
|
||||||
.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(|| {
|
let vmctx = match func_index.local_or_import(&self.module) {
|
||||||
signature
|
LocalOrImport::Local(local_func_index) => &mut *self.inner.vmctx,
|
||||||
.returns
|
LocalOrImport::Import(imported_func_index) => {
|
||||||
.first()
|
self.inner.import_backing.functions[imported_func_index].vmctx
|
||||||
.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) }),
|
let token = Token::generate();
|
||||||
Type::F64 => Value::F64(unsafe { libffi_call(func_ptr, &libffi_args) }),
|
|
||||||
})
|
self.module.protected_caller.call(
|
||||||
.or_else(|| {
|
&self.module,
|
||||||
// call with no returns
|
func_index,
|
||||||
unsafe {
|
args,
|
||||||
libffi_call::<()>(func_ptr, &libffi_args);
|
&mut returns,
|
||||||
}
|
vmctx,
|
||||||
None
|
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");
|
.expect("broken invariant, incorrect func index");
|
||||||
|
|
||||||
let (func_ptr, ctx) = match func_index.local_or_import(module) {
|
let (func_ptr, ctx) = match func_index.local_or_import(module) {
|
||||||
LocalOrImport::Local(local_func_index) => (
|
LocalOrImport::Local(local_func_index) => {
|
||||||
module
|
let token = Token::generate();
|
||||||
.func_resolver
|
(
|
||||||
.get(&module, local_func_index)
|
module
|
||||||
.expect("broken invariant, func resolver not synced with module.exports")
|
.func_resolver
|
||||||
.cast()
|
.get(&module, local_func_index, token)
|
||||||
.as_ptr() as *const _,
|
.expect("broken invariant, func resolver not synced with module.exports")
|
||||||
Context::Internal,
|
.cast()
|
||||||
),
|
.as_ptr() as *const _,
|
||||||
|
Context::Internal,
|
||||||
|
)
|
||||||
|
}
|
||||||
LocalOrImport::Import(imported_func_index) => {
|
LocalOrImport::Import(imported_func_index) => {
|
||||||
let imported_func = &self.import_backing.functions[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.
|
/// Compile a webassembly module using the provided compiler.
|
||||||
pub fn compile(wasm: &[u8], compiler: &dyn backend::Compiler) -> CompileResult<module::Module> {
|
pub fn compile(wasm: &[u8], compiler: &dyn backend::Compiler) -> CompileResult<module::Module> {
|
||||||
|
let token = backend::Token::generate();
|
||||||
compiler
|
compiler
|
||||||
.compile(wasm)
|
.compile(wasm, token)
|
||||||
.map(|inner| module::Module::new(Rc::new(inner)))
|
.map(|inner| module::Module::new(Rc::new(inner)))
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
backend::FuncResolver,
|
backend::{FuncResolver, ProtectedCaller},
|
||||||
error::Result,
|
error::Result,
|
||||||
import::Imports,
|
import::Imports,
|
||||||
sig_registry::SigRegistry,
|
sig_registry::SigRegistry,
|
||||||
@ -18,6 +18,7 @@ use std::rc::Rc;
|
|||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
pub struct ModuleInner {
|
pub struct ModuleInner {
|
||||||
pub func_resolver: Box<dyn FuncResolver>,
|
pub func_resolver: Box<dyn FuncResolver>,
|
||||||
|
pub protected_caller: Box<dyn ProtectedCaller>,
|
||||||
// This are strictly local and the typsystem ensures that.
|
// This are strictly local and the typsystem ensures that.
|
||||||
pub memories: Map<LocalMemoryIndex, Memory>,
|
pub memories: Map<LocalMemoryIndex, Memory>,
|
||||||
pub globals: Map<LocalGlobalIndex, Global>,
|
pub globals: Map<LocalGlobalIndex, Global>,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user