diff --git a/lib/clif-backend/Cargo.toml b/lib/clif-backend/Cargo.toml index 60100bb73..8c29c803a 100644 --- a/lib/clif-backend/Cargo.toml +++ b/lib/clif-backend/Cargo.toml @@ -14,3 +14,8 @@ hashbrown = "0.1" target-lexicon = "0.2.0" wasmparser = "0.23.0" byteorder = "1" +nix = "0.12.0" +# We depend on libffi for now. +# This will be removed asap. +libffi = "0.6.4" + diff --git a/lib/clif-backend/src/call/mod.rs b/lib/clif-backend/src/call/mod.rs new file mode 100644 index 000000000..9c87fa8c9 --- /dev/null +++ b/lib/clif-backend/src/call/mod.rs @@ -0,0 +1,125 @@ +mod recovery; +mod sighandler; + +use crate::call::recovery::call_protected; +use wasmer_runtime::{ + backend::{Token, ProtectedCaller}, + types::{FuncIndex, Value, Type, FuncSig, LocalOrImport}, + module::ModuleInner, + error::{RuntimeResult}, + export::Context, + vm::{self, ImportBacking}, +}; +use libffi::high::{arg as libffi_arg, call as libffi_call, CodePtr}; +use hashbrown::HashSet; +use std::iter; + +pub struct Caller { + func_export_set: HashSet, +} + +impl Caller { + pub fn new(module: &ModuleInner) -> Self { + + } +} + +impl ProtectedCaller for Caller { + fn call( + &self, + module: &ModuleInner, + func_index: FuncIndex, + params: &[Value], + returns: &mut [Value], + import_backing: &ImportBacking, + vmctx: *mut vm::Ctx, + _: Token, + ) -> RuntimeResult<()> { + let (func_ptr, ctx, signature) = get_func_from_index(&module, import_backing, func_index); + + let vmctx_ptr = match ctx { + Context::External(external_vmctx) => external_vmctx, + Context::Internal => vmctx, + }; + + assert!(self.func_export_set.contains(&func_index)); + + assert!( + returns.len() == signature.returns.len() && signature.returns.len() <= 1, + "multi-value returns not yet supported" + ); + + assert!(signature.check_sig(params), "incorrect signature"); + + let libffi_args: Vec<_> = params + .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(); + + let code_ptr = CodePtr::from_ptr(func_ptr as _); + + call_protected(|| { + // Only supports zero or one return values for now. + // To support multiple returns, we will have to + // generate trampolines instead of using libffi. + match signature.returns.first() { + Some(ty) => { + let val = match ty { + Type::I32 => Value::I32(unsafe { libffi_call(code_ptr, &libffi_args) }), + Type::I64 => Value::I64(unsafe { libffi_call(code_ptr, &libffi_args) }), + Type::F32 => Value::F32(unsafe { libffi_call(code_ptr, &libffi_args) }), + Type::F64 => Value::F64(unsafe { libffi_call(code_ptr, &libffi_args) }), + }; + returns[0] = val; + }, + // call with no returns + None => unsafe { + libffi_call::<()>(code_ptr, &libffi_args); + }, + } + }) + } +} + + +fn get_func_from_index<'a>( + module: &'a ModuleInner, + import_backing: &ImportBacking, + func_index: FuncIndex, +) -> (*const vm::Func, Context, &'a FuncSig) { + let sig_index = *module + .func_assoc + .get(func_index) + .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::Import(imported_func_index) => { + let imported_func = import_backing.imported_func(imported_func_index); + ( + imported_func.func as *const _, + Context::External(imported_func.vmctx), + ) + } + }; + + let signature = module.sig_registry.lookup_func_sig(sig_index); + + (func_ptr, ctx, signature) +} \ No newline at end of file diff --git a/lib/runtime/src/recovery.rs b/lib/clif-backend/src/call/recovery.rs similarity index 97% rename from lib/runtime/src/recovery.rs rename to lib/clif-backend/src/call/recovery.rs index ec7a7cbf2..3733dc51a 100644 --- a/lib/runtime/src/recovery.rs +++ b/lib/clif-backend/src/call/recovery.rs @@ -4,10 +4,10 @@ //! are very special, the async signal unsafety of Rust's TLS implementation generally does not affect the correctness here //! unless you have memory unsafety elsewhere in your code. -use crate::{ +use wasmer_runtime::{ error::{RuntimeError, RuntimeResult}, - sighandler::install_sighandler, }; +use crate::call::sighandler::install_sighandler; use nix::libc::siginfo_t; use nix::sys::signal::{Signal, SIGBUS, SIGFPE, SIGILL, SIGSEGV}; use std::cell::{Cell, UnsafeCell}; diff --git a/lib/runtime/src/sighandler.rs b/lib/clif-backend/src/call/sighandler.rs similarity index 97% rename from lib/runtime/src/sighandler.rs rename to lib/clif-backend/src/call/sighandler.rs index 7d5abd49d..e216bd6d7 100644 --- a/lib/runtime/src/sighandler.rs +++ b/lib/clif-backend/src/call/sighandler.rs @@ -4,7 +4,7 @@ //! //! Please read more about this here: https://github.com/CraneStation/wasmtime/issues/15 //! This code is inspired by: https://github.com/pepyakin/wasmtime/commit/625a2b6c0815b21996e111da51b9664feb174622 -use crate::recovery; +use crate::call::recovery; use nix::libc::{c_void, siginfo_t}; use nix::sys::signal::{ sigaction, SaFlags, SigAction, SigHandler, SigSet, SIGBUS, SIGFPE, SIGILL, SIGSEGV, diff --git a/lib/clif-backend/src/lib.rs b/lib/clif-backend/src/lib.rs index 969348688..5899dd51f 100644 --- a/lib/clif-backend/src/lib.rs +++ b/lib/clif-backend/src/lib.rs @@ -5,6 +5,7 @@ mod module; mod module_env; mod relocation; mod resolver; +mod call; use cranelift_codegen::{ isa, diff --git a/lib/runtime/Cargo.toml b/lib/runtime/Cargo.toml index 08f57ec56..3618aca99 100644 --- a/lib/runtime/Cargo.toml +++ b/lib/runtime/Cargo.toml @@ -7,7 +7,6 @@ build = "build/mod.rs" [dependencies] hashbrown = "0.1" -libffi = "0.6.4" nix = "0.12.0" page_size = "0.4.1" errno = "0.2.4" diff --git a/lib/runtime/src/backend.rs b/lib/runtime/src/backend.rs index 0ea709c3b..3cf7b0945 100644 --- a/lib/runtime/src/backend.rs +++ b/lib/runtime/src/backend.rs @@ -2,6 +2,7 @@ use crate::{ error::CompileResult, error::RuntimeResult, module::ModuleInner, + backing::ImportBacking, types::{FuncIndex, LocalFuncIndex, Value}, vm, }; @@ -54,6 +55,7 @@ pub trait ProtectedCaller { func_index: FuncIndex, params: &[Value], returns: &mut [Value], + import_backing: &ImportBacking, vmctx: *mut vm::Ctx, _: Token, ) -> RuntimeResult<()>; @@ -62,13 +64,9 @@ pub trait ProtectedCaller { 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>; } diff --git a/lib/runtime/src/backing.rs b/lib/runtime/src/backing.rs index b292a9637..48a5e6268 100644 --- a/lib/runtime/src/backing.rs +++ b/lib/runtime/src/backing.rs @@ -1,5 +1,4 @@ use crate::{ - backend::Token, error::{LinkError, LinkResult}, export::{Context, Export}, import::Imports, @@ -179,17 +178,14 @@ 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) => { - let token = Token::generate(); - vm::ImportedFunc { - func: module - .func_resolver - .get(module, local_func_index, token) - .unwrap() - .as_ptr(), - vmctx, - } - } + LocalOrImport::Local(local_func_index) => vm::ImportedFunc { + func: module + .func_resolver + .get(module, local_func_index) + .unwrap() + .as_ptr(), + vmctx, + }, LocalOrImport::Import(imported_func_index) => { imports.functions[imported_func_index].clone() } @@ -233,17 +229,14 @@ 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) => { - let token = Token::generate(); - vm::ImportedFunc { - func: module - .func_resolver - .get(module, local_func_index, token) - .unwrap() - .as_ptr(), - vmctx, - } - } + LocalOrImport::Local(local_func_index) => vm::ImportedFunc { + func: module + .func_resolver + .get(module, local_func_index) + .unwrap() + .as_ptr(), + vmctx, + }, LocalOrImport::Import(imported_func_index) => { imports.functions[imported_func_index].clone() } @@ -322,6 +315,10 @@ impl ImportBacking { }) } + pub fn imported_func(&self, func_index: ImportedFuncIndex) -> vm::ImportedFunc { + self.functions[func_index].clone() + } + pub fn imported_memory(&self, memory_index: ImportedMemoryIndex) -> vm::ImportedMemory { self.memories[memory_index].clone() } diff --git a/lib/runtime/src/instance.rs b/lib/runtime/src/instance.rs index ef57f2969..760ad2243 100644 --- a/lib/runtime/src/instance.rs +++ b/lib/runtime/src/instance.rs @@ -1,4 +1,3 @@ -use crate::recovery::call_protected; use crate::{ backend::Token, backing::{ImportBacking, LocalBacking}, @@ -10,13 +9,12 @@ use crate::{ module::{ExportIndex, Module, ModuleInner}, types::{ FuncIndex, FuncSig, GlobalDesc, GlobalIndex, LocalOrImport, Memory, MemoryIndex, Table, - TableIndex, Type, Value, + TableIndex, Value, }, vm, }; -use libffi::high::{arg as libffi_arg, call as libffi_call, CodePtr}; use std::rc::Rc; -use std::{iter, mem}; +use std::mem; pub(crate) struct InstanceInner { #[allow(dead_code)] @@ -122,7 +120,7 @@ impl Instance { let mut returns = vec![Value::I32(0); signature.returns.len()]; let vmctx = match func_index.local_or_import(&self.module) { - LocalOrImport::Local(local_func_index) => &mut *self.inner.vmctx, + LocalOrImport::Local(_) => &mut *self.inner.vmctx, LocalOrImport::Import(imported_func_index) => { self.inner.import_backing.functions[imported_func_index].vmctx } @@ -135,61 +133,12 @@ impl Instance { func_index, args, &mut returns, + &self.inner.import_backing, 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 - // }) - // })?) } } @@ -253,11 +202,10 @@ impl InstanceInner { let (func_ptr, ctx) = match func_index.local_or_import(module) { LocalOrImport::Local(local_func_index) => { - let token = Token::generate(); ( module .func_resolver - .get(&module, local_func_index, token) + .get(&module, local_func_index) .expect("broken invariant, func resolver not synced with module.exports") .cast() .as_ptr() as *const _, @@ -387,7 +335,7 @@ impl Namespace for Instance { // TODO Remove this later, only needed for compilation till emscripten is updated impl Instance { - pub fn memory_offset_addr(&self, index: usize, offset: usize) -> *const u8 { + pub fn memory_offset_addr(&self, _index: usize, _offset: usize) -> *const u8 { unimplemented!() } } diff --git a/lib/runtime/src/lib.rs b/lib/runtime/src/lib.rs index f7517c593..ba150cdd3 100644 --- a/lib/runtime/src/lib.rs +++ b/lib/runtime/src/lib.rs @@ -14,9 +14,7 @@ pub mod instance; pub mod memory; mod mmap; pub mod module; -mod recovery; mod sig_registry; -mod sighandler; pub mod structures; pub mod table; pub mod types; diff --git a/lib/runtime/src/types.rs b/lib/runtime/src/types.rs index d3082acd4..5fd0d1193 100644 --- a/lib/runtime/src/types.rs +++ b/lib/runtime/src/types.rs @@ -159,7 +159,7 @@ pub trait LocalImport { #[rustfmt::skip] macro_rules! define_map_index { ($ty:ident) => { - #[derive(Debug, Copy, Clone, PartialEq, Eq)] + #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] pub struct $ty (u32); impl TypedIndex for $ty { #[doc(hidden)]