Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Support closures for imported functions #882

Closed
wants to merge 27 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
683ea71
feat(runtime-core) Support closures for imported functions.
Hywan Oct 17, 2019
534dfec
feat(cranelift-backend) Support closures for imported functions.
Hywan Oct 17, 2019
3ecf2f2
feat(win-exception-handler) Use `wasmer_runtime_core::typed_func::Tra…
Hywan Oct 17, 2019
b7fa66a
feat(llvm-backend) Use `wasmer_runtime_core` trampoline and invoke de…
Hywan Oct 17, 2019
861865a
feat(runtime-core) `vm::Ctx` is explicitely passed to `Invoke`.
Hywan Oct 18, 2019
d6459e2
feat(singlepass-backend) Use `wasmer_runtime_core` trampoline and inv…
Hywan Oct 18, 2019
b66b016
feat(clif-backend) Update the `invoke` definition.
Hywan Oct 18, 2019
3288071
feat(llvm-backend) Update the `invoke_trampoline` definition.
Hywan Oct 18, 2019
356ea60
test(Makefile) Run `spectests-singlepass` on rustc nightly.
Hywan Oct 18, 2019
9e80125
fix(runtime-core) Remove dead code.
Hywan Oct 21, 2019
d16c765
test(runtime-core) Fix function names.
Hywan Oct 21, 2019
07acb45
feat(runtime-core) !temp Support optional `&mut vm::Ctx`.
Hywan Oct 21, 2019
7868926
test(runtime-core) Create the `wasmer-runtime-core-tests` crate.
Hywan Oct 23, 2019
95541d2
test(runtime-core) Test against the LLVM and Singlepass backends.
Hywan Oct 23, 2019
9baa11e
feat(runtime-core) Implement trap for closure and `fn` without vmctx/…
Hywan Oct 23, 2019
73175d9
feat(runtime-core) Handle the case of a closure with an environment +…
Hywan Oct 24, 2019
0e681be
test(runtime-core) Write more tests.
Hywan Oct 24, 2019
61c4eb4
test(runtime-core) Build `Func::new` with different functions of vari…
Hywan Oct 24, 2019
9f6e796
feat(singlepass-backend) Replace `vm::Ctx` by `vm::FuncEnv` when it m…
Hywan Oct 24, 2019
ee04f6e
test(runtime-core) Print more debugging info when a test fails.
Hywan Oct 24, 2019
4ee381b
fix(spectests) Various small fixes.
Hywan Oct 24, 2019
df9c1e6
chore(make) Test `wasmer-runtime-core-tests` for all backends.
Hywan Oct 24, 2019
3e277d3
chore(make) Exclude `wasmer-runtime-core-tests` from `test-rest`.
Hywan Oct 24, 2019
21d28a0
chore(cargo) Update the lockfile.
Hywan Oct 24, 2019
15e2915
chore(runtime-core) Use `std::{fmt, ptr}`.
Hywan Oct 24, 2019
d168e05
chore(runtime-core) Factorize code to remove duplicate code.
Hywan Oct 24, 2019
c428a74
feat(runtime-core) `export::Context::External` now holds a `vm::FuncE…
Hywan Oct 24, 2019
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
20 changes: 18 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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
Expand All @@ -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;
Expand Down
60 changes: 19 additions & 41 deletions lib/clif-backend/src/code.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand All @@ -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);
Expand All @@ -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,
Expand All @@ -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;
Expand All @@ -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,
);

Expand All @@ -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,
Expand All @@ -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()))
}
}
}
Expand Down Expand Up @@ -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,
Expand Down
3 changes: 2 additions & 1 deletion lib/clif-backend/src/resolver.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)]
Expand All @@ -62,6 +62,7 @@ pub struct FuncResolverBuilder {
}

pub struct NoopStackmapSink {}

impl StackmapSink for NoopStackmapSink {
fn add_stackmap(&mut self, _: u32, _: Stackmap) {}
}
Expand Down
11 changes: 6 additions & 5 deletions lib/clif-backend/src/signal/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
};
Expand Down Expand Up @@ -59,8 +59,9 @@ impl RunnableModule for Caller {

fn get_trampoline(&self, _: &ModuleInfo, sig_index: SigIndex) -> Option<Wasm> {
unsafe extern "C" fn invoke(
trampoline: unsafe extern "C" fn(*mut vm::Ctx, NonNull<vm::Func>, *const u64, *mut u64),
ctx: *mut vm::Ctx,
trampoline: Trampoline,
_vmctx: Option<NonNull<vm::Ctx>>,
func_env: Option<NonNull<vm::FuncEnv>>,
func: NonNull<vm::Func>,
args: *const u64,
rets: *mut u64,
Expand All @@ -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) => {
Expand Down
14 changes: 9 additions & 5 deletions lib/clif-backend/src/signal/unix.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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(
Expand Down
50 changes: 28 additions & 22 deletions lib/clif-backend/src/signal/windows.rs
Original file line number Diff line number Diff line change
@@ -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! {
Expand All @@ -28,8 +34,8 @@ thread_local! {
pub fn call_protected(
handler_data: &HandlerData,
trampoline: Trampoline,
ctx: *mut Ctx,
func: NonNull<Func>,
env: Option<NonNull<vm::FuncEnv>>,
func: NonNull<vm::Func>,
param_vec: *const u64,
return_vec: *mut u64,
) -> Result<(), CallProtError> {
Expand All @@ -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(());
Expand Down
Loading