diff --git a/Cargo.lock b/Cargo.lock index 86c0406594c..e6c0365392b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1668,6 +1668,17 @@ dependencies = [ "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "wasmer-runtime-core-tests" +version = "0.8.0" +dependencies = [ + "wabt 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)", + "wasmer-clif-backend 0.8.0", + "wasmer-llvm-backend 0.8.0", + "wasmer-runtime-core 0.8.0", + "wasmer-singlepass-backend 0.8.0", +] + [[package]] name = "wasmer-singlepass-backend" version = "0.8.0" diff --git a/Cargo.toml b/Cargo.toml index 4d619059e35..afa35be1f18 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -43,6 +43,7 @@ members = [ "lib/singlepass-backend", "lib/runtime", "lib/runtime-core", + "lib/runtime-core-tests", "lib/emscripten", "lib/spectests", "lib/win-exception-handler", diff --git a/Makefile b/Makefile index 58b85dbb1a5..f3e839b5a95 100644 --- a/Makefile +++ b/Makefile @@ -25,7 +25,7 @@ generate: generate-spectests generate-emtests generate-wasitests # Spectests spectests-singlepass: - cargo test --manifest-path lib/spectests/Cargo.toml --release --features singlepass -- --nocapture + cargo +nightly test --manifest-path lib/spectests/Cargo.toml --release --features singlepass -- --nocapture spectests-cranelift: cargo test --manifest-path lib/spectests/Cargo.toml --release --features clif -- --nocapture @@ -89,12 +89,15 @@ wasitests: wasitests-unit wasitests-singlepass wasitests-cranelift wasitests-llv # Backends singlepass: spectests-singlepass emtests-singlepass middleware-singlepass wasitests-singlepass cargo test -p wasmer-singlepass-backend --release + cargo test -p wasmer-runtime-core-tests --no-default-features --features backend-singlepass cranelift: spectests-cranelift emtests-cranelift middleware-cranelift wasitests-cranelift cargo test -p wasmer-clif-backend --release + cargo test -p wasmer-runtime-core-tests llvm: spectests-llvm emtests-llvm wasitests-llvm cargo test -p wasmer-llvm-backend --release + cargo test -p wasmer-runtime-core-tests --no-default-features --features backend-llvm # All tests @@ -106,7 +109,20 @@ test-capi: capi cargo test -p wasmer-runtime-c-api --release test-rest: - cargo test --release --all --exclude wasmer-runtime-c-api --exclude wasmer-emscripten --exclude wasmer-spectests --exclude wasmer-wasi --exclude wasmer-middleware-common --exclude wasmer-middleware-common-tests --exclude wasmer-singlepass-backend --exclude wasmer-clif-backend --exclude wasmer-llvm-backend --exclude wasmer-wasi-tests --exclude wasmer-emscripten-tests + cargo test --release \ + --all \ + --exclude wasmer-runtime-c-api \ + --exclude wasmer-emscripten \ + --exclude wasmer-spectests \ + --exclude wasmer-wasi \ + --exclude wasmer-middleware-common \ + --exclude wasmer-middleware-common-tests \ + --exclude wasmer-singlepass-backend \ + --exclude wasmer-clif-backend \ + --exclude wasmer-llvm-backend \ + --exclude wasmer-wasi-tests \ + --exclude wasmer-emscripten-tests \ + --exclude wasmer-runtime-core-tests circleci-clean: @if [ ! -z "${CIRCLE_JOB}" ]; then rm -f /home/circleci/project/target/debug/deps/libcranelift_wasm* && rm -f /Users/distiller/project/target/debug/deps/libcranelift_wasm*; fi; diff --git a/lib/clif-backend/src/code.rs b/lib/clif-backend/src/code.rs index b2ccc66520a..0ec270dfcf1 100644 --- a/lib/clif-backend/src/code.rs +++ b/lib/clif-backend/src/code.rs @@ -782,23 +782,12 @@ impl FuncEnvironment for FunctionEnvironment { vm::Anyfunc::offset_func() as i32, ); - let vmctx_ptr = { - let loaded_vmctx_ptr = pos.ins().load( - ptr_type, - mflags, - entry_addr, - vm::Anyfunc::offset_vmctx() as i32, - ); - - let argument_vmctx_ptr = pos - .func - .special_param(ir::ArgumentPurpose::VMContext) - .expect("missing vmctx parameter"); - - // If the loaded vmctx ptr is zero, use the caller vmctx, else use the callee (loaded) vmctx. - pos.ins() - .select(loaded_vmctx_ptr, loaded_vmctx_ptr, argument_vmctx_ptr) - }; + let env_ptr = pos.ins().load( + ptr_type, + mflags, + entry_addr, + vm::Anyfunc::offset_func_env() as i32, + ); let found_sig = pos.ins().load( ir::types::I32, @@ -821,16 +810,6 @@ impl FuncEnvironment for FunctionEnvironment { }); pos.ins().symbol_value(ir::types::I64, sig_index_global) - - // let dynamic_sigindices_array_ptr = pos.ins().load( - // ptr_type, - // mflags, - - // ) - - // let expected_sig = pos.ins().iconst(ir::types::I32, sig_index.index() as i64); - - // self.env.deduplicated[clif_sig_index] }; let not_equal_flags = pos.ins().ifcmp(found_sig, expected_sig); @@ -842,16 +821,15 @@ impl FuncEnvironment for FunctionEnvironment { ); // Build a value list for the indirect call instruction containing the call_args - // and the vmctx parameter. + // and the env parameter. let mut args = Vec::with_capacity(call_args.len() + 1); - args.push(vmctx_ptr); + args.push(env_ptr); args.extend(call_args.iter().cloned()); Ok(pos.ins().call_indirect(sig_ref, func_ptr, &args)) } /// Generates a call IR with `callee` and `call_args` and inserts it at `pos` - /// TODO: add support for imported functions fn translate_call( &mut self, mut pos: FuncCursor, @@ -865,13 +843,13 @@ impl FuncEnvironment for FunctionEnvironment { match callee_index.local_or_import(&self.module_info.read().unwrap()) { LocalOrImport::Local(local_function_index) => { // this is an internal function - let vmctx = pos + let env = pos .func .special_param(ir::ArgumentPurpose::VMContext) .expect("missing vmctx parameter"); let mut args = Vec::with_capacity(call_args.len() + 1); - args.push(vmctx); + args.push(env); args.extend(call_args.iter().cloned()); let sig_ref = pos.func.dfg.ext_funcs[callee].signature; @@ -881,7 +859,7 @@ impl FuncEnvironment for FunctionEnvironment { let function_array_ptr = pos.ins().load( ptr_type, mflags, - vmctx, + env, vm::Ctx::offset_local_functions() as i32, ); @@ -897,10 +875,10 @@ impl FuncEnvironment for FunctionEnvironment { } LocalOrImport::Import(imported_func_index) => { // this is an imported function - let vmctx = pos.func.create_global_value(ir::GlobalValueData::VMContext); + let env = pos.func.create_global_value(ir::GlobalValueData::VMContext); let imported_funcs = pos.func.create_global_value(ir::GlobalValueData::Load { - base: vmctx, + base: env, offset: (vm::Ctx::offset_imported_funcs() as i32).into(), global_type: ptr_type, readonly: true, @@ -923,25 +901,25 @@ impl FuncEnvironment for FunctionEnvironment { readonly: true, }); - let imported_vmctx_addr = pos.func.create_global_value(ir::GlobalValueData::Load { + let imported_env_addr = pos.func.create_global_value(ir::GlobalValueData::Load { base: imported_func_struct_addr, - offset: (vm::ImportedFunc::offset_vmctx() as i32).into(), + offset: (vm::ImportedFunc::offset_func_env() as i32).into(), global_type: ptr_type, readonly: true, }); let imported_func_addr = pos.ins().global_value(ptr_type, imported_func_addr); - let imported_vmctx_addr = pos.ins().global_value(ptr_type, imported_vmctx_addr); + let imported_env_addr = pos.ins().global_value(ptr_type, imported_env_addr); let sig_ref = pos.func.dfg.ext_funcs[callee].signature; let mut args = Vec::with_capacity(call_args.len() + 1); - args.push(imported_vmctx_addr); + args.push(imported_env_addr); args.extend(call_args.iter().cloned()); Ok(pos .ins() - .call_indirect(sig_ref, imported_func_addr, &args[..])) + .call_indirect(sig_ref, imported_func_addr, args.as_slice())) } } } @@ -1086,7 +1064,7 @@ impl FunctionEnvironment { Converter(sig_index).into() } - /// Creates a signature with VMContext as the last param + /// Creates a signature with VMContext as the first param pub fn generate_signature( &self, clif_sig_index: cranelift_wasm::SignatureIndex, diff --git a/lib/clif-backend/src/resolver.rs b/lib/clif-backend/src/resolver.rs index 7a868f35e46..f543b48298a 100644 --- a/lib/clif-backend/src/resolver.rs +++ b/lib/clif-backend/src/resolver.rs @@ -49,7 +49,7 @@ fn lookup_func( let offset = *map.get(local_func_index)?; let ptr = unsafe { memory.as_ptr().add(offset) }; - NonNull::new(ptr).map(|nonnull| nonnull.cast()) + NonNull::new(ptr).map(|ptr| ptr.cast()) } #[allow(dead_code)] @@ -62,6 +62,7 @@ pub struct FuncResolverBuilder { } pub struct NoopStackmapSink {} + impl StackmapSink for NoopStackmapSink { fn add_stackmap(&mut self, _: u32, _: Stackmap) {} } diff --git a/lib/clif-backend/src/signal/mod.rs b/lib/clif-backend/src/signal/mod.rs index 3facce2ad68..197757bfe02 100644 --- a/lib/clif-backend/src/signal/mod.rs +++ b/lib/clif-backend/src/signal/mod.rs @@ -6,7 +6,7 @@ use std::{any::Any, cell::Cell, ptr::NonNull, sync::Arc}; use wasmer_runtime_core::{ backend::RunnableModule, module::ModuleInfo, - typed_func::{Wasm, WasmTrapInfo}, + typed_func::{Trampoline, Wasm, WasmTrapInfo}, types::{LocalFuncIndex, SigIndex}, vm, }; @@ -59,8 +59,9 @@ impl RunnableModule for Caller { fn get_trampoline(&self, _: &ModuleInfo, sig_index: SigIndex) -> Option { unsafe extern "C" fn invoke( - trampoline: unsafe extern "C" fn(*mut vm::Ctx, NonNull, *const u64, *mut u64), - ctx: *mut vm::Ctx, + trampoline: Trampoline, + _vmctx: Option>, + func_env: Option>, func: NonNull, args: *const u64, rets: *mut u64, @@ -73,12 +74,12 @@ impl RunnableModule for Caller { #[cfg(not(target_os = "windows"))] let res = call_protected(handler_data, || { // Leap of faith. - trampoline(ctx, func, args, rets); + trampoline(func_env, func, args, rets); }); // the trampoline is called from C on windows #[cfg(target_os = "windows")] - let res = call_protected(handler_data, trampoline, ctx, func, args, rets); + let res = call_protected(handler_data, trampoline, func_env, func, args, rets); match res { Err(err) => { diff --git a/lib/clif-backend/src/signal/unix.rs b/lib/clif-backend/src/signal/unix.rs index 39f3aa893c6..06df736cc04 100644 --- a/lib/clif-backend/src/signal/unix.rs +++ b/lib/clif-backend/src/signal/unix.rs @@ -9,15 +9,19 @@ //! 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::relocation::{TrapCode, TrapData}; -use crate::signal::{CallProtError, HandlerData}; +use crate::{ + relocation::{TrapCode, TrapData}, + signal::{CallProtError, HandlerData}, +}; use libc::{c_int, c_void, siginfo_t}; use nix::sys::signal::{ sigaction, SaFlags, SigAction, SigHandler, SigSet, Signal, SIGBUS, SIGFPE, SIGILL, SIGSEGV, }; -use std::cell::{Cell, UnsafeCell}; -use std::ptr; -use std::sync::Once; +use std::{ + cell::{Cell, UnsafeCell}, + ptr, + sync::Once, +}; use wasmer_runtime_core::typed_func::WasmTrapInfo; extern "C" fn signal_trap_handler( diff --git a/lib/clif-backend/src/signal/windows.rs b/lib/clif-backend/src/signal/windows.rs index d755cd575d2..36b5656b397 100644 --- a/lib/clif-backend/src/signal/windows.rs +++ b/lib/clif-backend/src/signal/windows.rs @@ -1,24 +1,30 @@ -use crate::relocation::{TrapCode, TrapData}; -use crate::signal::{CallProtError, HandlerData}; -use crate::trampoline::Trampoline; -use std::cell::Cell; -use std::ffi::c_void; -use std::ptr::{self, NonNull}; -use wasmer_runtime_core::typed_func::WasmTrapInfo; -use wasmer_runtime_core::vm::Ctx; -use wasmer_runtime_core::vm::Func; +use crate::{ + relocation::{TrapCode, TrapData}, + signal::{CallProtError, HandlerData}, +}; +use std::{ + cell::Cell, + ffi::c_void, + ptr::{self, NonNull}, +}; +use wasmer_runtime_core::{ + typed_func::{Trampoline, WasmTrapInfo}, + vm, +}; use wasmer_win_exception_handler::CallProtectedData; pub use wasmer_win_exception_handler::_call_protected; -use winapi::shared::minwindef::DWORD; -use winapi::um::minwinbase::{ - EXCEPTION_ACCESS_VIOLATION, EXCEPTION_ARRAY_BOUNDS_EXCEEDED, EXCEPTION_BREAKPOINT, - EXCEPTION_DATATYPE_MISALIGNMENT, EXCEPTION_FLT_DENORMAL_OPERAND, EXCEPTION_FLT_DIVIDE_BY_ZERO, - EXCEPTION_FLT_INEXACT_RESULT, EXCEPTION_FLT_INVALID_OPERATION, EXCEPTION_FLT_OVERFLOW, - EXCEPTION_FLT_STACK_CHECK, EXCEPTION_FLT_UNDERFLOW, EXCEPTION_GUARD_PAGE, - EXCEPTION_ILLEGAL_INSTRUCTION, EXCEPTION_INT_DIVIDE_BY_ZERO, EXCEPTION_INT_OVERFLOW, - EXCEPTION_INVALID_HANDLE, EXCEPTION_IN_PAGE_ERROR, EXCEPTION_NONCONTINUABLE_EXCEPTION, - EXCEPTION_POSSIBLE_DEADLOCK, EXCEPTION_PRIV_INSTRUCTION, EXCEPTION_SINGLE_STEP, - EXCEPTION_STACK_OVERFLOW, +use winapi::{ + shared::minwindef::DWORD, + um::minwinbase::{ + EXCEPTION_ACCESS_VIOLATION, EXCEPTION_ARRAY_BOUNDS_EXCEEDED, EXCEPTION_BREAKPOINT, + EXCEPTION_DATATYPE_MISALIGNMENT, EXCEPTION_FLT_DENORMAL_OPERAND, + EXCEPTION_FLT_DIVIDE_BY_ZERO, EXCEPTION_FLT_INEXACT_RESULT, + EXCEPTION_FLT_INVALID_OPERATION, EXCEPTION_FLT_OVERFLOW, EXCEPTION_FLT_STACK_CHECK, + EXCEPTION_FLT_UNDERFLOW, EXCEPTION_GUARD_PAGE, EXCEPTION_ILLEGAL_INSTRUCTION, + EXCEPTION_INT_DIVIDE_BY_ZERO, EXCEPTION_INT_OVERFLOW, EXCEPTION_INVALID_HANDLE, + EXCEPTION_IN_PAGE_ERROR, EXCEPTION_NONCONTINUABLE_EXCEPTION, EXCEPTION_POSSIBLE_DEADLOCK, + EXCEPTION_PRIV_INSTRUCTION, EXCEPTION_SINGLE_STEP, EXCEPTION_STACK_OVERFLOW, + }, }; thread_local! { @@ -28,8 +34,8 @@ thread_local! { pub fn call_protected( handler_data: &HandlerData, trampoline: Trampoline, - ctx: *mut Ctx, - func: NonNull, + env: Option>, + func: NonNull, param_vec: *const u64, return_vec: *mut u64, ) -> Result<(), CallProtError> { @@ -39,7 +45,7 @@ pub fn call_protected( // return Err(RuntimeError::User { msg }); // } - let result = _call_protected(trampoline, ctx, func, param_vec, return_vec); + let result = _call_protected(trampoline, env, func, param_vec, return_vec); if let Ok(_) = result { return Ok(()); diff --git a/lib/clif-backend/src/trampoline.rs b/lib/clif-backend/src/trampoline.rs index a6fc6572bac..6f5655a304b 100644 --- a/lib/clif-backend/src/trampoline.rs +++ b/lib/clif-backend/src/trampoline.rs @@ -7,12 +7,12 @@ use cranelift_codegen::{ isa, Context, }; use std::collections::HashMap; -use std::{iter, mem, ptr::NonNull}; +use std::{iter, mem}; use wasmer_runtime_core::{ backend::sys::{Memory, Protect}, module::{ExportIndex, ModuleInfo}, + typed_func::Trampoline, types::{FuncSig, SigIndex, Type}, - vm, }; struct NullRelocSink {} @@ -28,8 +28,6 @@ impl RelocSink for NullRelocSink { fn reloc_jt(&mut self, _: u32, _: Reloc, _: ir::JumpTable) {} } -pub type Trampoline = unsafe extern "C" fn(*mut vm::Ctx, NonNull, *const u64, *mut u64); - pub struct Trampolines { memory: Memory, offsets: HashMap, @@ -37,12 +35,6 @@ pub struct Trampolines { impl Trampolines { pub fn from_trampoline_cache(cache: TrampolineCache) -> Self { - // pub struct TrampolineCache { - // #[serde(with = "serde_bytes")] - // code: Vec, - // offsets: HashMap, - // } - let mut memory = Memory::with_size(cache.code.len()).unwrap(); unsafe { memory.protect(.., Protect::ReadWrite).unwrap(); @@ -173,6 +165,7 @@ fn generate_func(func_sig: &FuncSig) -> ir::Function { let mut args_vec = Vec::with_capacity(func_sig.params().len() + 1); args_vec.push(vmctx_ptr); + for (index, wasm_ty) in func_sig.params().iter().enumerate() { let mem_flags = ir::MemFlags::trusted(); diff --git a/lib/llvm-backend/cpp/object_loader.hh b/lib/llvm-backend/cpp/object_loader.hh index bc9b9ab6717..1e75f548489 100644 --- a/lib/llvm-backend/cpp/object_loader.hh +++ b/lib/llvm-backend/cpp/object_loader.hh @@ -285,12 +285,12 @@ void module_delete(WasmModule *module) { delete module; } unsafe_unwind(new BreakpointException(callback)); } -bool invoke_trampoline(trampoline_t trampoline, void *ctx, void *func, +bool invoke_trampoline(trampoline_t trampoline, void *_vmctx, void *func_env, void *func, void *params, void *results, WasmTrapType *trap_out, - box_any_t *user_error, void *invoke_env) noexcept { + box_any_t *user_error, void *_invoke_env) noexcept { try { - catch_unwind([trampoline, ctx, func, params, results]() { - trampoline(ctx, func, params, results); + catch_unwind([trampoline, func_env, func, params, results]() { + trampoline(func_env, func, params, results); }); return true; } catch (std::unique_ptr &e) { diff --git a/lib/llvm-backend/src/backend.rs b/lib/llvm-backend/src/backend.rs index 682bd72782b..360dc03ead2 100644 --- a/lib/llvm-backend/src/backend.rs +++ b/lib/llvm-backend/src/backend.rs @@ -28,7 +28,7 @@ use wasmer_runtime_core::{ module::ModuleInfo, state::ModuleStateMap, structures::TypedIndex, - typed_func::{Wasm, WasmTrapInfo}, + typed_func::{Trampoline, Wasm, WasmTrapInfo}, types::{LocalFuncIndex, SigIndex}, vm, vmcalls, }; @@ -58,8 +58,9 @@ extern "C" { #[allow(improper_ctypes)] fn invoke_trampoline( - trampoline: unsafe extern "C" fn(*mut vm::Ctx, NonNull, *const u64, *mut u64), - vmctx_ptr: *mut vm::Ctx, + trampoline: Trampoline, + vmctx: Option>, + env_ptr: Option>, func_ptr: NonNull, params: *const u64, results: *mut u64, @@ -409,7 +410,7 @@ impl RunnableModule for LLVMBackend { fn get_trampoline(&self, _: &ModuleInfo, sig_index: SigIndex) -> Option { let trampoline: unsafe extern "C" fn( - *mut vm::Ctx, + Option>, NonNull, *const u64, *mut u64, diff --git a/lib/llvm-backend/src/stackmap.rs b/lib/llvm-backend/src/stackmap.rs index a56c3c6a38d..3942e294549 100644 --- a/lib/llvm-backend/src/stackmap.rs +++ b/lib/llvm-backend/src/stackmap.rs @@ -161,7 +161,7 @@ impl StackmapEntry { ValueSemantic::ImportedFuncCtx(idx) => MachineValue::VmctxDeref(vec![ Ctx::offset_imported_funcs() as usize, vm::ImportedFunc::size() as usize * idx - + vm::ImportedFunc::offset_vmctx() as usize, + + vm::ImportedFunc::offset_func_env() as usize, 0, ]), ValueSemantic::DynamicSigindice(idx) => { diff --git a/lib/runtime-core-tests/Cargo.toml b/lib/runtime-core-tests/Cargo.toml new file mode 100644 index 00000000000..66e7b1de96a --- /dev/null +++ b/lib/runtime-core-tests/Cargo.toml @@ -0,0 +1,21 @@ +[package] +name = "wasmer-runtime-core-tests" +version = "0.8.0" +description = "Tests for the Wasmer runtime core crate" +license = "MIT" +authors = ["The Wasmer Engineering Team "] +edition = "2018" +publish = false + +[dependencies] +wabt = "0.9.1" +wasmer-runtime-core = { path = "../runtime-core", version = "0.8" } +wasmer-clif-backend = { path = "../clif-backend", version = "0.8", optional = true } +wasmer-singlepass-backend = { path = "../singlepass-backend", version = "0.8", optional = true } +wasmer-llvm-backend = { path = "../llvm-backend", version = "0.8", optional = true } + +[features] +default = ["backend-cranelift"] +backend-cranelift = ["wasmer-clif-backend"] +backend-singlepass = ["wasmer-singlepass-backend"] +backend-llvm = ["wasmer-llvm-backend"] \ No newline at end of file diff --git a/lib/runtime-core-tests/src/lib.rs b/lib/runtime-core-tests/src/lib.rs new file mode 100644 index 00000000000..96f7e6265b8 --- /dev/null +++ b/lib/runtime-core-tests/src/lib.rs @@ -0,0 +1,21 @@ +pub use wabt::wat2wasm; +use wasmer_runtime_core::backend::Compiler; + +#[cfg(feature = "backend-cranelift")] +pub fn get_compiler() -> impl Compiler { + use wasmer_clif_backend::CraneliftCompiler; + + CraneliftCompiler::new() +} + +#[cfg(feature = "backend-singlepass")] +pub fn get_compiler() -> impl Compiler { + use wasmer_singlepass_backend::SinglePassCompiler; + SinglePassCompiler::new() +} + +#[cfg(feature = "backend-llvm")] +pub fn get_compiler() -> impl Compiler { + use wasmer_llvm_backend::LLVMCompiler; + LLVMCompiler::new() +} diff --git a/lib/runtime-core-tests/tests/imports.rs b/lib/runtime-core-tests/tests/imports.rs new file mode 100644 index 00000000000..73e05580c7f --- /dev/null +++ b/lib/runtime-core-tests/tests/imports.rs @@ -0,0 +1,215 @@ +use wasmer_runtime_core::{ + compile_with, error::RuntimeError, imports, memory::Memory, typed_func::Func, + types::MemoryDescriptor, units::Pages, vm, +}; +use wasmer_runtime_core_tests::{get_compiler, wat2wasm}; + +#[test] +fn imported_functions_forms() { + const MODULE: &str = r#" +(module + (type $type (func (param i32) (result i32))) + (import "env" "memory" (memory 1 1)) + (import "env" "callback_fn" (func $callback_fn (type $type))) + (import "env" "callback_closure" (func $callback_closure (type $type))) + (import "env" "callback_fn_with_vmctx" (func $callback_fn_with_vmctx (type $type))) + (import "env" "callback_closure_with_vmctx" (func $callback_closure_with_vmctx (type $type))) + (import "env" "callback_closure_with_env" (func $callback_closure_with_env (type $type))) + (import "env" "callback_fn_trap" (func $callback_fn_trap (type $type))) + (import "env" "callback_closure_trap" (func $callback_closure_trap (type $type))) + (import "env" "callback_fn_trap_with_vmctx" (func $callback_fn_trap_with_vmctx (type $type))) + (import "env" "callback_closure_trap_with_env" (func $callback_closure_trap_with_env (type $type))) + (func (export "function_fn") (type $type) + get_local 0 + call $callback_fn) + (func (export "function_closure") (type $type) + get_local 0 + call $callback_closure) + (func (export "function_fn_with_vmctx") (type $type) + get_local 0 + call $callback_fn_with_vmctx) + (func (export "function_closure_with_vmctx") (type $type) + get_local 0 + call $callback_closure_with_vmctx) + (func (export "function_closure_with_env") (type $type) + get_local 0 + call $callback_closure_with_env) + (func (export "function_fn_trap") (type $type) + get_local 0 + call $callback_fn_trap) + (func (export "function_closure_trap") (type $type) + get_local 0 + call $callback_closure_trap) + (func (export "function_fn_trap_with_vmctx") (type $type) + get_local 0 + call $callback_fn_trap_with_vmctx) + (func (export "function_closure_trap_with_env") (type $type) + get_local 0 + call $callback_closure_trap_with_env)) +"#; + + let wasm_binary = wat2wasm(MODULE.as_bytes()).expect("WAST not valid or malformed"); + let module = compile_with(&wasm_binary, &get_compiler()).unwrap(); + let memory_descriptor = MemoryDescriptor::new(Pages(1), Some(Pages(1)), false).unwrap(); + let memory = Memory::new(memory_descriptor).unwrap(); + let memory2 = memory.clone(); + + const SHIFT: i32 = 10; + memory.view()[0].set(SHIFT); + + let import_object = imports! { + "env" => { + "memory" => memory.clone(), + + // Without vmctx or env. + "callback_fn" => Func::new(callback_fn), + "callback_closure" => Func::new(|n: i32| -> Result { + Ok(n + 1) + }), + + // With vmctx or env. + "callback_fn_with_vmctx" => Func::new(callback_fn_with_vmctx), + "callback_closure_with_vmctx" => Func::new(|vmctx: &mut vm::Ctx, n: i32| -> Result { + let memory = vmctx.memory(0); + let shift: i32 = memory.view()[0].get(); + + Ok(shift + n + 1) + }), + "callback_closure_with_env" => Func::new(move |n: i32| -> Result { + let shift: i32 = memory.view()[0].get(); + + Ok(shift + n + 1) + }), + + // Trap without vmctx or env. + "callback_fn_trap" => Func::new(callback_fn_trap), + "callback_closure_trap" => Func::new(|n: i32| -> Result { + Err(format!("bar {}", SHIFT + n)) + }), + + // Trap with vmctx or env. + "callback_fn_trap_with_vmctx" => Func::new(callback_fn_trap_with_vmctx), + "callback_closure_trap_with_env" => Func::new(move |n: i32| -> Result { + let shift: i32 = memory2.view()[0].get(); + + Err(format!("qux {}", shift + n + 1)) + }), + }, + }; + let instance = module.instantiate(&import_object).unwrap(); + + macro_rules! call_and_assert { + ($function:ident, $expected_value:expr) => { + let $function: Func = instance.func(stringify!($function)).unwrap(); + + let result = $function.call(1); + + match (result, $expected_value) { + (Ok(value), expected_value) => assert_eq!( + Ok(value), + expected_value, + concat!("Expected right when calling `", stringify!($function), "`.") + ), + ( + Err(RuntimeError::Error { data }), + Err(RuntimeError::Error { + data: expected_data, + }), + ) => { + if let (Some(data), Some(expected_data)) = ( + data.downcast_ref::<&str>(), + expected_data.downcast_ref::<&str>(), + ) { + assert_eq!( + data, expected_data, + concat!("Expected right when calling `", stringify!($function), "`.") + ) + } else if let (Some(data), Some(expected_data)) = ( + data.downcast_ref::(), + expected_data.downcast_ref::(), + ) { + assert_eq!( + data, expected_data, + concat!("Expected right when calling `", stringify!($function), "`.") + ) + } else { + assert!(false, "Unexpected error, cannot compare it.") + } + } + (result, expected_value) => assert!( + false, + format!( + "Unexpected assertion for `{}`: left = `{:?}`, right = `{:?}`.", + stringify!($function), + result, + expected_value + ) + ), + } + }; + } + + call_and_assert!(function_fn, Ok(2)); + call_and_assert!(function_closure, Ok(2)); + call_and_assert!(function_fn_with_vmctx, Ok(2 + SHIFT)); + call_and_assert!(function_closure_with_vmctx, Ok(2 + SHIFT)); + call_and_assert!(function_closure_with_env, Ok(2 + SHIFT)); + call_and_assert!( + function_fn_trap, + Err(RuntimeError::Error { + data: Box::new(format!("foo {}", 1)) + }) + ); + call_and_assert!( + function_closure_trap, + Err(RuntimeError::Error { + data: Box::new(format!("bar {}", 1 + SHIFT)) + }) + ); + call_and_assert!( + function_fn_trap_with_vmctx, + Err(RuntimeError::Error { + data: Box::new(format!("baz {}", 2 + SHIFT)) + }) + ); + /* + call_and_assert!( + function_closure_trap_with_env, + Err(RuntimeError::Error { + data: Box::new(format!("qux {}", 2 + SHIFT)) + }) + ); + */ +} + +#[test] +#[should_panic( + expected = "A closure cannot capture its environment while having `&mut vm::Ctx` as its first argument." +)] +#[allow(non_snake_case)] +fn invalid_imported_functions_form__closure_with_vmctx_and_env() { + let p = 1; + let _func = Func::new(move |_vmctx: &mut vm::Ctx, n: i32| -> Result { Ok(n + p) }); +} + +fn callback_fn(n: i32) -> Result { + Ok(n + 1) +} + +fn callback_fn_with_vmctx(vmctx: &mut vm::Ctx, n: i32) -> Result { + let memory = vmctx.memory(0); + let shift: i32 = memory.view()[0].get(); + + Ok(shift + n + 1) +} + +fn callback_fn_trap(n: i32) -> Result { + Err(format!("foo {}", n)) +} + +fn callback_fn_trap_with_vmctx(vmctx: &mut vm::Ctx, n: i32) -> Result { + let memory = vmctx.memory(0); + let shift: i32 = memory.view()[0].get(); + + Err(format!("baz {}", shift + n + 1)) +} diff --git a/lib/runtime-core/src/backing.rs b/lib/runtime-core/src/backing.rs index ff21e9195f1..a6472feb0e1 100644 --- a/lib/runtime-core/src/backing.rs +++ b/lib/runtime-core/src/backing.rs @@ -15,14 +15,14 @@ use crate::{ }, vm, }; -use std::{fmt::Debug, slice}; +use std::{fmt, fmt::Debug, ptr, slice}; pub const INTERNALS_SIZE: usize = 256; pub(crate) struct Internals(pub(crate) [u64; INTERNALS_SIZE]); impl Debug for Internals { - fn fmt(&self, formatter: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { write!(formatter, "Internals({:?})", &self.0[..]) } } @@ -365,13 +365,12 @@ impl LocalBacking { table.anyfunc_direct_access_mut(|elements| { for (i, &func_index) in init.elements.iter().enumerate() { let sig_index = module.info.func_assoc[func_index]; - // let signature = &module.info.signatures[sig_index]; let signature = SigRegistry .lookup_signature_ref(&module.info.signatures[sig_index]); let sig_id = vm::SigId(SigRegistry.lookup_sig_index(signature).index() as u32); - let (func, ctx) = match func_index.local_or_import(&module.info) { + let (func, func_env) = match func_index.local_or_import(&module.info) { LocalOrImport::Local(local_func_index) => ( module .runnable_module @@ -379,16 +378,21 @@ impl LocalBacking { .unwrap() .as_ptr() as *const vm::Func, - vmctx, + vmctx as *mut vm::FuncEnv, ), LocalOrImport::Import(imported_func_index) => { - let vm::ImportedFunc { func, vmctx } = + let vm::ImportedFunc { func, func_env } = imports.vm_functions[imported_func_index]; - (func, vmctx) + + (func, func_env) } }; - elements[init_base + i] = vm::Anyfunc { func, ctx, sig_id }; + elements[init_base + i] = vm::Anyfunc { + func, + func_env, + sig_id, + }; } }); } @@ -400,11 +404,10 @@ impl LocalBacking { let sig_index = module.info.func_assoc[func_index]; let signature = SigRegistry .lookup_signature_ref(&module.info.signatures[sig_index]); - // let signature = &module.info.signatures[sig_index]; let sig_id = vm::SigId(SigRegistry.lookup_sig_index(signature).index() as u32); - let (func, ctx) = match func_index.local_or_import(&module.info) { + let (func, env) = match func_index.local_or_import(&module.info) { LocalOrImport::Local(local_func_index) => ( module .runnable_module @@ -412,16 +415,21 @@ impl LocalBacking { .unwrap() .as_ptr() as *const vm::Func, - vmctx, + vmctx as *mut vm::FuncEnv, ), LocalOrImport::Import(imported_func_index) => { - let vm::ImportedFunc { func, vmctx } = + let vm::ImportedFunc { func, func_env } = imports.vm_functions[imported_func_index]; - (func, vmctx) + + (func, func_env) } }; - elements[init_base + i] = vm::Anyfunc { func, ctx, sig_id }; + elements[init_base + i] = vm::Anyfunc { + func, + func_env: env, + sig_id, + }; } }); } @@ -527,7 +535,6 @@ impl ImportBacking { memories, tables, globals, - vm_functions, vm_memories, vm_tables, @@ -564,6 +571,7 @@ fn import_functions( let import = imports.maybe_with_namespace(namespace, |namespace| namespace.get_export(name)); + match import { Some(Export::Function { func, @@ -573,9 +581,9 @@ fn import_functions( if *expected_sig == *signature { functions.push(vm::ImportedFunc { func: func.inner(), - vmctx: match ctx { - Context::External(ctx) => ctx, - Context::Internal => vmctx, + func_env: match ctx { + Context::External(func_env) => func_env, + Context::Internal => vmctx as *mut vm::FuncEnv, }, }); } else { @@ -605,8 +613,8 @@ fn import_functions( None => { if imports.allow_missing_functions { functions.push(vm::ImportedFunc { - func: ::std::ptr::null(), - vmctx: ::std::ptr::null_mut(), + func: ptr::null(), + func_env: ptr::null_mut(), }); } else { link_errors.push(LinkError::ImportNotFound { diff --git a/lib/runtime-core/src/export.rs b/lib/runtime-core/src/export.rs index 7960d76e699..55c456286a4 100644 --- a/lib/runtime-core/src/export.rs +++ b/lib/runtime-core/src/export.rs @@ -7,7 +7,7 @@ use std::sync::Arc; #[derive(Debug, Copy, Clone)] pub enum Context { - External(*mut vm::Ctx), + External(*mut vm::FuncEnv), Internal, } diff --git a/lib/runtime-core/src/import.rs b/lib/runtime-core/src/import.rs index 9d86205b156..6d13f40521c 100644 --- a/lib/runtime-core/src/import.rs +++ b/lib/runtime-core/src/import.rs @@ -40,7 +40,7 @@ impl IsExport for Export { /// }, /// }; /// -/// fn foo(_: &mut Ctx, n: i32) -> i32 { +/// fn foo(n: i32) -> i32 { /// n /// } /// ``` diff --git a/lib/runtime-core/src/instance.rs b/lib/runtime-core/src/instance.rs index 85e9f8f768b..f7522a7e7b6 100644 --- a/lib/runtime-core/src/instance.rs +++ b/lib/runtime-core/src/instance.rs @@ -96,24 +96,26 @@ impl Instance { // 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 (func_ptr, func_env_ptr): (_, Option>) = + 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(), + NonNull::new(instance.inner.vmctx).map(|pointer| pointer.cast()), + ), + LocalOrImport::Import(imported_func_index) => { + let imported_func = + &instance.inner.import_backing.vm_functions[imported_func_index]; + + ( + NonNull::new(imported_func.func as *mut _).unwrap(), + NonNull::new(imported_func.func_env), + ) + } + }; let sig_index = *instance .module @@ -128,8 +130,14 @@ impl Instance { .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) }; + let start_func: Func<(), (), Wasm> = unsafe { + Func::from_raw_parts( + wasm_trampoline, + func_ptr, + func_env_ptr, + NonNull::new(instance.inner.vmctx), + ) + }; start_func.call()?; } @@ -193,33 +201,40 @@ impl Instance { })?; } - let ctx = 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 func_wasm_inner = self .module .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 - .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 _, - ) - .unwrap(), + let (func_ptr, func_env_ptr): (_, Option>) = match func_index + .local_or_import(&self.module.info) + { + LocalOrImport::Local(local_func_index) => ( + self.module + .runnable_module + .get_func(&self.module.info, local_func_index) + .unwrap(), + NonNull::new(self.inner.vmctx).map(|pointer| pointer.cast()), + ), + LocalOrImport::Import(import_func_index) => { + let imported_func = &self.inner.import_backing.vm_functions[import_func_index]; + + ( + NonNull::new(imported_func.func as *mut _).unwrap(), + NonNull::new(imported_func.func_env), + ) + } }; - let typed_func: Func = - unsafe { Func::from_raw_parts(func_wasm_inner, func_ptr, ctx) }; + let typed_func: Func = unsafe { + Func::from_raw_parts( + func_wasm_inner, + func_ptr, + func_env_ptr, + NonNull::new(self.inner.vmctx), + ) + }; Ok(typed_func) } else { @@ -345,7 +360,7 @@ impl Instance { &self.module.info, &*self.module.runnable_module, &self.inner.import_backing, - self.inner.vmctx, + NonNull::new(self.inner.vmctx), func_index, params, &mut results, @@ -403,7 +418,7 @@ impl InstanceInner { Export::Function { func, ctx: match ctx { - Context::Internal => Context::External(self.vmctx), + Context::Internal => Context::External(self.vmctx as *mut vm::FuncEnv), ctx @ Context::External(_) => ctx, }, signature, @@ -447,15 +462,15 @@ impl InstanceInner { ), LocalOrImport::Import(imported_func_index) => { let imported_func = &self.import_backing.vm_functions[imported_func_index]; + ( imported_func.func as *const _, - Context::External(imported_func.vmctx), + Context::External(imported_func.func_env), ) } }; let signature = SigRegistry.lookup_signature_ref(&module.info.signatures[sig_index]); - // let signature = &module.info.signatures[sig_index]; (unsafe { FuncPointer::new(func_ptr) }, ctx, signature) } @@ -551,7 +566,7 @@ fn call_func_with_index( info: &ModuleInfo, runnable: &dyn RunnableModule, import_backing: &ImportBacking, - local_ctx: *mut vm::Ctx, + vmctx: Option>, func_index: FuncIndex, args: &[Value], rets: &mut Vec, @@ -563,31 +578,32 @@ fn call_func_with_index( let signature = &info.signatures[sig_index]; - 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 (func_ptr, func_env_ptr): (_, Option>) = + match func_index.local_or_import(info) { + LocalOrImport::Local(local_func_index) => ( + runnable.get_func(info, local_func_index).unwrap(), + vmctx.map(|pointer| pointer.cast()), + ), + LocalOrImport::Import(import_func_index) => { + let imported_func = &import_backing.vm_functions[import_func_index]; - 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 - } - }; + ( + NonNull::new(imported_func.func as *mut _).unwrap(), + NonNull::new(imported_func.func_env), + ) + } + }; let wasm = runnable .get_trampoline(info, sig_index) .expect("wasm trampoline"); - call_func_with_index_inner(ctx_ptr, func_ptr, signature, wasm, args, rets) + call_func_with_index_inner(vmctx, func_env_ptr, func_ptr, signature, wasm, args, rets) } pub(crate) fn call_func_with_index_inner( - ctx_ptr: *mut vm::Ctx, + vmctx: Option>, + func_env_ptr: Option>, func_ptr: NonNull, signature: &FuncSig, wasm: Wasm, @@ -651,7 +667,8 @@ pub(crate) fn call_func_with_index_inner( let success = invoke( trampoline, - ctx_ptr, + vmctx, + func_env_ptr, func_ptr, raw_args.as_ptr(), result_space, @@ -765,7 +782,7 @@ impl<'a> DynFunc<'a> { &self.module.info, &*self.module.runnable_module, &self.instance_inner.import_backing, - self.instance_inner.vmctx, + NonNull::new(self.instance_inner.vmctx), self.func_index, params, &mut results, diff --git a/lib/runtime-core/src/macros.rs b/lib/runtime-core/src/macros.rs index 6dbb93ca09c..d5a81f7d4c4 100644 --- a/lib/runtime-core/src/macros.rs +++ b/lib/runtime-core/src/macros.rs @@ -69,7 +69,7 @@ macro_rules! func { /// }, /// }; /// -/// fn foo(_: &mut Ctx, n: i32) -> i32 { +/// fn foo(n: i32) -> i32 { /// n /// } /// ``` diff --git a/lib/runtime-core/src/table/anyfunc.rs b/lib/runtime-core/src/table/anyfunc.rs index 4a63c8f6249..f76ba0b4e49 100644 --- a/lib/runtime-core/src/table/anyfunc.rs +++ b/lib/runtime-core/src/table/anyfunc.rs @@ -6,12 +6,12 @@ use crate::{ types::{FuncSig, TableDescriptor}, vm, }; - -use std::{ptr, sync::Arc}; +use std::sync::Arc; enum AnyfuncInner<'a> { Host { ptr: *const vm::Func, + env: *mut vm::FuncEnv, signature: Arc, }, Managed(DynFunc<'a>), @@ -22,13 +22,14 @@ pub struct Anyfunc<'a> { } impl<'a> Anyfunc<'a> { - pub unsafe fn new(func: *const vm::Func, signature: Sig) -> Self + pub unsafe fn new(func: *const vm::Func, env: *mut vm::FuncEnv, signature: Sig) -> Self where Sig: Into>, { Self { inner: AnyfuncInner::Host { ptr: func as _, + env, signature: signature.into(), }, } @@ -99,13 +100,17 @@ impl AnyfuncTable { pub fn set(&mut self, index: u32, element: Anyfunc) -> Result<(), ()> { if let Some(slot) = self.backing.get_mut(index as usize) { let anyfunc = match element.inner { - AnyfuncInner::Host { ptr, signature } => { + AnyfuncInner::Host { + ptr, + env, + signature, + } => { let sig_index = SigRegistry.lookup_sig_index(signature); let sig_id = vm::SigId(sig_index.index() as u32); vm::Anyfunc { func: ptr, - ctx: ptr::null_mut(), + func_env: env, sig_id, } } @@ -115,7 +120,7 @@ impl AnyfuncTable { vm::Anyfunc { func: func.raw(), - ctx: func.instance_inner.vmctx, + func_env: func.instance_inner.vmctx as _, // cast `*mut vm::Ctx` to `*mut vm::FuncEnv` sig_id, } } diff --git a/lib/runtime-core/src/typed_func.rs b/lib/runtime-core/src/typed_func.rs index 74318747c2f..abff94b39f1 100644 --- a/lib/runtime-core/src/typed_func.rs +++ b/lib/runtime-core/src/typed_func.rs @@ -3,16 +3,10 @@ use crate::{ export::{Context, Export, FuncPointer}, import::IsExport, types::{FuncSig, NativeWasmType, Type, WasmExternType}, - vm::{self, Ctx}, + vm, }; use std::{ - any::Any, - convert::Infallible, - ffi::c_void, - fmt, - marker::PhantomData, - mem, panic, - ptr::{self, NonNull}, + any::Any, convert::Infallible, ffi::c_void, fmt, marker::PhantomData, mem, panic, ptr::NonNull, sync::Arc, }; @@ -52,16 +46,23 @@ impl fmt::Display for WasmTrapInfo { /// of the `Func` struct. pub trait Kind {} -pub type Trampoline = unsafe extern "C" fn(*mut Ctx, NonNull, *const u64, *mut u64); +pub type Trampoline = unsafe extern "C" fn( + func_env: Option>, + func: NonNull, + args: *const u64, + rets: *mut u64, +); + pub type Invoke = unsafe extern "C" fn( - Trampoline, - *mut Ctx, - NonNull, - *const u64, - *mut u64, - *mut WasmTrapInfo, - *mut Option>, - Option>, + trampoline: Trampoline, + vmctx: Option>, + func_env: Option>, + func: NonNull, + args: *const u64, + rets: *mut u64, + trap_info: *mut WasmTrapInfo, + user_error: *mut Option>, + extra: Option>, ) -> bool; /// TODO(lachlan): Naming TBD. @@ -122,22 +123,32 @@ pub trait WasmTypeList { /// directly in the code, see the `Func:call` implementation. unsafe fn call( self, - f: NonNull, + func: NonNull, + func_env: Option>, + vmctx: Option>, wasm: Wasm, - ctx: *mut Ctx, ) -> Result where Rets: WasmTypeList; } +pub trait ExternalFunctionKind {} + +pub struct ExplicitVmCtx(); +pub struct ClosedEnvironment(); + +impl ExternalFunctionKind for ExplicitVmCtx {} +impl ExternalFunctionKind for ClosedEnvironment {} + /// Represents a function that can be converted to a `vm::Func` /// (function pointer) that can be called within WebAssembly. -pub trait ExternalFunction +pub trait ExternalFunction where + Kind: ExternalFunctionKind, Args: WasmTypeList, Rets: WasmTypeList, { - fn to_raw(&self) -> NonNull; + fn to_raw(self) -> (NonNull, Option>); } pub trait TrapEarly @@ -172,8 +183,9 @@ where /// Represents a function that can be used by WebAssembly. pub struct Func<'a, Args = (), Rets = (), Inner: Kind = Wasm> { inner: Inner, - f: NonNull, - ctx: *mut Ctx, + func: NonNull, + func_env: Option>, + vmctx: Option>, _phantom: PhantomData<(&'a (), Args, Rets)>, } @@ -187,19 +199,21 @@ where { pub(crate) unsafe fn from_raw_parts( inner: Wasm, - f: NonNull, - ctx: *mut Ctx, + func: NonNull, + func_env: Option>, + vmctx: Option>, ) -> Func<'a, Args, Rets, Wasm> { Func { inner, - f, - ctx, + func, + func_env, + vmctx, _phantom: PhantomData, } } pub fn get_vm_func(&self) -> NonNull { - self.f + self.func } } @@ -208,14 +222,18 @@ where Args: WasmTypeList, Rets: WasmTypeList, { - pub fn new(f: F) -> Func<'a, Args, Rets, Host> + pub fn new(func: F) -> Func<'a, Args, Rets, Host> where - F: ExternalFunction, + Kind: ExternalFunctionKind, + F: ExternalFunction, { + let (func, func_env) = func.to_raw(); + Func { inner: Host(()), - f: f.to_raw(), - ctx: ptr::null_mut(), + func, + func_env, + vmctx: None, _phantom: PhantomData, } } @@ -266,8 +284,9 @@ impl WasmTypeList for Infallible { unsafe fn call( self, _: NonNull, + _: Option>, + _: Option>, _: Wasm, - _: *mut Ctx, ) -> Result where Rets: WasmTypeList, @@ -276,86 +295,6 @@ impl WasmTypeList for Infallible { } } -impl WasmTypeList for (A,) -where - A: WasmExternType, -{ - type CStruct = S1; - type RetArray = [u64; 1]; - - fn from_ret_array(array: Self::RetArray) -> Self { - (WasmExternType::from_native(NativeWasmType::from_binary( - array[0], - )),) - } - - fn empty_ret_array() -> Self::RetArray { - [0u64] - } - - fn from_c_struct(c_struct: Self::CStruct) -> Self { - let S1(a) = c_struct; - (WasmExternType::from_native(a),) - } - - fn into_c_struct(self) -> Self::CStruct { - #[allow(unused_parens, non_snake_case)] - let (a,) = self; - S1(WasmExternType::to_native(a)) - } - - fn types() -> &'static [Type] { - &[A::Native::TYPE] - } - - #[allow(non_snake_case)] - unsafe fn call( - self, - f: NonNull, - wasm: Wasm, - ctx: *mut Ctx, - ) -> Result - where - Rets: WasmTypeList, - { - let (a,) = self; - let args = [a.to_native().to_binary()]; - let mut rets = Rets::empty_ret_array(); - let mut trap = WasmTrapInfo::Unknown; - let mut user_error = None; - - if (wasm.invoke)( - wasm.trampoline, - ctx, - f, - args.as_ptr(), - rets.as_mut().as_mut_ptr(), - &mut trap, - &mut user_error, - wasm.invoke_env, - ) { - Ok(Rets::from_ret_array(rets)) - } else { - if let Some(data) = user_error { - Err(RuntimeError::Error { data }) - } else { - Err(RuntimeError::Trap { - msg: trap.to_string().into(), - }) - } - } - } -} - -impl<'a, A: WasmExternType, Rets> Func<'a, (A,), Rets, Wasm> -where - Rets: WasmTypeList, -{ - pub fn call(&self, a: A) -> Result { - unsafe { ::call(a, self.f, self.inner, self.ctx) } - } -} - macro_rules! impl_traits { ( [$repr:ident] $struct_name:ident, $( $x:ident ),* ) => { #[repr($repr)] @@ -403,24 +342,26 @@ macro_rules! impl_traits { #[allow(non_snake_case)] unsafe fn call( self, - f: NonNull, + func: NonNull, + func_env: Option>, + vmctx: Option>, wasm: Wasm, - ctx: *mut Ctx, ) -> Result where Rets: WasmTypeList { #[allow(unused_parens)] let ( $( $x ),* ) = self; - let args = [ $( $x.to_native().to_binary()),* ]; + let args = [ $( $x.to_native().to_binary() ),* ]; let mut rets = Rets::empty_ret_array(); let mut trap = WasmTrapInfo::Unknown; let mut user_error = None; if (wasm.invoke)( wasm.trampoline, - ctx, - f, + vmctx, + func_env, + func, args.as_ptr(), rets.as_mut().as_mut_ptr(), &mut trap, @@ -438,33 +379,148 @@ macro_rules! impl_traits { } } - impl< $( $x, )* Rets, Trap, FN > ExternalFunction<( $( $x ),* ), Rets> for FN + impl<'a $( , $x )*, Rets> Func<'a, ( $( $x ),* ), Rets, Wasm> + where + $( $x: WasmExternType, )* + Rets: WasmTypeList, + { + #[allow(non_snake_case)] + pub fn call(&self, $( $x: $x, )* ) -> Result { + #[allow(unused_parens)] + unsafe { + <( $( $x ),* ) as WasmTypeList>::call( + ( $( $x ),* ), + self.func, + self.func_env, + self.vmctx, + self.inner, + ) + } + } + } + + // Generic implementation for `Fn` (without `&mut Ctx` as first argument). + impl< $( $x, )* Rets, Trap, FN > ExternalFunction for FN + where + $( $x: WasmExternType, )* + Rets: WasmTypeList, + Trap: TrapEarly, + FN: Fn( $( $x ),* ) -> Trap + 'static, + { + #[allow(non_snake_case)] + fn to_raw(self) -> (NonNull, Option>) { + let env: Option> = + // `FN` is a function pointer, or a closure + // _without_ a captured environment. + if mem::size_of::() == 0 { + None + } + // `FN` is a closure _with_ a captured + // environment. Grab it. + else { + NonNull::new(Box::leak(Box::new(self))).map(|pointer| pointer.cast()) + }; + + // This is required for the LLVM backend to be able to + // unwind through this function. + #[cfg_attr(nightly, unwind(allowed))] + extern fn wrap<$( $x, )* Rets, Trap, FN>( + env: *mut vm::FuncEnv + $( , $x: <$x as WasmExternType>::Native )* + ) -> Rets::CStruct + where + $( $x: WasmExternType, )* + Rets: WasmTypeList, + Trap: TrapEarly, + FN: Fn( $( $x ),* ) -> Trap + 'static, + { + let (func, vmctx): (&FN, Option<&mut vm::Ctx>) = + // `FN` is a function pointer, or a closure + // _without_ a captured + // environment. Consequently `env` holds a + // pointer to `vm::Ctx`. + if mem::size_of::() == 0 { + ( + unsafe { mem::transmute(&()) }, + Some(unsafe { &mut *(env as *mut vm::Ctx) }), + ) + } + // `FN` is a closure _with_ a captured + // environment. `env` effectively represents + // the closure environment, and we don't have + // a pointer to `vm::Ctx`. + else { + ( + unsafe { &*(env as *const FN) }, + None + ) + }; + + let err = match panic::catch_unwind( + panic::AssertUnwindSafe( + || { + func( $( WasmExternType::from_native($x) ),* ).report() + } + ) + ) { + Ok(Ok(returns)) => return returns.into_c_struct(), + Ok(Err(err)) => { + let b: Box<_> = err.into(); + b as Box + }, + Err(err) => err, + }; + + match vmctx { + Some(vmctx) => { + unsafe { (&*vmctx.module).runnable_module.do_early_trap(err) } + }, + None => { + eprintln!("yolo"); + ::std::process::exit(1) + } + } + } + + ( + NonNull::new(wrap::<$( $x, )* Rets, Trap, Self> as *mut vm::Func).unwrap(), + env, + ) + } + } + + // Specific implementation for `Fn` (with a `&mut Ctx` as first argument). + impl< $( $x, )* Rets, Trap, FN > ExternalFunction for FN where $( $x: WasmExternType, )* Rets: WasmTypeList, Trap: TrapEarly, - FN: Fn(&mut Ctx $( , $x )*) -> Trap, + FN: Fn( &mut vm::Ctx $( , $x )* ) -> Trap + 'static, { #[allow(non_snake_case)] - fn to_raw(&self) -> NonNull { + fn to_raw(self) -> (NonNull, Option>) { + // `FN` is a function pointer, or a closure _without_ + // a captured environment. if mem::size_of::() == 0 { - /// This is required for the llvm backend to be able to unwind through this function. + // This is required for the LLVM backend to be + // able to unwind through this function. #[cfg_attr(nightly, unwind(allowed))] extern fn wrap<$( $x, )* Rets, Trap, FN>( - ctx: &mut Ctx $( , $x: <$x as WasmExternType>::Native )* + vmctx: &mut vm::Ctx + $( , $x: <$x as WasmExternType>::Native )* ) -> Rets::CStruct where $( $x: WasmExternType, )* Rets: WasmTypeList, Trap: TrapEarly, - FN: Fn(&mut Ctx $( , $x )*) -> Trap, + FN: Fn( &mut vm::Ctx $( , $x )* ) -> Trap + 'static, { - let f: FN = unsafe { mem::transmute_copy(&()) }; + let func: FN = unsafe { mem::transmute_copy(&()) }; let err = match panic::catch_unwind( panic::AssertUnwindSafe( || { - f(ctx $( , WasmExternType::from_native($x) )* ).report() + func(vmctx $( , WasmExternType::from_native($x) )* ).report() } ) ) { @@ -477,41 +533,27 @@ macro_rules! impl_traits { }; unsafe { - (&*ctx.module).runnable_module.do_early_trap(err) + (&*vmctx.module).runnable_module.do_early_trap(err) } } - NonNull::new(wrap::<$( $x, )* Rets, Trap, Self> as *mut vm::Func).unwrap() - } else { - assert_eq!( - mem::size_of::(), - mem::size_of::(), - "you cannot use a closure that captures state for `Func`." - ); - - NonNull::new(unsafe { - ::std::mem::transmute_copy::<_, *mut vm::Func>(self) - }).unwrap() - } - } - } - - impl<'a $( , $x )*, Rets> Func<'a, ( $( $x ),* ), Rets, Wasm> - where - $( $x: WasmExternType, )* - Rets: WasmTypeList, - { - #[allow(non_snake_case)] - pub fn call(&self, $( $x: $x, )* ) -> Result { - #[allow(unused_parens)] - unsafe { - <( $( $x ),* ) as WasmTypeList>::call( - ( $( $x ),* ), - self.f, - self.inner, - self.ctx + ( + NonNull::new(wrap::<$( $x, )* Rets, Trap, Self> as *mut vm::Func).unwrap(), + None, ) } + // `FN` is a closure _with_ a captured + // environment. Since it also has a `&mut vm::Ctx` as + // its first argument, `vm::FuncEnv` has 2 pointers to + // hold, and it is impossible (it represents only 1 + // pointer). It is OK-ish to panic: It happens during + // runtime (at compile-time would be far better) but + // it happens when `Func::new` is called, so when the + // import object is built, which happens before the + // module instantiation and its execution. + else { + panic!("A closure cannot capture its environment while having `&mut vm::Ctx` as its first argument."); + } } } }; @@ -547,8 +589,12 @@ where Inner: Kind, { fn to_export(&self) -> Export { - let func = unsafe { FuncPointer::new(self.f.as_ptr()) }; - let ctx = Context::Internal; + let func = unsafe { FuncPointer::new(self.func.as_ptr()) }; + let ctx = if let Some(ptr) = self.func_env { + Context::External(ptr.cast().as_ptr()) + } else { + Context::Internal + }; let signature = Arc::new(FuncSig::new(Args::types(), Rets::types())); Export::Function { @@ -562,24 +608,73 @@ where #[cfg(test)] mod tests { use super::*; + + macro_rules! test_func_arity_n { + ($test_name:ident, $($x:ident),*) => { + #[test] + fn $test_name() { + use crate::vm; + + fn without_vmctx($($x: i32),*) -> i32 { + vec![$($x),*].iter().sum() + } + + fn with_vmctx(_: &mut vm::Ctx, $($x: i32),*) -> i32 { + vec![$($x),*].iter().sum() + } + + let _func = Func::new(without_vmctx); + let _func = Func::new(with_vmctx); + let _func = Func::new(|$($x: i32),*| -> i32 { + vec![$($x),*].iter().sum() + }); + let _func = Func::new(|_: &mut vm::Ctx, $($x: i32),*| -> i32 { + vec![$($x),*].iter().sum() + }); + } + } + } + + #[test] + fn test_func_arity_0() { + fn foo() -> i32 { + 0 + } + + let _ = Func::new(foo); + } + + test_func_arity_n!(test_func_arity_1, a); + test_func_arity_n!(test_func_arity_2, a, b); + test_func_arity_n!(test_func_arity_3, a, b, c); + test_func_arity_n!(test_func_arity_4, a, b, c, d); + test_func_arity_n!(test_func_arity_5, a, b, c, d, e); + test_func_arity_n!(test_func_arity_6, a, b, c, d, e, f); + test_func_arity_n!(test_func_arity_7, a, b, c, d, e, f, g); + test_func_arity_n!(test_func_arity_8, a, b, c, d, e, f, g, h); + test_func_arity_n!(test_func_arity_9, a, b, c, d, e, f, g, h, i); + test_func_arity_n!(test_func_arity_10, a, b, c, d, e, f, g, h, i, j); + test_func_arity_n!(test_func_arity_11, a, b, c, d, e, f, g, h, i, j, k); + test_func_arity_n!(test_func_arity_12, a, b, c, d, e, f, g, h, i, j, k, l); + #[test] fn test_call() { - fn foo(_ctx: &mut Ctx, a: i32, b: i32) -> (i32, i32) { + fn foo(a: i32, b: i32) -> (i32, i32) { (a, b) } - let _f = Func::new(foo); + let _ = Func::new(foo); } #[test] fn test_imports() { use crate::{func, imports}; - fn foo(_ctx: &mut Ctx, a: i32) -> i32 { + fn foo(a: i32) -> i32 { a } - let _import_object = imports! { + let _ = imports! { "env" => { "foo" => func!(foo), }, diff --git a/lib/runtime-core/src/vm.rs b/lib/runtime-core/src/vm.rs index fd8cebbec9a..0ce78487ff3 100644 --- a/lib/runtime-core/src/vm.rs +++ b/lib/runtime-core/src/vm.rs @@ -406,7 +406,11 @@ impl Ctx { ) -> CallResult> { let anyfunc_table = unsafe { &*((**self.internal.tables).table as *mut crate::table::AnyfuncTable) }; - let Anyfunc { func, ctx, sig_id } = anyfunc_table.backing[index.index()]; + let Anyfunc { + func, + func_env, + sig_id, + } = anyfunc_table.backing[index.index()]; let signature = SigRegistry.lookup_signature(unsafe { std::mem::transmute(sig_id.0) }); let mut rets = vec![]; @@ -422,7 +426,8 @@ impl Ctx { }; call_func_with_index_inner( - ctx, + None, + NonNull::new(func_env), NonNull::new(func as *mut _).unwrap(), &signature, wasm, @@ -498,22 +503,25 @@ impl Ctx { } } -enum InnerFunc {} /// Used to provide type safety (ish) for passing around function pointers. -/// The typesystem ensures this cannot be dereferenced since an -/// empty enum cannot actually exist. #[repr(C)] -pub struct Func(InnerFunc); +pub struct Func { + _private: [u8; 0], +} + +#[repr(C)] +pub struct FuncEnv { + _private: [u8; 0], +} -/// An imported function, which contains the vmctx that owns this function. +/// An imported function, which contains an environment. #[derive(Debug, Clone)] #[repr(C)] pub struct ImportedFunc { pub func: *const Func, - pub vmctx: *mut Ctx, + pub func_env: *mut FuncEnv, } -// manually implemented because ImportedFunc contains raw pointers directly; `Func` is marked Send (But `Ctx` actually isn't! (TODO: review this, shouldn't `Ctx` be Send?)) unsafe impl Send for ImportedFunc {} impl ImportedFunc { @@ -522,7 +530,7 @@ impl ImportedFunc { 0 * (mem::size_of::() as u8) } - pub fn offset_vmctx() -> u8 { + pub fn offset_func_env() -> u8 { 1 * (mem::size_of::() as u8) } @@ -624,7 +632,7 @@ pub struct SigId(pub u32); #[repr(C)] pub struct Anyfunc { pub func: *const Func, - pub ctx: *mut Ctx, + pub func_env: *mut FuncEnv, pub sig_id: SigId, } @@ -635,7 +643,7 @@ impl Anyfunc { pub fn null() -> Self { Self { func: ptr::null(), - ctx: ptr::null_mut(), + func_env: ptr::null_mut(), sig_id: SigId(u32::max_value()), } } @@ -645,7 +653,7 @@ impl Anyfunc { 0 * (mem::size_of::() as u8) } - pub fn offset_vmctx() -> u8 { + pub fn offset_func_env() -> u8 { 1 * (mem::size_of::() as u8) } @@ -745,8 +753,8 @@ mod vm_offset_tests { ); assert_eq!( - ImportedFunc::offset_vmctx() as usize, - offset_of!(ImportedFunc => vmctx).get_byte_offset(), + ImportedFunc::offset_func_env() as usize, + offset_of!(ImportedFunc => func_env).get_byte_offset(), ); } @@ -792,8 +800,8 @@ mod vm_offset_tests { ); assert_eq!( - Anyfunc::offset_vmctx() as usize, - offset_of!(Anyfunc => ctx).get_byte_offset(), + Anyfunc::offset_func_env() as usize, + offset_of!(Anyfunc => func_env).get_byte_offset(), ); assert_eq!( diff --git a/lib/singlepass-backend/src/codegen_x64.rs b/lib/singlepass-backend/src/codegen_x64.rs index c2543b987d8..ea5b1426c46 100644 --- a/lib/singlepass-backend/src/codegen_x64.rs +++ b/lib/singlepass-backend/src/codegen_x64.rs @@ -10,6 +10,7 @@ use std::ptr::NonNull; use std::{ any::Any, collections::{BTreeMap, HashMap}, + mem, ptr, sync::{Arc, RwLock}, }; use wasmer_runtime_core::{ @@ -38,7 +39,7 @@ use wasmparser::{MemoryImmediate, Operator, Type as WpType, TypeOrFuncType as Wp lazy_static! { /// Performs a System V call to `target` with [stack_top..stack_base] as the argument list, from right to left. - static ref CONSTRUCT_STACK_AND_CALL_WASM: unsafe extern "C" fn (stack_top: *const u64, stack_base: *const u64, ctx: *mut vm::Ctx, target: *const vm::Func) -> u64 = { + static ref CONSTRUCT_STACK_AND_CALL_WASM: unsafe extern "C" fn (stack_top: *const u64, stack_base: *const u64, func_env: *mut vm::FuncEnv, target: *const vm::Func) -> u64 = { let mut assembler = Assembler::new().unwrap(); let offset = assembler.offset(); dynasm!( @@ -56,7 +57,7 @@ lazy_static! { ; mov r13, rdx ; mov r12, rcx - ; mov rdi, r13 // ctx + ; mov rdi, r13 // func_env ; sub r14, 8 ; cmp r14, r15 @@ -118,8 +119,8 @@ lazy_static! { ; ret ); let buf = assembler.finalize().unwrap(); - let ret = unsafe { ::std::mem::transmute(buf.ptr(offset)) }; - ::std::mem::forget(buf); + let ret = unsafe { mem::transmute(buf.ptr(offset)) }; + mem::forget(buf); ret }; } @@ -255,17 +256,13 @@ impl RunnableModule for X64ExecutionContext { } fn get_trampoline(&self, _: &ModuleInfo, sig_index: SigIndex) -> Option { - use std::ffi::c_void; - use wasmer_runtime_core::typed_func::WasmTrapInfo; + use std::{ffi::c_void, slice}; + use wasmer_runtime_core::typed_func::{Trampoline, WasmTrapInfo}; unsafe extern "C" fn invoke( - _trampoline: unsafe extern "C" fn( - *mut vm::Ctx, - NonNull, - *const u64, - *mut u64, - ), - ctx: *mut vm::Ctx, + _trampoline: Trampoline, + vmctx: Option>, + func_env: Option>, func: NonNull, args: *const u64, rets: *mut u64, @@ -273,21 +270,24 @@ impl RunnableModule for X64ExecutionContext { user_error: *mut Option>, num_params_plus_one: Option>, ) -> bool { - let rm: &Box = &(&*(*ctx).module).runnable_module; + let vmctx: &vm::Ctx = vmctx + .map(|pointer| &*pointer.as_ptr()) + .expect("vmctx is null"); + let rm: &Box = &(*(vmctx.module)).runnable_module; let execution_context = - ::std::mem::transmute_copy::<&dyn RunnableModule, &X64ExecutionContext>(&&**rm); + mem::transmute_copy::<&dyn RunnableModule, &X64ExecutionContext>(&&**rm); - let args = std::slice::from_raw_parts( - args, - num_params_plus_one.unwrap().as_ptr() as usize - 1, - ); + let args = + slice::from_raw_parts(args, num_params_plus_one.unwrap().as_ptr() as usize - 1); let args_reverse: SmallVec<[u64; 8]> = args.iter().cloned().rev().collect(); let ret = match protect_unix::call_protected( || { CONSTRUCT_STACK_AND_CALL_WASM( args_reverse.as_ptr(), args_reverse.as_ptr().offset(args_reverse.len() as isize), - ctx, + func_env + .map(|pointer| pointer.as_ptr()) + .unwrap_or_else(ptr::null_mut), func.as_ptr(), ) }, @@ -311,7 +311,7 @@ impl RunnableModule for X64ExecutionContext { } unsafe extern "C" fn dummy_trampoline( - _: *mut vm::Ctx, + _: Option>, _: NonNull, _: *const u64, _: *mut u64, diff --git a/lib/spectests/examples/test.rs b/lib/spectests/examples/test.rs index 8ce199695fc..006fc1397d2 100644 --- a/lib/spectests/examples/test.rs +++ b/lib/spectests/examples/test.rs @@ -1,5 +1,4 @@ use wabt::wat2wasm; -use wasmer_clif_backend::CraneliftCompiler; use wasmer_runtime_core::{backend::Compiler, import::ImportObject, Instance}; fn main() { diff --git a/lib/spectests/tests/spectest.rs b/lib/spectests/tests/spectest.rs index 62bfc7d5381..a49e866e1fd 100644 --- a/lib/spectests/tests/spectest.rs +++ b/lib/spectests/tests/spectest.rs @@ -721,7 +721,7 @@ mod tests { CommandKind::AssertUninstantiable { module: _, message: _, - } => println!("AssertUninstantiable not yet implmented "), + } => println!("AssertUninstantiable not yet implemented "), CommandKind::AssertExhaustion { action, message: _ } => { match action { Action::Invoke { diff --git a/lib/win-exception-handler/exception_handling/exception_handling.c b/lib/win-exception-handler/exception_handling/exception_handling.c index c3ecbab1d74..47ad2809f90 100644 --- a/lib/win-exception-handler/exception_handling/exception_handling.c +++ b/lib/win-exception-handler/exception_handling/exception_handling.c @@ -49,13 +49,14 @@ static void removeExceptionHandler() { exceptionHandlerInstalled = FALSE; } -uint8_t callProtected(trampoline_t trampoline, - const struct wasmer_instance_context_t* ctx, - const struct func_t* func, - const uint64_t* param_vec, - uint64_t* return_vec, - struct call_protected_result_t* out_result) { - +uint8_t callProtected( + trampoline_t trampoline, + const funcenv_t* func_env, + const func_t* func, + const uint64_t* param_vec, + uint64_t* return_vec, + call_protected_result_t* out_result +) { // install exception handler if (exceptionHandlerInstalled == FALSE) { exceptionHandlerInstalled = TRUE; @@ -68,7 +69,7 @@ uint8_t callProtected(trampoline_t trampoline, { // save the stack pointer savedStackPointer = get_callee_frame_address(); - trampoline(ctx, func, param_vec, return_vec); + trampoline(func_env, func, param_vec, return_vec); out_result->code = 0; out_result->exception_address = 0; out_result->instruction_pointer = 0; @@ -86,4 +87,4 @@ uint8_t callProtected(trampoline_t trampoline, removeExceptionHandler(); return FALSE; -} \ No newline at end of file +} diff --git a/lib/win-exception-handler/exception_handling/exception_handling.h b/lib/win-exception-handler/exception_handling/exception_handling.h index f00227600f1..b06ac97273a 100644 --- a/lib/win-exception-handler/exception_handling/exception_handling.h +++ b/lib/win-exception-handler/exception_handling/exception_handling.h @@ -3,23 +3,24 @@ #include -struct func_t; -struct wasmer_instance_context_t; +typedef struct func_t func_t; +typedef struct funcenv_t funcenv_t; -typedef void(*trampoline_t)(struct wasmer_instance_context_t*, const struct func_t*, const uint64_t*, uint64_t*); +typedef void(*trampoline_t)(const funcenv_t*, const func_t*, const uint64_t*, uint64_t*); -struct call_protected_result_t { +typedef struct call_protected_result_t { uint64_t code; uint64_t exception_address; uint64_t instruction_pointer; -}; +} call_protected_result_t; uint8_t callProtected( - trampoline_t trampoline, - const struct wasmer_instance_context_t* ctx, - const struct func_t* func, - const uint64_t* param_vec, - uint64_t* return_vec, - struct call_protected_result_t* out_result); + trampoline_t trampoline, + const funcenv_t* func_env, + const func_t* func, + const uint64_t* param_vec, + uint64_t* return_vec, + call_protected_result_t* out_result +); #endif //WASMER_EXCEPTION_HANDLING_H diff --git a/lib/win-exception-handler/src/exception_handling.rs b/lib/win-exception-handler/src/exception_handling.rs index c448392b0a3..fde22068b40 100644 --- a/lib/win-exception-handler/src/exception_handling.rs +++ b/lib/win-exception-handler/src/exception_handling.rs @@ -1,7 +1,9 @@ use std::ptr::NonNull; -use wasmer_runtime_core::vm::{Ctx, Func}; +use wasmer_runtime_core::{ + typed_func::Trampoline, + vm::{self, Ctx}, +}; -type Trampoline = unsafe extern "C" fn(*mut Ctx, NonNull, *const u64, *mut u64); type CallProtectedResult = Result<(), CallProtectedData>; #[repr(C)] @@ -15,8 +17,8 @@ extern "C" { #[link_name = "callProtected"] pub fn __call_protected( trampoline: Trampoline, - ctx: *mut Ctx, - func: NonNull, + env: Option>, + func: NonNull, param_vec: *const u64, return_vec: *mut u64, out_result: *mut CallProtectedData, @@ -25,8 +27,8 @@ extern "C" { pub fn _call_protected( trampoline: Trampoline, - ctx: *mut Ctx, - func: NonNull, + env: Option>, + func: NonNull, param_vec: *const u64, return_vec: *mut u64, ) -> CallProtectedResult { @@ -38,13 +40,14 @@ pub fn _call_protected( let result = unsafe { __call_protected( trampoline, - ctx, + env, func, param_vec, return_vec, &mut out_result, ) }; + if result == 1 { Ok(()) } else {