Skip to content

Runtime is shared with Modules and Functions without refs #43

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

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
**/target
Cargo.lock
wasm3-sys/wrapper.h
.vscode
30 changes: 15 additions & 15 deletions src/function.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,27 +60,27 @@ pub(crate) type NNM3Function = NonNull<ffi::M3Function>;
/// A callable wasm3 function.
/// This has a generic `call` function for up to 26 parameters emulating an overloading behaviour without having to resort to tuples.
/// These are hidden to not pollute the documentation.
#[derive(Debug, Copy, Clone)]
pub struct Function<'rt, Args, Ret> {
#[derive(Debug, Clone)]
pub struct Function<Args, Ret> {
raw: NNM3Function,
rt: &'rt Runtime,
rt: Runtime,
_pd: PhantomData<*const (Args, Ret)>,
}

impl<'rt, Args, Ret> Eq for Function<'rt, Args, Ret> {}
impl<'rt, Args, Ret> PartialEq for Function<'rt, Args, Ret> {
impl<Args, Ret> Eq for Function<Args, Ret> {}
impl<Args, Ret> PartialEq for Function<Args, Ret> {
fn eq(&self, other: &Self) -> bool {
self.raw == other.raw
}
}

impl<'rt, Args, Ret> Hash for Function<'rt, Args, Ret> {
impl<Args, Ret> Hash for Function<Args, Ret> {
fn hash<H: Hasher>(&self, state: &mut H) {
self.raw.hash(state);
}
}

impl<'rt, Args, Ret> Function<'rt, Args, Ret>
impl<Args, Ret> Function<Args, Ret>
where
Args: WasmArgs,
Ret: WasmType,
Expand All @@ -91,17 +91,17 @@ where
}

/// The module containing this function.
pub fn module(&self) -> Option<Module<'rt>> {
pub fn module(&self) -> Option<Module> {
let module = unsafe { ffi::m3_GetFunctionModule(self.raw.as_ptr()) };
if !module.is_null() {
Some(Module::from_raw(self.rt, module))
Some(Module::from_raw(&self.rt, module))
} else {
None
}
}
}

impl<'rt, Args, Ret> Function<'rt, Args, Ret>
impl<Args, Ret> Function<Args, Ret>
where
Args: WasmArgs,
Ret: WasmType,
Expand All @@ -125,13 +125,13 @@ where
}

#[inline]
pub(crate) fn from_raw(rt: &'rt Runtime, raw: NNM3Function) -> Result<Self> {
pub(crate) fn from_raw(rt: &Runtime, raw: NNM3Function) -> Result<Self> {
if !Self::validate_sig(raw) {
return Err(Error::InvalidFunctionSignature);
}
Ok(Function {
raw,
rt,
rt: rt.clone(),
_pd: PhantomData,
})
}
Expand All @@ -156,7 +156,7 @@ macro_rules! func_call_impl {
(@do_impl) => {};
(@do_impl $($types:ident,)*) => {
#[doc(hidden)] // this really pollutes the documentation
impl<'rt, $($types,)* Ret> Function<'rt, ($($types,)*), Ret>
impl<$($types,)* Ret> Function<($($types,)*), Ret>
where
Ret: WasmType,
($($types,)*): WasmArgs,
Expand All @@ -173,7 +173,7 @@ macro_rules! func_call_impl {
}
func_call_impl!(A, B, C, D, E, F, G, H, J, K, L, M, N, O, P, Q);

impl<'rt, ARG, Ret> Function<'rt, ARG, Ret>
impl<ARG, Ret> Function<ARG, Ret>
where
Ret: WasmType,
ARG: WasmArg,
Expand All @@ -188,7 +188,7 @@ where
}
}

impl<'rt, Ret> Function<'rt, (), Ret>
impl<Ret> Function<(), Ret>
where
Ret: WasmType,
{
Expand Down
14 changes: 7 additions & 7 deletions src/module.rs
Original file line number Diff line number Diff line change
Expand Up @@ -67,12 +67,12 @@ impl ParsedModule {

/// A loaded module belonging to a specific runtime. Allows for linking and looking up functions.
// needs no drop as loaded modules will be cleaned up by the runtime
pub struct Module<'rt> {
pub struct Module {
raw: ffi::IM3Module,
rt: &'rt Runtime,
rt: Runtime,
}

impl<'rt> Module<'rt> {
impl Module {
/// Parses a wasm module from raw bytes.
#[inline]
pub fn parse<TData: Into<Box<[u8]>>>(
Expand Down Expand Up @@ -204,7 +204,7 @@ impl<'rt> Module<'rt> {
/// * a memory allocation failed
/// * no function by the given name in the given module could be found
/// * the function has been found but the signature did not match
pub fn find_function<Args, Ret>(&self, function_name: &str) -> Result<Function<'rt, Args, Ret>>
pub fn find_function<Args, Ret>(&self, function_name: &str) -> Result<Function<Args, Ret>>
where
Args: crate::WasmArgs,
Ret: crate::WasmType,
Expand All @@ -228,9 +228,9 @@ impl<'rt> Module<'rt> {
}
}

impl<'rt> Module<'rt> {
pub(crate) fn from_raw(rt: &'rt Runtime, raw: ffi::IM3Module) -> Self {
Module { raw, rt }
impl Module {
pub(crate) fn from_raw(rt: &Runtime, raw: ffi::IM3Module) -> Self {
Module { raw, rt: rt.clone() }
}
}

Expand Down
26 changes: 17 additions & 9 deletions src/runtime.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
use alloc::boxed::Box;
use alloc::rc::Rc;
use alloc::vec::Vec;
use core::cell::UnsafeCell;
use core::pin::Pin;
Expand All @@ -13,8 +14,14 @@ use crate::utils::str_to_cstr_owned;
type PinnedAnyClosure = Pin<Box<dyn core::any::Any + 'static>>;

/// A runtime context for wasm3 modules.
#[derive(Debug)]
#[derive(Clone, Debug)]
pub struct Runtime {
inner: Rc<RuntimeInner>,
}

/// A runtime context for wasm3 modules.
#[derive(Debug)]
struct RuntimeInner {
raw: NonNull<ffi::M3Runtime>,
environment: Environment,
// holds all linked closures so that they properly get disposed of when runtime drops
Expand All @@ -38,17 +45,18 @@ impl Runtime {
))
}
.ok_or_else(Error::malloc_error)
.map(|raw| Runtime {
.map(|raw| RuntimeInner {
raw,
environment: environment.clone(),
closure_store: UnsafeCell::new(Vec::new()),
module_data: UnsafeCell::new(Vec::new()),
})
.map(|inner| Runtime { inner: Rc::new(inner) })
}

/// Parses and loads a module from bytes.
pub fn parse_and_load_module<TData: Into<Box<[u8]>>>(&self, bytes: TData) -> Result<Module> {
Module::parse(&self.environment, bytes).and_then(|module| self.load_module(module))
Module::parse(&self.inner.environment, bytes).and_then(|module| self.load_module(module))
}

/// Loads a parsed module returning the module if unsuccessful.
Expand All @@ -57,14 +65,14 @@ impl Runtime {
///
/// This function will error if the module's environment differs from the one this runtime uses.
pub fn load_module(&self, module: ParsedModule) -> Result<Module> {
if &self.environment != module.environment() {
if &self.inner.environment != module.environment() {
Err(Error::ModuleLoadEnvMismatch)
} else {
let raw_mod = module.as_ptr();
Error::from_ffi_res(unsafe { ffi::m3_LoadModule(self.raw.as_ptr(), raw_mod) })?;
Error::from_ffi_res(unsafe { ffi::m3_LoadModule(self.inner.raw.as_ptr(), raw_mod) })?;
// SAFETY: Runtime isn't Send, therefor this access is single-threaded and kept alive only for the Vec::push call
// as such this can not alias.
unsafe { (*self.module_data.get()).push(module.take_data()) };
unsafe { (*self.inner.module_data.get()).push(module.take_data()) };

Ok(Module::from_raw(self, raw_mod))
}
Expand Down Expand Up @@ -118,15 +126,15 @@ impl Runtime {

impl Runtime {
pub(crate) fn push_closure(&self, closure: PinnedAnyClosure) {
unsafe { (*self.closure_store.get()).push(closure) };
unsafe { (*self.inner.closure_store.get()).push(closure) };
}

pub(crate) fn as_ptr(&self) -> ffi::IM3Runtime {
self.raw.as_ptr()
self.inner.raw.as_ptr()
}
}

impl Drop for Runtime {
impl Drop for RuntimeInner {
fn drop(&mut self) {
unsafe { ffi::m3_FreeRuntime(self.raw.as_ptr()) };
}
Expand Down