mirror of
https://github.com/mii443/wasmer.git
synced 2025-12-08 05:38:19 +00:00
Move Webassembly objects to Store and remove Context
Co-authored-by: ptitSeb <sebastien.chev@gmail.com> Co-authored-by: Manos Pitsidianakis <manos@wasmer.io>
This commit is contained in:
committed by
Manos Pitsidianakis
parent
b5ae6399ce
commit
a419ccdf52
@@ -1,449 +0,0 @@
|
||||
#![allow(dead_code)]
|
||||
use crate::Store;
|
||||
|
||||
/// We require the context to have a fixed memory address for its lifetime since
|
||||
/// various bits of the VM have raw pointers that point back to it. Hence we
|
||||
/// wrap the actual context in a box.
|
||||
pub(crate) struct ContextInner<T> {
|
||||
pub(crate) objects: ContextObjects,
|
||||
pub(crate) store: Store,
|
||||
pub(crate) data: T,
|
||||
}
|
||||
|
||||
/// A context containing a set of WebAssembly instances, along with host state.
|
||||
///
|
||||
/// All WebAssembly instances must exist within a context. In the majority of
|
||||
/// cases each instance will have its own context, but it is possible to have
|
||||
/// multiple instances in a context when these instances need to interact with
|
||||
/// each other, for example sharing a memory between instances or calling
|
||||
/// functions in another instance.
|
||||
///
|
||||
/// The lifetimes of run-time WebAssembly objects, notably [`Instance`],
|
||||
/// [`Memory`], [`Global`], [`Table`] and [`Function`] is tied to a context:
|
||||
/// the backing memory for these objects is only freed when the context is
|
||||
/// freed.
|
||||
///
|
||||
/// The `T` generic parameter allows arbitrary data to be attached to a context.
|
||||
/// This data can be accessed using the [`Context::data`] and
|
||||
/// [`Context::data_mut`] methods. Host functions defined using
|
||||
/// [`Function::new`] and [`Function::new_native`] receive
|
||||
/// a reference to the context when they are called.
|
||||
pub struct Context<T> {
|
||||
pub(crate) inner: Box<ContextInner<T>>,
|
||||
}
|
||||
|
||||
impl<T> Context<T> {
|
||||
/// Creates a new context with the given host state.
|
||||
// TODO: Eliminate the Store type and move its functionality into Engine.
|
||||
pub fn new(store: &Store, data: T) -> Self {
|
||||
Self {
|
||||
inner: Box::new(ContextInner {
|
||||
objects: Default::default(),
|
||||
store: store.clone(),
|
||||
data,
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns a reference to the host state in this context.
|
||||
pub fn data(&self) -> &T {
|
||||
&self.inner.data
|
||||
}
|
||||
|
||||
/// Returns a mutable- reference to the host state in this context.
|
||||
pub fn data_mut(&mut self) -> &mut T {
|
||||
&mut self.inner.data
|
||||
}
|
||||
|
||||
/// Drops the context and returns the host state that was stored in it.
|
||||
pub fn into_data(self) -> T {
|
||||
self.inner.data
|
||||
}
|
||||
|
||||
/// Returns a reference to the `Store` of this context.
|
||||
pub fn store(&self) -> &Store {
|
||||
&self.inner.store
|
||||
}
|
||||
}
|
||||
|
||||
/// A temporary handle to a [`Context`].
|
||||
pub struct ContextRef<'a, T: 'a> {
|
||||
inner: &'a ContextInner<T>,
|
||||
}
|
||||
|
||||
impl<'a, T> ContextRef<'a, T> {
|
||||
/// Returns a reference to the host state in this context.
|
||||
pub fn data(&self) -> &'a T {
|
||||
&self.inner.data
|
||||
}
|
||||
|
||||
/// Returns a reference to the `Store` of this context.
|
||||
pub fn store(&self) -> &Store {
|
||||
&self.inner.store
|
||||
}
|
||||
|
||||
pub(crate) fn objects(&self) -> &'a ContextObjects {
|
||||
&self.inner.objects
|
||||
}
|
||||
}
|
||||
|
||||
/// A temporary handle to a [`Context`].
|
||||
pub struct ContextMut<'a, T: 'a> {
|
||||
inner: &'a mut ContextInner<T>,
|
||||
}
|
||||
|
||||
impl<T> ContextMut<'_, T> {
|
||||
/// Returns a reference to the host state in this context.
|
||||
pub fn data(&self) -> &T {
|
||||
&self.inner.data
|
||||
}
|
||||
|
||||
/// Returns a mutable- reference to the host state in this context.
|
||||
pub fn data_mut(&mut self) -> &mut T {
|
||||
&mut self.inner.data
|
||||
}
|
||||
|
||||
pub(crate) fn objects_mut(&mut self) -> &mut ContextObjects {
|
||||
&mut self.inner.objects
|
||||
}
|
||||
|
||||
/// Returns a reference to the `Store` of this context.
|
||||
pub fn store(&self) -> &Store {
|
||||
&self.inner.store
|
||||
}
|
||||
|
||||
/// Returns the raw pointer of the context
|
||||
pub(crate) fn as_raw(&self) -> *mut ContextInner<T> {
|
||||
self.inner as *const ContextInner<T> as *mut ContextInner<T>
|
||||
}
|
||||
|
||||
/// Constructs the context from the raw pointer
|
||||
pub(crate) unsafe fn from_raw(raw: *mut ContextInner<T>) -> Self {
|
||||
Self { inner: &mut *raw }
|
||||
}
|
||||
}
|
||||
|
||||
/// Helper trait for a value that is convertible to a [`ContextRef`].
|
||||
pub trait AsContextRef {
|
||||
/// Host state associated with the [`Context`].
|
||||
type Data;
|
||||
|
||||
/// Returns a `ContextRef` pointing to the underlying context.
|
||||
fn as_context_ref(&self) -> ContextRef<'_, Self::Data>;
|
||||
}
|
||||
|
||||
/// Helper trait for a value that is convertible to a [`ContextMut`].
|
||||
pub trait AsContextMut: AsContextRef {
|
||||
/// Returns a `ContextMut` pointing to the underlying context.
|
||||
fn as_context_mut(&mut self) -> ContextMut<'_, Self::Data>;
|
||||
}
|
||||
|
||||
impl<T> AsContextRef for Context<T> {
|
||||
type Data = T;
|
||||
|
||||
fn as_context_ref(&self) -> ContextRef<'_, Self::Data> {
|
||||
ContextRef { inner: &self.inner }
|
||||
}
|
||||
}
|
||||
impl<T> AsContextMut for Context<T> {
|
||||
fn as_context_mut(&mut self) -> ContextMut<'_, Self::Data> {
|
||||
ContextMut {
|
||||
inner: &mut self.inner,
|
||||
}
|
||||
}
|
||||
}
|
||||
impl<T> AsContextRef for ContextRef<'_, T> {
|
||||
type Data = T;
|
||||
|
||||
fn as_context_ref(&self) -> ContextRef<'_, Self::Data> {
|
||||
ContextRef { inner: self.inner }
|
||||
}
|
||||
}
|
||||
impl<T> AsContextRef for ContextMut<'_, T> {
|
||||
type Data = T;
|
||||
|
||||
fn as_context_ref(&self) -> ContextRef<'_, Self::Data> {
|
||||
ContextRef { inner: self.inner }
|
||||
}
|
||||
}
|
||||
impl<T> AsContextMut for ContextMut<'_, T> {
|
||||
fn as_context_mut(&mut self) -> ContextMut<'_, Self::Data> {
|
||||
ContextMut { inner: self.inner }
|
||||
}
|
||||
}
|
||||
impl<T: AsContextRef> AsContextRef for &'_ T {
|
||||
type Data = T::Data;
|
||||
|
||||
fn as_context_ref(&self) -> ContextRef<'_, Self::Data> {
|
||||
T::as_context_ref(*self)
|
||||
}
|
||||
}
|
||||
impl<T: AsContextRef> AsContextRef for &'_ mut T {
|
||||
type Data = T::Data;
|
||||
|
||||
fn as_context_ref(&self) -> ContextRef<'_, Self::Data> {
|
||||
T::as_context_ref(*self)
|
||||
}
|
||||
}
|
||||
impl<T: AsContextMut> AsContextMut for &'_ mut T {
|
||||
fn as_context_mut(&mut self) -> ContextMut<'_, Self::Data> {
|
||||
T::as_context_mut(*self)
|
||||
}
|
||||
}
|
||||
|
||||
pub use objects::*;
|
||||
mod objects {
|
||||
use crate::js::export::{VMFunction, VMGlobal, VMMemory, VMTable};
|
||||
use std::{
|
||||
cell::UnsafeCell,
|
||||
fmt,
|
||||
marker::PhantomData,
|
||||
num::{NonZeroU64, NonZeroUsize},
|
||||
ptr::NonNull,
|
||||
sync::atomic::{AtomicU64, Ordering},
|
||||
};
|
||||
|
||||
/// Unique ID to identify a context.
|
||||
///
|
||||
/// Every handle to an object managed by a context also contains the ID of the
|
||||
/// context. This is used to check that a handle is always used with the
|
||||
/// correct context.
|
||||
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
|
||||
pub struct ContextId(NonZeroU64);
|
||||
|
||||
impl Default for ContextId {
|
||||
// Allocates a unique ID for a new context.
|
||||
fn default() -> Self {
|
||||
// No overflow checking is needed here: overflowing this would take
|
||||
// thousands of years.
|
||||
static NEXT_ID: AtomicU64 = AtomicU64::new(1);
|
||||
Self(NonZeroU64::new(NEXT_ID.fetch_add(1, Ordering::Relaxed)).unwrap())
|
||||
}
|
||||
}
|
||||
|
||||
/// Trait to represent an object managed by a context. This is implemented on
|
||||
/// the VM types managed by the context.
|
||||
pub trait ContextObject: Sized {
|
||||
fn list(ctx: &ContextObjects) -> &Vec<Self>;
|
||||
fn list_mut(ctx: &mut ContextObjects) -> &mut Vec<Self>;
|
||||
}
|
||||
|
||||
macro_rules! impl_context_object {
|
||||
($($field:ident => $ty:ty,)*) => {
|
||||
$(
|
||||
impl ContextObject for $ty {
|
||||
fn list(ctx: &ContextObjects) -> &Vec<Self> {
|
||||
&ctx.$field
|
||||
}
|
||||
fn list_mut(ctx: &mut ContextObjects) -> &mut Vec<Self> {
|
||||
&mut ctx.$field
|
||||
}
|
||||
}
|
||||
)*
|
||||
};
|
||||
}
|
||||
|
||||
impl_context_object! {
|
||||
functions => VMFunction,
|
||||
tables => VMTable,
|
||||
globals => VMGlobal,
|
||||
memories => VMMemory,
|
||||
instances => js_sys::WebAssembly::Instance,
|
||||
}
|
||||
|
||||
/// Set of objects managed by a context.
|
||||
#[derive(Default)]
|
||||
pub struct ContextObjects {
|
||||
id: ContextId,
|
||||
memories: Vec<VMMemory>,
|
||||
tables: Vec<VMTable>,
|
||||
globals: Vec<VMGlobal>,
|
||||
functions: Vec<VMFunction>,
|
||||
instances: Vec<js_sys::WebAssembly::Instance>,
|
||||
}
|
||||
|
||||
impl ContextObjects {
|
||||
/// Returns the ID of this context.
|
||||
pub fn id(&self) -> ContextId {
|
||||
self.id
|
||||
}
|
||||
|
||||
/// Returns a pair of mutable references from two handles.
|
||||
///
|
||||
/// Panics if both handles point to the same object.
|
||||
pub fn get_2_mut<T: ContextObject>(
|
||||
&mut self,
|
||||
a: InternalContextHandle<T>,
|
||||
b: InternalContextHandle<T>,
|
||||
) -> (&mut T, &mut T) {
|
||||
assert_ne!(a.index(), b.index());
|
||||
let list = T::list_mut(self);
|
||||
if a.index() < b.index() {
|
||||
let (low, high) = list.split_at_mut(b.index());
|
||||
(&mut low[a.index()], &mut high[0])
|
||||
} else {
|
||||
let (low, high) = list.split_at_mut(a.index());
|
||||
(&mut high[0], &mut low[a.index()])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Handle to an object managed by a context.
|
||||
///
|
||||
/// Internally this is just an integer index into a context. A reference to the
|
||||
/// context must be passed in separately to access the actual object.
|
||||
pub struct ContextHandle<T> {
|
||||
id: ContextId,
|
||||
internal: InternalContextHandle<T>,
|
||||
}
|
||||
|
||||
impl<T> core::cmp::PartialEq for ContextHandle<T> {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.id == other.id
|
||||
}
|
||||
}
|
||||
impl<T> Clone for ContextHandle<T> {
|
||||
fn clone(&self) -> Self {
|
||||
Self {
|
||||
id: self.id,
|
||||
internal: self.internal,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: ContextObject> fmt::Debug for ContextHandle<T> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.debug_struct("ContextHandle")
|
||||
.field("id", &self.id)
|
||||
.field("internal", &self.internal.index())
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: ContextObject> ContextHandle<T> {
|
||||
/// Moves the given object into a context and returns a handle to it.
|
||||
pub fn new(ctx: &mut ContextObjects, val: T) -> Self {
|
||||
Self {
|
||||
id: ctx.id,
|
||||
internal: InternalContextHandle::new(ctx, val),
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns a reference to the object that this handle points to.
|
||||
pub fn get<'a>(&self, ctx: &'a ContextObjects) -> &'a T {
|
||||
assert_eq!(self.id, ctx.id, "object used with the wrong context");
|
||||
self.internal.get(ctx)
|
||||
}
|
||||
|
||||
/// Returns a mutable reference to the object that this handle points to.
|
||||
pub fn get_mut<'a>(&self, ctx: &'a mut ContextObjects) -> &'a mut T {
|
||||
assert_eq!(self.id, ctx.id, "object used with the wrong context");
|
||||
self.internal.get_mut(ctx)
|
||||
}
|
||||
|
||||
/// Returns the internal handle contains within this handle.
|
||||
pub fn internal_handle(&self) -> InternalContextHandle<T> {
|
||||
self.internal
|
||||
}
|
||||
|
||||
/// Returns the ID of the context associated with the handle.
|
||||
pub fn context_id(&self) -> ContextId {
|
||||
self.id
|
||||
}
|
||||
|
||||
/// Constructs a `ContextHandle` from a `ContextId` and an `InternalContextHandle`.
|
||||
///
|
||||
/// # Safety
|
||||
/// Handling `InternalContextHandle` values is unsafe because they do not track context ID.
|
||||
pub unsafe fn from_internal(id: ContextId, internal: InternalContextHandle<T>) -> Self {
|
||||
Self { id, internal }
|
||||
}
|
||||
}
|
||||
|
||||
/// Internal handle to an object owned by the current context.
|
||||
///
|
||||
/// Unlike `ContextHandle` this does not track the context ID: it is only
|
||||
/// intended to be used within objects already owned by a context.
|
||||
#[repr(transparent)]
|
||||
pub struct InternalContextHandle<T> {
|
||||
// Use a NonZero here to reduce the size of Option<InternalContextHandle>.
|
||||
idx: NonZeroUsize,
|
||||
marker: PhantomData<fn() -> T>,
|
||||
}
|
||||
|
||||
impl<T> Clone for InternalContextHandle<T> {
|
||||
fn clone(&self) -> Self {
|
||||
*self
|
||||
}
|
||||
}
|
||||
impl<T> Copy for InternalContextHandle<T> {}
|
||||
|
||||
impl<T> fmt::Debug for InternalContextHandle<T> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.debug_struct("InternalContextHandle")
|
||||
.field("idx", &self.idx)
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
impl<T> PartialEq for InternalContextHandle<T> {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.idx == other.idx
|
||||
}
|
||||
}
|
||||
impl<T> Eq for InternalContextHandle<T> {}
|
||||
|
||||
impl<T: ContextObject> InternalContextHandle<T> {
|
||||
/// Moves the given object into a context and returns a handle to it.
|
||||
pub fn new(ctx: &mut ContextObjects, val: T) -> Self {
|
||||
let list = T::list_mut(ctx);
|
||||
let idx = NonZeroUsize::new(list.len() + 1).unwrap();
|
||||
list.push(val);
|
||||
Self {
|
||||
idx,
|
||||
marker: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns a reference to the object that this handle points to.
|
||||
pub fn get<'a>(&self, ctx: &'a ContextObjects) -> &'a T {
|
||||
&T::list(ctx)[self.idx.get() - 1]
|
||||
}
|
||||
|
||||
/// Returns a mutable reference to the object that this handle points to.
|
||||
pub fn get_mut<'a>(&self, ctx: &'a mut ContextObjects) -> &'a mut T {
|
||||
&mut T::list_mut(ctx)[self.idx.get() - 1]
|
||||
}
|
||||
|
||||
pub(crate) fn index(&self) -> usize {
|
||||
self.idx.get()
|
||||
}
|
||||
|
||||
pub(crate) fn from_index(idx: usize) -> Option<Self> {
|
||||
NonZeroUsize::new(idx).map(|idx| Self {
|
||||
idx,
|
||||
marker: PhantomData,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/// Data used by the generated code is generally located inline within the
|
||||
/// `VMContext` for items defined in an instance. Host-defined objects are
|
||||
/// allocated separately and owned directly by the context.
|
||||
pub enum MaybeInstanceOwned<T> {
|
||||
/// The data is owned here.
|
||||
Host(Box<UnsafeCell<T>>),
|
||||
|
||||
/// The data is stored inline in the `VMContext` of an instance.
|
||||
Instance(NonNull<T>),
|
||||
}
|
||||
|
||||
impl<T> MaybeInstanceOwned<T> {
|
||||
/// Returns underlying pointer to the VM data.
|
||||
pub fn as_ptr(&self) -> NonNull<T> {
|
||||
match self {
|
||||
MaybeInstanceOwned::Host(p) => unsafe { NonNull::new_unchecked(p.get()) },
|
||||
MaybeInstanceOwned::Instance(p) => *p,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -163,10 +163,10 @@ pub enum InstantiationError {
|
||||
#[cfg_attr(feature = "std", error(transparent))]
|
||||
Start(RuntimeError),
|
||||
|
||||
/// Import from a different [`Context`].
|
||||
/// This error occurs when an import from a different context is used.
|
||||
#[cfg_attr(feature = "std", error("cannot mix imports from different contexts"))]
|
||||
BadContext,
|
||||
/// Import from a different [`Store`].
|
||||
/// This error occurs when an import from a different store is used.
|
||||
#[cfg_attr(feature = "std", error("cannot mix imports from different stores"))]
|
||||
DifferentStores,
|
||||
|
||||
/// A generic error occured while invoking API functions
|
||||
#[cfg_attr(feature = "std", error(transparent))]
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
use crate::js::context::{AsContextMut, AsContextRef, InternalContextHandle};
|
||||
use crate::js::error::WasmError;
|
||||
use crate::js::store::{AsStoreMut, AsStoreRef, InternalStoreHandle};
|
||||
use crate::js::wasm_bindgen_polyfill::Global;
|
||||
use js_sys::Function;
|
||||
use js_sys::WebAssembly::{Memory, Table};
|
||||
@@ -85,36 +85,33 @@ impl fmt::Debug for VMFunction {
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum Export {
|
||||
/// A function export value.
|
||||
Function(InternalContextHandle<VMFunction>),
|
||||
Function(InternalStoreHandle<VMFunction>),
|
||||
|
||||
/// A table export value.
|
||||
Table(InternalContextHandle<VMTable>),
|
||||
Table(InternalStoreHandle<VMTable>),
|
||||
|
||||
/// A memory export value.
|
||||
Memory(InternalContextHandle<VMMemory>),
|
||||
Memory(InternalStoreHandle<VMMemory>),
|
||||
|
||||
/// A global export value.
|
||||
Global(InternalContextHandle<VMGlobal>),
|
||||
Global(InternalStoreHandle<VMGlobal>),
|
||||
}
|
||||
|
||||
impl Export {
|
||||
/// Return the export as a `JSValue`.
|
||||
pub fn as_jsvalue<'context>(&self, ctx: &'context impl AsContextRef) -> &'context JsValue {
|
||||
pub fn as_jsvalue<'context>(&self, ctx: &'context impl AsStoreRef) -> &'context JsValue {
|
||||
match self {
|
||||
Self::Memory(js_wasm_memory) => js_wasm_memory
|
||||
.get(ctx.as_context_ref().objects())
|
||||
.get(ctx.as_store_ref().objects())
|
||||
.memory
|
||||
.as_ref(),
|
||||
Self::Function(js_func) => js_func
|
||||
.get(ctx.as_context_ref().objects())
|
||||
.function
|
||||
.as_ref(),
|
||||
Self::Function(js_func) => js_func.get(ctx.as_store_ref().objects()).function.as_ref(),
|
||||
Self::Table(js_wasm_table) => js_wasm_table
|
||||
.get(ctx.as_context_ref().objects())
|
||||
.get(ctx.as_store_ref().objects())
|
||||
.table
|
||||
.as_ref(),
|
||||
Self::Global(js_wasm_global) => js_wasm_global
|
||||
.get(ctx.as_context_ref().objects())
|
||||
.get(ctx.as_store_ref().objects())
|
||||
.global
|
||||
.as_ref(),
|
||||
}
|
||||
@@ -123,14 +120,14 @@ impl Export {
|
||||
/// Convert a `JsValue` into an `Export` within a given `Context`.
|
||||
pub fn from_js_value(
|
||||
val: JsValue,
|
||||
ctx: &mut impl AsContextMut,
|
||||
ctx: &mut impl AsStoreMut,
|
||||
extern_type: ExternType,
|
||||
) -> Result<Self, WasmError> {
|
||||
match extern_type {
|
||||
ExternType::Memory(memory_type) => {
|
||||
if val.is_instance_of::<Memory>() {
|
||||
Ok(Self::Memory(InternalContextHandle::new(
|
||||
&mut ctx.as_context_mut().objects_mut(),
|
||||
Ok(Self::Memory(InternalStoreHandle::new(
|
||||
&mut ctx.objects_mut(),
|
||||
VMMemory::new(val.unchecked_into::<Memory>(), memory_type),
|
||||
)))
|
||||
} else {
|
||||
@@ -145,8 +142,8 @@ impl Export {
|
||||
}
|
||||
ExternType::Global(global_type) => {
|
||||
if val.is_instance_of::<Global>() {
|
||||
Ok(Self::Global(InternalContextHandle::new(
|
||||
&mut ctx.as_context_mut().objects_mut(),
|
||||
Ok(Self::Global(InternalStoreHandle::new(
|
||||
&mut ctx.objects_mut(),
|
||||
VMGlobal::new(val.unchecked_into::<Global>(), global_type),
|
||||
)))
|
||||
} else {
|
||||
@@ -155,8 +152,8 @@ impl Export {
|
||||
}
|
||||
ExternType::Function(function_type) => {
|
||||
if val.is_instance_of::<Function>() {
|
||||
Ok(Self::Function(InternalContextHandle::new(
|
||||
&mut ctx.as_context_mut().objects_mut(),
|
||||
Ok(Self::Function(InternalStoreHandle::new(
|
||||
&mut ctx.objects_mut(),
|
||||
VMFunction::new(val.unchecked_into::<Function>(), function_type),
|
||||
)))
|
||||
} else {
|
||||
@@ -165,8 +162,8 @@ impl Export {
|
||||
}
|
||||
ExternType::Table(table_type) => {
|
||||
if val.is_instance_of::<Table>() {
|
||||
Ok(Self::Table(InternalContextHandle::new(
|
||||
&mut ctx.as_context_mut().objects_mut(),
|
||||
Ok(Self::Table(InternalStoreHandle::new(
|
||||
&mut ctx.objects_mut(),
|
||||
VMTable::new(val.unchecked_into::<Table>(), table_type),
|
||||
)))
|
||||
} else {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use crate::js::context::AsContextRef;
|
||||
use crate::js::externals::{Extern, Function, Global, Memory, Table};
|
||||
use crate::js::native::TypedFunction;
|
||||
use crate::js::store::AsStoreRef;
|
||||
use crate::js::WasmTypeList;
|
||||
use indexmap::IndexMap;
|
||||
use std::fmt;
|
||||
@@ -18,7 +18,7 @@ use thiserror::Error;
|
||||
///
|
||||
/// ```should_panic
|
||||
/// # use wasmer::{imports, wat2wasm, Function, Instance, Module, Store, Type, Value, ExportError};
|
||||
/// # let store = Store::default();
|
||||
/// # let mut store = Store::default();
|
||||
/// # let wasm_bytes = wat2wasm(r#"
|
||||
/// # (module
|
||||
/// # (global $one (export "glob") f32 (f32.const 1)))
|
||||
@@ -35,7 +35,7 @@ use thiserror::Error;
|
||||
///
|
||||
/// ```should_panic
|
||||
/// # use wasmer::{imports, wat2wasm, Function, Instance, Module, Store, Type, Value, ExportError};
|
||||
/// # let store = Store::default();
|
||||
/// # let mut store = Store::default();
|
||||
/// # let wasm_bytes = wat2wasm("(module)".as_bytes()).unwrap();
|
||||
/// # let module = Module::new(&store, wasm_bytes).unwrap();
|
||||
/// # let import_object = imports! {};
|
||||
@@ -141,7 +141,7 @@ impl Exports {
|
||||
/// Get an export as a `TypedFunction`.
|
||||
pub fn get_native_function<Args, Rets>(
|
||||
&self,
|
||||
ctx: &impl AsContextRef,
|
||||
ctx: &impl AsStoreRef,
|
||||
name: &str,
|
||||
) -> Result<TypedFunction<Args, Rets>, ExportError>
|
||||
where
|
||||
@@ -154,7 +154,7 @@ impl Exports {
|
||||
/// Get an export as a `TypedFunction`.
|
||||
pub fn get_typed_function<Args, Rets>(
|
||||
&self,
|
||||
ctx: &impl AsContextRef,
|
||||
store: &impl AsStoreRef,
|
||||
name: &str,
|
||||
) -> Result<TypedFunction<Args, Rets>, ExportError>
|
||||
where
|
||||
@@ -162,14 +162,14 @@ impl Exports {
|
||||
Rets: WasmTypeList,
|
||||
{
|
||||
self.get_function(name)?
|
||||
.native(ctx)
|
||||
.native(store)
|
||||
.map_err(|_| ExportError::IncompatibleType)
|
||||
}
|
||||
|
||||
/// Hack to get this working with nativefunc too
|
||||
pub fn get_with_generics<'a, T, Args, Rets>(
|
||||
&'a self,
|
||||
ctx: &impl AsContextRef,
|
||||
ctx: &impl AsStoreRef,
|
||||
name: &str,
|
||||
) -> Result<T, ExportError>
|
||||
where
|
||||
@@ -187,7 +187,7 @@ impl Exports {
|
||||
/// This is useful for passing data into Context data, for example.
|
||||
pub fn get_with_generics_weak<'a, T, Args, Rets>(
|
||||
&'a self,
|
||||
ctx: &impl AsContextRef,
|
||||
ctx: &impl AsStoreRef,
|
||||
name: &str,
|
||||
) -> Result<T, ExportError>
|
||||
where
|
||||
@@ -334,7 +334,7 @@ pub trait Exportable<'a>: Sized {
|
||||
pub trait ExportableWithGenerics<'a, Args: WasmTypeList, Rets: WasmTypeList>: Sized {
|
||||
/// Get an export with the given generics.
|
||||
fn get_self_from_extern_with_generics(
|
||||
ctx: &impl AsContextRef,
|
||||
ctx: &impl AsStoreRef,
|
||||
_extern: &'a Extern,
|
||||
) -> Result<Self, ExportError>;
|
||||
}
|
||||
@@ -343,7 +343,7 @@ pub trait ExportableWithGenerics<'a, Args: WasmTypeList, Rets: WasmTypeList>: Si
|
||||
/// with empty `Args` and `Rets`.
|
||||
impl<'a, T: Exportable<'a> + Clone + 'static> ExportableWithGenerics<'a, (), ()> for T {
|
||||
fn get_self_from_extern_with_generics(
|
||||
_ctx: &impl AsContextRef,
|
||||
_ctx: &impl AsStoreRef,
|
||||
_extern: &'a Extern,
|
||||
) -> Result<Self, ExportError> {
|
||||
T::get_self_from_extern(_extern).map(|i| i.clone())
|
||||
|
||||
193
lib/api/src/js/externals/function.rs
vendored
193
lib/api/src/js/externals/function.rs
vendored
@@ -1,14 +1,13 @@
|
||||
pub use self::inner::{FromToNativeWasmType, HostFunction, WasmTypeList};
|
||||
use crate::js::context::{
|
||||
AsContextMut, AsContextRef, ContextHandle, ContextMut, InternalContextHandle,
|
||||
};
|
||||
use crate::js::exports::{ExportError, Exportable};
|
||||
use crate::js::externals::Extern;
|
||||
use crate::js::function_env::FunctionEnvMut;
|
||||
use crate::js::store::{AsStoreMut, AsStoreRef, InternalStoreHandle, StoreHandle, StoreMut};
|
||||
use crate::js::types::{param_from_js, AsJs}; /* ValFuncRef */
|
||||
use crate::js::FunctionType;
|
||||
use crate::js::RuntimeError;
|
||||
use crate::js::TypedFunction;
|
||||
use crate::js::Value;
|
||||
use crate::js::{FunctionEnv, FunctionType};
|
||||
use js_sys::{Array, Function as JSFunction};
|
||||
use std::iter::FromIterator;
|
||||
use wasm_bindgen::prelude::*;
|
||||
@@ -58,7 +57,7 @@ fn results_to_js_array(values: &[Value]) -> Array {
|
||||
/// [Closures as host functions tracking issue](https://github.com/wasmerio/wasmer/issues/1840)
|
||||
#[derive(Clone, PartialEq)]
|
||||
pub struct Function {
|
||||
pub(crate) handle: ContextHandle<VMFunction>,
|
||||
pub(crate) handle: StoreHandle<VMFunction>,
|
||||
}
|
||||
|
||||
impl Function {
|
||||
@@ -71,7 +70,7 @@ impl Function {
|
||||
///
|
||||
/// ```
|
||||
/// # use wasmer::{Function, FunctionType, Type, Store, Value};
|
||||
/// # let store = Store::default();
|
||||
/// # let mut store = Store::default();
|
||||
/// #
|
||||
/// let signature = FunctionType::new(vec![Type::I32, Type::I32], vec![Type::I32]);
|
||||
///
|
||||
@@ -85,7 +84,7 @@ impl Function {
|
||||
///
|
||||
/// ```
|
||||
/// # use wasmer::{Function, FunctionType, Type, Store, Value};
|
||||
/// # let store = Store::default();
|
||||
/// # let mut store = Store::default();
|
||||
/// #
|
||||
/// const I32_I32_TO_I32: ([Type; 2], [Type; 1]) = ([Type::I32, Type::I32], [Type::I32]);
|
||||
///
|
||||
@@ -95,55 +94,63 @@ impl Function {
|
||||
/// });
|
||||
/// ```
|
||||
#[allow(clippy::cast_ptr_alignment)]
|
||||
pub fn new<FT, F, T>(ctx: &mut impl AsContextMut<Data = T>, ty: FT, func: F) -> Self
|
||||
pub fn new<FT, F, T: Send + 'static>(
|
||||
store: &mut impl AsStoreMut,
|
||||
ctx: &FunctionEnv<T>,
|
||||
ty: FT,
|
||||
func: F,
|
||||
) -> Self
|
||||
where
|
||||
FT: Into<FunctionType>,
|
||||
F: Fn(ContextMut<'_, T>, &[Value]) -> Result<Vec<Value>, RuntimeError>
|
||||
F: Fn(FunctionEnvMut<'_, T>, &[Value]) -> Result<Vec<Value>, RuntimeError>
|
||||
+ 'static
|
||||
+ Send
|
||||
+ Sync,
|
||||
{
|
||||
let mut ctx = ctx.as_context_mut();
|
||||
let mut store = store.as_store_mut();
|
||||
let function_type = ty.into();
|
||||
let func_ty = function_type.clone();
|
||||
let raw_ctx = ctx.as_raw() as *mut u8;
|
||||
|
||||
let raw_store = store.as_raw() as *mut u8;
|
||||
let raw_ctx = ctx.clone();
|
||||
let wrapped_func: JsValue = match function_type.results().len() {
|
||||
0 => Closure::wrap(Box::new(move |args: &Array| {
|
||||
let mut ctx: ContextMut<T> = unsafe { ContextMut::from_raw(raw_ctx as _) };
|
||||
let mut store: StoreMut = unsafe { StoreMut::from_raw(raw_store as _) };
|
||||
let mut ctx: FunctionEnvMut<T> = raw_ctx.clone().into_mut(&mut store);
|
||||
let wasm_arguments = function_type
|
||||
.params()
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(i, param)| param_from_js(param, &args.get(i as u32)))
|
||||
.collect::<Vec<_>>();
|
||||
let _results = func(ctx.as_context_mut(), &wasm_arguments)?;
|
||||
let _results = func(ctx, &wasm_arguments)?;
|
||||
Ok(())
|
||||
})
|
||||
as Box<dyn FnMut(&Array) -> Result<(), JsValue>>)
|
||||
.into_js_value(),
|
||||
1 => Closure::wrap(Box::new(move |args: &Array| {
|
||||
let mut ctx: ContextMut<T> = unsafe { ContextMut::from_raw(raw_ctx as _) };
|
||||
let mut store: StoreMut = unsafe { StoreMut::from_raw(raw_store as _) };
|
||||
let mut ctx: FunctionEnvMut<T> = raw_ctx.clone().into_mut(&mut store);
|
||||
let wasm_arguments = function_type
|
||||
.params()
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(i, param)| param_from_js(param, &args.get(i as u32)))
|
||||
.collect::<Vec<_>>();
|
||||
let results = func(ctx.as_context_mut(), &wasm_arguments)?;
|
||||
let results = func(ctx, &wasm_arguments)?;
|
||||
return Ok(result_to_js(&results[0]));
|
||||
})
|
||||
as Box<dyn FnMut(&Array) -> Result<JsValue, JsValue>>)
|
||||
.into_js_value(),
|
||||
_n => Closure::wrap(Box::new(move |args: &Array| {
|
||||
let mut ctx: ContextMut<T> = unsafe { ContextMut::from_raw(raw_ctx as _) };
|
||||
let mut store: StoreMut = unsafe { StoreMut::from_raw(raw_store as _) };
|
||||
let mut ctx: FunctionEnvMut<T> = raw_ctx.clone().into_mut(&mut store);
|
||||
let wasm_arguments = function_type
|
||||
.params()
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(i, param)| param_from_js(param, &args.get(i as u32)))
|
||||
.collect::<Vec<_>>();
|
||||
let results = func(ctx.as_context_mut(), &wasm_arguments)?;
|
||||
let results = func(ctx, &wasm_arguments)?;
|
||||
return Ok(results_to_js_array(&results));
|
||||
})
|
||||
as Box<dyn FnMut(&Array) -> Result<Array, JsValue>>)
|
||||
@@ -154,7 +161,7 @@ impl Function {
|
||||
JSFunction::new_with_args("f", "return f(Array.prototype.slice.call(arguments, 1))");
|
||||
let binded_func = dyn_func.bind1(&JsValue::UNDEFINED, &wrapped_func);
|
||||
let vm_function = VMFunction::new(binded_func, func_ty);
|
||||
Self::from_vm_export(&mut ctx, vm_function)
|
||||
Self::from_vm_export(&mut store, vm_function)
|
||||
}
|
||||
|
||||
/// Creates a new host `Function` from a native function.
|
||||
@@ -166,7 +173,7 @@ impl Function {
|
||||
///
|
||||
/// ```
|
||||
/// # use wasmer::{Store, Function};
|
||||
/// # let store = Store::default();
|
||||
/// # let mut store = Store::default();
|
||||
/// #
|
||||
/// fn sum(a: i32, b: i32) -> i32 {
|
||||
/// a + b
|
||||
@@ -174,13 +181,17 @@ impl Function {
|
||||
///
|
||||
/// let f = Function::new_native(&store, sum);
|
||||
/// ```
|
||||
pub fn new_native<T, F, Args, Rets>(ctx: &mut impl AsContextMut<Data = T>, func: F) -> Self
|
||||
pub fn new_native<T, F, Args, Rets>(
|
||||
store: &mut impl AsStoreMut,
|
||||
env: &FunctionEnv<T>,
|
||||
func: F,
|
||||
) -> Self
|
||||
where
|
||||
F: HostFunction<T, Args, Rets>,
|
||||
Args: WasmTypeList,
|
||||
Rets: WasmTypeList,
|
||||
{
|
||||
let mut ctx = ctx.as_context_mut();
|
||||
let mut store = store.as_store_mut();
|
||||
if std::mem::size_of::<F>() != 0 {
|
||||
Self::closures_unsupported_panic();
|
||||
}
|
||||
@@ -191,14 +202,15 @@ impl Function {
|
||||
let as_table = ft.unchecked_ref::<js_sys::WebAssembly::Table>();
|
||||
let func = as_table.get(address).unwrap();
|
||||
|
||||
let binded_func = func.bind1(
|
||||
let binded_func = func.bind2(
|
||||
&JsValue::UNDEFINED,
|
||||
&JsValue::from_f64(ctx.as_raw() as *mut u8 as usize as f64),
|
||||
&JsValue::from_f64(store.as_raw() as *mut u8 as usize as f64),
|
||||
&JsValue::from_f64(env.handle.internal_handle().index() as f64),
|
||||
);
|
||||
let ty = function.ty();
|
||||
let vm_function = VMFunction::new(binded_func, ty);
|
||||
Self {
|
||||
handle: ContextHandle::new(ctx.as_context_mut().objects_mut(), vm_function),
|
||||
handle: StoreHandle::new(store.objects_mut(), vm_function),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -208,7 +220,7 @@ impl Function {
|
||||
///
|
||||
/// ```
|
||||
/// # use wasmer::{Function, Store, Type};
|
||||
/// # let store = Store::default();
|
||||
/// # let mut store = Store::default();
|
||||
/// #
|
||||
/// fn sum(a: i32, b: i32) -> i32 {
|
||||
/// a + b
|
||||
@@ -219,8 +231,8 @@ impl Function {
|
||||
/// assert_eq!(f.ty().params(), vec![Type::I32, Type::I32]);
|
||||
/// assert_eq!(f.ty().results(), vec![Type::I32]);
|
||||
/// ```
|
||||
pub fn ty<'context>(&self, ctx: &'context impl AsContextRef) -> &'context FunctionType {
|
||||
&self.handle.get(ctx.as_context_ref().objects()).ty
|
||||
pub fn ty<'context>(&self, ctx: &'context impl AsStoreRef) -> &'context FunctionType {
|
||||
&self.handle.get(ctx.as_store_ref().objects()).ty
|
||||
}
|
||||
|
||||
/// Returns the number of parameters that this function takes.
|
||||
@@ -228,18 +240,19 @@ impl Function {
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// # use wasmer::{Function, Store, Type};
|
||||
/// # let store = Store::default();
|
||||
/// # use wasmer::{Function, FunctionEnv, FunctionEnvMut, Store, Type};
|
||||
/// # let mut store = Store::default();
|
||||
/// # let env = FunctionEnv::new(&mut store, ());
|
||||
/// #
|
||||
/// fn sum(a: i32, b: i32) -> i32 {
|
||||
/// fn sum(_ctx: FunctionEnvMut<()>, a: i32, b: i32) -> i32 {
|
||||
/// a + b
|
||||
/// }
|
||||
///
|
||||
/// let f = Function::new_native(&store, sum);
|
||||
/// let f = Function::new_native(&store, &env, sum);
|
||||
///
|
||||
/// assert_eq!(f.param_arity(), 2);
|
||||
/// assert_eq!(f.param_arity(&store), 2);
|
||||
/// ```
|
||||
pub fn param_arity(&self, ctx: &impl AsContextRef) -> usize {
|
||||
pub fn param_arity(&self, ctx: &impl AsStoreRef) -> usize {
|
||||
self.ty(ctx).params().len()
|
||||
}
|
||||
|
||||
@@ -248,18 +261,19 @@ impl Function {
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// # use wasmer::{Function, Store, Type};
|
||||
/// # let store = Store::default();
|
||||
/// # use wasmer::{Function, FunctionEnv, FunctionEnvMut, Store, Type};
|
||||
/// # let mut store = Store::default();
|
||||
/// # let env = FunctionEnv::new(&mut store, ());
|
||||
/// #
|
||||
/// fn sum(a: i32, b: i32) -> i32 {
|
||||
/// fn sum(_ctx: FunctionEnvMut<()>, a: i32, b: i32) -> i32 {
|
||||
/// a + b
|
||||
/// }
|
||||
///
|
||||
/// let f = Function::new_native(&store, sum);
|
||||
/// let f = Function::new_native(&store, &env, sum);
|
||||
///
|
||||
/// assert_eq!(f.result_arity(), 1);
|
||||
/// assert_eq!(f.result_arity(&store), 1);
|
||||
/// ```
|
||||
pub fn result_arity(&self, ctx: &impl AsContextRef) -> usize {
|
||||
pub fn result_arity(&self, ctx: &impl AsStoreRef) -> usize {
|
||||
self.ty(ctx).results().len()
|
||||
}
|
||||
|
||||
@@ -275,7 +289,7 @@ impl Function {
|
||||
///
|
||||
/// ```
|
||||
/// # use wasmer::{imports, wat2wasm, Function, Instance, Module, Store, Type, Value};
|
||||
/// # let store = Store::default();
|
||||
/// # let mut store = Store::default();
|
||||
/// # let wasm_bytes = wat2wasm(r#"
|
||||
/// # (module
|
||||
/// # (func (export "sum") (param $x i32) (param $y i32) (result i32)
|
||||
@@ -292,27 +306,27 @@ impl Function {
|
||||
///
|
||||
/// assert_eq!(sum.call(&[Value::I32(1), Value::I32(2)]).unwrap().to_vec(), vec![Value::I32(3)]);
|
||||
/// ```
|
||||
pub fn call<T>(
|
||||
pub fn call(
|
||||
&self,
|
||||
ctx: &mut impl AsContextMut<Data = T>,
|
||||
store: &mut impl AsStoreMut,
|
||||
params: &[Value],
|
||||
) -> Result<Box<[Value]>, RuntimeError> {
|
||||
let arr = js_sys::Array::new_with_length(params.len() as u32);
|
||||
|
||||
// let raw_ctx = ctx.as_context_mut().as_raw() as *mut u8;
|
||||
// let mut ctx = unsafe { ContextMut::from_raw(raw_ctx as *mut ContextInner<()>) };
|
||||
// let raw_ctx = ctx.as_raw() as *mut u8;
|
||||
// let mut env = unsafe { FunctionEnvMut::from_raw(raw_ctx as *mut StoreInner<()>) };
|
||||
|
||||
for (i, param) in params.iter().enumerate() {
|
||||
let js_value = param.as_jsvalue(&ctx.as_context_ref());
|
||||
let js_value = param.as_jsvalue(&store.as_store_ref());
|
||||
arr.set(i as u32, js_value);
|
||||
}
|
||||
let result = js_sys::Reflect::apply(
|
||||
&self.handle.get(ctx.as_context_ref().objects()).function,
|
||||
&self.handle.get(store.as_store_ref().objects()).function,
|
||||
&wasm_bindgen::JsValue::NULL,
|
||||
&arr,
|
||||
)?;
|
||||
|
||||
let result_types = self.handle.get(ctx.as_context_ref().objects()).ty.results();
|
||||
let result_types = self.handle.get(store.as_store_ref().objects()).ty.results();
|
||||
match result_types.len() {
|
||||
0 => Ok(Box::new([])),
|
||||
1 => {
|
||||
@@ -331,19 +345,19 @@ impl Function {
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn from_vm_export(ctx: &mut impl AsContextMut, vm_function: VMFunction) -> Self {
|
||||
pub(crate) fn from_vm_export(ctx: &mut impl AsStoreMut, vm_function: VMFunction) -> Self {
|
||||
Self {
|
||||
handle: ContextHandle::new(ctx.as_context_mut().objects_mut(), vm_function),
|
||||
handle: StoreHandle::new(ctx.objects_mut(), vm_function),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn from_vm_extern(
|
||||
ctx: &mut impl AsContextMut,
|
||||
internal: InternalContextHandle<VMFunction>,
|
||||
ctx: &mut impl AsStoreMut,
|
||||
internal: InternalStoreHandle<VMFunction>,
|
||||
) -> Self {
|
||||
Self {
|
||||
handle: unsafe {
|
||||
ContextHandle::from_internal(ctx.as_context_ref().objects().id(), internal)
|
||||
StoreHandle::from_internal(ctx.as_store_ref().objects().id(), internal)
|
||||
},
|
||||
}
|
||||
}
|
||||
@@ -355,7 +369,7 @@ impl Function {
|
||||
///
|
||||
/// ```
|
||||
/// # use wasmer::{imports, wat2wasm, Function, Instance, Module, Store, Type, Value};
|
||||
/// # let store = Store::default();
|
||||
/// # let mut store = Store::default();
|
||||
/// # let wasm_bytes = wat2wasm(r#"
|
||||
/// # (module
|
||||
/// # (func (export "sum") (param $x i32) (param $y i32) (result i32)
|
||||
@@ -371,7 +385,7 @@ impl Function {
|
||||
/// let sum = instance.exports.get_function("sum").unwrap();
|
||||
/// let sum_native = sum.native::<(i32, i32), i32>().unwrap();
|
||||
///
|
||||
/// assert_eq!(sum_native.call(1, 2).unwrap(), 3);
|
||||
/// assert_eq!(sum_native.call(&mut store, 1, 2).unwrap(), 3);
|
||||
/// ```
|
||||
///
|
||||
/// # Errors
|
||||
@@ -381,7 +395,7 @@ impl Function {
|
||||
///
|
||||
/// ```should_panic
|
||||
/// # use wasmer::{imports, wat2wasm, Function, Instance, Module, Store, Type, Value};
|
||||
/// # let store = Store::default();
|
||||
/// # let mut store = Store::default();
|
||||
/// # let wasm_bytes = wat2wasm(r#"
|
||||
/// # (module
|
||||
/// # (func (export "sum") (param $x i32) (param $y i32) (result i32)
|
||||
@@ -397,7 +411,7 @@ impl Function {
|
||||
/// let sum = instance.exports.get_function("sum").unwrap();
|
||||
///
|
||||
/// // This results in an error: `RuntimeError`
|
||||
/// let sum_native = sum.native::<(i64, i64), i32>().unwrap();
|
||||
/// let sum_native = sum.native::<(i64, i64), i32>(&mut store).unwrap();
|
||||
/// ```
|
||||
///
|
||||
/// If the `Rets` generic parameter does not match the exported function
|
||||
@@ -405,7 +419,7 @@ impl Function {
|
||||
///
|
||||
/// ```should_panic
|
||||
/// # use wasmer::{imports, wat2wasm, Function, Instance, Module, Store, Type, Value};
|
||||
/// # let store = Store::default();
|
||||
/// # let mut store = Store::default();
|
||||
/// # let wasm_bytes = wat2wasm(r#"
|
||||
/// # (module
|
||||
/// # (func (export "sum") (param $x i32) (param $y i32) (result i32)
|
||||
@@ -421,17 +435,17 @@ impl Function {
|
||||
/// let sum = instance.exports.get_function("sum").unwrap();
|
||||
///
|
||||
/// // This results in an error: `RuntimeError`
|
||||
/// let sum_native = sum.native::<(i32, i32), i64>().unwrap();
|
||||
/// let sum_native = sum.native::<(i32, i32), i64>(&mut store).unwrap();
|
||||
/// ```
|
||||
pub fn native<Args, Rets>(
|
||||
&self,
|
||||
ctx: &impl AsContextRef,
|
||||
ctx: &impl AsStoreRef,
|
||||
) -> Result<TypedFunction<Args, Rets>, RuntimeError>
|
||||
where
|
||||
Args: WasmTypeList,
|
||||
Rets: WasmTypeList,
|
||||
{
|
||||
let vm_function = self.handle.get(ctx.as_context_ref().objects());
|
||||
let vm_function = self.handle.get(ctx.as_store_ref().objects());
|
||||
|
||||
// type check
|
||||
{
|
||||
@@ -470,8 +484,8 @@ impl Function {
|
||||
}
|
||||
|
||||
/// Checks whether this `Function` can be used with the given context.
|
||||
pub fn is_from_context(&self, ctx: &impl AsContextRef) -> bool {
|
||||
self.handle.context_id() == ctx.as_context_ref().objects().id()
|
||||
pub fn is_from_store(&self, ctx: &impl AsStoreRef) -> bool {
|
||||
self.handle.store_id() == ctx.as_store_ref().objects().id()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -495,7 +509,9 @@ impl fmt::Debug for Function {
|
||||
mod inner {
|
||||
use super::RuntimeError;
|
||||
use super::VMFunctionBody;
|
||||
use crate::js::context::{AsContextMut, ContextInner, ContextMut};
|
||||
use crate::js::function_env::{FunctionEnvMut, VMFunctionEnvironment};
|
||||
use crate::js::store::{AsStoreMut, InternalStoreHandle, StoreHandle, StoreInner, StoreMut};
|
||||
use crate::js::FunctionEnv;
|
||||
use crate::js::NativeWasmTypeInto;
|
||||
use std::array::TryFromSliceError;
|
||||
use std::convert::{Infallible, TryInto};
|
||||
@@ -641,7 +657,7 @@ mod inner {
|
||||
/// Constructs `Self` based on an array of values.
|
||||
///
|
||||
/// # Safety
|
||||
unsafe fn from_array(ctx: &mut impl AsContextMut, array: Self::Array) -> Self;
|
||||
unsafe fn from_array(ctx: &mut impl AsStoreMut, array: Self::Array) -> Self;
|
||||
|
||||
/// Constructs `Self` based on a slice of values.
|
||||
///
|
||||
@@ -652,7 +668,7 @@ mod inner {
|
||||
///
|
||||
/// # Safety
|
||||
unsafe fn from_slice(
|
||||
ctx: &mut impl AsContextMut,
|
||||
ctx: &mut impl AsStoreMut,
|
||||
slice: &[f64],
|
||||
) -> Result<Self, TryFromSliceError>;
|
||||
|
||||
@@ -660,7 +676,7 @@ mod inner {
|
||||
/// (list) of values.
|
||||
///
|
||||
/// # Safety
|
||||
unsafe fn into_array(self, ctx: &mut impl AsContextMut) -> Self::Array;
|
||||
unsafe fn into_array(self, ctx: &mut impl AsStoreMut) -> Self::Array;
|
||||
|
||||
/// Allocates and return an empty array of type `Array` that
|
||||
/// will hold a tuple (list) of values, usually to hold the
|
||||
@@ -671,13 +687,13 @@ mod inner {
|
||||
/// `CStruct`.
|
||||
///
|
||||
/// # Safety
|
||||
unsafe fn from_c_struct(ctx: &mut impl AsContextMut, c_struct: Self::CStruct) -> Self;
|
||||
unsafe fn from_c_struct(ctx: &mut impl AsStoreMut, c_struct: Self::CStruct) -> Self;
|
||||
|
||||
/// Builds and returns a C struct of type `CStruct` from a
|
||||
/// tuple (list) of values.
|
||||
///
|
||||
/// # Safety
|
||||
unsafe fn into_c_struct(self, ctx: &mut impl AsContextMut) -> Self::CStruct;
|
||||
unsafe fn into_c_struct(self, ctx: &mut impl AsStoreMut) -> Self::CStruct;
|
||||
|
||||
/// Writes the contents of a C struct to an array of `f64`.
|
||||
///
|
||||
@@ -863,7 +879,7 @@ mod inner {
|
||||
#[allow(unused_mut)]
|
||||
#[allow(clippy::unused_unit)]
|
||||
#[allow(clippy::missing_safety_doc)]
|
||||
unsafe fn from_array(mut _ctx: &mut impl AsContextMut, array: Self::Array) -> Self {
|
||||
unsafe fn from_array(mut _ctx: &mut impl AsStoreMut, array: Self::Array) -> Self {
|
||||
// Unpack items of the array.
|
||||
#[allow(non_snake_case)]
|
||||
let [ $( $x ),* ] = array;
|
||||
@@ -877,13 +893,13 @@ mod inner {
|
||||
}
|
||||
|
||||
#[allow(clippy::missing_safety_doc)]
|
||||
unsafe fn from_slice(ctx: &mut impl AsContextMut, slice: &[f64]) -> Result<Self, TryFromSliceError> {
|
||||
unsafe fn from_slice(ctx: &mut impl AsStoreMut, slice: &[f64]) -> Result<Self, TryFromSliceError> {
|
||||
Ok(Self::from_array(ctx, slice.try_into()?))
|
||||
}
|
||||
|
||||
#[allow(unused_mut)]
|
||||
#[allow(clippy::missing_safety_doc)]
|
||||
unsafe fn into_array(self, mut _ctx: &mut impl AsContextMut) -> Self::Array {
|
||||
unsafe fn into_array(self, mut _ctx: &mut impl AsStoreMut) -> Self::Array {
|
||||
// Unpack items of the tuple.
|
||||
#[allow(non_snake_case)]
|
||||
let ( $( $x ),* ) = self;
|
||||
@@ -904,7 +920,7 @@ mod inner {
|
||||
#[allow(unused_mut)]
|
||||
#[allow(clippy::unused_unit)]
|
||||
#[allow(clippy::missing_safety_doc)]
|
||||
unsafe fn from_c_struct(mut _ctx: &mut impl AsContextMut, c_struct: Self::CStruct) -> Self {
|
||||
unsafe fn from_c_struct(mut _ctx: &mut impl AsStoreMut, c_struct: Self::CStruct) -> Self {
|
||||
// Unpack items of the C structure.
|
||||
#[allow(non_snake_case)]
|
||||
let $c_struct_name( $( $x ),* ) = c_struct;
|
||||
@@ -918,7 +934,7 @@ mod inner {
|
||||
|
||||
#[allow(unused_parens, non_snake_case, unused_mut)]
|
||||
#[allow(clippy::missing_safety_doc)]
|
||||
unsafe fn into_c_struct(self, mut _ctx: &mut impl AsContextMut) -> Self::CStruct {
|
||||
unsafe fn into_c_struct(self, mut _ctx: &mut impl AsStoreMut) -> Self::CStruct {
|
||||
// Unpack items of the tuple.
|
||||
let ( $( $x ),* ) = self;
|
||||
|
||||
@@ -961,30 +977,35 @@ mod inner {
|
||||
$( $x: FromToNativeWasmType, )*
|
||||
Rets: WasmTypeList,
|
||||
RetsAsResult: IntoResult<Rets>,
|
||||
Func: Fn(ContextMut<'_, T>, $( $x , )*) -> RetsAsResult + 'static,
|
||||
T: Send + 'static,
|
||||
Func: Fn(FunctionEnvMut<'_, T>, $( $x , )*) -> RetsAsResult + 'static,
|
||||
{
|
||||
#[allow(non_snake_case)]
|
||||
fn function_body_ptr(self) -> *const VMFunctionBody {
|
||||
/// This is a function that wraps the real host
|
||||
/// function. Its address will be used inside the
|
||||
/// runtime.
|
||||
unsafe extern "C" fn func_wrapper<T, $( $x, )* Rets, RetsAsResult, Func>( ctx_ptr: usize, $( $x: <$x::Native as NativeWasmType>::Abi, )* ) -> Rets::CStruct
|
||||
unsafe extern "C" fn func_wrapper<T, $( $x, )* Rets, RetsAsResult, Func>( store_ptr: usize, handle_index: usize, $( $x: <$x::Native as NativeWasmType>::Abi, )* ) -> Rets::CStruct
|
||||
where
|
||||
$( $x: FromToNativeWasmType, )*
|
||||
Rets: WasmTypeList,
|
||||
RetsAsResult: IntoResult<Rets>,
|
||||
Func: Fn(ContextMut<'_, T>, $( $x , )*) -> RetsAsResult + 'static,
|
||||
T: Send + 'static,
|
||||
Func: Fn(FunctionEnvMut<'_, T>, $( $x , )*) -> RetsAsResult + 'static,
|
||||
{
|
||||
// let env: &Env = unsafe { &*(ptr as *const u8 as *const Env) };
|
||||
let func: &Func = &*(&() as *const () as *const Func);
|
||||
let mut ctx = ContextMut::from_raw(ctx_ptr as *mut ContextInner<T>);
|
||||
let mut ctx2 = ContextMut::from_raw(ctx_ptr as *mut ContextInner<T>);
|
||||
let mut store = StoreMut::from_raw(store_ptr as *mut _);
|
||||
let mut store2 = StoreMut::from_raw(store_ptr as *mut _);
|
||||
|
||||
let result = panic::catch_unwind(AssertUnwindSafe(|| {
|
||||
func(ctx2.as_context_mut(), $( FromToNativeWasmType::from_native(NativeWasmTypeInto::from_abi(&mut ctx, $x)) ),* ).into_result()
|
||||
let handle: StoreHandle<VMFunctionEnvironment> = StoreHandle::from_internal(store2.objects_mut().id(), InternalStoreHandle::from_index(handle_index).unwrap());
|
||||
let ctx: FunctionEnvMut<T> = FunctionEnv::from_handle(handle).into_mut(&mut store2);
|
||||
func(ctx, $( FromToNativeWasmType::from_native(NativeWasmTypeInto::from_abi(&mut store, $x)) ),* ).into_result()
|
||||
}));
|
||||
|
||||
match result {
|
||||
Ok(Ok(result)) => return result.into_c_struct(&mut ctx),
|
||||
Ok(Ok(result)) => return result.into_c_struct(&mut store),
|
||||
#[allow(deprecated)]
|
||||
Ok(Err(trap)) => RuntimeError::raise(Box::new(trap)),
|
||||
Err(_panic) => unimplemented!(),
|
||||
@@ -1051,18 +1072,18 @@ mod inner {
|
||||
0
|
||||
}
|
||||
|
||||
unsafe fn from_array(_: &mut impl AsContextMut, _: Self::Array) -> Self {
|
||||
unsafe fn from_array(_: &mut impl AsStoreMut, _: Self::Array) -> Self {
|
||||
unreachable!()
|
||||
}
|
||||
|
||||
unsafe fn from_slice(
|
||||
_: &mut impl AsContextMut,
|
||||
_: &mut impl AsStoreMut,
|
||||
_: &[f64],
|
||||
) -> Result<Self, TryFromSliceError> {
|
||||
unreachable!()
|
||||
}
|
||||
|
||||
unsafe fn into_array(self, _: &mut impl AsContextMut) -> Self::Array {
|
||||
unsafe fn into_array(self, _: &mut impl AsStoreMut) -> Self::Array {
|
||||
[]
|
||||
}
|
||||
|
||||
@@ -1070,11 +1091,11 @@ mod inner {
|
||||
[]
|
||||
}
|
||||
|
||||
unsafe fn from_c_struct(_: &mut impl AsContextMut, self_: Self::CStruct) -> Self {
|
||||
unsafe fn from_c_struct(_: &mut impl AsStoreMut, self_: Self::CStruct) -> Self {
|
||||
self_
|
||||
}
|
||||
|
||||
unsafe fn into_c_struct(self, _: &mut impl AsContextMut) -> Self::CStruct {
|
||||
unsafe fn into_c_struct(self, _: &mut impl AsStoreMut) -> Self::CStruct {
|
||||
self
|
||||
}
|
||||
|
||||
|
||||
66
lib/api/src/js/externals/global.rs
vendored
66
lib/api/src/js/externals/global.rs
vendored
@@ -1,7 +1,7 @@
|
||||
use crate::js::context::{AsContextMut, AsContextRef, ContextHandle, InternalContextHandle};
|
||||
use crate::js::export::VMGlobal;
|
||||
use crate::js::exports::{ExportError, Exportable};
|
||||
use crate::js::externals::Extern;
|
||||
use crate::js::store::{AsStoreMut, AsStoreRef, InternalStoreHandle, StoreHandle};
|
||||
use crate::js::value::Value;
|
||||
use crate::js::wasm_bindgen_polyfill::Global as JSGlobal;
|
||||
use crate::js::GlobalType;
|
||||
@@ -17,7 +17,7 @@ use wasm_bindgen::JsValue;
|
||||
/// Spec: <https://webassembly.github.io/spec/core/exec/runtime.html#global-instances>
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub struct Global {
|
||||
pub(crate) handle: ContextHandle<VMGlobal>,
|
||||
pub(crate) handle: StoreHandle<VMGlobal>,
|
||||
}
|
||||
|
||||
impl Global {
|
||||
@@ -27,14 +27,14 @@ impl Global {
|
||||
///
|
||||
/// ```
|
||||
/// # use wasmer::{Global, Mutability, Store, Value};
|
||||
/// # let store = Store::default();
|
||||
/// # let mut store = Store::default();
|
||||
/// #
|
||||
/// let g = Global::new(&store, Value::I32(1));
|
||||
///
|
||||
/// assert_eq!(g.get(), Value::I32(1));
|
||||
/// assert_eq!(g.ty().mutability, Mutability::Const);
|
||||
/// ```
|
||||
pub fn new(ctx: &mut impl AsContextMut, val: Value) -> Self {
|
||||
pub fn new(ctx: &mut impl AsStoreMut, val: Value) -> Self {
|
||||
Self::from_value(ctx, val, Mutability::Const).unwrap()
|
||||
}
|
||||
|
||||
@@ -44,26 +44,26 @@ impl Global {
|
||||
///
|
||||
/// ```
|
||||
/// # use wasmer::{Global, Mutability, Store, Value};
|
||||
/// # let store = Store::default();
|
||||
/// # let mut store = Store::default();
|
||||
/// #
|
||||
/// let g = Global::new_mut(&store, Value::I32(1));
|
||||
///
|
||||
/// assert_eq!(g.get(), Value::I32(1));
|
||||
/// assert_eq!(g.ty().mutability, Mutability::Var);
|
||||
/// ```
|
||||
pub fn new_mut(ctx: &mut impl AsContextMut, val: Value) -> Self {
|
||||
pub fn new_mut(ctx: &mut impl AsStoreMut, val: Value) -> Self {
|
||||
Self::from_value(ctx, val, Mutability::Var).unwrap()
|
||||
}
|
||||
|
||||
/// Create a `Global` with the initial value [`Value`] and the provided [`Mutability`].
|
||||
fn from_value(
|
||||
ctx: &mut impl AsContextMut,
|
||||
ctx: &mut impl AsStoreMut,
|
||||
val: Value,
|
||||
mutability: Mutability,
|
||||
) -> Result<Self, RuntimeError> {
|
||||
if !val.is_from_context(ctx) {
|
||||
if !val.is_from_store(ctx) {
|
||||
return Err(RuntimeError::new(
|
||||
"cross-`Context` values are not supported",
|
||||
"cross-`WasmerEnv` values are not supported",
|
||||
));
|
||||
}
|
||||
let global_ty = GlobalType {
|
||||
@@ -99,7 +99,7 @@ impl Global {
|
||||
///
|
||||
/// ```
|
||||
/// # use wasmer::{Global, Mutability, Store, Type, Value, GlobalType};
|
||||
/// # let store = Store::default();
|
||||
/// # let mut store = Store::default();
|
||||
/// #
|
||||
/// let c = Global::new(&store, Value::I32(1));
|
||||
/// let v = Global::new_mut(&store, Value::I64(1));
|
||||
@@ -107,8 +107,8 @@ impl Global {
|
||||
/// assert_eq!(c.ty(), &GlobalType::new(Type::I32, Mutability::Const));
|
||||
/// assert_eq!(v.ty(), &GlobalType::new(Type::I64, Mutability::Var));
|
||||
/// ```
|
||||
pub fn ty(&self, ctx: &impl AsContextRef) -> GlobalType {
|
||||
self.handle.get(ctx.as_context_ref().objects()).ty
|
||||
pub fn ty(&self, store: &impl AsStoreRef) -> GlobalType {
|
||||
self.handle.get(store.as_store_ref().objects()).ty
|
||||
}
|
||||
|
||||
/// Retrieves the current value [`Value`] that the Global has.
|
||||
@@ -117,23 +117,23 @@ impl Global {
|
||||
///
|
||||
/// ```
|
||||
/// # use wasmer::{Global, Store, Value};
|
||||
/// # let store = Store::default();
|
||||
/// # let mut store = Store::default();
|
||||
/// #
|
||||
/// let g = Global::new(&store, Value::I32(1));
|
||||
///
|
||||
/// assert_eq!(g.get(), Value::I32(1));
|
||||
/// ```
|
||||
pub fn get(&self, ctx: &impl AsContextRef) -> Value {
|
||||
pub fn get(&self, store: &impl AsStoreRef) -> Value {
|
||||
unsafe {
|
||||
let raw = self
|
||||
.handle
|
||||
.get(ctx.as_context_ref().objects())
|
||||
.get(store.as_store_ref().objects())
|
||||
.global
|
||||
.value()
|
||||
.as_f64()
|
||||
.unwrap();
|
||||
let ty = self.handle.get(ctx.as_context_ref().objects()).ty;
|
||||
Value::from_raw(ctx, ty.ty, raw)
|
||||
let ty = self.handle.get(store.as_store_ref().objects()).ty;
|
||||
Value::from_raw(store, ty.ty, raw)
|
||||
}
|
||||
/*
|
||||
match self.vm_global.ty.ty {
|
||||
@@ -152,7 +152,7 @@ impl Global {
|
||||
///
|
||||
/// ```
|
||||
/// # use wasmer::{Global, Store, Value};
|
||||
/// # let store = Store::default();
|
||||
/// # let mut store = Store::default();
|
||||
/// #
|
||||
/// let g = Global::new_mut(&store, Value::I32(1));
|
||||
///
|
||||
@@ -169,7 +169,7 @@ impl Global {
|
||||
///
|
||||
/// ```should_panic
|
||||
/// # use wasmer::{Global, Store, Value};
|
||||
/// # let store = Store::default();
|
||||
/// # let mut store = Store::default();
|
||||
/// #
|
||||
/// let g = Global::new(&store, Value::I32(1));
|
||||
///
|
||||
@@ -180,20 +180,20 @@ impl Global {
|
||||
///
|
||||
/// ```should_panic
|
||||
/// # use wasmer::{Global, Store, Value};
|
||||
/// # let store = Store::default();
|
||||
/// # let mut store = Store::default();
|
||||
/// #
|
||||
/// let g = Global::new(&store, Value::I32(1));
|
||||
///
|
||||
/// // This results in an error: `RuntimeError`.
|
||||
/// g.set(Value::I64(2)).unwrap();
|
||||
/// ```
|
||||
pub fn set(&self, ctx: &mut impl AsContextMut, val: Value) -> Result<(), RuntimeError> {
|
||||
if !val.is_from_context(ctx) {
|
||||
pub fn set(&self, store: &mut impl AsStoreMut, val: Value) -> Result<(), RuntimeError> {
|
||||
if !val.is_from_store(store) {
|
||||
return Err(RuntimeError::new(
|
||||
"cross-`Context` values are not supported",
|
||||
"cross-`WasmerEnv` values are not supported",
|
||||
));
|
||||
}
|
||||
let global_ty = self.ty(&ctx);
|
||||
let global_ty = self.ty(&store);
|
||||
if global_ty.mutability == Mutability::Const {
|
||||
return Err(RuntimeError::new("The global is immutable".to_owned()));
|
||||
}
|
||||
@@ -212,32 +212,32 @@ impl Global {
|
||||
}
|
||||
};
|
||||
self.handle
|
||||
.get_mut(ctx.as_context_mut().objects_mut())
|
||||
.get_mut(store.objects_mut())
|
||||
.global
|
||||
.set_value(&new_value);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub(crate) fn from_vm_export(ctx: &mut impl AsContextMut, vm_global: VMGlobal) -> Self {
|
||||
pub(crate) fn from_vm_export(store: &mut impl AsStoreMut, vm_global: VMGlobal) -> Self {
|
||||
Self {
|
||||
handle: ContextHandle::new(ctx.as_context_mut().objects_mut(), vm_global),
|
||||
handle: StoreHandle::new(store.objects_mut(), vm_global),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn from_vm_extern(
|
||||
ctx: &mut impl AsContextMut,
|
||||
internal: InternalContextHandle<VMGlobal>,
|
||||
store: &mut impl AsStoreMut,
|
||||
internal: InternalStoreHandle<VMGlobal>,
|
||||
) -> Self {
|
||||
Self {
|
||||
handle: unsafe {
|
||||
ContextHandle::from_internal(ctx.as_context_ref().objects().id(), internal)
|
||||
StoreHandle::from_internal(store.as_store_ref().objects().id(), internal)
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
/// Checks whether this `Global` can be used with the given context.
|
||||
pub fn is_from_context(&self, ctx: &impl AsContextRef) -> bool {
|
||||
self.handle.context_id() == ctx.as_context_ref().objects().id()
|
||||
/// Checks whether this `Global` can be used with the given store.
|
||||
pub fn is_from_store(&self, store: &impl AsStoreRef) -> bool {
|
||||
self.handle.store_id() == store.as_store_ref().objects().id()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
67
lib/api/src/js/externals/memory.rs
vendored
67
lib/api/src/js/externals/memory.rs
vendored
@@ -1,9 +1,7 @@
|
||||
use crate::js::context::{
|
||||
AsContextMut, AsContextRef, ContextHandle, ContextObjects, InternalContextHandle,
|
||||
};
|
||||
use crate::js::export::VMMemory;
|
||||
use crate::js::exports::{ExportError, Exportable};
|
||||
use crate::js::externals::Extern;
|
||||
use crate::js::store::{AsStoreMut, AsStoreRef, InternalStoreHandle, StoreHandle, StoreObjects};
|
||||
use crate::js::{MemoryAccessError, MemoryType};
|
||||
use std::convert::TryInto;
|
||||
use std::marker::PhantomData;
|
||||
@@ -80,7 +78,7 @@ extern "C" {
|
||||
/// Spec: <https://webassembly.github.io/spec/core/exec/runtime.html#memory-instances>
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Memory {
|
||||
pub(crate) handle: ContextHandle<VMMemory>,
|
||||
pub(crate) handle: StoreHandle<VMMemory>,
|
||||
#[allow(dead_code)]
|
||||
view: js_sys::Uint8Array,
|
||||
}
|
||||
@@ -98,11 +96,11 @@ impl Memory {
|
||||
///
|
||||
/// ```
|
||||
/// # use wasmer::{Memory, MemoryType, Pages, Store, Type, Value};
|
||||
/// # let store = Store::default();
|
||||
/// # let mut store = Store::default();
|
||||
/// #
|
||||
/// let m = Memory::new(&store, MemoryType::new(1, None, false)).unwrap();
|
||||
/// ```
|
||||
pub fn new(ctx: &mut impl AsContextMut, ty: MemoryType) -> Result<Self, MemoryError> {
|
||||
pub fn new(ctx: &mut impl AsStoreMut, ty: MemoryType) -> Result<Self, MemoryError> {
|
||||
let descriptor = js_sys::Object::new();
|
||||
js_sys::Reflect::set(&descriptor, &"initial".into(), &ty.minimum.0.into()).unwrap();
|
||||
if let Some(max) = ty.maximum {
|
||||
@@ -123,15 +121,15 @@ impl Memory {
|
||||
///
|
||||
/// ```
|
||||
/// # use wasmer::{Memory, MemoryType, Pages, Store, Type, Value};
|
||||
/// # let store = Store::default();
|
||||
/// # let mut store = Store::default();
|
||||
/// #
|
||||
/// let mt = MemoryType::new(1, None, false);
|
||||
/// let m = Memory::new(&store, mt).unwrap();
|
||||
///
|
||||
/// assert_eq!(m.ty(), mt);
|
||||
/// ```
|
||||
pub fn ty(&self, ctx: &impl AsContextRef) -> MemoryType {
|
||||
self.handle.get(ctx.as_context_ref().objects()).ty
|
||||
pub fn ty(&self, ctx: &impl AsStoreRef) -> MemoryType {
|
||||
self.handle.get(ctx.as_store_ref().objects()).ty
|
||||
}
|
||||
|
||||
/// Returns the pointer to the raw bytes of the `Memory`.
|
||||
@@ -141,11 +139,11 @@ impl Memory {
|
||||
}
|
||||
|
||||
/// Returns the size (in bytes) of the `Memory`.
|
||||
pub fn data_size(&self, ctx: &impl AsContextRef) -> u64 {
|
||||
pub fn data_size(&self, ctx: &impl AsStoreRef) -> u64 {
|
||||
js_sys::Reflect::get(
|
||||
&self
|
||||
.handle
|
||||
.get(ctx.as_context_ref().objects())
|
||||
.get(ctx.as_store_ref().objects())
|
||||
.memory
|
||||
.buffer(),
|
||||
&"byteLength".into(),
|
||||
@@ -161,17 +159,17 @@ impl Memory {
|
||||
///
|
||||
/// ```
|
||||
/// # use wasmer::{Memory, MemoryType, Pages, Store, Type, Value};
|
||||
/// # let store = Store::default();
|
||||
/// # let mut store = Store::default();
|
||||
/// #
|
||||
/// let m = Memory::new(&store, MemoryType::new(1, None, false)).unwrap();
|
||||
///
|
||||
/// assert_eq!(m.size(), Pages(1));
|
||||
/// ```
|
||||
pub fn size(&self, ctx: &impl AsContextRef) -> Pages {
|
||||
pub fn size(&self, ctx: &impl AsStoreRef) -> Pages {
|
||||
let bytes = js_sys::Reflect::get(
|
||||
&self
|
||||
.handle
|
||||
.get(ctx.as_context_ref().objects())
|
||||
.get(ctx.as_store_ref().objects())
|
||||
.memory
|
||||
.buffer(),
|
||||
&"byteLength".into(),
|
||||
@@ -189,7 +187,7 @@ impl Memory {
|
||||
///
|
||||
/// ```
|
||||
/// # use wasmer::{Memory, MemoryType, Pages, Store, Type, Value, WASM_MAX_PAGES};
|
||||
/// # let store = Store::default();
|
||||
/// # let mut store = Store::default();
|
||||
/// #
|
||||
/// let m = Memory::new(&store, MemoryType::new(1, Some(3), false)).unwrap();
|
||||
/// let p = m.grow(2).unwrap();
|
||||
@@ -205,7 +203,7 @@ impl Memory {
|
||||
///
|
||||
/// ```should_panic
|
||||
/// # use wasmer::{Memory, MemoryType, Pages, Store, Type, Value, WASM_MAX_PAGES};
|
||||
/// # let store = Store::default();
|
||||
/// # let mut store = Store::default();
|
||||
/// #
|
||||
/// let m = Memory::new(&store, MemoryType::new(1, Some(1), false)).unwrap();
|
||||
///
|
||||
@@ -214,20 +212,19 @@ impl Memory {
|
||||
/// ```
|
||||
pub fn grow<IntoPages>(
|
||||
&self,
|
||||
ctx: &mut impl AsContextMut,
|
||||
store: &mut impl AsStoreMut,
|
||||
delta: IntoPages,
|
||||
) -> Result<Pages, MemoryError>
|
||||
where
|
||||
IntoPages: Into<Pages>,
|
||||
{
|
||||
let pages = delta.into();
|
||||
let mut ctx_mut = ctx.as_context_mut();
|
||||
let js_memory = &self.handle.get_mut(ctx_mut.objects_mut()).memory;
|
||||
let js_memory = &self.handle.get_mut(store.objects_mut()).memory;
|
||||
let our_js_memory: &JSMemory = JsCast::unchecked_from_js_ref(js_memory);
|
||||
let new_pages = our_js_memory.grow(pages.0).map_err(|err| {
|
||||
if err.is_instance_of::<js_sys::RangeError>() {
|
||||
MemoryError::CouldNotGrow {
|
||||
current: self.size(&ctx.as_context_ref()),
|
||||
current: self.size(&store.as_store_ref()),
|
||||
attempted_delta: pages,
|
||||
}
|
||||
} else {
|
||||
@@ -239,40 +236,40 @@ impl Memory {
|
||||
|
||||
/// Used by tests
|
||||
#[doc(hidden)]
|
||||
pub fn uint8view(&self, ctx: &impl AsContextRef) -> js_sys::Uint8Array {
|
||||
pub fn uint8view(&self, ctx: &impl AsStoreRef) -> js_sys::Uint8Array {
|
||||
js_sys::Uint8Array::new(
|
||||
&self
|
||||
.handle
|
||||
.get(ctx.as_context_ref().objects())
|
||||
.get(ctx.as_store_ref().objects())
|
||||
.memory
|
||||
.buffer(),
|
||||
)
|
||||
}
|
||||
|
||||
pub(crate) fn buffer<'a>(&'a self, _ctx: &'a impl AsContextRef) -> MemoryBuffer<'a> {
|
||||
pub(crate) fn buffer<'a>(&'a self, _ctx: &'a impl AsStoreRef) -> MemoryBuffer<'a> {
|
||||
MemoryBuffer {
|
||||
base: &self.view as *const _ as *mut _,
|
||||
marker: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn from_vm_export(ctx: &mut impl AsContextMut, vm_memory: VMMemory) -> Self {
|
||||
pub(crate) fn from_vm_export(ctx: &mut impl AsStoreMut, vm_memory: VMMemory) -> Self {
|
||||
let view = js_sys::Uint8Array::new(&vm_memory.memory.buffer());
|
||||
Self {
|
||||
handle: ContextHandle::new(ctx.as_context_mut().objects_mut(), vm_memory),
|
||||
handle: StoreHandle::new(ctx.objects_mut(), vm_memory),
|
||||
view,
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn from_vm_extern(
|
||||
ctx: &mut impl AsContextMut,
|
||||
internal: InternalContextHandle<VMMemory>,
|
||||
ctx: &mut impl AsStoreMut,
|
||||
internal: InternalStoreHandle<VMMemory>,
|
||||
) -> Self {
|
||||
let view =
|
||||
js_sys::Uint8Array::new(&internal.get(ctx.as_context_ref().objects()).memory.buffer());
|
||||
js_sys::Uint8Array::new(&internal.get(ctx.as_store_ref().objects()).memory.buffer());
|
||||
Self {
|
||||
handle: unsafe {
|
||||
ContextHandle::from_internal(ctx.as_context_ref().objects().id(), internal)
|
||||
StoreHandle::from_internal(ctx.as_store_ref().objects().id(), internal)
|
||||
},
|
||||
view,
|
||||
}
|
||||
@@ -287,7 +284,7 @@ impl Memory {
|
||||
/// concurrent writes.
|
||||
pub fn read(
|
||||
&self,
|
||||
_ctx: &impl AsContextRef,
|
||||
_ctx: &impl AsStoreRef,
|
||||
offset: u64,
|
||||
data: &mut [u8],
|
||||
) -> Result<(), MemoryAccessError> {
|
||||
@@ -317,7 +314,7 @@ impl Memory {
|
||||
/// concurrent writes.
|
||||
pub fn read_uninit<'a>(
|
||||
&self,
|
||||
_ctx: &impl AsContextRef,
|
||||
_ctx: &impl AsStoreRef,
|
||||
offset: u64,
|
||||
buf: &'a mut [MaybeUninit<u8>],
|
||||
) -> Result<&'a mut [u8], MemoryAccessError> {
|
||||
@@ -352,7 +349,7 @@ impl Memory {
|
||||
/// concurrent reads/writes.
|
||||
pub fn write(
|
||||
&self,
|
||||
_ctx: &mut impl AsContextMut,
|
||||
_ctx: &mut impl AsStoreMut,
|
||||
offset: u64,
|
||||
data: &[u8],
|
||||
) -> Result<(), MemoryAccessError> {
|
||||
@@ -371,8 +368,8 @@ impl Memory {
|
||||
}
|
||||
|
||||
/// Checks whether this `Global` can be used with the given context.
|
||||
pub fn is_from_context(&self, ctx: &impl AsContextRef) -> bool {
|
||||
self.handle.context_id() == ctx.as_context_ref().objects().id()
|
||||
pub fn is_from_store(&self, ctx: &impl AsStoreRef) -> bool {
|
||||
self.handle.store_id() == ctx.as_store_ref().objects().id()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -389,7 +386,7 @@ impl<'a> Exportable<'a> for Memory {
|
||||
#[derive(Copy, Clone)]
|
||||
pub(crate) struct MemoryBuffer<'a> {
|
||||
base: *mut js_sys::Uint8Array,
|
||||
marker: PhantomData<(&'a Memory, &'a ContextObjects)>,
|
||||
marker: PhantomData<(&'a Memory, &'a StoreObjects)>,
|
||||
}
|
||||
|
||||
impl<'a> MemoryBuffer<'a> {
|
||||
|
||||
18
lib/api/src/js/externals/mod.rs
vendored
18
lib/api/src/js/externals/mod.rs
vendored
@@ -8,10 +8,10 @@ pub use self::global::Global;
|
||||
pub use self::memory::{Memory, MemoryError};
|
||||
pub use self::table::Table;
|
||||
|
||||
use crate::js::context::{AsContextMut, AsContextRef};
|
||||
use crate::js::export::Export;
|
||||
use crate::js::exports::{ExportError, Exportable};
|
||||
use crate::js::store::StoreObject;
|
||||
use crate::js::store::{AsStoreMut, AsStoreRef};
|
||||
use crate::js::types::AsJs;
|
||||
use crate::js::ExternType;
|
||||
use std::fmt;
|
||||
@@ -34,7 +34,7 @@ pub enum Extern {
|
||||
|
||||
impl Extern {
|
||||
/// Return the underlying type of the inner `Extern`.
|
||||
pub fn ty(&self, ctx: &impl AsContextRef) -> ExternType {
|
||||
pub fn ty(&self, ctx: &impl AsStoreRef) -> ExternType {
|
||||
match self {
|
||||
Self::Function(ft) => ExternType::Function(ft.ty(ctx).clone()),
|
||||
Self::Memory(ft) => ExternType::Memory(ft.ty(ctx)),
|
||||
@@ -44,7 +44,7 @@ impl Extern {
|
||||
}
|
||||
|
||||
/// Create an `Extern` from an `wasmer_compiler::Export`.
|
||||
pub fn from_vm_export(ctx: &mut impl AsContextMut, export: Export) -> Self {
|
||||
pub fn from_vm_export(ctx: &mut impl AsStoreMut, export: Export) -> Self {
|
||||
match export {
|
||||
Export::Function(f) => Self::Function(Function::from_vm_extern(ctx, f)),
|
||||
Export::Memory(m) => Self::Memory(Memory::from_vm_extern(ctx, m)),
|
||||
@@ -54,12 +54,12 @@ impl Extern {
|
||||
}
|
||||
|
||||
/// Checks whether this `Extern` can be used with the given context.
|
||||
pub fn is_from_context(&self, ctx: &impl AsContextRef) -> bool {
|
||||
pub fn is_from_store(&self, ctx: &impl AsStoreRef) -> bool {
|
||||
match self {
|
||||
Self::Function(val) => val.is_from_context(ctx),
|
||||
Self::Memory(val) => val.is_from_context(ctx),
|
||||
Self::Global(val) => val.is_from_context(ctx),
|
||||
Self::Table(val) => val.is_from_context(ctx),
|
||||
Self::Function(val) => val.is_from_store(ctx),
|
||||
Self::Memory(val) => val.is_from_store(ctx),
|
||||
Self::Global(val) => val.is_from_store(ctx),
|
||||
Self::Table(val) => val.is_from_store(ctx),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -74,7 +74,7 @@ impl Extern {
|
||||
}
|
||||
|
||||
impl AsJs for Extern {
|
||||
fn as_jsvalue(&self, ctx: &impl AsContextRef) -> wasm_bindgen::JsValue {
|
||||
fn as_jsvalue(&self, ctx: &impl AsStoreRef) -> wasm_bindgen::JsValue {
|
||||
match self {
|
||||
Self::Function(_) => self.to_export().as_jsvalue(ctx),
|
||||
Self::Global(_) => self.to_export().as_jsvalue(ctx),
|
||||
|
||||
60
lib/api/src/js/externals/table.rs
vendored
60
lib/api/src/js/externals/table.rs
vendored
@@ -1,7 +1,7 @@
|
||||
use crate::js::context::{AsContextMut, AsContextRef, ContextHandle, InternalContextHandle};
|
||||
use crate::js::export::{VMFunction, VMTable};
|
||||
use crate::js::exports::{ExportError, Exportable};
|
||||
use crate::js::externals::Extern;
|
||||
use crate::js::store::{AsStoreMut, AsStoreRef, InternalStoreHandle, StoreHandle};
|
||||
use crate::js::value::Value;
|
||||
use crate::js::RuntimeError;
|
||||
use crate::js::{FunctionType, TableType};
|
||||
@@ -18,21 +18,21 @@ use js_sys::Function;
|
||||
/// Spec: <https://webassembly.github.io/spec/core/exec/runtime.html#table-instances>
|
||||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub struct Table {
|
||||
pub(crate) handle: ContextHandle<VMTable>,
|
||||
pub(crate) handle: StoreHandle<VMTable>,
|
||||
}
|
||||
|
||||
fn set_table_item(table: &VMTable, item_index: u32, item: &Function) -> Result<(), RuntimeError> {
|
||||
table.table.set(item_index, item).map_err(|e| e.into())
|
||||
}
|
||||
|
||||
fn get_function(ctx: &mut impl AsContextMut, val: Value) -> Result<Function, RuntimeError> {
|
||||
if !val.is_from_context(ctx) {
|
||||
fn get_function(ctx: &mut impl AsStoreMut, val: Value) -> Result<Function, RuntimeError> {
|
||||
if !val.is_from_store(ctx) {
|
||||
return Err(RuntimeError::new("cannot pass Value across contexts"));
|
||||
}
|
||||
match val {
|
||||
Value::FuncRef(Some(ref func)) => Ok(func
|
||||
.handle
|
||||
.get(&ctx.as_context_ref().objects())
|
||||
.get(&ctx.as_store_ref().objects())
|
||||
.function
|
||||
.clone()
|
||||
.into()),
|
||||
@@ -49,11 +49,11 @@ impl Table {
|
||||
/// This function will construct the `Table` using the store
|
||||
/// [`BaseTunables`][crate::js::tunables::BaseTunables].
|
||||
pub fn new(
|
||||
ctx: &mut impl AsContextMut,
|
||||
ctx: &mut impl AsStoreMut,
|
||||
ty: TableType,
|
||||
init: Value,
|
||||
) -> Result<Self, RuntimeError> {
|
||||
let mut ctx = ctx.as_context_mut();
|
||||
let mut ctx = ctx;
|
||||
let descriptor = js_sys::Object::new();
|
||||
js_sys::Reflect::set(&descriptor, &"initial".into(), &ty.minimum.into())?;
|
||||
if let Some(max) = ty.maximum {
|
||||
@@ -71,20 +71,20 @@ impl Table {
|
||||
}
|
||||
|
||||
Ok(Self {
|
||||
handle: ContextHandle::new(ctx.objects_mut(), table),
|
||||
handle: StoreHandle::new(ctx.objects_mut(), table),
|
||||
})
|
||||
}
|
||||
|
||||
/// Returns the [`TableType`] of the `Table`.
|
||||
pub fn ty(&self, ctx: &impl AsContextRef) -> TableType {
|
||||
self.handle.get(ctx.as_context_ref().objects()).ty
|
||||
pub fn ty(&self, ctx: &impl AsStoreRef) -> TableType {
|
||||
self.handle.get(ctx.as_store_ref().objects()).ty
|
||||
}
|
||||
|
||||
/// Retrieves an element of the table at the provided `index`.
|
||||
pub fn get(&self, ctx: &mut impl AsContextMut, index: u32) -> Option<Value> {
|
||||
pub fn get(&self, ctx: &mut impl AsStoreMut, index: u32) -> Option<Value> {
|
||||
if let Some(func) = self
|
||||
.handle
|
||||
.get(ctx.as_context_ref().objects())
|
||||
.get(ctx.as_store_ref().objects())
|
||||
.table
|
||||
.get(index)
|
||||
.ok()
|
||||
@@ -101,24 +101,17 @@ impl Table {
|
||||
/// Sets an element `val` in the Table at the provided `index`.
|
||||
pub fn set(
|
||||
&self,
|
||||
ctx: &mut impl AsContextMut,
|
||||
ctx: &mut impl AsStoreMut,
|
||||
index: u32,
|
||||
val: Value,
|
||||
) -> Result<(), RuntimeError> {
|
||||
let item = get_function(ctx, val)?;
|
||||
set_table_item(
|
||||
self.handle.get_mut(ctx.as_context_mut().objects_mut()),
|
||||
index,
|
||||
&item,
|
||||
)
|
||||
set_table_item(self.handle.get_mut(ctx.objects_mut()), index, &item)
|
||||
}
|
||||
|
||||
/// Retrieves the size of the `Table` (in elements)
|
||||
pub fn size(&self, ctx: &impl AsContextRef) -> u32 {
|
||||
self.handle
|
||||
.get(ctx.as_context_ref().objects())
|
||||
.table
|
||||
.length()
|
||||
pub fn size(&self, ctx: &impl AsStoreRef) -> u32 {
|
||||
self.handle.get(ctx.as_store_ref().objects()).table.length()
|
||||
}
|
||||
|
||||
/// Grows the size of the `Table` by `delta`, initializating
|
||||
@@ -130,7 +123,12 @@ impl Table {
|
||||
/// # Errors
|
||||
///
|
||||
/// Returns an error if the `delta` is out of bounds for the table.
|
||||
pub fn grow(&self, _delta: u32, _init: Value) -> Result<u32, RuntimeError> {
|
||||
pub fn grow(
|
||||
&self,
|
||||
store: &mut AsStoreMut,
|
||||
_delta: u32,
|
||||
_init: Value,
|
||||
) -> Result<u32, RuntimeError> {
|
||||
unimplemented!();
|
||||
}
|
||||
|
||||
@@ -152,19 +150,19 @@ impl Table {
|
||||
}
|
||||
|
||||
pub(crate) fn from_vm_extern(
|
||||
ctx: &mut impl AsContextMut,
|
||||
internal: InternalContextHandle<VMTable>,
|
||||
ctx: &mut impl AsStoreMut,
|
||||
internal: InternalStoreHandle<VMTable>,
|
||||
) -> Self {
|
||||
Self {
|
||||
handle: unsafe {
|
||||
ContextHandle::from_internal(ctx.as_context_ref().objects().id(), internal)
|
||||
StoreHandle::from_internal(ctx.as_store_ref().objects().id(), internal)
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
/// Checks whether this `Table` can be used with the given context.
|
||||
pub fn is_from_context(&self, ctx: &impl AsContextRef) -> bool {
|
||||
self.handle.context_id() == ctx.as_context_ref().objects().id()
|
||||
pub fn is_from_store(&self, ctx: &impl AsStoreRef) -> bool {
|
||||
self.handle.store_id() == ctx.as_store_ref().objects().id()
|
||||
}
|
||||
|
||||
/// Get access to the backing VM value for this extern. This function is for
|
||||
@@ -177,9 +175,9 @@ impl Table {
|
||||
#[doc(hidden)]
|
||||
pub unsafe fn get_vm_table<'context>(
|
||||
&self,
|
||||
ctx: &'context impl AsContextRef,
|
||||
ctx: &'context impl AsStoreRef,
|
||||
) -> &'context VMTable {
|
||||
self.handle.get(ctx.as_context_ref().objects())
|
||||
self.handle.get(ctx.as_store_ref().objects())
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
153
lib/api/src/js/function_env.rs
Normal file
153
lib/api/src/js/function_env.rs
Normal file
@@ -0,0 +1,153 @@
|
||||
use std::{any::Any, marker::PhantomData};
|
||||
|
||||
use crate::js::{StoreHandle, StoreObjects};
|
||||
|
||||
use crate::js::{AsStoreMut, AsStoreRef, StoreMut, StoreRef};
|
||||
|
||||
#[derive(Debug)]
|
||||
#[repr(transparent)]
|
||||
/// An opaque reference to a function environment.
|
||||
/// The function environment data is owned by the `Store`.
|
||||
pub struct FunctionEnv<T> {
|
||||
pub(crate) handle: StoreHandle<VMFunctionEnvironment>,
|
||||
_phantom: PhantomData<T>,
|
||||
}
|
||||
|
||||
impl<T> FunctionEnv<T> {
|
||||
/// Make a new extern reference
|
||||
pub fn new(store: &mut impl AsStoreMut, value: T) -> Self
|
||||
where
|
||||
T: Any + Send + 'static + Sized,
|
||||
{
|
||||
Self {
|
||||
handle: StoreHandle::new(
|
||||
store.as_store_mut().objects_mut(),
|
||||
VMFunctionEnvironment::new(value),
|
||||
),
|
||||
_phantom: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn from_handle(handle: StoreHandle<VMFunctionEnvironment>) -> Self {
|
||||
Self {
|
||||
handle,
|
||||
_phantom: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
/// Get the data as reference
|
||||
pub fn as_ref<'a>(&self, store: &'a impl AsStoreMut) -> &'a T
|
||||
where
|
||||
T: Any + Send + 'static + Sized,
|
||||
{
|
||||
self.handle
|
||||
.get(store.as_store_ref().objects())
|
||||
.as_ref()
|
||||
.downcast_ref::<T>()
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
/// Get the data as mutable
|
||||
pub fn as_mut<'a>(&self, store: &'a mut impl AsStoreMut) -> &'a mut T
|
||||
where
|
||||
T: Any + Send + 'static + Sized,
|
||||
{
|
||||
self.handle
|
||||
.get_mut(store.objects_mut())
|
||||
.as_mut()
|
||||
.downcast_mut::<T>()
|
||||
.unwrap()
|
||||
}
|
||||
|
||||
/// Convert it into a `FunctionEnvMut`
|
||||
pub fn into_mut(self, store: &mut impl AsStoreMut) -> FunctionEnvMut<T>
|
||||
where
|
||||
T: Any + Send + 'static + Sized,
|
||||
{
|
||||
FunctionEnvMut {
|
||||
store_mut: store.as_store_mut(),
|
||||
func_env: self,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Clone for FunctionEnv<T> {
|
||||
fn clone(&self) -> Self {
|
||||
Self {
|
||||
handle: self.handle.clone(),
|
||||
_phantom: self._phantom,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A temporary handle to a [`Context`].
|
||||
pub struct FunctionEnvMut<'a, T: 'a> {
|
||||
pub(crate) store_mut: StoreMut<'a>,
|
||||
pub(crate) func_env: FunctionEnv<T>,
|
||||
}
|
||||
|
||||
impl<T: Send + 'static> FunctionEnvMut<'_, T> {
|
||||
/// Returns a reference to the host state in this context.
|
||||
pub fn data(&self) -> &T {
|
||||
self.func_env.as_ref(&self.store_mut)
|
||||
}
|
||||
|
||||
/// Returns a mutable- reference to the host state in this context.
|
||||
pub fn data_mut<'a>(&'a mut self) -> &'a mut T {
|
||||
self.func_env.as_mut(&mut self.store_mut)
|
||||
}
|
||||
|
||||
/// Borrows a new mutable reference
|
||||
pub fn as_mut<'a>(&'a mut self) -> FunctionEnvMut<'a, T> {
|
||||
FunctionEnvMut {
|
||||
store_mut: self.store_mut.as_store_mut(),
|
||||
func_env: self.func_env.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> AsStoreRef for FunctionEnvMut<'_, T> {
|
||||
fn as_store_ref(&self) -> StoreRef<'_> {
|
||||
StoreRef {
|
||||
inner: self.store_mut.inner,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> AsStoreMut for FunctionEnvMut<'_, T> {
|
||||
fn as_store_mut(&mut self) -> StoreMut<'_> {
|
||||
StoreMut {
|
||||
inner: self.store_mut.inner,
|
||||
}
|
||||
}
|
||||
#[inline]
|
||||
fn objects_mut(&mut self) -> &mut StoreObjects {
|
||||
&mut self.store_mut.inner.objects
|
||||
}
|
||||
}
|
||||
|
||||
/// Underlying FunctionEnvironment used by a `VMFunction`.
|
||||
pub struct VMFunctionEnvironment {
|
||||
contents: Box<dyn Any + Send + 'static>,
|
||||
}
|
||||
|
||||
impl VMFunctionEnvironment {
|
||||
/// Wraps the given value to expose it to Wasm code as a function context.
|
||||
pub fn new(val: impl Any + Send + 'static) -> Self {
|
||||
Self {
|
||||
contents: Box::new(val),
|
||||
}
|
||||
}
|
||||
|
||||
#[allow(clippy::should_implement_trait)]
|
||||
/// Returns a reference to the underlying value.
|
||||
pub fn as_ref(&self) -> &(dyn Any + Send + 'static) {
|
||||
&*self.contents
|
||||
}
|
||||
|
||||
#[allow(clippy::should_implement_trait)]
|
||||
/// Returns a mutable reference to the underlying value.
|
||||
pub fn as_mut(&mut self) -> &mut (dyn Any + Send + 'static) {
|
||||
&mut *self.contents
|
||||
}
|
||||
}
|
||||
@@ -1,10 +1,10 @@
|
||||
//! The import module contains the implementation data structures and helper functions used to
|
||||
//! manipulate and access a wasm module's imports including memories, tables, globals, and
|
||||
//! functions.
|
||||
use crate::js::context::AsContextRef;
|
||||
use crate::js::error::InstantiationError;
|
||||
use crate::js::exports::Exports;
|
||||
use crate::js::module::Module;
|
||||
use crate::js::store::AsStoreRef;
|
||||
use crate::js::types::AsJs;
|
||||
use crate::Extern;
|
||||
use std::collections::HashMap;
|
||||
@@ -97,7 +97,7 @@ impl Imports {
|
||||
///
|
||||
/// # Usage
|
||||
/// ```no_run
|
||||
/// # let store = Default::default();
|
||||
/// # let mut store = Default::default();
|
||||
/// use wasmer::{Imports, Function};
|
||||
/// fn foo(n: i32) -> i32 {
|
||||
/// n
|
||||
@@ -151,7 +151,7 @@ impl Imports {
|
||||
}
|
||||
|
||||
/// Returns the `Imports` as a Javascript `Object`
|
||||
pub fn as_jsobject(&self, ctx: &impl AsContextRef) -> js_sys::Object {
|
||||
pub fn as_jsobject(&self, ctx: &impl AsStoreRef) -> js_sys::Object {
|
||||
let imports = js_sys::Object::new();
|
||||
let namespaces: HashMap<&str, Vec<(&str, &Extern)>> =
|
||||
self.map
|
||||
@@ -235,7 +235,7 @@ impl fmt::Debug for Imports {
|
||||
///
|
||||
/// ```
|
||||
/// # use wasmer::{Function, Store};
|
||||
/// # let store = Store::default();
|
||||
/// # let mut store = Store::default();
|
||||
/// use wasmer::imports;
|
||||
///
|
||||
/// let import_object = imports! {
|
||||
@@ -300,7 +300,7 @@ mod test {
|
||||
use crate::js::export::Export;
|
||||
use wasm_bindgen_test::*;
|
||||
fn namespace() {
|
||||
let store = Store::default();
|
||||
let mut store = Store::default();
|
||||
let g1 = Global::new(&store, Val::I32(0));
|
||||
let namespace = namespace! {
|
||||
"happy" => g1
|
||||
@@ -323,7 +323,7 @@ mod test {
|
||||
fn imports_macro_allows_trailing_comma_and_none() {
|
||||
use crate::js::Function;
|
||||
|
||||
let store = Default::default();
|
||||
let mut store = Default::default();
|
||||
|
||||
fn func(arg: i32) -> i32 {
|
||||
arg + 1
|
||||
@@ -372,7 +372,7 @@ mod test {
|
||||
}
|
||||
|
||||
fn chaining_works() {
|
||||
let store = Store::default();
|
||||
let mut store = Store::default();
|
||||
let g = Global::new(&store, Val::I32(0));
|
||||
|
||||
let mut imports1 = imports! {
|
||||
@@ -402,7 +402,7 @@ mod test {
|
||||
}
|
||||
|
||||
fn extending_conflict_overwrites() {
|
||||
let store = Store::default();
|
||||
let mut store = Store::default();
|
||||
let g1 = Global::new(&store, Val::I32(0));
|
||||
let g2 = Global::new(&store, Val::F32(0.));
|
||||
|
||||
@@ -430,7 +430,7 @@ mod test {
|
||||
);
|
||||
|
||||
// now test it in reverse
|
||||
let store = Store::default();
|
||||
let mut store = Store::default();
|
||||
let g1 = Global::new(&store, Val::I32(0));
|
||||
let g2 = Global::new(&store, Val::F32(0.));
|
||||
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
use crate::js::context::{AsContextMut, AsContextRef, ContextHandle};
|
||||
use crate::js::error::InstantiationError;
|
||||
use crate::js::export::Export;
|
||||
use crate::js::exports::Exports;
|
||||
use crate::js::externals::Extern;
|
||||
use crate::js::imports::Imports;
|
||||
use crate::js::module::Module;
|
||||
use crate::js::store::{AsStoreMut, AsStoreRef, StoreHandle};
|
||||
use js_sys::WebAssembly;
|
||||
use std::fmt;
|
||||
|
||||
@@ -18,7 +18,7 @@ use std::fmt;
|
||||
/// Spec: <https://webassembly.github.io/spec/core/exec/runtime.html#module-instances>
|
||||
#[derive(Clone)]
|
||||
pub struct Instance {
|
||||
_handle: ContextHandle<WebAssembly::Instance>,
|
||||
_handle: StoreHandle<WebAssembly::Instance>,
|
||||
module: Module,
|
||||
#[allow(dead_code)]
|
||||
imports: Imports,
|
||||
@@ -41,7 +41,7 @@ impl Instance {
|
||||
/// ```
|
||||
/// # use wasmer::{imports, Store, Module, Global, Value, Instance};
|
||||
/// # fn main() -> anyhow::Result<()> {
|
||||
/// let store = Store::default();
|
||||
/// let mut store = Store::default();
|
||||
/// let module = Module::new(&store, "(module)")?;
|
||||
/// let imports = imports!{
|
||||
/// "host" => {
|
||||
@@ -61,13 +61,13 @@ impl Instance {
|
||||
/// * Link errors that happen when plugging the imports into the instance
|
||||
/// * Runtime errors that happen when running the module `start` function.
|
||||
pub fn new(
|
||||
ctx: &mut impl AsContextMut,
|
||||
mut ctx: &mut impl AsStoreMut,
|
||||
module: &Module,
|
||||
imports: &Imports,
|
||||
) -> Result<Self, InstantiationError> {
|
||||
let import_copy = imports.clone();
|
||||
let (instance, _imports): (ContextHandle<WebAssembly::Instance>, Vec<Extern>) = module
|
||||
.instantiate(&mut ctx.as_context_mut(), imports)
|
||||
let (instance, _imports): (StoreHandle<WebAssembly::Instance>, Vec<Extern>) = module
|
||||
.instantiate(&mut ctx, imports)
|
||||
.map_err(|e| InstantiationError::Start(e))?;
|
||||
|
||||
let self_instance = Self::from_module_and_instance(ctx, module, instance, import_copy)?;
|
||||
@@ -85,12 +85,12 @@ impl Instance {
|
||||
///
|
||||
/// *This method is only available when targeting JS environments*
|
||||
pub fn from_module_and_instance(
|
||||
ctx: &mut impl AsContextMut,
|
||||
mut ctx: &mut impl AsStoreMut,
|
||||
module: &Module,
|
||||
instance: ContextHandle<WebAssembly::Instance>,
|
||||
instance: StoreHandle<WebAssembly::Instance>,
|
||||
imports: Imports,
|
||||
) -> Result<Self, InstantiationError> {
|
||||
let instance_exports = instance.get(ctx.as_context_ref().objects()).exports();
|
||||
let instance_exports = instance.get(ctx.as_store_ref().objects()).exports();
|
||||
let exports = module
|
||||
.exports()
|
||||
.map(|export_type| {
|
||||
@@ -104,9 +104,8 @@ impl Instance {
|
||||
))
|
||||
})?;
|
||||
let export: Export =
|
||||
Export::from_js_value(js_export, &mut ctx.as_context_mut(), extern_type)?
|
||||
.into();
|
||||
let extern_ = Extern::from_vm_export(&mut ctx.as_context_mut(), export);
|
||||
Export::from_js_value(js_export, &mut ctx, extern_type)?.into();
|
||||
let extern_ = Extern::from_vm_export(&mut ctx, export);
|
||||
Ok((name.to_string(), extern_))
|
||||
})
|
||||
.collect::<Result<Exports, InstantiationError>>()?;
|
||||
@@ -126,11 +125,8 @@ impl Instance {
|
||||
|
||||
/// Returns the inner WebAssembly Instance
|
||||
#[doc(hidden)]
|
||||
pub fn raw<'context>(
|
||||
&self,
|
||||
ctx: &'context impl AsContextRef,
|
||||
) -> &'context WebAssembly::Instance {
|
||||
&self._handle.get(ctx.as_context_ref().objects())
|
||||
pub fn raw<'context>(&self, ctx: &'context impl AsStoreRef) -> &'context WebAssembly::Instance {
|
||||
&self._handle.get(ctx.as_store_ref().objects())
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
use crate::js::context::AsContextMut;
|
||||
use crate::js::error::WasmError;
|
||||
use crate::js::store::AsStoreMut;
|
||||
use crate::js::{Export, ExternType, Module};
|
||||
use std::collections::HashMap;
|
||||
|
||||
@@ -53,7 +53,7 @@ impl JsImportObject {
|
||||
/// ```
|
||||
pub fn get_export(
|
||||
&self,
|
||||
ctx: &mut impl AsContextMut,
|
||||
ctx: &mut impl AsStoreMut,
|
||||
module: &str,
|
||||
name: &str,
|
||||
) -> Result<Export, WasmError> {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
use crate::js::context::AsContextRef;
|
||||
use crate::js::externals::memory::MemoryBuffer;
|
||||
use crate::RuntimeError;
|
||||
use crate::{Memory, Memory32, Memory64, WasmPtr};
|
||||
use crate::js::store::AsStoreRef;
|
||||
use crate::js::RuntimeError;
|
||||
use crate::js::{Memory, Memory32, Memory64, WasmPtr};
|
||||
use std::{
|
||||
convert::TryInto,
|
||||
fmt,
|
||||
@@ -61,7 +61,7 @@ pub struct WasmRef<'a, T: ValueType> {
|
||||
impl<'a, T: ValueType> WasmRef<'a, T> {
|
||||
/// Creates a new `WasmRef` at the given offset in a memory.
|
||||
#[inline]
|
||||
pub fn new(ctx: &'a impl AsContextRef, memory: &'a Memory, offset: u64) -> Self {
|
||||
pub fn new(ctx: &'a impl AsStoreRef, memory: &'a Memory, offset: u64) -> Self {
|
||||
Self {
|
||||
buffer: memory.buffer(ctx),
|
||||
offset,
|
||||
@@ -160,7 +160,7 @@ impl<'a, T: ValueType> WasmSlice<'a, T> {
|
||||
/// Returns a `MemoryAccessError` if the slice length overflows.
|
||||
#[inline]
|
||||
pub fn new(
|
||||
ctx: &'a impl AsContextRef,
|
||||
ctx: &'a impl AsStoreRef,
|
||||
memory: &'a Memory,
|
||||
offset: u64,
|
||||
len: u64,
|
||||
|
||||
@@ -23,11 +23,11 @@ mod lib {
|
||||
}
|
||||
}
|
||||
|
||||
mod context;
|
||||
mod error;
|
||||
mod export;
|
||||
mod exports;
|
||||
mod externals;
|
||||
mod function_env;
|
||||
mod imports;
|
||||
mod instance;
|
||||
mod js_import_object;
|
||||
@@ -44,7 +44,6 @@ mod types;
|
||||
mod value;
|
||||
mod wasm_bindgen_polyfill;
|
||||
|
||||
pub use crate::js::context::{AsContextMut, AsContextRef, Context, ContextMut, ContextRef};
|
||||
pub use crate::js::error::{DeserializeError, InstantiationError, SerializeError};
|
||||
pub use crate::js::export::Export;
|
||||
pub use crate::js::exports::{ExportError, Exportable, Exports, ExportsIterator};
|
||||
@@ -52,6 +51,7 @@ pub use crate::js::externals::{
|
||||
Extern, FromToNativeWasmType, Function, Global, HostFunction, Memory, MemoryError, Table,
|
||||
WasmTypeList,
|
||||
};
|
||||
pub use crate::js::function_env::{FunctionEnv, FunctionEnvMut};
|
||||
pub use crate::js::imports::Imports;
|
||||
pub use crate::js::instance::Instance;
|
||||
pub use crate::js::js_import_object::JsImportObject;
|
||||
@@ -62,7 +62,9 @@ pub use crate::js::native_type::NativeWasmTypeInto;
|
||||
pub use crate::js::ptr::{Memory32, Memory64, MemorySize, WasmPtr, WasmPtr64};
|
||||
pub use crate::js::trap::RuntimeError;
|
||||
|
||||
pub use crate::js::store::{Store, StoreObject};
|
||||
pub use crate::js::store::{
|
||||
AsStoreMut, AsStoreRef, Store, StoreHandle, StoreMut, StoreObject, StoreObjects, StoreRef,
|
||||
};
|
||||
pub use crate::js::types::ValType as Type;
|
||||
pub use crate::js::types::{
|
||||
ExportType, ExternType, FunctionType, GlobalType, ImportType, MemoryType, Mutability,
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
use crate::js::context::{AsContextMut, ContextHandle};
|
||||
#[cfg(feature = "wat")]
|
||||
use crate::js::error::WasmError;
|
||||
use crate::js::error::{CompileError, InstantiationError};
|
||||
@@ -7,8 +6,10 @@ use crate::js::error::{DeserializeError, SerializeError};
|
||||
use crate::js::externals::Extern;
|
||||
use crate::js::imports::Imports;
|
||||
use crate::js::store::Store;
|
||||
use crate::js::store::{AsStoreMut, StoreHandle};
|
||||
use crate::js::types::{AsJs, ExportType, ImportType};
|
||||
use crate::js::RuntimeError;
|
||||
use crate::AsStoreRef;
|
||||
use js_sys::{Reflect, Uint8Array, WebAssembly};
|
||||
use std::fmt;
|
||||
use std::io;
|
||||
@@ -59,7 +60,6 @@ pub struct ModuleTypeHints {
|
||||
/// contents rather than a deep copy.
|
||||
#[derive(Clone)]
|
||||
pub struct Module {
|
||||
store: Store,
|
||||
module: WebAssembly::Module,
|
||||
name: Option<String>,
|
||||
// WebAssembly type hints
|
||||
@@ -95,7 +95,7 @@ impl Module {
|
||||
/// ```
|
||||
/// use wasmer::*;
|
||||
/// # fn main() -> anyhow::Result<()> {
|
||||
/// # let store = Store::default();
|
||||
/// # let mut store = Store::default();
|
||||
/// let wat = "(module)";
|
||||
/// let module = Module::new(&store, wat)?;
|
||||
/// # Ok(())
|
||||
@@ -107,7 +107,7 @@ impl Module {
|
||||
/// ```
|
||||
/// use wasmer::*;
|
||||
/// # fn main() -> anyhow::Result<()> {
|
||||
/// # let store = Store::default();
|
||||
/// # let mut store = Store::default();
|
||||
/// // The following is the same as:
|
||||
/// // (module
|
||||
/// // (type $t0 (func (param i32) (result i32)))
|
||||
@@ -129,7 +129,7 @@ impl Module {
|
||||
/// # }
|
||||
/// ```
|
||||
#[allow(unreachable_code)]
|
||||
pub fn new(store: &Store, bytes: impl AsRef<[u8]>) -> Result<Self, CompileError> {
|
||||
pub fn new(_store: &impl AsStoreRef, bytes: impl AsRef<[u8]>) -> Result<Self, CompileError> {
|
||||
#[cfg(feature = "wat")]
|
||||
let bytes = wat::parse_bytes(bytes.as_ref()).map_err(|e| {
|
||||
CompileError::Wasm(WasmError::Generic(format!(
|
||||
@@ -137,11 +137,14 @@ impl Module {
|
||||
e
|
||||
)))
|
||||
})?;
|
||||
Self::from_binary(store, bytes.as_ref())
|
||||
Self::from_binary(_store, bytes.as_ref())
|
||||
}
|
||||
|
||||
/// Creates a new WebAssembly module from a file path.
|
||||
pub fn from_file(_store: &Store, _file: impl AsRef<Path>) -> Result<Self, IoCompileError> {
|
||||
pub fn from_file(
|
||||
_store: &impl AsStoreRef,
|
||||
_file: impl AsRef<Path>,
|
||||
) -> Result<Self, IoCompileError> {
|
||||
unimplemented!();
|
||||
}
|
||||
|
||||
@@ -150,10 +153,10 @@ impl Module {
|
||||
/// Opposed to [`Module::new`], this function is not compatible with
|
||||
/// the WebAssembly text format (if the "wat" feature is enabled for
|
||||
/// this crate).
|
||||
pub fn from_binary(store: &Store, binary: &[u8]) -> Result<Self, CompileError> {
|
||||
pub fn from_binary(_store: &impl AsStoreRef, binary: &[u8]) -> Result<Self, CompileError> {
|
||||
//
|
||||
// Self::validate(store, binary)?;
|
||||
unsafe { Self::from_binary_unchecked(store, binary) }
|
||||
unsafe { Self::from_binary_unchecked(_store, binary) }
|
||||
}
|
||||
|
||||
/// Creates a new WebAssembly module skipping any kind of validation.
|
||||
@@ -163,7 +166,7 @@ impl Module {
|
||||
/// This is safe since the JS vm should be safe already.
|
||||
/// We maintain the `unsafe` to preserve the same API as Wasmer
|
||||
pub unsafe fn from_binary_unchecked(
|
||||
store: &Store,
|
||||
_store: &impl AsStoreRef,
|
||||
binary: &[u8],
|
||||
) -> Result<Self, CompileError> {
|
||||
let js_bytes = Uint8Array::view(binary);
|
||||
@@ -194,7 +197,6 @@ impl Module {
|
||||
let (type_hints, name) = (None, None);
|
||||
|
||||
Ok(Self {
|
||||
store: store.clone(),
|
||||
module,
|
||||
type_hints,
|
||||
name,
|
||||
@@ -209,7 +211,7 @@ impl Module {
|
||||
/// This validation is normally pretty fast and checks the enabled
|
||||
/// WebAssembly features in the Store Engine to assure deterministic
|
||||
/// validation of the Module.
|
||||
pub fn validate(_store: &Store, binary: &[u8]) -> Result<(), CompileError> {
|
||||
pub fn validate(_store: &impl AsStoreRef, binary: &[u8]) -> Result<(), CompileError> {
|
||||
let js_bytes = unsafe { Uint8Array::view(binary) };
|
||||
match WebAssembly::validate(&js_bytes.into()) {
|
||||
Ok(true) => Ok(()),
|
||||
@@ -219,16 +221,17 @@ impl Module {
|
||||
|
||||
pub(crate) fn instantiate(
|
||||
&self,
|
||||
ctx: &mut impl AsContextMut,
|
||||
store: &mut impl AsStoreMut,
|
||||
imports: &Imports,
|
||||
) -> Result<(ContextHandle<WebAssembly::Instance>, Vec<Extern>), RuntimeError> {
|
||||
// Ensure all imports come from the same context.
|
||||
) -> Result<(StoreHandle<WebAssembly::Instance>, Vec<Extern>), RuntimeError> {
|
||||
// Ensure all imports come from the same store.
|
||||
if imports
|
||||
.into_iter()
|
||||
.any(|(_, import)| !import.is_from_context(ctx))
|
||||
.any(|(_, import)| !import.is_from_store(store))
|
||||
{
|
||||
// FIXME is RuntimeError::User appropriate?
|
||||
return Err(RuntimeError::user(Box::new(InstantiationError::BadContext)));
|
||||
return Err(RuntimeError::user(Box::new(
|
||||
InstantiationError::DifferentStores,
|
||||
)));
|
||||
}
|
||||
let imports_object = js_sys::Object::new();
|
||||
let mut import_externs: Vec<Extern> = vec![];
|
||||
@@ -241,7 +244,7 @@ impl Module {
|
||||
js_sys::Reflect::set(
|
||||
&val,
|
||||
&import_type.name().into(),
|
||||
&import.as_jsvalue(&ctx.as_context_ref()),
|
||||
&import.as_jsvalue(&store.as_store_ref()),
|
||||
)?;
|
||||
} else {
|
||||
// If the namespace doesn't exist
|
||||
@@ -249,7 +252,7 @@ impl Module {
|
||||
js_sys::Reflect::set(
|
||||
&import_namespace,
|
||||
&import_type.name().into(),
|
||||
&import.as_jsvalue(&ctx.as_context_ref()),
|
||||
&import.as_jsvalue(&store.as_store_ref()),
|
||||
)?;
|
||||
js_sys::Reflect::set(
|
||||
&imports_object,
|
||||
@@ -263,8 +266,8 @@ impl Module {
|
||||
// the error for us, so we don't need to handle it
|
||||
}
|
||||
Ok((
|
||||
ContextHandle::new(
|
||||
ctx.as_context_mut().objects_mut(),
|
||||
StoreHandle::new(
|
||||
store.as_store_mut().objects_mut(),
|
||||
WebAssembly::Instance::new(&self.module, &imports_object)
|
||||
.map_err(|e: JsValue| -> RuntimeError { e.into() })?,
|
||||
),
|
||||
@@ -282,7 +285,7 @@ impl Module {
|
||||
/// ```
|
||||
/// # use wasmer::*;
|
||||
/// # fn main() -> anyhow::Result<()> {
|
||||
/// # let store = Store::default();
|
||||
/// # let mut store = Store::default();
|
||||
/// let wat = "(module $moduleName)";
|
||||
/// let module = Module::new(&store, wat)?;
|
||||
/// assert_eq!(module.name(), Some("moduleName"));
|
||||
@@ -309,8 +312,11 @@ impl Module {
|
||||
/// This is safe since deserialization under `js` is essentially same as reconstructing `Module`.
|
||||
/// We maintain the `unsafe` to preserve the same API as Wasmer
|
||||
#[cfg(feature = "js-serializable-module")]
|
||||
pub unsafe fn deserialize(store: &Store, bytes: &[u8]) -> Result<Self, DeserializeError> {
|
||||
Self::new(store, bytes).map_err(|e| DeserializeError::Compiler(e))
|
||||
pub unsafe fn deserialize(
|
||||
_store: &impl AsStoreRef,
|
||||
bytes: &[u8],
|
||||
) -> Result<Self, DeserializeError> {
|
||||
Self::new(_store, bytes).map_err(|e| DeserializeError::Compiler(e))
|
||||
}
|
||||
|
||||
/// Sets the name of the current module.
|
||||
@@ -325,7 +331,7 @@ impl Module {
|
||||
/// ```
|
||||
/// # use wasmer::*;
|
||||
/// # fn main() -> anyhow::Result<()> {
|
||||
/// # let store = Store::default();
|
||||
/// # let mut store = Store::default();
|
||||
/// let wat = "(module)";
|
||||
/// let mut module = Module::new(&store, wat)?;
|
||||
/// assert_eq!(module.name(), None);
|
||||
@@ -360,7 +366,7 @@ impl Module {
|
||||
/// ```
|
||||
/// # use wasmer::*;
|
||||
/// # fn main() -> anyhow::Result<()> {
|
||||
/// # let store = Store::default();
|
||||
/// # let mut store = Store::default();
|
||||
/// let wat = r#"(module
|
||||
/// (import "host" "func1" (func))
|
||||
/// (import "host" "func2" (func))
|
||||
@@ -458,7 +464,7 @@ impl Module {
|
||||
/// ```
|
||||
/// # use wasmer::*;
|
||||
/// # fn main() -> anyhow::Result<()> {
|
||||
/// # let store = Store::default();
|
||||
/// # let mut store = Store::default();
|
||||
/// let wat = r#"(module
|
||||
/// (func (export "namedfunc"))
|
||||
/// (memory (export "namedmemory") 1)
|
||||
@@ -530,11 +536,6 @@ impl Module {
|
||||
// pub fn custom_sections<'a>(&'a self, name: &'a str) -> impl Iterator<Item = Arc<[u8]>> + 'a {
|
||||
// unimplemented!();
|
||||
// }
|
||||
|
||||
/// Returns the [`Store`] where the `Instance` belongs.
|
||||
pub fn store(&self) -> &Store {
|
||||
&self.store
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for Module {
|
||||
@@ -548,7 +549,6 @@ impl fmt::Debug for Module {
|
||||
impl From<WebAssembly::Module> for Module {
|
||||
fn from(module: WebAssembly::Module) -> Module {
|
||||
Module {
|
||||
store: Store::default(),
|
||||
module,
|
||||
name: None,
|
||||
type_hints: None,
|
||||
|
||||
@@ -9,8 +9,9 @@
|
||||
//! ```
|
||||
use std::marker::PhantomData;
|
||||
|
||||
use crate::js::context::{AsContextMut, AsContextRef, ContextHandle};
|
||||
use crate::js::externals::Function;
|
||||
use crate::js::store::{AsStoreMut, AsStoreRef, StoreHandle};
|
||||
use crate::js::FunctionEnv;
|
||||
use crate::js::{FromToNativeWasmType, RuntimeError, WasmTypeList};
|
||||
// use std::panic::{catch_unwind, AssertUnwindSafe};
|
||||
use crate::js::export::VMFunction;
|
||||
@@ -23,7 +24,7 @@ use wasm_bindgen::JsValue;
|
||||
/// (using the Native ABI).
|
||||
#[derive(Clone)]
|
||||
pub struct TypedFunction<Args = (), Rets = ()> {
|
||||
pub(crate) handle: ContextHandle<VMFunction>,
|
||||
pub(crate) handle: StoreHandle<VMFunction>,
|
||||
_phantom: PhantomData<(Args, Rets)>,
|
||||
}
|
||||
|
||||
@@ -36,9 +37,13 @@ where
|
||||
Rets: WasmTypeList,
|
||||
{
|
||||
#[allow(dead_code)]
|
||||
pub(crate) fn new<T>(ctx: &mut impl AsContextMut<Data = T>, vm_function: VMFunction) -> Self {
|
||||
pub(crate) fn new<T>(
|
||||
store: &mut impl AsStoreMut,
|
||||
env: &FunctionEnv<T>,
|
||||
vm_function: VMFunction,
|
||||
) -> Self {
|
||||
Self {
|
||||
handle: ContextHandle::new(ctx.as_context_mut().objects_mut(), vm_function),
|
||||
handle: StoreHandle::new(store.as_store_mut().objects_mut(), vm_function),
|
||||
_phantom: PhantomData,
|
||||
}
|
||||
}
|
||||
@@ -61,11 +66,11 @@ macro_rules! impl_native_traits {
|
||||
{
|
||||
/// Call the typed func and return results.
|
||||
#[allow(clippy::too_many_arguments)]
|
||||
pub fn call(&self, ctx: &mut impl AsContextMut, $( $x: $x, )* ) -> Result<Rets, RuntimeError> where
|
||||
pub fn call(&self, mut ctx: &mut impl AsStoreMut, $( $x: $x, )* ) -> Result<Rets, RuntimeError> where
|
||||
$( $x: FromToNativeWasmType + crate::js::NativeWasmTypeInto, )*
|
||||
{
|
||||
let params_list: Vec<JsValue> = vec![ $( JsValue::from_f64($x.into_raw(ctx))),* ];
|
||||
let results = self.handle.get(ctx.as_context_ref().objects()).function.apply(
|
||||
let params_list: Vec<JsValue> = vec![ $( JsValue::from_f64($x.into_raw(&mut ctx))),* ];
|
||||
let results = self.handle.get(ctx.as_store_ref().objects()).function.apply(
|
||||
&JsValue::UNDEFINED,
|
||||
&Array::from_iter(params_list.iter())
|
||||
)?;
|
||||
@@ -76,7 +81,7 @@ macro_rules! impl_native_traits {
|
||||
1 => unsafe {
|
||||
let ty = Rets::wasm_types()[0];
|
||||
let val = param_from_js(&ty, &results);
|
||||
*mut_rets = val.as_raw(&mut ctx.as_context_mut());
|
||||
*mut_rets = val.as_raw(&mut ctx);
|
||||
}
|
||||
_n => {
|
||||
let results: Array = results.into();
|
||||
@@ -85,7 +90,7 @@ macro_rules! impl_native_traits {
|
||||
unsafe {
|
||||
let val = param_from_js(&ret_type, &ret);
|
||||
let slot = mut_rets.add(i);
|
||||
*slot = val.as_raw(&mut ctx.as_context_mut());
|
||||
*slot = val.as_raw(&mut ctx);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -101,7 +106,7 @@ macro_rules! impl_native_traits {
|
||||
$( $x: FromToNativeWasmType, )*
|
||||
Rets: WasmTypeList,
|
||||
{
|
||||
fn get_self_from_extern_with_generics(ctx: &impl AsContextRef, _extern: &crate::js::externals::Extern) -> Result<Self, crate::js::exports::ExportError> {
|
||||
fn get_self_from_extern_with_generics(ctx: &impl AsStoreRef, _extern: &crate::js::externals::Extern) -> Result<Self, crate::js::exports::ExportError> {
|
||||
use crate::js::exports::Exportable;
|
||||
crate::js::Function::get_self_from_extern(_extern)?.native(ctx).map_err(|_| crate::js::exports::ExportError::IncompatibleType)
|
||||
}
|
||||
|
||||
@@ -3,113 +3,113 @@
|
||||
|
||||
use wasmer_types::{NativeWasmType, Type};
|
||||
|
||||
use crate::Function;
|
||||
use crate::js::Function;
|
||||
|
||||
use super::context::AsContextMut;
|
||||
use super::store::AsStoreMut;
|
||||
|
||||
/// `NativeWasmTypeInto` performs conversions from and into `NativeWasmType`
|
||||
/// types with a context.
|
||||
pub trait NativeWasmTypeInto: NativeWasmType + Sized {
|
||||
#[doc(hidden)]
|
||||
fn into_abi(self, ctx: &mut impl AsContextMut) -> Self::Abi;
|
||||
fn into_abi(self, ctx: &mut impl AsStoreMut) -> Self::Abi;
|
||||
|
||||
#[doc(hidden)]
|
||||
unsafe fn from_abi(ctx: &mut impl AsContextMut, abi: Self::Abi) -> Self;
|
||||
unsafe fn from_abi(ctx: &mut impl AsStoreMut, abi: Self::Abi) -> Self;
|
||||
|
||||
/// Convert self to raw value representation.
|
||||
fn into_raw(self, ctx: &mut impl AsContextMut) -> f64;
|
||||
fn into_raw(self, ctx: &mut impl AsStoreMut) -> f64;
|
||||
|
||||
/// Convert to self from raw value representation.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
unsafe fn from_raw(ctx: &mut impl AsContextMut, raw: f64) -> Self;
|
||||
unsafe fn from_raw(ctx: &mut impl AsStoreMut, raw: f64) -> Self;
|
||||
}
|
||||
|
||||
impl NativeWasmTypeInto for i32 {
|
||||
#[inline]
|
||||
unsafe fn from_abi(_ctx: &mut impl AsContextMut, abi: Self::Abi) -> Self {
|
||||
unsafe fn from_abi(_ctx: &mut impl AsStoreMut, abi: Self::Abi) -> Self {
|
||||
abi
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn into_abi(self, _ctx: &mut impl AsContextMut) -> Self::Abi {
|
||||
fn into_abi(self, _ctx: &mut impl AsStoreMut) -> Self::Abi {
|
||||
self
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn into_raw(self, _ctx: &mut impl AsContextMut) -> f64 {
|
||||
fn into_raw(self, _ctx: &mut impl AsStoreMut) -> f64 {
|
||||
self.into()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
unsafe fn from_raw(_ctx: &mut impl AsContextMut, raw: f64) -> Self {
|
||||
unsafe fn from_raw(_ctx: &mut impl AsStoreMut, raw: f64) -> Self {
|
||||
raw as _
|
||||
}
|
||||
}
|
||||
|
||||
impl NativeWasmTypeInto for i64 {
|
||||
#[inline]
|
||||
unsafe fn from_abi(_ctx: &mut impl AsContextMut, abi: Self::Abi) -> Self {
|
||||
unsafe fn from_abi(_ctx: &mut impl AsStoreMut, abi: Self::Abi) -> Self {
|
||||
abi
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn into_abi(self, _ctx: &mut impl AsContextMut) -> Self::Abi {
|
||||
fn into_abi(self, _ctx: &mut impl AsStoreMut) -> Self::Abi {
|
||||
self
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn into_raw(self, _ctx: &mut impl AsContextMut) -> f64 {
|
||||
fn into_raw(self, _ctx: &mut impl AsStoreMut) -> f64 {
|
||||
self as _
|
||||
}
|
||||
|
||||
#[inline]
|
||||
unsafe fn from_raw(_ctx: &mut impl AsContextMut, raw: f64) -> Self {
|
||||
unsafe fn from_raw(_ctx: &mut impl AsStoreMut, raw: f64) -> Self {
|
||||
raw as _
|
||||
}
|
||||
}
|
||||
|
||||
impl NativeWasmTypeInto for f32 {
|
||||
#[inline]
|
||||
unsafe fn from_abi(_ctx: &mut impl AsContextMut, abi: Self::Abi) -> Self {
|
||||
unsafe fn from_abi(_ctx: &mut impl AsStoreMut, abi: Self::Abi) -> Self {
|
||||
abi
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn into_abi(self, _ctx: &mut impl AsContextMut) -> Self::Abi {
|
||||
fn into_abi(self, _ctx: &mut impl AsStoreMut) -> Self::Abi {
|
||||
self
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn into_raw(self, _ctx: &mut impl AsContextMut) -> f64 {
|
||||
fn into_raw(self, _ctx: &mut impl AsStoreMut) -> f64 {
|
||||
self as _
|
||||
}
|
||||
|
||||
#[inline]
|
||||
unsafe fn from_raw(_ctx: &mut impl AsContextMut, raw: f64) -> Self {
|
||||
unsafe fn from_raw(_ctx: &mut impl AsStoreMut, raw: f64) -> Self {
|
||||
raw as _
|
||||
}
|
||||
}
|
||||
|
||||
impl NativeWasmTypeInto for f64 {
|
||||
#[inline]
|
||||
unsafe fn from_abi(_ctx: &mut impl AsContextMut, abi: Self::Abi) -> Self {
|
||||
unsafe fn from_abi(_ctx: &mut impl AsStoreMut, abi: Self::Abi) -> Self {
|
||||
abi
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn into_abi(self, _ctx: &mut impl AsContextMut) -> Self::Abi {
|
||||
fn into_abi(self, _ctx: &mut impl AsStoreMut) -> Self::Abi {
|
||||
self
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn into_raw(self, _ctx: &mut impl AsContextMut) -> f64 {
|
||||
fn into_raw(self, _ctx: &mut impl AsStoreMut) -> f64 {
|
||||
self
|
||||
}
|
||||
|
||||
#[inline]
|
||||
unsafe fn from_raw(_ctx: &mut impl AsContextMut, raw: f64) -> Self {
|
||||
unsafe fn from_raw(_ctx: &mut impl AsStoreMut, raw: f64) -> Self {
|
||||
raw
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
use crate::js::context::AsContextRef;
|
||||
use crate::js::store::AsStoreRef;
|
||||
use crate::js::NativeWasmTypeInto;
|
||||
use crate::js::{externals::Memory, FromToNativeWasmType};
|
||||
use crate::{MemoryAccessError, WasmRef, WasmSlice};
|
||||
use crate::js::{MemoryAccessError, WasmRef, WasmSlice};
|
||||
use std::convert::TryFrom;
|
||||
use std::{fmt, marker::PhantomData, mem};
|
||||
pub use wasmer_types::Memory32;
|
||||
@@ -138,13 +138,13 @@ impl<T: ValueType, M: MemorySize> WasmPtr<T, M> {
|
||||
/// Creates a `WasmRef` from this `WasmPtr` which allows reading and
|
||||
/// mutating of the value being pointed to.
|
||||
#[inline]
|
||||
pub fn deref<'a>(self, ctx: &'a impl AsContextRef, memory: &'a Memory) -> WasmRef<'a, T> {
|
||||
pub fn deref<'a>(self, ctx: &'a impl AsStoreRef, memory: &'a Memory) -> WasmRef<'a, T> {
|
||||
WasmRef::new(ctx, memory, self.offset.into())
|
||||
}
|
||||
|
||||
/// Reads the address pointed to by this `WasmPtr` in a memory.
|
||||
#[inline]
|
||||
pub fn read(self, ctx: &impl AsContextRef, memory: &Memory) -> Result<T, MemoryAccessError> {
|
||||
pub fn read(self, ctx: &impl AsStoreRef, memory: &Memory) -> Result<T, MemoryAccessError> {
|
||||
self.deref(ctx, memory).read()
|
||||
}
|
||||
|
||||
@@ -152,7 +152,7 @@ impl<T: ValueType, M: MemorySize> WasmPtr<T, M> {
|
||||
#[inline]
|
||||
pub fn write(
|
||||
self,
|
||||
ctx: &impl AsContextRef,
|
||||
ctx: &impl AsStoreRef,
|
||||
memory: &Memory,
|
||||
val: T,
|
||||
) -> Result<(), MemoryAccessError> {
|
||||
@@ -167,7 +167,7 @@ impl<T: ValueType, M: MemorySize> WasmPtr<T, M> {
|
||||
#[inline]
|
||||
pub fn slice<'a>(
|
||||
self,
|
||||
ctx: &'a impl AsContextRef,
|
||||
ctx: &'a impl AsStoreRef,
|
||||
memory: &'a Memory,
|
||||
len: M::Offset,
|
||||
) -> Result<WasmSlice<'a, T>, MemoryAccessError> {
|
||||
@@ -181,7 +181,7 @@ impl<T: ValueType, M: MemorySize> WasmPtr<T, M> {
|
||||
#[inline]
|
||||
pub fn read_until<'a>(
|
||||
self,
|
||||
ctx: &'a impl AsContextRef,
|
||||
ctx: &'a impl AsStoreRef,
|
||||
memory: &'a Memory,
|
||||
mut end: impl FnMut(&T) -> bool,
|
||||
) -> Result<Vec<T>, MemoryAccessError> {
|
||||
@@ -206,7 +206,7 @@ impl<M: MemorySize> WasmPtr<u8, M> {
|
||||
#[inline]
|
||||
pub fn read_utf8_string<'a>(
|
||||
self,
|
||||
ctx: &'a impl AsContextRef,
|
||||
ctx: &'a impl AsStoreRef,
|
||||
memory: &'a Memory,
|
||||
len: M::Offset,
|
||||
) -> Result<String, MemoryAccessError> {
|
||||
@@ -221,7 +221,7 @@ impl<M: MemorySize> WasmPtr<u8, M> {
|
||||
#[inline]
|
||||
pub fn read_utf8_string_with_nul<'a>(
|
||||
self,
|
||||
ctx: &'a impl AsContextRef,
|
||||
ctx: &'a impl AsStoreRef,
|
||||
memory: &'a Memory,
|
||||
) -> Result<String, MemoryAccessError> {
|
||||
let vec = self.read_until(ctx, memory, |&byte| byte == 0)?;
|
||||
|
||||
@@ -1,5 +1,12 @@
|
||||
use std::fmt;
|
||||
|
||||
/// We require the context to have a fixed memory address for its lifetime since
|
||||
/// various bits of the VM have raw pointers that point back to it. Hence we
|
||||
/// wrap the actual context in a box.
|
||||
pub(crate) struct StoreInner {
|
||||
pub(crate) objects: StoreObjects,
|
||||
}
|
||||
|
||||
/// The store represents all global state that can be manipulated by
|
||||
/// WebAssembly programs. It consists of the runtime representation
|
||||
/// of all instances of functions, tables, memories, and globals that
|
||||
@@ -10,13 +17,18 @@ use std::fmt;
|
||||
/// [`Tunables`] (that are used to create the memories, tables and globals).
|
||||
///
|
||||
/// Spec: <https://webassembly.github.io/spec/core/exec/runtime.html#store>
|
||||
#[derive(Clone)]
|
||||
pub struct Store;
|
||||
pub struct Store {
|
||||
pub(crate) inner: Box<StoreInner>,
|
||||
}
|
||||
|
||||
impl Store {
|
||||
/// Creates a new `Store`.
|
||||
pub fn new() -> Self {
|
||||
Self
|
||||
Self {
|
||||
inner: Box::new(StoreInner {
|
||||
objects: Default::default(),
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
/// Checks whether two stores are identical. A store is considered
|
||||
@@ -57,3 +69,377 @@ pub trait StoreObject {
|
||||
true
|
||||
}
|
||||
}
|
||||
|
||||
impl AsStoreRef for Store {
|
||||
fn as_store_ref(&self) -> StoreRef<'_> {
|
||||
StoreRef { inner: &self.inner }
|
||||
}
|
||||
}
|
||||
impl AsStoreMut for Store {
|
||||
fn as_store_mut(&mut self) -> StoreMut<'_> {
|
||||
StoreMut {
|
||||
inner: &mut self.inner,
|
||||
}
|
||||
}
|
||||
fn objects_mut(&mut self) -> &mut StoreObjects {
|
||||
&mut self.inner.objects
|
||||
}
|
||||
}
|
||||
|
||||
/// A temporary handle to a [`Context`].
|
||||
pub struct StoreRef<'a> {
|
||||
pub(crate) inner: &'a StoreInner,
|
||||
}
|
||||
|
||||
impl<'a> StoreRef<'a> {
|
||||
pub(crate) fn objects(&self) -> &'a StoreObjects {
|
||||
&self.inner.objects
|
||||
}
|
||||
|
||||
/// Checks whether two stores are identical. A store is considered
|
||||
/// equal to another store if both have the same engine. The
|
||||
/// tunables are excluded from the logic.
|
||||
pub fn same(a: &Self, b: &Self) -> bool {
|
||||
a.inner.objects.id() == b.inner.objects.id()
|
||||
}
|
||||
}
|
||||
|
||||
/// A temporary handle to a [`Context`].
|
||||
pub struct StoreMut<'a> {
|
||||
pub(crate) inner: &'a mut StoreInner,
|
||||
}
|
||||
|
||||
impl<'a> StoreMut<'a> {
|
||||
/// Checks whether two stores are identical. A store is considered
|
||||
/// equal to another store if both have the same engine. The
|
||||
/// tunables are excluded from the logic.
|
||||
pub fn same(a: &Self, b: &Self) -> bool {
|
||||
a.inner.objects.id() == b.inner.objects.id()
|
||||
}
|
||||
|
||||
pub(crate) fn as_raw(&self) -> *mut StoreInner {
|
||||
self.inner as *const StoreInner as *mut StoreInner
|
||||
}
|
||||
|
||||
pub(crate) unsafe fn from_raw(raw: *mut StoreInner) -> Self {
|
||||
Self { inner: &mut *raw }
|
||||
}
|
||||
}
|
||||
|
||||
/// Helper trait for a value that is convertible to a [`StoreRef`].
|
||||
pub trait AsStoreRef {
|
||||
/// Returns a `StoreRef` pointing to the underlying context.
|
||||
fn as_store_ref(&self) -> StoreRef<'_>;
|
||||
}
|
||||
|
||||
/// Helper trait for a value that is convertible to a [`StoreMut`].
|
||||
pub trait AsStoreMut: AsStoreRef {
|
||||
/// Returns a `StoreMut` pointing to the underlying context.
|
||||
fn as_store_mut(&mut self) -> StoreMut<'_>;
|
||||
|
||||
/// Returns the ObjectMutable
|
||||
fn objects_mut(&mut self) -> &mut StoreObjects;
|
||||
}
|
||||
|
||||
impl AsStoreRef for StoreRef<'_> {
|
||||
fn as_store_ref(&self) -> StoreRef<'_> {
|
||||
StoreRef { inner: self.inner }
|
||||
}
|
||||
}
|
||||
|
||||
impl AsStoreRef for StoreMut<'_> {
|
||||
fn as_store_ref(&self) -> StoreRef<'_> {
|
||||
StoreRef { inner: self.inner }
|
||||
}
|
||||
}
|
||||
impl AsStoreMut for StoreMut<'_> {
|
||||
fn as_store_mut(&mut self) -> StoreMut<'_> {
|
||||
StoreMut { inner: self.inner }
|
||||
}
|
||||
fn objects_mut(&mut self) -> &mut StoreObjects {
|
||||
&mut self.inner.objects
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: AsStoreRef> AsStoreRef for &'_ T {
|
||||
fn as_store_ref(&self) -> StoreRef<'_> {
|
||||
T::as_store_ref(*self)
|
||||
}
|
||||
}
|
||||
impl<T: AsStoreRef> AsStoreRef for &'_ mut T {
|
||||
fn as_store_ref(&self) -> StoreRef<'_> {
|
||||
T::as_store_ref(*self)
|
||||
}
|
||||
}
|
||||
impl<T: AsStoreMut> AsStoreMut for &'_ mut T {
|
||||
fn as_store_mut(&mut self) -> StoreMut<'_> {
|
||||
T::as_store_mut(*self)
|
||||
}
|
||||
fn objects_mut(&mut self) -> &mut StoreObjects {
|
||||
T::objects_mut(*self)
|
||||
}
|
||||
}
|
||||
|
||||
pub use objects::*;
|
||||
|
||||
use crate::js::FunctionEnv;
|
||||
mod objects {
|
||||
use crate::js::{
|
||||
export::{VMFunction, VMGlobal, VMMemory, VMTable},
|
||||
function_env::VMFunctionEnvironment,
|
||||
};
|
||||
use std::{
|
||||
cell::UnsafeCell,
|
||||
fmt,
|
||||
marker::PhantomData,
|
||||
num::{NonZeroU64, NonZeroUsize},
|
||||
ptr::NonNull,
|
||||
sync::atomic::{AtomicU64, Ordering},
|
||||
};
|
||||
|
||||
/// Unique ID to identify a context.
|
||||
///
|
||||
/// Every handle to an object managed by a context also contains the ID of the
|
||||
/// context. This is used to check that a handle is always used with the
|
||||
/// correct context.
|
||||
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
|
||||
pub struct StoreId(NonZeroU64);
|
||||
|
||||
impl Default for StoreId {
|
||||
// Allocates a unique ID for a new context.
|
||||
fn default() -> Self {
|
||||
// No overflow checking is needed here: overflowing this would take
|
||||
// thousands of years.
|
||||
static NEXT_ID: AtomicU64 = AtomicU64::new(1);
|
||||
Self(NonZeroU64::new(NEXT_ID.fetch_add(1, Ordering::Relaxed)).unwrap())
|
||||
}
|
||||
}
|
||||
|
||||
/// Trait to represent an object managed by a context. This is implemented on
|
||||
/// the VM types managed by the context.
|
||||
pub trait StoreObject: Sized {
|
||||
fn list(ctx: &StoreObjects) -> &Vec<Self>;
|
||||
fn list_mut(ctx: &mut StoreObjects) -> &mut Vec<Self>;
|
||||
}
|
||||
|
||||
macro_rules! impl_store_object {
|
||||
($($field:ident => $ty:ty,)*) => {
|
||||
$(
|
||||
impl StoreObject for $ty {
|
||||
fn list(ctx: &StoreObjects) -> &Vec<Self> {
|
||||
&ctx.$field
|
||||
}
|
||||
fn list_mut(ctx: &mut StoreObjects) -> &mut Vec<Self> {
|
||||
&mut ctx.$field
|
||||
}
|
||||
}
|
||||
)*
|
||||
};
|
||||
}
|
||||
|
||||
impl_store_object! {
|
||||
functions => VMFunction,
|
||||
tables => VMTable,
|
||||
globals => VMGlobal,
|
||||
memories => VMMemory,
|
||||
instances => js_sys::WebAssembly::Instance,
|
||||
function_environments => VMFunctionEnvironment,
|
||||
}
|
||||
|
||||
/// Set of objects managed by a context.
|
||||
#[derive(Default)]
|
||||
pub struct StoreObjects {
|
||||
id: StoreId,
|
||||
memories: Vec<VMMemory>,
|
||||
tables: Vec<VMTable>,
|
||||
globals: Vec<VMGlobal>,
|
||||
functions: Vec<VMFunction>,
|
||||
instances: Vec<js_sys::WebAssembly::Instance>,
|
||||
function_environments: Vec<VMFunctionEnvironment>,
|
||||
}
|
||||
|
||||
impl StoreObjects {
|
||||
/// Returns the ID of this context.
|
||||
pub fn id(&self) -> StoreId {
|
||||
self.id
|
||||
}
|
||||
|
||||
/// Returns a pair of mutable references from two handles.
|
||||
///
|
||||
/// Panics if both handles point to the same object.
|
||||
pub fn get_2_mut<T: StoreObject>(
|
||||
&mut self,
|
||||
a: InternalStoreHandle<T>,
|
||||
b: InternalStoreHandle<T>,
|
||||
) -> (&mut T, &mut T) {
|
||||
assert_ne!(a.index(), b.index());
|
||||
let list = T::list_mut(self);
|
||||
if a.index() < b.index() {
|
||||
let (low, high) = list.split_at_mut(b.index());
|
||||
(&mut low[a.index()], &mut high[0])
|
||||
} else {
|
||||
let (low, high) = list.split_at_mut(a.index());
|
||||
(&mut high[0], &mut low[a.index()])
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Handle to an object managed by a context.
|
||||
///
|
||||
/// Internally this is just an integer index into a context. A reference to the
|
||||
/// context must be passed in separately to access the actual object.
|
||||
pub struct StoreHandle<T> {
|
||||
id: StoreId,
|
||||
internal: InternalStoreHandle<T>,
|
||||
}
|
||||
|
||||
impl<T> core::cmp::PartialEq for StoreHandle<T> {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.id == other.id
|
||||
}
|
||||
}
|
||||
impl<T> Clone for StoreHandle<T> {
|
||||
fn clone(&self) -> Self {
|
||||
Self {
|
||||
id: self.id,
|
||||
internal: self.internal,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: StoreObject> fmt::Debug for StoreHandle<T> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.debug_struct("StoreHandle")
|
||||
.field("id", &self.id)
|
||||
.field("internal", &self.internal.index())
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: StoreObject> StoreHandle<T> {
|
||||
/// Moves the given object into a context and returns a handle to it.
|
||||
pub fn new(ctx: &mut StoreObjects, val: T) -> Self {
|
||||
Self {
|
||||
id: ctx.id,
|
||||
internal: InternalStoreHandle::new(ctx, val),
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns a reference to the object that this handle points to.
|
||||
pub fn get<'a>(&self, ctx: &'a StoreObjects) -> &'a T {
|
||||
assert_eq!(self.id, ctx.id, "object used with the wrong context");
|
||||
self.internal.get(ctx)
|
||||
}
|
||||
|
||||
/// Returns a mutable reference to the object that this handle points to.
|
||||
pub fn get_mut<'a>(&self, ctx: &'a mut StoreObjects) -> &'a mut T {
|
||||
assert_eq!(self.id, ctx.id, "object used with the wrong context");
|
||||
self.internal.get_mut(ctx)
|
||||
}
|
||||
|
||||
/// Returns the internal handle contains within this handle.
|
||||
pub fn internal_handle(&self) -> InternalStoreHandle<T> {
|
||||
self.internal
|
||||
}
|
||||
|
||||
/// Returns the ID of the context associated with the handle.
|
||||
pub fn store_id(&self) -> StoreId {
|
||||
self.id
|
||||
}
|
||||
|
||||
/// Constructs a `StoreHandle` from a `StoreId` and an `InternalStoreHandle`.
|
||||
///
|
||||
/// # Safety
|
||||
/// Handling `InternalStoreHandle` values is unsafe because they do not track context ID.
|
||||
pub unsafe fn from_internal(id: StoreId, internal: InternalStoreHandle<T>) -> Self {
|
||||
Self { id, internal }
|
||||
}
|
||||
}
|
||||
|
||||
/// Internal handle to an object owned by the current context.
|
||||
///
|
||||
/// Unlike `StoreHandle` this does not track the context ID: it is only
|
||||
/// intended to be used within objects already owned by a context.
|
||||
#[repr(transparent)]
|
||||
pub struct InternalStoreHandle<T> {
|
||||
// Use a NonZero here to reduce the size of Option<InternalStoreHandle>.
|
||||
idx: NonZeroUsize,
|
||||
marker: PhantomData<fn() -> T>,
|
||||
}
|
||||
|
||||
impl<T> Clone for InternalStoreHandle<T> {
|
||||
fn clone(&self) -> Self {
|
||||
*self
|
||||
}
|
||||
}
|
||||
impl<T> Copy for InternalStoreHandle<T> {}
|
||||
|
||||
impl<T> fmt::Debug for InternalStoreHandle<T> {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.debug_struct("InternalStoreHandle")
|
||||
.field("idx", &self.idx)
|
||||
.finish()
|
||||
}
|
||||
}
|
||||
impl<T> PartialEq for InternalStoreHandle<T> {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.idx == other.idx
|
||||
}
|
||||
}
|
||||
impl<T> Eq for InternalStoreHandle<T> {}
|
||||
|
||||
impl<T: StoreObject> InternalStoreHandle<T> {
|
||||
/// Moves the given object into a context and returns a handle to it.
|
||||
pub fn new(ctx: &mut StoreObjects, val: T) -> Self {
|
||||
let list = T::list_mut(ctx);
|
||||
let idx = NonZeroUsize::new(list.len() + 1).unwrap();
|
||||
list.push(val);
|
||||
Self {
|
||||
idx,
|
||||
marker: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns a reference to the object that this handle points to.
|
||||
pub fn get<'a>(&self, ctx: &'a StoreObjects) -> &'a T {
|
||||
&T::list(ctx)[self.idx.get() - 1]
|
||||
}
|
||||
|
||||
/// Returns a mutable reference to the object that this handle points to.
|
||||
pub fn get_mut<'a>(&self, ctx: &'a mut StoreObjects) -> &'a mut T {
|
||||
&mut T::list_mut(ctx)[self.idx.get() - 1]
|
||||
}
|
||||
|
||||
pub(crate) fn index(&self) -> usize {
|
||||
self.idx.get()
|
||||
}
|
||||
|
||||
pub(crate) fn from_index(idx: usize) -> Option<Self> {
|
||||
NonZeroUsize::new(idx).map(|idx| Self {
|
||||
idx,
|
||||
marker: PhantomData,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/// Data used by the generated code is generally located inline within the
|
||||
/// `VMContext` for items defined in an instance. Host-defined objects are
|
||||
/// allocated separately and owned directly by the context.
|
||||
pub enum MaybeInstanceOwned<T> {
|
||||
/// The data is owned here.
|
||||
Host(Box<UnsafeCell<T>>),
|
||||
|
||||
/// The data is stored inline in the `VMContext` of an instance.
|
||||
Instance(NonNull<T>),
|
||||
}
|
||||
|
||||
impl<T> MaybeInstanceOwned<T> {
|
||||
/// Returns underlying pointer to the VM data.
|
||||
pub fn as_ptr(&self) -> NonNull<T> {
|
||||
match self {
|
||||
MaybeInstanceOwned::Host(p) => unsafe { NonNull::new_unchecked(p.get()) },
|
||||
MaybeInstanceOwned::Instance(p) => *p,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
//use crate::js::externals::Function;
|
||||
// use crate::js::store::{Store, StoreObject};
|
||||
// use crate::js::RuntimeError;
|
||||
use crate::js::context::AsContextRef;
|
||||
use crate::js::store::AsStoreRef;
|
||||
use crate::js::value::Value;
|
||||
use wasm_bindgen::JsValue;
|
||||
pub use wasmer_types::{
|
||||
@@ -19,7 +19,7 @@ pub use wasmer_types::{
|
||||
//pub type Value = Value<Function>;
|
||||
|
||||
pub trait AsJs {
|
||||
fn as_jsvalue(&self, ctx: &impl AsContextRef) -> JsValue;
|
||||
fn as_jsvalue(&self, ctx: &impl AsStoreRef) -> JsValue;
|
||||
}
|
||||
|
||||
#[inline]
|
||||
@@ -37,7 +37,7 @@ pub fn param_from_js(ty: &ValType, js_val: &JsValue) -> Value {
|
||||
}
|
||||
|
||||
impl AsJs for Value {
|
||||
fn as_jsvalue(&self, ctx: &impl AsContextRef) -> JsValue {
|
||||
fn as_jsvalue(&self, ctx: &impl AsStoreRef) -> JsValue {
|
||||
match self {
|
||||
Self::I32(i) => JsValue::from_f64(*i as f64),
|
||||
Self::I64(i) => JsValue::from_f64(*i as f64),
|
||||
@@ -45,7 +45,7 @@ impl AsJs for Value {
|
||||
Self::F64(f) => JsValue::from_f64(*f),
|
||||
Self::FuncRef(Some(func)) => func
|
||||
.handle
|
||||
.get(ctx.as_context_ref().objects())
|
||||
.get(ctx.as_store_ref().objects())
|
||||
.function
|
||||
.clone()
|
||||
.into(),
|
||||
|
||||
@@ -7,7 +7,7 @@ use wasmer_types::Type;
|
||||
//use crate::ExternRef;
|
||||
use crate::js::externals::function::Function;
|
||||
|
||||
use super::context::AsContextRef;
|
||||
use super::store::AsStoreRef;
|
||||
|
||||
/// WebAssembly computations manipulate values of basic value types:
|
||||
/// * Integers (32 or 64 bit width)
|
||||
@@ -82,7 +82,7 @@ impl Value {
|
||||
}
|
||||
|
||||
/// Converts the `Value` into a `f64`.
|
||||
pub fn as_raw(&self, ctx: &impl AsContextRef) -> f64 {
|
||||
pub fn as_raw(&self, ctx: &impl AsStoreRef) -> f64 {
|
||||
match *self {
|
||||
Self::I32(v) => v as f64,
|
||||
Self::I64(v) => v as f64,
|
||||
@@ -90,7 +90,7 @@ impl Value {
|
||||
Self::F64(v) => v,
|
||||
Self::FuncRef(Some(ref f)) => f
|
||||
.handle
|
||||
.get(ctx.as_context_ref().objects())
|
||||
.get(ctx.as_store_ref().objects())
|
||||
.function
|
||||
.as_f64()
|
||||
.unwrap_or(0_f64), //TODO is this correct?
|
||||
@@ -105,7 +105,7 @@ impl Value {
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
pub unsafe fn from_raw(_ctx: &impl AsContextRef, ty: Type, raw: f64) -> Self {
|
||||
pub unsafe fn from_raw(_ctx: &impl AsStoreRef, ty: Type, raw: f64) -> Self {
|
||||
match ty {
|
||||
Type::I32 => Self::I32(raw as i32),
|
||||
Type::I64 => Self::I64(raw as i64),
|
||||
@@ -128,7 +128,7 @@ impl Value {
|
||||
///
|
||||
/// Externref and funcref values are tied to a context and can only be used
|
||||
/// with that context.
|
||||
pub fn is_from_context(&self, ctx: &impl AsContextRef) -> bool {
|
||||
pub fn is_from_store(&self, ctx: &impl AsStoreRef) -> bool {
|
||||
match self {
|
||||
Self::I32(_)
|
||||
| Self::I64(_)
|
||||
@@ -136,8 +136,8 @@ impl Value {
|
||||
| Self::F64(_)
|
||||
//| Self::ExternRef(None)
|
||||
| Self::FuncRef(None) => true,
|
||||
//Self::ExternRef(Some(e)) => e.is_from_context(ctx),
|
||||
Self::FuncRef(Some(f)) => f.is_from_context(ctx),
|
||||
//Self::ExternRef(Some(e)) => e.is_from_store(ctx),
|
||||
Self::FuncRef(Some(f)) => f.is_from_store(ctx),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user