Merge branch 'master' into feature/multi-example-wasm-c-api

This commit is contained in:
Mark McCaskey
2020-12-18 12:42:45 -08:00
committed by GitHub
14 changed files with 317 additions and 223 deletions

View File

@@ -12,9 +12,13 @@
* [#1894](https://github.com/wasmerio/wasmer/pull/1894) Added exports `wasmer::{CraneliftOptLevel, LLVMOptLevel}` to allow using `Cranelift::opt_level` and `LLVM::opt_level` directly via the `wasmer` crate * [#1894](https://github.com/wasmerio/wasmer/pull/1894) Added exports `wasmer::{CraneliftOptLevel, LLVMOptLevel}` to allow using `Cranelift::opt_level` and `LLVM::opt_level` directly via the `wasmer` crate
### Changed ### Changed
* [#1944](https://github.com/wasmerio/wasmer/pull/1944) Require `WasmerEnv` to be `Send + Sync` even in dynamic functions.
### Fixed ### Fixed
- [#1949](https://github.com/wasmerio/wasmer/pull/1949) `wasm_<type>_vec_delete` functions no longer crash when the given vector is uninitialized, in the Wasmer C API
- [#1949](https://github.com/wasmerio/wasmer/pull/1949) The `wasm_frame_vec_t`, `wasm_functype_vec_t`, `wasm_globaltype_vec_t`, `wasm_memorytype_vec_t`, and `wasm_tabletype_vec_t` are now boxed vectors in the Wasmer C API
## 1.0.0-beta2 - 2020-12-16 ## 1.0.0-beta2 - 2020-12-16
### Added ### Added

View File

@@ -229,10 +229,13 @@ test-packages:
cargo test -p wasmer-wasi --release cargo test -p wasmer-wasi --release
cargo test -p wasmer-object --release cargo test -p wasmer-object --release
cargo test -p wasmer-engine-native --release --no-default-features cargo test -p wasmer-engine-native --release --no-default-features
cargo test -p wasmer-engine-jit --release --no-default-features
cargo test -p wasmer-compiler --release
cargo test -p wasmer-cli --release cargo test -p wasmer-cli --release
cargo test -p wasmer-cache --release cargo test -p wasmer-cache --release
cargo test -p wasmer-engine --release cargo test -p wasmer-engine --release
# The test-capi rules depend on the build-capi rules to build the .a files to # The test-capi rules depend on the build-capi rules to build the .a files to
# link the tests against. cargo test doesn't know that the tests will be running # link the tests against. cargo test doesn't know that the tests will be running
test-capi: $(foreach compiler_engine,$(test_compilers_engines),test-capi-$(compiler_engine)) test-capi: $(foreach compiler_engine,$(test_compilers_engines),test-capi-$(compiler_engine))
@@ -355,10 +358,26 @@ endif
update-testsuite: update-testsuite:
git subtree pull --prefix tests/wast/spec https://github.com/WebAssembly/testsuite.git master --squash git subtree pull --prefix tests/wast/spec https://github.com/WebAssembly/testsuite.git master --squash
RUSTFLAGS := "-D dead-code -D nonstandard-style -D unused-imports -D unused-mut -D unused-variables -D unused-unsafe -D unreachable-patterns -D bad-style -D improper-ctypes -D unused-allocation -D unused-comparisons -D while-true -D unconditional-recursion -D bare-trait-objects -D function_item_references" # TODO: add `-D missing-docs` RUSTFLAGS := "-D dead-code -D nonstandard-style -D unused-imports -D unused-mut -D unused-variables -D unused-unsafe -D unreachable-patterns -D bad-style -D improper-ctypes -D unused-allocation -D unused-comparisons -D while-true -D unconditional-recursion -D bare-trait-objects" # TODO: add `-D missing-docs` # TODO: add `-D function_item_references` (not available on Rust 1.47, try when upgrading)
lint: lint-packages:
RUSTFLAGS=${RUSTFLAGS} cargo clippy -p wasmer
RUSTFLAGS=${RUSTFLAGS} cargo clippy -p wasmer-vm
RUSTFLAGS=${RUSTFLAGS} cargo clippy -p wasmer-types
RUSTFLAGS=${RUSTFLAGS} cargo clippy -p wasmer-wasi
RUSTFLAGS=${RUSTFLAGS} cargo clippy -p wasmer-object
RUSTFLAGS=${RUSTFLAGS} cargo clippy -p wasmer-engine-native
RUSTFLAGS=${RUSTFLAGS} cargo clippy -p wasmer-engine-jit
RUSTFLAGS=${RUSTFLAGS} cargo clippy -p wasmer-compiler
RUSTFLAGS=${RUSTFLAGS} cargo clippy -p wasmer-compiler-cranelift
RUSTFLAGS=${RUSTFLAGS} cargo clippy -p wasmer-compiler-singlepass
RUSTFLAGS=${RUSTFLAGS} cargo clippy -p wasmer-cli
RUSTFLAGS=${RUSTFLAGS} cargo clippy -p wasmer-cache
RUSTFLAGS=${RUSTFLAGS} cargo clippy -p wasmer-engine
lint-formatting:
cargo fmt --all -- --check cargo fmt --all -- --check
RUSTFLAGS=${RUSTFLAGS} cargo clippy $(compiler_features)
lint: lint-formatting lint-packages
install-local: package install-local: package
tar -C ~/.wasmer -zxvf wasmer.tar.gz tar -C ~/.wasmer -zxvf wasmer.tar.gz

View File

@@ -67,6 +67,49 @@ pub struct Function {
pub(crate) exported: ExportFunction, pub(crate) exported: ExportFunction,
} }
fn build_export_function_metadata<Env>(
env: Env,
import_init_function_ptr: for<'a> fn(
&'a mut Env,
&'a crate::Instance,
) -> Result<(), crate::HostEnvInitError>,
) -> (*mut std::ffi::c_void, ExportFunctionMetadata)
where
Env: Clone + Sized + 'static + Send + Sync,
{
let import_init_function_ptr = Some(unsafe {
std::mem::transmute::<fn(_, _) -> Result<(), _>, fn(_, _) -> Result<(), _>>(
import_init_function_ptr,
)
});
let host_env_clone_fn: fn(*mut std::ffi::c_void) -> *mut std::ffi::c_void = |ptr| {
let env_ref: &Env = unsafe {
ptr.cast::<Env>()
.as_ref()
.expect("`ptr` to the environment is null when cloning it")
};
Box::into_raw(Box::new(env_ref.clone())) as _
};
let host_env_drop_fn: fn(*mut std::ffi::c_void) = |ptr| {
unsafe { Box::from_raw(ptr.cast::<Env>()) };
};
let env = Box::into_raw(Box::new(env)) as _;
// # Safety
// - All these functions work on all threads
// - The host env is `Send`.
let metadata = unsafe {
ExportFunctionMetadata::new(
env,
import_init_function_ptr,
host_env_clone_fn,
host_env_drop_fn,
)
};
(env, metadata)
}
impl Function { impl Function {
/// Creates a new host `Function` (dynamic) with the provided signature. /// Creates a new host `Function` (dynamic) with the provided signature.
/// ///
@@ -104,7 +147,7 @@ impl Function {
pub fn new<FT, F>(store: &Store, ty: FT, func: F) -> Self pub fn new<FT, F>(store: &Store, ty: FT, func: F) -> Self
where where
FT: Into<FunctionType>, FT: Into<FunctionType>,
F: Fn(&[Val]) -> Result<Vec<Val>, RuntimeError> + 'static, F: Fn(&[Val]) -> Result<Vec<Val>, RuntimeError> + 'static + Send + Sync,
{ {
let ty: FunctionType = ty.into(); let ty: FunctionType = ty.into();
let dynamic_ctx: VMDynamicFunctionContext<DynamicFunctionWithoutEnv> = let dynamic_ctx: VMDynamicFunctionContext<DynamicFunctionWithoutEnv> =
@@ -209,7 +252,7 @@ impl Function {
pub fn new_with_env<FT, F, Env>(store: &Store, ty: FT, env: Env, func: F) -> Self pub fn new_with_env<FT, F, Env>(store: &Store, ty: FT, env: Env, func: F) -> Self
where where
FT: Into<FunctionType>, FT: Into<FunctionType>,
F: Fn(&Env, &[Val]) -> Result<Vec<Val>, RuntimeError> + 'static, F: Fn(&Env, &[Val]) -> Result<Vec<Val>, RuntimeError> + 'static + Send + Sync,
Env: Sized + WasmerEnv + 'static, Env: Sized + WasmerEnv + 'static,
{ {
let ty: FunctionType = ty.into(); let ty: FunctionType = ty.into();
@@ -220,58 +263,27 @@ impl Function {
function_type: ty.clone(), function_type: ty.clone(),
}); });
let import_init_function_ptr: for<'a> fn(&'a mut _, &'a _) -> Result<(), _> =
|env: &mut VMDynamicFunctionContext<DynamicFunctionWithEnv<Env>>,
instance: &crate::Instance| {
Env::init_with_instance(&mut *env.ctx.env, instance)
};
let (host_env, metadata) = build_export_function_metadata::<
VMDynamicFunctionContext<DynamicFunctionWithEnv<Env>>,
>(dynamic_ctx, import_init_function_ptr);
// We don't yet have the address with the Wasm ABI signature. // We don't yet have the address with the Wasm ABI signature.
// The engine linker will replace the address with one pointing to a // The engine linker will replace the address with one pointing to a
// generated dynamic trampoline. // generated dynamic trampoline.
let address = std::ptr::null() as *const VMFunctionBody; let address = std::ptr::null() as *const VMFunctionBody;
let host_env = Box::into_raw(Box::new(dynamic_ctx)) as *mut _;
let vmctx = VMFunctionEnvironment { host_env }; let vmctx = VMFunctionEnvironment { host_env };
let import_init_function_ptr: fn(_, _) -> Result<(), _> =
|ptr: *mut std::ffi::c_void, instance: *const std::ffi::c_void| {
let ptr = ptr as *mut VMDynamicFunctionContext<DynamicFunctionWithEnv<Env>>;
unsafe {
let env = &mut *ptr;
let env: &mut Env = &mut *env.ctx.env;
let instance = &*(instance as *const crate::Instance);
Env::init_with_instance(env, instance)
}
};
let import_init_function_ptr = Some(unsafe {
std::mem::transmute::<fn(_, _) -> Result<(), _>, fn(_, _) -> Result<(), _>>(
import_init_function_ptr,
)
});
let host_env_clone_fn: fn(*mut std::ffi::c_void) -> *mut std::ffi::c_void = |ptr| {
let duped_env: VMDynamicFunctionContext<DynamicFunctionWithEnv<Env>> = unsafe {
let ptr: *mut VMDynamicFunctionContext<DynamicFunctionWithEnv<Env>> = ptr as _;
let item: &VMDynamicFunctionContext<DynamicFunctionWithEnv<Env>> = &*ptr;
item.clone()
};
Box::into_raw(Box::new(duped_env)) as _
};
let host_env_drop_fn: fn(*mut std::ffi::c_void) = |ptr: *mut std::ffi::c_void| {
unsafe {
Box::from_raw(ptr as *mut VMDynamicFunctionContext<DynamicFunctionWithEnv<Env>>)
};
};
Self { Self {
store: store.clone(), store: store.clone(),
definition: FunctionDefinition::Host(HostFunctionDefinition { has_env: true }), definition: FunctionDefinition::Host(HostFunctionDefinition { has_env: true }),
exported: ExportFunction { exported: ExportFunction {
metadata: Some(Arc::new( metadata: Some(Arc::new(metadata)),
// # Safety
// - All these functions work on all threads
// - The host env is `Send`.
unsafe {
ExportFunctionMetadata::new(
host_env,
import_init_function_ptr,
host_env_clone_fn,
host_env_drop_fn,
)
},
)),
vm_function: VMExportFunction { vm_function: VMExportFunction {
address, address,
kind: VMFunctionKind::Dynamic, kind: VMFunctionKind::Dynamic,
@@ -374,50 +386,17 @@ impl Function {
let function = inner::Function::<Args, Rets>::new(func); let function = inner::Function::<Args, Rets>::new(func);
let address = function.address(); let address = function.address();
// TODO: We need to refactor the Function context. let (host_env, metadata) =
// Right now is structured as it's always a `VMContext`. However, only build_export_function_metadata::<Env>(env, Env::init_with_instance);
// 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 host_env = Box::into_raw(Box::new(env)) as *mut _;
let vmctx = VMFunctionEnvironment { host_env };
let host_env_clone_fn: fn(*mut std::ffi::c_void) -> *mut std::ffi::c_void = |ptr| {
let duped_env = unsafe {
let ptr: *mut Env = ptr as _;
let item: &Env = &*ptr;
item.clone()
};
Box::into_raw(Box::new(duped_env)) as _
};
let host_env_drop_fn: fn(*mut std::ffi::c_void) = |ptr: *mut std::ffi::c_void| {
unsafe { Box::from_raw(ptr as *mut Env) };
};
// TODO: look into removing transmute by changing API type signatures let vmctx = VMFunctionEnvironment { host_env };
let import_init_function_ptr = Some(unsafe {
std::mem::transmute::<fn(_, _) -> Result<(), _>, fn(_, _) -> Result<(), _>>(
Env::init_with_instance,
)
});
let signature = function.ty(); let signature = function.ty();
Self { Self {
store: store.clone(), store: store.clone(),
definition: FunctionDefinition::Host(HostFunctionDefinition { has_env: true }), definition: FunctionDefinition::Host(HostFunctionDefinition { has_env: true }),
exported: ExportFunction { exported: ExportFunction {
metadata: Some(Arc::new( metadata: Some(Arc::new(metadata)),
// # Safety
// - All these functions work on all threads
// - The host env is `Send`.
unsafe {
ExportFunctionMetadata::new(
host_env,
import_init_function_ptr,
host_env_clone_fn,
host_env_drop_fn,
)
},
)),
vm_function: VMExportFunction { vm_function: VMExportFunction {
address, address,
kind: VMFunctionKind::Static, kind: VMFunctionKind::Static,
@@ -455,43 +434,17 @@ impl Function {
let function = inner::Function::<Args, Rets>::new(func); let function = inner::Function::<Args, Rets>::new(func);
let address = function.address(); let address = function.address();
let box_env = Box::new(env); let (host_env, metadata) =
let host_env = Box::into_raw(box_env) as *mut _; build_export_function_metadata::<Env>(env, Env::init_with_instance);
let vmctx = VMFunctionEnvironment { host_env };
let host_env_clone_fn: fn(*mut std::ffi::c_void) -> *mut std::ffi::c_void = |ptr| {
let duped_env: Env = {
let ptr: *mut Env = ptr as _;
let item: &Env = &*ptr;
item.clone()
};
Box::into_raw(Box::new(duped_env)) as _
};
let host_env_drop_fn: fn(*mut std::ffi::c_void) = |ptr: *mut std::ffi::c_void| {
Box::from_raw(ptr as *mut Env);
};
let vmctx = VMFunctionEnvironment { host_env };
let signature = function.ty(); let signature = function.ty();
// TODO: look into removing transmute by changing API type signatures
let import_init_function_ptr = Some(std::mem::transmute::<
fn(_, _) -> Result<(), _>,
fn(_, _) -> Result<(), _>,
>(Env::init_with_instance));
Self { Self {
store: store.clone(), store: store.clone(),
definition: FunctionDefinition::Host(HostFunctionDefinition { has_env: true }), definition: FunctionDefinition::Host(HostFunctionDefinition { has_env: true }),
exported: ExportFunction { exported: ExportFunction {
metadata: Some(Arc::new( metadata: Some(Arc::new(metadata)),
// # Safety
// - All these functions work on all threads
// - The host env is `Send`.
ExportFunctionMetadata::new(
host_env,
import_init_function_ptr,
host_env_clone_fn,
host_env_drop_fn,
),
)),
vm_function: VMExportFunction { vm_function: VMExportFunction {
address, address,
kind: VMFunctionKind::Static, kind: VMFunctionKind::Static,
@@ -855,7 +808,7 @@ impl fmt::Debug for Function {
} }
/// This trait is one that all dynamic functions must fulfill. /// This trait is one that all dynamic functions must fulfill.
pub(crate) trait VMDynamicFunction { pub(crate) trait VMDynamicFunction: Send + Sync {
fn call(&self, args: &[Val]) -> Result<Vec<Val>, RuntimeError>; fn call(&self, args: &[Val]) -> Result<Vec<Val>, RuntimeError>;
fn function_type(&self) -> &FunctionType; fn function_type(&self) -> &FunctionType;
} }
@@ -863,7 +816,7 @@ pub(crate) trait VMDynamicFunction {
#[derive(Clone)] #[derive(Clone)]
pub(crate) struct DynamicFunctionWithoutEnv { pub(crate) struct DynamicFunctionWithoutEnv {
#[allow(clippy::type_complexity)] #[allow(clippy::type_complexity)]
func: Arc<dyn Fn(&[Val]) -> Result<Vec<Val>, RuntimeError> + 'static>, func: Arc<dyn Fn(&[Val]) -> Result<Vec<Val>, RuntimeError> + 'static + Send + Sync>,
function_type: FunctionType, function_type: FunctionType,
} }
@@ -878,15 +831,15 @@ impl VMDynamicFunction for DynamicFunctionWithoutEnv {
pub(crate) struct DynamicFunctionWithEnv<Env> pub(crate) struct DynamicFunctionWithEnv<Env>
where where
Env: Sized + 'static, Env: Sized + 'static + Send + Sync,
{ {
function_type: FunctionType, function_type: FunctionType,
#[allow(clippy::type_complexity)] #[allow(clippy::type_complexity)]
func: Arc<dyn Fn(&Env, &[Val]) -> Result<Vec<Val>, RuntimeError> + 'static>, func: Arc<dyn Fn(&Env, &[Val]) -> Result<Vec<Val>, RuntimeError> + 'static + Send + Sync>,
env: Box<Env>, env: Box<Env>,
} }
impl<Env: Sized + Clone + 'static> Clone for DynamicFunctionWithEnv<Env> { impl<Env: Sized + Clone + 'static + Send + Sync> Clone for DynamicFunctionWithEnv<Env> {
fn clone(&self) -> Self { fn clone(&self) -> Self {
Self { Self {
env: self.env.clone(), env: self.env.clone(),
@@ -898,7 +851,7 @@ impl<Env: Sized + Clone + 'static> Clone for DynamicFunctionWithEnv<Env> {
impl<Env> VMDynamicFunction for DynamicFunctionWithEnv<Env> impl<Env> VMDynamicFunction for DynamicFunctionWithEnv<Env>
where where
Env: Sized + 'static, Env: Sized + 'static + Send + Sync,
{ {
fn call(&self, args: &[Val]) -> Result<Vec<Val>, RuntimeError> { fn call(&self, args: &[Val]) -> Result<Vec<Val>, RuntimeError> {
(*self.func)(&*self.env, &args) (*self.func)(&*self.env, &args)

View File

@@ -3,8 +3,31 @@
macro_rules! wasm_declare_vec_inner { macro_rules! wasm_declare_vec_inner {
($name:ident) => { ($name:ident) => {
paste::paste! { paste::paste! {
/// Creates an empty vector of #[doc = "Creates an empty vector of [`wasm_" $name "_t`].
#[doc = "Creates an empty vector of [`wasm_" $name "_t`]."]
# Example
```rust
# use inline_c::assert_c;
# fn main() {
# (assert_c! {
# #include \"tests/wasmer_wasm.h\"
#
int main() {
// Creates an empty vector of `wasm_" $name "_t`.
wasm_" $name "_vec_t vector;
wasm_" $name "_vec_new_empty(&vector);
// Check that it is empty.
assert(vector.size == 0);
// Free it.
wasm_" $name "_vec_delete(&vector);
}
# })
# .success();
# }
```"]
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn [<wasm_ $name _vec_new_empty>](out: *mut [<wasm_ $name _vec_t>]) { pub unsafe extern "C" fn [<wasm_ $name _vec_new_empty>](out: *mut [<wasm_ $name _vec_t>]) {
// TODO: actually implement this // TODO: actually implement this
@@ -19,7 +42,37 @@ macro_rules! wasm_declare_vec_inner {
macro_rules! wasm_declare_vec { macro_rules! wasm_declare_vec {
($name:ident) => { ($name:ident) => {
paste::paste! { paste::paste! {
#[doc = "Represents of a vector of [`wasm_" $name "_t`]."] #[doc = "Represents a vector of `wasm_" $name "_t`.
Read the documentation of [`wasm_" $name "_t`] to see more concrete examples.
# Example
```rust
# use inline_c::assert_c;
# fn main() {
# (assert_c! {
# #include \"tests/wasmer_wasm.h\"
#
int main() {
// Create a vector of 2 `wasm_" $name "_t`.
wasm_" $name "_t x;
wasm_" $name "_t y;
wasm_" $name "_t* items[2] = {&x, &y};
wasm_" $name "_vec_t vector;
wasm_" $name "_vec_new(&vector, 2, (wasm_" $name "_t*) items);
// Check that it contains 2 items.
assert(vector.size == 2);
// Free it.
wasm_" $name "_vec_delete(&vector);
}
# })
# .success();
# }
```"]
#[derive(Debug)] #[derive(Debug)]
#[repr(C)] #[repr(C)]
pub struct [<wasm_ $name _vec_t>] { pub struct [<wasm_ $name _vec_t>] {
@@ -81,6 +134,7 @@ macro_rules! wasm_declare_vec {
.into_boxed_slice(); .into_boxed_slice();
let data = copied_data.as_mut_ptr(); let data = copied_data.as_mut_ptr();
::std::mem::forget(copied_data); ::std::mem::forget(copied_data);
Self { Self {
size, size,
data, data,
@@ -111,27 +165,60 @@ macro_rules! wasm_declare_vec {
} }
// TODO: investigate possible memory leak on `init` (owned pointer) // TODO: investigate possible memory leak on `init` (owned pointer)
#[doc = "Creates a new vector of [`wasm_" $name "_t`]."] #[doc = "Creates a new vector of [`wasm_" $name "_t`].
# Example
See the [`wasm_" $name "_vec_t`] type to get an example."]
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn [<wasm_ $name _vec_new>](out: *mut [<wasm_ $name _vec_t>], length: usize, init: *mut [<wasm_ $name _t>]) { pub unsafe extern "C" fn [<wasm_ $name _vec_new>](out: *mut [<wasm_ $name _vec_t>], length: usize, init: *mut [<wasm_ $name _t>]) {
let mut bytes: Vec<[<wasm_ $name _t>]> = Vec::with_capacity(length); let mut bytes: Vec<[<wasm_ $name _t>]> = Vec::with_capacity(length);
for i in 0..length { for i in 0..length {
bytes.push(::std::ptr::read(init.add(i))); bytes.push(::std::ptr::read(init.add(i)));
} }
let pointer = bytes.as_mut_ptr(); let pointer = bytes.as_mut_ptr();
debug_assert!(bytes.len() == bytes.capacity()); debug_assert!(bytes.len() == bytes.capacity());
(*out).data = pointer; (*out).data = pointer;
(*out).size = length; (*out).size = length;
::std::mem::forget(bytes); ::std::mem::forget(bytes);
} }
#[doc = "Creates a new uninitialized vector of [`wasm_" $name "_t`]."] #[doc = "Creates a new uninitialized vector of [`wasm_" $name "_t`].
# Example
```rust
# use inline_c::assert_c;
# fn main() {
# (assert_c! {
# #include \"tests/wasmer_wasm.h\"
#
int main() {
// Creates an empty vector of `wasm_" $name "_t`.
wasm_" $name "_vec_t vector;
wasm_" $name "_vec_new_uninitialized(&vector, 3);
// Check that it contains 3 items.
assert(vector.size == 3);
// Free it.
wasm_" $name "_vec_delete(&vector);
}
# })
# .success();
# }
```"]
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn [<wasm_ $name _vec_new_uninitialized>](out: *mut [<wasm_ $name _vec_t>], length: usize) { pub unsafe extern "C" fn [<wasm_ $name _vec_new_uninitialized>](out: *mut [<wasm_ $name _vec_t>], length: usize) {
let mut bytes: Vec<[<wasm_ $name _t>]> = Vec::with_capacity(length); let mut bytes: Vec<[<wasm_ $name _t>]> = Vec::with_capacity(length);
let pointer = bytes.as_mut_ptr(); let pointer = bytes.as_mut_ptr();
(*out).data = pointer; (*out).data = pointer;
(*out).size = length; (*out).size = length;
::std::mem::forget(bytes); ::std::mem::forget(bytes);
} }
@@ -144,7 +231,11 @@ macro_rules! wasm_declare_vec {
*out_ptr = in_ptr.clone(); *out_ptr = in_ptr.clone();
} }
#[doc = "Deletes a vector of [`wasm_" $name "_t`]."] #[doc = "Deletes a vector of [`wasm_" $name "_t`].
# Example
See the [`wasm_" $name "_vec_t`] type to get an example."]
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn [<wasm_ $name _vec_delete>](ptr: Option<&mut [<wasm_ $name _vec_t>]>) { pub unsafe extern "C" fn [<wasm_ $name _vec_delete>](ptr: Option<&mut [<wasm_ $name _vec_t>]>) {
if let Some(vec) = ptr { if let Some(vec) = ptr {
@@ -166,7 +257,9 @@ macro_rules! wasm_declare_vec {
macro_rules! wasm_declare_boxed_vec { macro_rules! wasm_declare_boxed_vec {
($name:ident) => { ($name:ident) => {
paste::paste! { paste::paste! {
#[doc = "Represents of a vector of [`wasm_" $name "_t`]."] #[doc = "Represents a vector of `wasm_" $name "_t`.
Read the documentation of [`wasm_" $name "_t`] to see more concrete examples."]
#[derive(Debug)] #[derive(Debug)]
#[repr(C)] #[repr(C)]
pub struct [<wasm_ $name _vec_t>] { pub struct [<wasm_ $name _vec_t>] {
@@ -217,6 +310,27 @@ macro_rules! wasm_declare_boxed_vec {
} }
} }
impl<'a, T: Into<[<wasm_ $name _t>]> + Clone> From<&'a [T]> for [<wasm_ $name _vec_t>] {
fn from(other: &'a [T]) -> Self {
let size = other.len();
let mut copied_data = other
.iter()
.cloned()
.map(Into::into)
.map(Box::new)
.map(Box::into_raw)
.collect::<Vec<*mut [<wasm_ $name _t>]>>()
.into_boxed_slice();
let data = copied_data.as_mut_ptr();
::std::mem::forget(copied_data);
Self {
size,
data,
}
}
}
// TODO: do this properly // TODO: do this properly
impl [<wasm_ $name _vec_t>] { impl [<wasm_ $name _vec_t>] {
pub unsafe fn into_slice(&self) -> Option<&[Box<[<wasm_ $name _t>]>]>{ pub unsafe fn into_slice(&self) -> Option<&[Box<[<wasm_ $name _t>]>]>{
@@ -235,23 +349,53 @@ macro_rules! wasm_declare_boxed_vec {
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn [<wasm_ $name _vec_new>](out: *mut [<wasm_ $name _vec_t>], length: usize, init: *const *mut [<wasm_ $name _t>]) { pub unsafe extern "C" fn [<wasm_ $name _vec_new>](out: *mut [<wasm_ $name _vec_t>], length: usize, init: *const *mut [<wasm_ $name _t>]) {
let mut bytes: Vec<*mut [<wasm_ $name _t>]> = Vec::with_capacity(length); let mut bytes: Vec<*mut [<wasm_ $name _t>]> = Vec::with_capacity(length);
for i in 0..length { for i in 0..length {
bytes.push(*init.add(i)); bytes.push(*init.add(i));
} }
let mut boxed_vec = bytes.into_boxed_slice(); let mut boxed_vec = bytes.into_boxed_slice();
let pointer = boxed_vec.as_mut_ptr(); let pointer = boxed_vec.as_mut_ptr();
(*out).data = pointer; (*out).data = pointer;
(*out).size = length; (*out).size = length;
::std::mem::forget(boxed_vec); ::std::mem::forget(boxed_vec);
} }
#[doc = "Creates a new uninitialized vector of [`wasm_" $name "_t`]."] #[doc = "Creates a new uninitialized vector of [`wasm_" $name "_t`].
# Example
```rust
# use inline_c::assert_c;
# fn main() {
# (assert_c! {
# #include \"tests/wasmer_wasm.h\"
#
int main() {
// Creates an empty vector of `wasm_" $name "_t`.
wasm_" $name "_vec_t vector;
wasm_" $name "_vec_new_uninitialized(&vector, 3);
// Check that it contains 3 items.
assert(vector.size == 3);
// Free it.
wasm_" $name "_vec_delete(&vector);
}
# })
# .success();
# }
```"]
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn [<wasm_ $name _vec_new_uninitialized>](out: *mut [<wasm_ $name _vec_t>], length: usize) { pub unsafe extern "C" fn [<wasm_ $name _vec_new_uninitialized>](out: *mut [<wasm_ $name _vec_t>], length: usize) {
let mut bytes: Vec<*mut [<wasm_ $name _t>]> = Vec::with_capacity(length); let mut bytes: Vec<*mut [<wasm_ $name _t>]> = vec![::std::ptr::null_mut(); length];
let pointer = bytes.as_mut_ptr(); let pointer = bytes.as_mut_ptr();
(*out).data = pointer; (*out).data = pointer;
(*out).size = length; (*out).size = length;
::std::mem::forget(bytes); ::std::mem::forget(bytes);
} }
@@ -264,11 +408,14 @@ macro_rules! wasm_declare_boxed_vec {
*out_ptr = in_ptr.clone(); *out_ptr = in_ptr.clone();
} }
#[doc = "Deletes a vector of [`wasm_" $name "_t`].
#[doc = "Deletes a vector of [`wasm_" $name "_t`]."] # Example
See the [`wasm_" $name "_vec_t`] type to get an example."]
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn [<wasm_ $name _vec_delete>](ptr: Option<&mut[<wasm_ $name _vec_t>]>) { pub unsafe extern "C" fn [<wasm_ $name _vec_delete>](ptr: Option<&mut [<wasm_ $name _vec_t>]>) {
if let Some(vec) = ptr { if let Some(vec) = ptr {
if !vec.data.is_null() { if !vec.data.is_null() {
let ptr: *mut Option<Box<[<wasm_ $name _t>]>> = vec.data as _; let ptr: *mut Option<Box<[<wasm_ $name _t>]>> = vec.data as _;
let data: Vec<Option<Box<[<wasm_ $name _t>]>>> = Vec::from_raw_parts(ptr, vec.size, vec.size); let data: Vec<Option<Box<[<wasm_ $name _t>]>>> = Vec::from_raw_parts(ptr, vec.size, vec.size);
@@ -298,7 +445,6 @@ macro_rules! wasm_declare_ref_base {
} }
// TODO: finish this... // TODO: finish this...
} }
}; };
} }

View File

@@ -48,4 +48,4 @@ pub unsafe extern "C" fn wasm_frame_module_offset(frame: &wasm_frame_t) -> usize
frame.info.module_offset() frame.info.module_offset()
} }
wasm_declare_vec!(frame); wasm_declare_boxed_vec!(frame);

View File

@@ -1,7 +1,4 @@
use super::{ use super::{wasm_externtype_t, wasm_valtype_vec_delete, wasm_valtype_vec_t, WasmExternType};
wasm_externtype_t, wasm_valtype_t, wasm_valtype_vec_delete, wasm_valtype_vec_t, WasmExternType,
};
use std::mem;
use wasmer::{ExternType, FunctionType, ValType}; use wasmer::{ExternType, FunctionType, ValType};
#[derive(Debug)] #[derive(Debug)]
@@ -13,44 +10,8 @@ pub(crate) struct WasmFunctionType {
impl WasmFunctionType { impl WasmFunctionType {
pub(crate) fn new(function_type: FunctionType) -> Self { pub(crate) fn new(function_type: FunctionType) -> Self {
let params = { let params: Box<wasm_valtype_vec_t> = Box::new(function_type.params().into());
let mut valtypes = function_type let results: Box<wasm_valtype_vec_t> = Box::new(function_type.results().into());
.params()
.iter()
.cloned()
.map(Into::into)
.map(Box::new)
.map(Box::into_raw)
.collect::<Vec<*mut wasm_valtype_t>>();
let valtypes_vec = Box::new(wasm_valtype_vec_t {
size: valtypes.len(),
data: valtypes.as_mut_ptr(),
});
mem::forget(valtypes);
valtypes_vec
};
let results = {
let mut valtypes = function_type
.results()
.iter()
.cloned()
.map(Into::into)
.map(Box::new)
.map(Box::into_raw)
.collect::<Vec<*mut wasm_valtype_t>>();
let valtypes_vec = Box::new(wasm_valtype_vec_t {
size: valtypes.len(),
data: valtypes.as_mut_ptr(),
});
mem::forget(valtypes);
valtypes_vec
};
Self { Self {
function_type, function_type,
@@ -90,12 +51,12 @@ impl wasm_functype_t {
} }
} }
wasm_declare_vec!(functype); wasm_declare_boxed_vec!(functype);
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn wasm_functype_new( pub unsafe extern "C" fn wasm_functype_new(
params: Option<Box<wasm_valtype_vec_t>>, params: Option<&mut wasm_valtype_vec_t>,
results: Option<Box<wasm_valtype_vec_t>>, results: Option<&mut wasm_valtype_vec_t>,
) -> Option<Box<wasm_functype_t>> { ) -> Option<Box<wasm_functype_t>> {
let params = params?; let params = params?;
let results = results?; let results = results?;
@@ -111,8 +72,8 @@ pub unsafe extern "C" fn wasm_functype_new(
.map(|val| val.as_ref().into()) .map(|val| val.as_ref().into())
.collect::<Vec<_>>(); .collect::<Vec<_>>();
wasm_valtype_vec_delete(Some(&mut *Box::into_raw(params))); wasm_valtype_vec_delete(Some(params));
wasm_valtype_vec_delete(Some(&mut *Box::into_raw(results))); wasm_valtype_vec_delete(Some(results));
Some(Box::new(wasm_functype_t::new(FunctionType::new( Some(Box::new(wasm_functype_t::new(FunctionType::new(
params_as_valtype, params_as_valtype,

View File

@@ -46,7 +46,7 @@ impl wasm_globaltype_t {
} }
} }
wasm_declare_vec!(globaltype); wasm_declare_boxed_vec!(globaltype);
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn wasm_globaltype_new( pub unsafe extern "C" fn wasm_globaltype_new(

View File

@@ -48,7 +48,7 @@ impl wasm_memorytype_t {
} }
} }
wasm_declare_vec!(memorytype); wasm_declare_boxed_vec!(memorytype);
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn wasm_memorytype_new(limits: &wasm_limits_t) -> Box<wasm_memorytype_t> { pub unsafe extern "C" fn wasm_memorytype_new(limits: &wasm_limits_t) -> Box<wasm_memorytype_t> {

View File

@@ -53,7 +53,7 @@ impl wasm_tabletype_t {
} }
} }
wasm_declare_vec!(tabletype); wasm_declare_boxed_vec!(tabletype);
#[no_mangle] #[no_mangle]
pub unsafe extern "C" fn wasm_tabletype_new( pub unsafe extern "C" fn wasm_tabletype_new(

View File

@@ -216,15 +216,15 @@ pub fn translate_operator<FE: FuncEnvironment + ?Sized>(
// destination block following the whole `if...end`. If we do end // destination block following the whole `if...end`. If we do end
// up discovering an `else`, then we will allocate a block for it // up discovering an `else`, then we will allocate a block for it
// and go back and patch the jump. // and go back and patch the jump.
let destination = block_with_params(builder, results.clone(), environ)?; let destination = block_with_params(builder, results, environ)?;
let branch_inst = let branch_inst =
canonicalise_then_brz(builder, val, destination, state.peekn(params.len())); canonicalise_then_brz(builder, val, destination, state.peekn(params.len()));
(destination, ElseData::NoElse { branch_inst }) (destination, ElseData::NoElse { branch_inst })
} else { } else {
// The `if` type signature is not valid without an `else` block, // The `if` type signature is not valid without an `else` block,
// so we eagerly allocate the `else` block here. // so we eagerly allocate the `else` block here.
let destination = block_with_params(builder, results.clone(), environ)?; let destination = block_with_params(builder, results, environ)?;
let else_block = block_with_params(builder, params.clone(), environ)?; let else_block = block_with_params(builder, params, environ)?;
canonicalise_then_brz(builder, val, else_block, state.peekn(params.len())); canonicalise_then_brz(builder, val, else_block, state.peekn(params.len()));
builder.seal_block(else_block); builder.seal_block(else_block);
(destination, ElseData::WithElse { else_block }) (destination, ElseData::WithElse { else_block })
@@ -271,8 +271,7 @@ pub fn translate_operator<FE: FuncEnvironment + ?Sized>(
let (params, _results) = let (params, _results) =
module_translation_state.blocktype_params_results(blocktype)?; module_translation_state.blocktype_params_results(blocktype)?;
debug_assert_eq!(params.len(), num_return_values); debug_assert_eq!(params.len(), num_return_values);
let else_block = let else_block = block_with_params(builder, params, environ)?;
block_with_params(builder, params.clone(), environ)?;
canonicalise_then_jump( canonicalise_then_jump(
builder, builder,
destination, destination,

View File

@@ -1158,7 +1158,7 @@ checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519"
[[package]] [[package]]
name = "wasmer" name = "wasmer"
version = "1.0.0-beta1" version = "1.0.0-beta2"
dependencies = [ dependencies = [
"cfg-if 0.1.10", "cfg-if 0.1.10",
"indexmap", "indexmap",
@@ -1181,7 +1181,7 @@ dependencies = [
[[package]] [[package]]
name = "wasmer-cache" name = "wasmer-cache"
version = "1.0.0-beta1" version = "1.0.0-beta2"
dependencies = [ dependencies = [
"blake3", "blake3",
"hex", "hex",
@@ -1191,7 +1191,7 @@ dependencies = [
[[package]] [[package]]
name = "wasmer-compiler" name = "wasmer-compiler"
version = "1.0.0-beta1" version = "1.0.0-beta2"
dependencies = [ dependencies = [
"enumset", "enumset",
"raw-cpuid", "raw-cpuid",
@@ -1207,7 +1207,7 @@ dependencies = [
[[package]] [[package]]
name = "wasmer-compiler-cranelift" name = "wasmer-compiler-cranelift"
version = "1.0.0-beta1" version = "1.0.0-beta2"
dependencies = [ dependencies = [
"cranelift-codegen", "cranelift-codegen",
"cranelift-frontend", "cranelift-frontend",
@@ -1224,7 +1224,7 @@ dependencies = [
[[package]] [[package]]
name = "wasmer-compiler-llvm" name = "wasmer-compiler-llvm"
version = "1.0.0-beta1" version = "1.0.0-beta2"
dependencies = [ dependencies = [
"byteorder", "byteorder",
"cc", "cc",
@@ -1246,7 +1246,7 @@ dependencies = [
[[package]] [[package]]
name = "wasmer-compiler-singlepass" name = "wasmer-compiler-singlepass"
version = "1.0.0-beta1" version = "1.0.0-beta2"
dependencies = [ dependencies = [
"byteorder", "byteorder",
"dynasm", "dynasm",
@@ -1263,7 +1263,7 @@ dependencies = [
[[package]] [[package]]
name = "wasmer-derive" name = "wasmer-derive"
version = "1.0.0-beta1" version = "1.0.0-beta2"
dependencies = [ dependencies = [
"proc-macro-error", "proc-macro-error",
"proc-macro2", "proc-macro2",
@@ -1273,7 +1273,7 @@ dependencies = [
[[package]] [[package]]
name = "wasmer-engine" name = "wasmer-engine"
version = "1.0.0-beta1" version = "1.0.0-beta2"
dependencies = [ dependencies = [
"backtrace", "backtrace",
"bincode", "bincode",
@@ -1292,7 +1292,7 @@ dependencies = [
[[package]] [[package]]
name = "wasmer-engine-jit" name = "wasmer-engine-jit"
version = "1.0.0-beta1" version = "1.0.0-beta2"
dependencies = [ dependencies = [
"bincode", "bincode",
"cfg-if 0.1.10", "cfg-if 0.1.10",
@@ -1308,7 +1308,7 @@ dependencies = [
[[package]] [[package]]
name = "wasmer-engine-native" name = "wasmer-engine-native"
version = "1.0.0-beta1" version = "1.0.0-beta2"
dependencies = [ dependencies = [
"bincode", "bincode",
"cfg-if 0.1.10", "cfg-if 0.1.10",
@@ -1327,7 +1327,7 @@ dependencies = [
[[package]] [[package]]
name = "wasmer-object" name = "wasmer-object"
version = "1.0.0-beta1" version = "1.0.0-beta2"
dependencies = [ dependencies = [
"object 0.22.0", "object 0.22.0",
"thiserror", "thiserror",
@@ -1355,7 +1355,7 @@ dependencies = [
[[package]] [[package]]
name = "wasmer-types" name = "wasmer-types"
version = "1.0.0-beta1" version = "1.0.0-beta2"
dependencies = [ dependencies = [
"cranelift-entity", "cranelift-entity",
"serde", "serde",
@@ -1364,7 +1364,7 @@ dependencies = [
[[package]] [[package]]
name = "wasmer-vm" name = "wasmer-vm"
version = "1.0.0-beta1" version = "1.0.0-beta2"
dependencies = [ dependencies = [
"backtrace", "backtrace",
"cc", "cc",

View File

@@ -10,10 +10,10 @@ use crate::{
}; };
use new::wasmer::Export; use new::wasmer::Export;
use std::{ use std::{
cell::RefCell,
collections::HashMap, collections::HashMap,
convert::{AsRef, Infallible}, convert::{AsRef, Infallible},
ptr, ptr,
sync::{Arc, Mutex},
}; };
pub use new::wasmer_types::{DataInitializer, ExportIndex, TableInitializer}; pub use new::wasmer_types::{DataInitializer, ExportIndex, TableInitializer};
@@ -126,20 +126,22 @@ impl Module {
// is the same! // is the same!
struct VMDynamicFunctionWithEnv<Env> struct VMDynamicFunctionWithEnv<Env>
where where
Env: Sized + 'static, Env: Sized + 'static + Send + Sync,
{ {
#[allow(unused)] #[allow(unused)]
function_type: FuncSig, function_type: FuncSig,
#[allow(unused)] #[allow(unused)]
func: Box< func: Arc<
dyn Fn( dyn Fn(
&mut Env, &mut Env,
&[Value], &[Value],
) )
-> Result<Vec<Value>, RuntimeError> -> Result<Vec<Value>, RuntimeError>
+ 'static, + 'static
+ Send
+ Sync,
>, >,
env: RefCell<Env>, env: Box<Mutex<Env>>,
} }
// Get back the `vmctx` as it is // Get back the `vmctx` as it is
@@ -154,7 +156,10 @@ impl Module {
}; };
// Replace the environment by ours. // Replace the environment by ours.
vmctx.ctx.env.borrow_mut().vmctx = pre_instance.vmctx(); {
let mut guard = vmctx.ctx.env.lock().unwrap();
guard.vmctx = pre_instance.vmctx();
}
// … without anyone noticing… // … without anyone noticing…
function.vm_function.vmctx.host_env = Box::into_raw(vmctx) as _; function.vm_function.vmctx.host_env = Box::into_raw(vmctx) as _;

View File

@@ -1158,7 +1158,7 @@ checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519"
[[package]] [[package]]
name = "wasmer" name = "wasmer"
version = "1.0.0-beta1" version = "1.0.0-beta2"
dependencies = [ dependencies = [
"cfg-if 0.1.10", "cfg-if 0.1.10",
"indexmap", "indexmap",
@@ -1181,7 +1181,7 @@ dependencies = [
[[package]] [[package]]
name = "wasmer-cache" name = "wasmer-cache"
version = "1.0.0-beta1" version = "1.0.0-beta2"
dependencies = [ dependencies = [
"blake3", "blake3",
"hex", "hex",
@@ -1191,7 +1191,7 @@ dependencies = [
[[package]] [[package]]
name = "wasmer-compiler" name = "wasmer-compiler"
version = "1.0.0-beta1" version = "1.0.0-beta2"
dependencies = [ dependencies = [
"enumset", "enumset",
"raw-cpuid", "raw-cpuid",
@@ -1207,7 +1207,7 @@ dependencies = [
[[package]] [[package]]
name = "wasmer-compiler-cranelift" name = "wasmer-compiler-cranelift"
version = "1.0.0-beta1" version = "1.0.0-beta2"
dependencies = [ dependencies = [
"cranelift-codegen", "cranelift-codegen",
"cranelift-frontend", "cranelift-frontend",
@@ -1224,7 +1224,7 @@ dependencies = [
[[package]] [[package]]
name = "wasmer-compiler-llvm" name = "wasmer-compiler-llvm"
version = "1.0.0-beta1" version = "1.0.0-beta2"
dependencies = [ dependencies = [
"byteorder", "byteorder",
"cc", "cc",
@@ -1246,7 +1246,7 @@ dependencies = [
[[package]] [[package]]
name = "wasmer-compiler-singlepass" name = "wasmer-compiler-singlepass"
version = "1.0.0-beta1" version = "1.0.0-beta2"
dependencies = [ dependencies = [
"byteorder", "byteorder",
"dynasm", "dynasm",
@@ -1263,7 +1263,7 @@ dependencies = [
[[package]] [[package]]
name = "wasmer-derive" name = "wasmer-derive"
version = "1.0.0-beta1" version = "1.0.0-beta2"
dependencies = [ dependencies = [
"proc-macro-error", "proc-macro-error",
"proc-macro2", "proc-macro2",
@@ -1273,7 +1273,7 @@ dependencies = [
[[package]] [[package]]
name = "wasmer-engine" name = "wasmer-engine"
version = "1.0.0-beta1" version = "1.0.0-beta2"
dependencies = [ dependencies = [
"backtrace", "backtrace",
"bincode", "bincode",
@@ -1292,7 +1292,7 @@ dependencies = [
[[package]] [[package]]
name = "wasmer-engine-jit" name = "wasmer-engine-jit"
version = "1.0.0-beta1" version = "1.0.0-beta2"
dependencies = [ dependencies = [
"bincode", "bincode",
"cfg-if 0.1.10", "cfg-if 0.1.10",
@@ -1308,7 +1308,7 @@ dependencies = [
[[package]] [[package]]
name = "wasmer-engine-native" name = "wasmer-engine-native"
version = "1.0.0-beta1" version = "1.0.0-beta2"
dependencies = [ dependencies = [
"bincode", "bincode",
"cfg-if 0.1.10", "cfg-if 0.1.10",
@@ -1327,7 +1327,7 @@ dependencies = [
[[package]] [[package]]
name = "wasmer-object" name = "wasmer-object"
version = "1.0.0-beta1" version = "1.0.0-beta2"
dependencies = [ dependencies = [
"object 0.22.0", "object 0.22.0",
"thiserror", "thiserror",
@@ -1362,7 +1362,7 @@ dependencies = [
[[package]] [[package]]
name = "wasmer-types" name = "wasmer-types"
version = "1.0.0-beta1" version = "1.0.0-beta2"
dependencies = [ dependencies = [
"cranelift-entity", "cranelift-entity",
"serde", "serde",
@@ -1371,7 +1371,7 @@ dependencies = [
[[package]] [[package]]
name = "wasmer-vm" name = "wasmer-vm"
version = "1.0.0-beta1" version = "1.0.0-beta2"
dependencies = [ dependencies = [
"backtrace", "backtrace",
"cc", "cc",

View File

@@ -95,7 +95,7 @@ mod test_vmfunction_import {
/// containing the relevant context for running the function indicated /// containing the relevant context for running the function indicated
/// in `address`. /// in `address`.
#[repr(C)] #[repr(C)]
pub struct VMDynamicFunctionContext<T: Sized> { pub struct VMDynamicFunctionContext<T: Sized + Send + Sync> {
/// The address of the inner dynamic function. /// The address of the inner dynamic function.
/// ///
/// Note: The function must be on the form of /// Note: The function must be on the form of
@@ -106,7 +106,14 @@ pub struct VMDynamicFunctionContext<T: Sized> {
pub ctx: T, pub ctx: T,
} }
impl<T: Sized + Clone> Clone for VMDynamicFunctionContext<T> { // The `ctx` itself must be `Send`, `address` can be passed between
// threads because all usage is `unsafe` and synchronized.
unsafe impl<T: Sized + Send + Sync> Send for VMDynamicFunctionContext<T> {}
// The `ctx` itself must be `Sync`, `address` can be shared between
// threads because all usage is `unsafe` and synchronized.
unsafe impl<T: Sized + Send + Sync> Sync for VMDynamicFunctionContext<T> {}
impl<T: Sized + Clone + Send + Sync> Clone for VMDynamicFunctionContext<T> {
fn clone(&self) -> Self { fn clone(&self) -> Self {
Self { Self {
address: self.address, address: self.address,