-
Notifications
You must be signed in to change notification settings - Fork 824
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
Synchronize mutable env in functions #1625
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -6,9 +6,10 @@ use crate::FunctionType; | |
use crate::NativeFunc; | ||
use crate::RuntimeError; | ||
pub use inner::{FromToNativeWasmType, HostFunction, WasmTypeList, WithEnv, WithoutEnv}; | ||
use std::cell::RefCell; | ||
use std::borrow::BorrowMut; | ||
use std::cmp::max; | ||
use std::fmt; | ||
use std::sync::Mutex; | ||
use wasmer_vm::{ | ||
raise_user_trap, resume_panic, wasmer_call_trampoline, Export, ExportFunction, | ||
VMCallerCheckedAnyfunc, VMContext, VMDynamicFunctionContext, VMFunctionBody, VMFunctionKind, | ||
|
@@ -126,7 +127,7 @@ impl Function { | |
Env: Sized + 'static, | ||
{ | ||
let dynamic_ctx = VMDynamicFunctionContext::from_context(VMDynamicFunctionWithEnv { | ||
env: RefCell::new(env), | ||
env: Mutex::new(Box::new(env)), | ||
func: Box::new(func), | ||
function_type: ty.clone(), | ||
}); | ||
|
@@ -226,7 +227,7 @@ impl Function { | |
// Wasm-defined functions have a `VMContext`. | ||
// In the case of Host-defined functions `VMContext` is whatever environment | ||
// the user want to attach to the function. | ||
let box_env = Box::new(env); | ||
let box_env = Box::new(Mutex::new(env)); | ||
let vmctx = Box::into_raw(box_env) as *mut _ as *mut VMContext; | ||
let signature = function.ty(); | ||
|
||
|
@@ -409,7 +410,6 @@ impl Function { | |
))); | ||
} | ||
} | ||
|
||
Ok(NativeFunc::new( | ||
self.store.clone(), | ||
self.exported.address, | ||
|
@@ -463,24 +463,27 @@ impl VMDynamicFunction for VMDynamicFunctionWithoutEnv { | |
} | ||
} | ||
|
||
#[repr(C)] | ||
pub(crate) struct VMDynamicFunctionWithEnv<Env> | ||
where | ||
Env: Sized + 'static, | ||
{ | ||
function_type: FunctionType, | ||
#[allow(clippy::type_complexity)] | ||
func: Box<dyn Fn(&mut Env, &[Val]) -> Result<Vec<Val>, RuntimeError> + 'static>, | ||
env: RefCell<Env>, | ||
// We have to box this because of the way we call the `call` function, we don't know the | ||
// size of the env when calling from NativeFunc. | ||
env: Mutex<Box<Env>>, | ||
} | ||
|
||
impl<Env> VMDynamicFunction for VMDynamicFunctionWithEnv<Env> | ||
where | ||
Env: Sized + 'static, | ||
{ | ||
fn call(&self, args: &[Val]) -> Result<Vec<Val>, RuntimeError> { | ||
// TODO: the `&mut *self.env.as_ptr()` is likely invoking some "mild" | ||
// undefined behavior due to how it's used in the static fn call | ||
unsafe { (*self.func)(&mut *self.env.as_ptr(), &args) } | ||
let mut env_guard = self.env.lock().unwrap(); | ||
let env_mut = env_guard.borrow_mut(); | ||
(*self.func)(&mut **env_mut, &args) | ||
} | ||
fn function_type(&self) -> &FunctionType { | ||
&self.function_type | ||
|
@@ -1022,18 +1025,22 @@ mod inner { | |
/// This is a function that wraps the real host | ||
/// function. Its address will be used inside the | ||
/// runtime. | ||
extern fn func_wrapper<$( $x, )* Rets, RetsAsResult, Env, Func>( env: &mut Env, $( $x: $x::Native, )* ) -> Rets::CStruct | ||
extern fn func_wrapper<$( $x, )* Rets, RetsAsResult, Env, Func>( env: &std::sync::Mutex<Env>, $( $x: $x::Native, )* ) -> Rets::CStruct | ||
where | ||
$( $x: FromToNativeWasmType, )* | ||
Rets: WasmTypeList, | ||
RetsAsResult: IntoResult<Rets>, | ||
Env: Sized, | ||
Func: Fn(&mut Env, $( $x ),* ) -> RetsAsResult + 'static | ||
{ | ||
use std::borrow::BorrowMut; | ||
|
||
let func: &Func = unsafe { &*(&() as *const () as *const Func) }; | ||
let mut env_guard = env.lock().unwrap(); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm not really a fan of this. This is a clear performance penalty that we are now incurring for all function calls. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We should measure this penalty, because I don't see a lot more options to solve this sync problem. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm completely in favor of measurement, but I'm also sympathetic to wanting a fast path for singlethreaded code which will likely be the majority of uses (at least in the short-term). Also, I agree that yeah, this change is nice because it just works without much changes. I wrote up a design doc about solutions to this problem and I'll ping people about it next week: I think it's probable that we can make a more complex solution to this problem, but it will require breaking changes to our API or duplicating our API (singlethreaded version vs general version). I also talked about some more exotic options with Nick in regards to things like updating vtables at runtime to dynamically synchronize code when it becomes multithreaded but I don't think we're realistically going to be trying anything fancy any time soon and also I haven't thought of any fancy solutions that aren't a bad trade off in terms of complexity. |
||
let env_mut: &mut Env = env_guard.borrow_mut(); | ||
|
||
let result = panic::catch_unwind(AssertUnwindSafe(|| { | ||
func(env, $( FromToNativeWasmType::from_native($x) ),* ).into_result() | ||
func(env_mut, $( FromToNativeWasmType::from_native($x) ),* ).into_result() | ||
})); | ||
|
||
match result { | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not really a fan of this. This is a clear performance penalty that we are now incurring for all function calls.