Updated js-api to latest

This commit is contained in:
Syrus Akbary
2021-07-12 14:53:54 -07:00
parent 5451d71133
commit 0d84e33b25
16 changed files with 371 additions and 440 deletions

View File

@@ -8,74 +8,36 @@ use std::marker::PhantomData;
use js_sys::Uint8Array;
use wasm_bindgen::JsValue;
/// A mutable memory location.
///
/// # Examples
///
/// In this example, you can see that `WasmCell<T>` enables mutation inside an
/// immutable struct. In other words, it enables "interior mutability".
///
/// ```
/// use wasmer::WasmCell;
///
/// struct SomeStruct {
/// regular_field: u8,
/// special_field: WasmCell<u8>,
/// }
///
/// let my_struct = SomeStruct {
/// regular_field: 0,
/// special_field: WasmCell::new(1),
/// };
///
/// let new_value = 100;
///
/// // ERROR: `my_struct` is immutable
/// // my_struct.regular_field = new_value;
///
/// // WORKS: although `my_struct` is immutable, `special_field` is a `WasmCell`,
/// // which can always be mutated
/// my_struct.special_field.set(new_value);
/// assert_eq!(my_struct.special_field.get(), new_value);
/// ```
///
/// See the [module-level documentation](self) for more.
#[derive(Clone)]
pub struct WasmCell<T: ?Sized> {
/// A mutable Wasm-memory location.
pub struct WasmCell<'a, T: ?Sized> {
pub(crate) memory: Uint8Array,
phantom: PhantomData<T>,
phantom: &'a PhantomData<T>,
}
unsafe impl<T: ?Sized> Send for WasmCell<T> where T: Send {}
unsafe impl<T: ?Sized> Send for WasmCell<'_, T> where T: Send {}
unsafe impl<T: ?Sized> Sync for WasmCell<T> {}
unsafe impl<T: ?Sized> Sync for WasmCell<'_, T> {}
// impl<T: Copy> Clone for WasmCell<T> {
// #[inline]
// fn clone(&self) -> WasmCell<T> {
// WasmCell::new(self.get())
// }
// }
impl<T: Default> Default for WasmCell<T> {
/// Creates a `WasmCell<T>`, with the `Default` value for T.
impl<'a, T: Copy> Clone for WasmCell<'a, T> {
#[inline]
fn default() -> WasmCell<T> {
unimplemented!()
// WasmCell::new(Default::default())
fn clone(&self) -> WasmCell<'a, T> {
WasmCell {
memory: self.memory.clone(),
phantom: &PhantomData,
}
}
}
impl<T: PartialEq + Copy> PartialEq for WasmCell<T> {
impl<T: PartialEq + Copy> PartialEq for WasmCell<'_, T> {
#[inline]
fn eq(&self, other: &WasmCell<T>) -> bool {
true
}
}
impl<T: Eq + Copy> Eq for WasmCell<T> {}
impl<T: Eq + Copy> Eq for WasmCell<'_, T> {}
impl<T: PartialOrd + Copy> PartialOrd for WasmCell<T> {
impl<T: PartialOrd + Copy> PartialOrd for WasmCell<'_, T> {
#[inline]
fn partial_cmp(&self, other: &WasmCell<T>) -> Option<Ordering> {
self.get().partial_cmp(&other.get())
@@ -102,118 +64,46 @@ impl<T: PartialOrd + Copy> PartialOrd for WasmCell<T> {
}
}
impl<T: Ord + Copy> Ord for WasmCell<T> {
impl<T: Ord + Copy> Ord for WasmCell<'_, T> {
#[inline]
fn cmp(&self, other: &WasmCell<T>) -> Ordering {
self.get().cmp(&other.get())
}
}
impl<T> From<T> for WasmCell<T> {
fn from(t: T) -> WasmCell<T> {
unimplemented!();
// WasmCell::new(t)
}
}
impl<T> WasmCell<T> {
impl<'a, T> WasmCell<'a, T> {
/// Creates a new `WasmCell` containing the given value.
///
/// # Examples
///
/// ```
/// use std::cell::Cell;
/// use wasmer::WasmCell;
///
/// let c = WasmCell::new(5);
/// let cell = Cell::new(5);
/// let wasm_cell = WasmCell::new(&cell);
/// ```
#[inline]
pub const fn new(memory: Uint8Array) -> WasmCell<T> {
// WasmCell { value: UnsafeWasmCell::new(value) }
pub const fn new(memory: Uint8Array) -> WasmCell<'a, T> {
WasmCell {
memory,
phantom: PhantomData,
phantom: &PhantomData,
}
}
/// Swaps the values of two WasmCells.
/// Difference with `std::mem::swap` is that this function doesn't require `&mut` reference.
///
/// # Examples
///
/// ```
/// use wasmer::WasmCell;
///
/// let c1 = WasmCell::new(5i32);
/// let c2 = WasmCell::new(10i32);
/// c1.swap(&c2);
/// assert_eq!(10, c1.get());
/// assert_eq!(5, c2.get());
/// ```
#[inline]
pub fn swap(&self, other: &Self) {
unimplemented!();
// if ptr::eq(self, other) {
// return;
// }
// // SAFETY: This can be risky if called from separate threads, but `WasmCell`
// // is `!Sync` so this won't happen. This also won't invalidate any
// // pointers since `WasmCell` makes sure nothing else will be pointing into
// // either of these `WasmCell`s.
// unsafe {
// ptr::swap(self.value.get(), other.value.get());
// }
}
/// Replaces the contained value with `val`, and returns the old contained value.
///
/// # Examples
///
/// ```
/// use wasmer::WasmCell;
///
/// let cell = WasmCell::new(5);
/// assert_eq!(cell.get(), 5);
/// assert_eq!(cell.replace(10), 5);
/// assert_eq!(cell.get(), 10);
/// ```
pub fn replace(&self, val: T) -> T {
unimplemented!();
// SAFETY: This can cause data races if called from a separate thread,
// but `WasmCell` is `!Sync` so this won't happen.
// mem::replace(unsafe { &mut *self.value.get() }, val)
}
// /// Unwraps the value.
// ///
// /// # Examples
// ///
// /// ```
// /// use wasmer::WasmCell;
// ///
// /// let c = WasmCell::new(5);
// /// let five = c.into_inner();
// ///
// /// assert_eq!(five, 5);
// /// ```
// pub const fn into_inner(self) -> T {
// // This will get the item out of the MemoryView and into
// // Rust memory allocator
// unimplemented!()
// // self.get()
// }
}
impl<T: Copy> WasmCell<T> {
impl<'a, T: Copy> WasmCell<'a, T> {
/// Returns a copy of the contained value.
///
/// # Examples
///
/// ```
/// use std::cell::Cell;
/// use wasmer::WasmCell;
///
/// let c = WasmCell::new(5);
///
/// let five = c.get();
/// let cell = Cell::new(5);
/// let wasm_cell = WasmCell::new(&cell);
/// let five = wasm_cell.get();
/// ```
#[inline]
pub fn get(&self) -> T {
@@ -222,44 +112,47 @@ impl<T: Copy> WasmCell<T> {
// unimplemented!();
}
/// Updates the contained value using a function and returns the new value.
/// Get an unsafe mutable pointer to the inner item
/// in the Cell.
///
/// # Examples
/// # Safety
///
/// ```
/// #![feature(cell_update)]
/// This method is highly discouraged to use. We have it for
/// compatibility reasons with Emscripten.
/// It is unsafe because changing an item inline will change
/// the underlying memory.
///
/// use wasmer::WasmCell;
///
/// let c = WasmCell::new(5);
/// let new = c.update(|x| x + 1);
///
/// assert_eq!(new, 6);
/// assert_eq!(c.get(), 6);
/// ```
#[inline]
pub fn update<F>(&self, f: F) -> T
where
F: FnOnce(T) -> T,
{
let old = self.get();
let new = f(old);
self.set(new);
new
/// It's highly encouraged to use the `set` method instead.
#[deprecated(
since = "2.0.0",
note = "Please use the memory-safe set method instead"
)]
#[doc(hidden)]
pub unsafe fn get_mut(&self) -> &'a mut T {
&mut *self.inner.as_ptr()
}
}
impl<T: Sized> WasmCell<T> {
impl<T: Debug> Debug for WasmCell<'_, T> {
#[inline]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.get().fmt(f)
}
}
impl<T: Sized> WasmCell<'_, T> {
/// Sets the contained value.
///
/// # Examples
///
/// ```
/// use std::cell::Cell;
/// use wasmer::WasmCell;
///
/// let c = WasmCell::new(5);
///
/// c.set(10);
/// let cell = Cell::new(5);
/// let wasm_cell = WasmCell::new(&cell);
/// wasm_cell.set(10);
/// assert_eq!(cell.get(), 10);
/// ```
#[inline]
pub fn set(&self, val: T) {
@@ -269,98 +162,3 @@ impl<T: Sized> WasmCell<T> {
self.memory.copy_from(slice);
}
}
// /// Returns a raw pointer to the underlying data in this cell.
// ///
// /// # Examples
// ///
// /// ```
// /// use wasmer::WasmCell;
// ///
// /// let c = WasmCell::new(5);
// ///
// /// let ptr = c.as_ptr();
// /// ```
// #[inline]
// pub const fn as_ptr(&self) -> *mut T {
// self.value.get()
// }
// /// Returns a mutable reference to the underlying data.
// ///
// /// This call borrows `WasmCell` mutably (at compile-time) which guarantees
// /// that we possess the only reference.
// ///
// /// # Examples
// ///
// /// ```
// /// use wasmer::WasmCell;
// ///
// /// let mut c = WasmCell::new(5);
// /// *c.get_mut() += 1;
// ///
// /// assert_eq!(c.get(), 6);
// /// ```
// #[inline]
// pub fn get_mut(&mut self) -> &mut T {
// self.value.get_mut()
// }
// /// Returns a `&WasmCell<T>` from a `&mut T`
// ///
// /// # Examples
// ///
// /// ```
// /// use wasmer::WasmCell;
// ///
// /// let slice: &mut [i32] = &mut [1, 2, 3];
// /// let cell_slice: &WasmCell<[i32]> = WasmCell::from_mut(slice);
// /// let slice_cell: &[WasmCell<i32>] = cell_slice.as_slice_of_cells();
// ///
// /// assert_eq!(slice_cell.len(), 3);
// /// ```
// #[inline]
// pub fn from_mut(t: &mut T) -> &WasmCell<T> {
// // SAFETY: `&mut` ensures unique access.
// unsafe { &*(t as *mut T as *const WasmCell<T>) }
// }
// }
// impl<T: Default> WasmCell<T> {
// /// Takes the value of the cell, leaving `Default::default()` in its place.
// ///
// /// # Examples
// ///
// /// ```
// /// use wasmer::WasmCell;
// ///
// /// let c = WasmCell::new(5);
// /// let five = c.take();
// ///
// /// assert_eq!(five, 5);
// /// assert_eq!(c.into_inner(), 0);
// /// ```
// pub fn take(&self) -> T {
// self.replace(Default::default())
// }
// }
impl<T> WasmCell<[T]> {
/// Returns a `&[WasmCell<T>]` from a `&WasmCell<[T]>`
///
/// # Examples
///
/// ```
/// use wasmer::WasmCell;
///
/// let slice: &mut [i32] = &mut [1, 2, 3];
/// let cell_slice: &WasmCell<[i32]> = WasmCell::from_mut(slice);
/// let slice_cell: &[WasmCell<i32>] = cell_slice.as_slice_of_cells();
///
/// assert_eq!(slice_cell.len(), 3);
/// ```
pub fn as_slice_of_cells(&self) -> &[WasmCell<T>] {
unimplemented!();
// SAFETY: `WasmCell<T>` has the same memory layout as `T`.
// unsafe { &*(self as *const WasmCell<[T]> as *const [WasmCell<T>]) }
}
}

View File

@@ -82,7 +82,11 @@ impl From<ExportError> for HostEnvInitError {
/// When implementing the trait manually, it's important to get a "weak" export to
/// prevent a cyclic reference leaking memory. You can access a "weak" export with
/// a method like `get_with_generics_weak`.
pub trait WasmerEnv: Clone + Send + Sync {
pub trait WasmerEnv {
// TODO: Had to not use Clone here
// pub trait WasmerEnv: Clone + Send + Sync {
/// The function that Wasmer will call on your type to let it finish
/// setting up the environment with data from the `Instance`.
///

View File

@@ -1,10 +1,50 @@
use crate::instance::Instance;
use crate::WasmerEnv;
use core::any::TypeId;
use js_sys::Function;
use js_sys::WebAssembly::Memory;
use std::any::Any;
use std::cell::RefCell;
use std::fmt;
use std::sync::Arc;
use wasm_bindgen::JsCast;
use wasm_bindgen::JsValue;
pub type VMMemory = Memory;
pub type VMFunction = Function;
#[derive(Clone)]
pub struct VMFunction {
pub(crate) function: Function,
pub(crate) environment: Option<Arc<RefCell<Box<dyn WasmerEnv>>>>,
}
impl VMFunction {
pub(crate) fn new(function: Function, environment: Option<Box<dyn WasmerEnv>>) -> Self {
Self {
function,
environment: environment.map(|env| Arc::new(RefCell::new(env))),
}
}
pub(crate) fn init_envs(&self, instance: &Instance) {
if let Some(env) = &self.environment {
let mut borrowed_env = env.borrow_mut();
borrowed_env.init_with_instance(instance);
}
}
}
impl PartialEq for VMFunction {
fn eq(&self, other: &Self) -> bool {
self.function == other.function
}
}
impl fmt::Debug for VMFunction {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("VMFunction")
.field("function", &self.function)
.finish()
}
}
/// The value of an export passed from one instance to another.
#[derive(Debug, Clone)]
@@ -24,7 +64,7 @@ impl Export {
pub fn as_jsvalue(&self) -> &JsValue {
match self {
Export::Memory(js_wasm_memory) => js_wasm_memory.as_ref(),
Export::Function(js_func) => js_func.as_ref(),
Export::Function(js_func) => js_func.function.as_ref(),
_ => unimplemented!(),
}
}
@@ -32,12 +72,12 @@ impl Export {
impl From<JsValue> for Export {
fn from(val: JsValue) -> Export {
if val.is_instance_of::<VMMemory>() {
return Export::Memory(val.unchecked_into::<VMMemory>());
if val.is_instance_of::<Memory>() {
return Export::Memory(val.unchecked_into::<Memory>());
}
// Leave this last
else if val.is_instance_of::<VMFunction>() {
return Export::Function(val.unchecked_into::<VMFunction>());
else if val.is_instance_of::<Function>() {
return Export::Function(VMFunction::new(val.unchecked_into::<Function>(), None));
}
unimplemented!();
}

View File

@@ -2,7 +2,7 @@ use crate::export::Export;
use crate::externals::{Extern, Function /* , Global, Table */, Memory};
use crate::import_object::LikeNamespace;
// use crate::native::NativeFunc;
// use crate::WasmTypeList;
use crate::WasmTypeList;
use indexmap::IndexMap;
use std::fmt;
use std::iter::{ExactSizeIterator, FromIterator};
@@ -153,31 +153,30 @@ impl Exports {
// .map_err(|_| ExportError::IncompatibleType)
// }
// /// Hack to get this working with nativefunc too
// pub fn get_with_generics<'a, T, Args, Rets>(&'a self, name: &str) -> Result<T, ExportError>
// where
// Args: WasmTypeList,
// Rets: WasmTypeList,
// T: ExportableWithGenerics<'a, Args, Rets>,
// {
// match self.map.get(name) {
// None => Err(ExportError::Missing(name.to_string())),
// Some(extern_) => T::get_self_from_extern_with_generics(extern_),
// }
// }
/// Hack to get this working with nativefunc too
pub fn get_with_generics<'a, T, Args, Rets>(&'a self, name: &str) -> Result<T, ExportError>
where
Args: WasmTypeList,
Rets: WasmTypeList,
T: ExportableWithGenerics<'a, Args, Rets>,
{
match self.map.get(name) {
None => Err(ExportError::Missing(name.to_string())),
Some(extern_) => T::get_self_from_extern_with_generics(extern_),
}
}
// /// Like `get_with_generics` but with a WeakReference to the `InstanceRef` internally.
// /// This is useful for passing data into `WasmerEnv`, for example.
// pub fn get_with_generics_weak<'a, T, Args, Rets>(&'a self, name: &str) -> Result<T, ExportError>
// where
// Args: WasmTypeList,
// Rets: WasmTypeList,
// T: ExportableWithGenerics<'a, Args, Rets>,
// {
// let mut out: T = self.get_with_generics(name)?;
// out.into_weak_instance_ref();
// Ok(out)
// }
/// Like `get_with_generics` but with a WeakReference to the `InstanceRef` internally.
/// This is useful for passing data into `WasmerEnv`, for example.
pub fn get_with_generics_weak<'a, T, Args, Rets>(&'a self, name: &str) -> Result<T, ExportError>
where
Args: WasmTypeList,
Rets: WasmTypeList,
T: ExportableWithGenerics<'a, Args, Rets>,
{
let mut out: T = self.get_with_generics(name)?;
Ok(out)
}
/// Get an export as an `Extern`.
pub fn get_extern(&self, name: &str) -> Option<&Extern> {
@@ -307,33 +306,20 @@ pub trait Exportable<'a>: Sized {
///
/// [`Instance`]: crate::Instance
fn get_self_from_extern(_extern: &'a Extern) -> Result<&'a Self, ExportError>;
/// Convert the extern internally to hold a weak reference to the `InstanceRef`.
/// This is useful for preventing cycles, for example for data stored in a
/// type implementing `WasmerEnv`.
fn into_weak_instance_ref(&mut self);
}
// /// A trait for accessing exports (like [`Exportable`]) but it takes generic
// /// `Args` and `Rets` parameters so that `NativeFunc` can be accessed directly
// /// as well.
// pub trait ExportableWithGenerics<'a, Args: WasmTypeList, Rets: WasmTypeList>: Sized {
// /// Get an export with the given generics.
// fn get_self_from_extern_with_generics(_extern: &'a Extern) -> Result<Self, ExportError>;
// /// Convert the extern internally to hold a weak reference to the `InstanceRef`.
// /// This is useful for preventing cycles, for example for data stored in a
// /// type implementing `WasmerEnv`.
// fn into_weak_instance_ref(&mut self);
// }
/// A trait for accessing exports (like [`Exportable`]) but it takes generic
/// `Args` and `Rets` parameters so that `NativeFunc` can be accessed directly
/// as well.
pub trait ExportableWithGenerics<'a, Args: WasmTypeList, Rets: WasmTypeList>: Sized {
/// Get an export with the given generics.
fn get_self_from_extern_with_generics(_extern: &'a Extern) -> Result<Self, ExportError>;
}
// /// We implement it for all concrete [`Exportable`] types (that are `Clone`)
// /// with empty `Args` and `Rets`.
// impl<'a, T: Exportable<'a> + Clone + 'static> ExportableWithGenerics<'a, (), ()> for T {
// fn get_self_from_extern_with_generics(_extern: &'a Extern) -> Result<Self, ExportError> {
// T::get_self_from_extern(_extern).map(|i| i.clone())
// }
// fn into_weak_instance_ref(&mut self) {
// <Self as Exportable>::into_weak_instance_ref(self);
// }
// }
/// We implement it for all concrete [`Exportable`] types (that are `Clone`)
/// with empty `Args` and `Rets`.
impl<'a, T: Exportable<'a> + Clone + 'static> ExportableWithGenerics<'a, (), ()> for T {
fn get_self_from_extern_with_generics(_extern: &'a Extern) -> Result<Self, ExportError> {
T::get_self_from_extern(_extern).map(|i| i.clone())
}
}

View File

@@ -45,8 +45,8 @@ pub struct VMFunctionBody(u8);
// #[derive(PartialEq)]
pub struct Function {
pub(crate) store: Store,
ty: FunctionType,
pub(crate) exported: VMFunction,
pub(crate) environment: Option<*const u8>, // environment: Option<WasmRefCell<Box<Any>>>,
}
impl PartialEq for Function {
@@ -172,11 +172,11 @@ impl Function {
let ft = wasm_bindgen::function_table();
let as_table = ft.unchecked_ref::<js_sys::WebAssembly::Table>();
let func = as_table.get(call_func_dynamic as usize as u32).unwrap();
let environment = None;
// let environment: Option<Arc>
Self {
store: store.clone(),
exported: func,
environment,
ty: ty.into(),
exported: VMFunction::new(func, None),
}
// Function::new
// let wrapped_func =
@@ -311,11 +311,11 @@ impl Function {
let as_table = ft.unchecked_ref::<js_sys::WebAssembly::Table>();
let func = as_table.get(address).unwrap();
let binded_func = func.bind1(&JsValue::UNDEFINED, &JsValue::UNDEFINED);
let environment = None;
let ty = FunctionType::new(Args::wasm_types(), Rets::wasm_types());
Self {
store: store.clone(),
exported: binded_func,
environment,
ty,
exported: VMFunction::new(binded_func, None),
}
// let vmctx = VMFunctionEnvironment {
@@ -341,6 +341,11 @@ impl Function {
// }
}
// /// Get a reference to the Function environment, if any
// pub fn get_host_env(&self) -> Option<&Any> {
// self.environment.as_ref().map(|e|&**e)
// }
/// Creates a new host `Function` from a native function and a provided environment.
///
/// The function signature is automatically retrieved using the
@@ -380,17 +385,19 @@ impl Function {
let ft = wasm_bindgen::function_table();
let as_table = ft.unchecked_ref::<js_sys::WebAssembly::Table>();
let func = as_table.get(address).unwrap();
let ty = FunctionType::new(Args::wasm_types(), Rets::wasm_types());
// let b: Box<Any> = Box::new(env);
// let environment = Some(WasmRefCell::new(b));
let environment = Box::into_raw(Box::new(env)) as *mut u8;
let environment = Box::new(env);
let binded_func = func.bind1(
&JsValue::UNDEFINED,
&JsValue::from_f64(environment as usize as f64),
&JsValue::from_f64(&*environment as *const Env as *const u8 as usize as f64),
);
// panic!("Function env {:?}", environment.type_id());
Self {
store: store.clone(),
exported: binded_func,
environment: Some(environment),
ty,
exported: VMFunction::new(binded_func, Some(environment)),
}
// let function = inner::Function::<Args, Rets>::new(func);
@@ -590,8 +597,10 @@ impl Function {
let js_value = param.as_jsvalue();
arr.set(i as u32, js_value);
}
let result = js_sys::Reflect::apply(&self.exported, &wasm_bindgen::JsValue::NULL, &arr);
Ok(vec![Val::F64(result.unwrap().as_f64().unwrap())].into_boxed_slice())
let result =
js_sys::Reflect::apply(&self.exported.function, &wasm_bindgen::JsValue::NULL, &arr);
// Ok(vec![Val::F64(result.unwrap().as_f64().unwrap())].into_boxed_slice())
Ok(Box::new([]))
// if let Some(trampoline) = self.exported.vm_function.call_trampoline {
// let mut results = vec![Val::null(); self.result_arity()];
// self.call_wasm(trampoline, params, &mut results)?;
@@ -602,11 +611,10 @@ impl Function {
}
pub(crate) fn from_vm_export(store: &Store, wasmer_export: VMFunction) -> Self {
let environment = None;
Self {
store: store.clone(),
ty: FunctionType::new(vec![], vec![]),
exported: wasmer_export,
environment,
}
}
@@ -750,15 +758,6 @@ impl<'a> Exportable<'a> for Function {
_ => Err(ExportError::IncompatibleType),
}
}
fn into_weak_instance_ref(&mut self) {
unimplemented!();
// self.exported
// .vm_function
// .instance_ref
// .as_mut()
// .map(|v| *v = v.downgrade());
}
}
impl Clone for Function {

View File

@@ -239,11 +239,4 @@ impl<'a> Exportable<'a> for Global {
_ => Err(ExportError::IncompatibleType),
}
}
fn into_weak_instance_ref(&mut self) {
self.vm_global
.instance_ref
.as_mut()
.map(|v| *v = v.downgrade());
}
}

View File

@@ -46,7 +46,7 @@ extern "C" {
/// mutable from both host and WebAssembly.
///
/// Spec: <https://webassembly.github.io/spec/core/exec/runtime.html#memory-instances>
#[derive(Debug)]
#[derive(Debug, Clone)]
pub struct Memory {
store: Store,
ty: MemoryType,
@@ -300,18 +300,18 @@ impl Memory {
}
}
impl Clone for Memory {
fn clone(&self) -> Self {
unimplemented!();
// let mut vm_memory = self.vm_memory.clone();
// vm_memory.upgrade_instance_ref().unwrap();
// impl Clone for Memory {
// fn clone(&self) -> Self {
// unimplemented!();
// // let mut vm_memory = self.vm_memory.clone();
// // vm_memory.upgrade_instance_ref().unwrap();
// Self {
// store: self.store.clone(),
// vm_memory,
// }
}
}
// // Self {
// // store: self.store.clone(),
// // vm_memory,
// // }
// }
// }
impl<'a> Exportable<'a> for Memory {
fn to_export(&self) -> Export {
@@ -325,12 +325,4 @@ impl<'a> Exportable<'a> for Memory {
_ => Err(ExportError::IncompatibleType),
}
}
fn into_weak_instance_ref(&mut self) {
unimplemented!();
// self.vm_memory
// .instance_ref
// .as_mut()
// .map(|v| *v = v.downgrade());
}
}

View File

@@ -69,15 +69,6 @@ impl<'a> Exportable<'a> for Extern {
// Since this is already an extern, we can just return it.
Ok(_extern)
}
fn into_weak_instance_ref(&mut self) {
match self {
Self::Function(f) => f.into_weak_instance_ref(),
// Self::Global(g) => g.into_weak_instance_ref(),
Self::Memory(m) => m.into_weak_instance_ref(),
// Self::Table(t) => t.into_weak_instance_ref(),
}
}
}
impl StoreObject for Extern {}

View File

@@ -184,10 +184,4 @@ impl<'a> Exportable<'a> for Table {
}
}
fn into_weak_instance_ref(&mut self) {
self.vm_table
.instance_ref
.as_mut()
.map(|v| *v = v.downgrade());
}
}

View File

@@ -109,9 +109,9 @@ impl Instance {
/// Those are, as defined by the spec:
/// * Link errors that happen when plugging the imports into the instance
/// * Runtime errors that happen when running the module `start` function.
pub fn new(module: &Module, resolver: &dyn NamedResolver) -> Result<Self, InstantiationError> {
pub fn new(module: &Module, resolver: &dyn Resolver) -> Result<Self, InstantiationError> {
let store = module.store();
let instance = module.instantiate(resolver).unwrap();
let (instance, functions) = module.instantiate(resolver).unwrap();
let instance_exports = instance.exports();
let exports = module
.exports()
@@ -123,11 +123,15 @@ impl Instance {
})
.collect::<Exports>();
Ok(Self {
let self_instance = Self {
module: module.clone(),
instance: instance,
exports,
})
};
for mut func in functions {
func.init_envs(&self_instance);
}
Ok(self_instance)
}
/// Gets the [`Module`] associated with this instance.

View File

@@ -287,11 +287,11 @@ mod error;
mod export;
mod exports;
mod externals;
mod resolver;
mod import_object;
mod instance;
mod iterators;
mod module;
mod resolver;
// mod native;
mod ptr;
mod store;
@@ -303,6 +303,7 @@ mod utils;
/// See the [`WasmerEnv`] trait for more information.
pub use wasmer_derive::WasmerEnv;
pub use crate::cell::WasmCell;
pub use crate::env::{HostEnvInitError, LazyInit, WasmerEnv};
pub use crate::exports::{ExportError, Exportable, Exports, ExportsIterator};
pub use crate::externals::{
@@ -316,6 +317,8 @@ pub use crate::module::Module;
pub use wasm_bindgen::JsValue as RuntimeError;
// pub use crate::native::NativeFunc;
pub use crate::ptr::{Array, Item, WasmPtr};
pub use crate::resolver::{ChainableNamedResolver, NamedResolver, NamedResolverChain, Resolver};
pub use crate::store::{Store, StoreObject};
pub use crate::types::{
ExportType, ExternType, FunctionType, GlobalType, ImportType, MemoryType, Mutability,

View File

@@ -1,5 +1,6 @@
use crate::export::{Export, VMFunction};
use crate::iterators::{ExportsIterator, ImportsIterator};
use crate::resolver::{NamedResolver, Resolver};
use crate::resolver::Resolver;
use crate::store::Store;
use crate::types::{ExportType, ImportType};
// use crate::InstantiationError;
@@ -175,12 +176,13 @@ impl Module {
pub(crate) fn instantiate(
&self,
resolver: &dyn NamedResolver,
) -> Result<WebAssembly::Instance, ()> {
resolver: &dyn Resolver,
) -> Result<(WebAssembly::Instance, Vec<VMFunction>), ()> {
let imports = js_sys::Object::new();
for import_type in self.imports() {
let mut functions: Vec<VMFunction> = vec![];
for (i, import_type) in self.imports().enumerate() {
let resolved_import =
resolver.resolve_by_name(import_type.module(), import_type.name());
resolver.resolve(i as u32, import_type.module(), import_type.name());
if let Some(import) = resolved_import {
match js_sys::Reflect::get(&imports, &import_type.module().into()) {
Ok(val) => {
@@ -192,6 +194,7 @@ impl Module {
import.as_jsvalue(),
);
} else {
// If the namespace doesn't exist
let import_namespace = js_sys::Object::new();
js_sys::Reflect::set(
&import_namespace,
@@ -207,9 +210,17 @@ impl Module {
}
Err(_) => return Err(()),
};
if let Export::Function(func) = import {
functions.push(func);
}
}
// in case the import is not found, the JS Wasm VM will handle
// the error for us, so we don't need to handle it
}
Ok(WebAssembly::Instance::new(&self.module, &imports).unwrap())
Ok((
WebAssembly::Instance::new(&self.module, &imports).unwrap(),
functions,
))
}
/// Returns the name of the current module.

View File

@@ -112,18 +112,6 @@ impl<T: Copy + ValueType> WasmPtr<T, Item> {
let subarray = memory.uint8view().subarray(self.offset, total_len as u32);
Some(WasmCell::new(subarray))
}
/// Mutably dereference this `WasmPtr` getting a `&mut Cell<T>` allowing for
/// direct access to a `&mut T`.
///
/// # Safety
/// - This method does not do any aliasing checks: it's possible to create
/// `&mut T` that point to the same memory. You should ensure that you have
/// exclusive access to Wasm linear memory before calling this method.
#[inline]
pub unsafe fn deref_mut<'a>(self, memory: &'a Memory) -> Option<WasmCell<T>> {
self.deref(memory)
}
}
/// Methods for `WasmPtr`s to arrays of data that can be dereferenced, namely to
@@ -137,7 +125,7 @@ impl<T: Copy + ValueType> WasmPtr<T, Array> {
/// If you're unsure what that means, it likely does not apply to you.
/// This invariant will be enforced in the future.
#[inline]
pub fn deref(self, memory: &Memory, index: u32, length: u32) -> Option<Box<[WasmCell<T>]>> {
pub fn deref(self, memory: &Memory, index: u32, length: u32) -> Option<Vec<WasmCell<T>>> {
// gets the size of the item in the array with padding added such that
// for any index, we will always result an aligned memory access
let item_size = mem::size_of::<T>() as u32;
@@ -160,28 +148,10 @@ impl<T: Copy + ValueType> WasmPtr<T, Array> {
);
WasmCell::new(subarray)
})
.collect::<Vec<_>>()
.into_boxed_slice(),
.collect::<Vec<_>>(),
)
}
/// Mutably dereference this `WasmPtr` getting a `&mut [Cell<T>]` allowing for
/// direct access to a `&mut [T]`.
///
/// # Safety
/// - This method does not do any aliasing checks: it's possible to create
/// `&mut T` that point to the same memory. You should ensure that you have
/// exclusive access to Wasm linear memory before calling this method.
#[inline]
pub unsafe fn deref_mut(
self,
memory: &Memory,
index: u32,
length: u32,
) -> Option<Box<[WasmCell<T>]>> {
self.deref(memory, index, length)
}
/// Get a UTF-8 string from the `WasmPtr` with the given length.
///
/// Note that . The
@@ -212,7 +182,9 @@ impl<T: Copy + ValueType> WasmPtr<T, Array> {
return None;
}
let subarray_as_vec = memory.uint8view().subarray(self.offset, str_len).to_vec();
String::from_utf8(subarray_as_vec).ok().map(std::borrow::Cow::from)
String::from_utf8(subarray_as_vec)
.ok()
.map(std::borrow::Cow::from)
}
/// Get a UTF-8 `String` from the `WasmPtr` with the given length.
@@ -319,29 +291,23 @@ mod test {
let start_wasm_ptr_array: WasmPtr<u8, Array> = WasmPtr::new(0);
assert!(start_wasm_ptr.deref(&memory).is_some());
assert!(unsafe { start_wasm_ptr.deref_mut(&memory).is_some() });
assert!(start_wasm_ptr_array.deref(&memory, 0, 0).is_some());
assert!(unsafe { start_wasm_ptr_array.get_utf8_str(&memory, 0).is_some() });
assert!(start_wasm_ptr_array.get_utf8_string(&memory, 0).is_some());
assert!(unsafe { start_wasm_ptr_array.deref_mut(&memory, 0, 0).is_some() });
assert!(start_wasm_ptr_array.deref(&memory, 0, 1).is_some());
assert!(unsafe { start_wasm_ptr_array.deref_mut(&memory, 0, 1).is_some() });
// test that accessing the last valid memory address works correctly and OOB is caught
let last_valid_address_for_u8 = (memory.size().bytes().0 - 1) as u32;
let end_wasm_ptr: WasmPtr<u8> = WasmPtr::new(last_valid_address_for_u8);
assert!(end_wasm_ptr.deref(&memory).is_some());
assert!(unsafe { end_wasm_ptr.deref_mut(&memory).is_some() });
let end_wasm_ptr_array: WasmPtr<u8, Array> = WasmPtr::new(last_valid_address_for_u8);
assert!(end_wasm_ptr_array.deref(&memory, 0, 1).is_some());
assert!(unsafe { end_wasm_ptr_array.deref_mut(&memory, 0, 1).is_some() });
let invalid_idx_len_combos: [(u32, u32); 3] =
[(last_valid_address_for_u8 + 1, 0), (0, 2), (1, 1)];
for &(idx, len) in invalid_idx_len_combos.iter() {
assert!(end_wasm_ptr_array.deref(&memory, idx, len).is_none());
assert!(unsafe { end_wasm_ptr_array.deref_mut(&memory, idx, len).is_none() });
}
assert!(unsafe { end_wasm_ptr_array.get_utf8_str(&memory, 2).is_none() });
assert!(end_wasm_ptr_array.get_utf8_string(&memory, 2).is_none());
@@ -351,9 +317,7 @@ mod test {
let last_valid_address_for_u32 = (memory.size().bytes().0 - 4) as u32;
let end_wasm_ptr: WasmPtr<u32> = WasmPtr::new(last_valid_address_for_u32);
assert!(end_wasm_ptr.deref(&memory).is_some());
assert!(unsafe { end_wasm_ptr.deref_mut(&memory).is_some() });
assert!(end_wasm_ptr.deref(&memory).is_some());
assert!(unsafe { end_wasm_ptr.deref_mut(&memory).is_some() });
let end_wasm_ptr_oob_array: [WasmPtr<u32>; 4] = [
WasmPtr::new(last_valid_address_for_u32 + 1),
@@ -363,17 +327,14 @@ mod test {
];
for oob_end_ptr in end_wasm_ptr_oob_array.iter() {
assert!(oob_end_ptr.deref(&memory).is_none());
assert!(unsafe { oob_end_ptr.deref_mut(&memory).is_none() });
}
let end_wasm_ptr_array: WasmPtr<u32, Array> = WasmPtr::new(last_valid_address_for_u32);
assert!(end_wasm_ptr_array.deref(&memory, 0, 1).is_some());
assert!(unsafe { end_wasm_ptr_array.deref_mut(&memory, 0, 1).is_some() });
let invalid_idx_len_combos: [(u32, u32); 3] =
[(last_valid_address_for_u32 + 1, 0), (0, 2), (1, 1)];
for &(idx, len) in invalid_idx_len_combos.iter() {
assert!(end_wasm_ptr_array.deref(&memory, idx, len).is_none());
assert!(unsafe { end_wasm_ptr_array.deref_mut(&memory, idx, len).is_none() });
}
let end_wasm_ptr_array_oob_array: [WasmPtr<u32, Array>; 4] = [
@@ -385,9 +346,7 @@ mod test {
for oob_end_array_ptr in end_wasm_ptr_array_oob_array.iter() {
assert!(oob_end_array_ptr.deref(&memory, 0, 1).is_none());
assert!(unsafe { oob_end_array_ptr.deref_mut(&memory, 0, 1).is_none() });
assert!(oob_end_array_ptr.deref(&memory, 1, 0).is_none());
assert!(unsafe { oob_end_array_ptr.deref_mut(&memory, 1, 0).is_none() });
}
}
}

View File

@@ -3,7 +3,7 @@ use wasmer_types::entity::{BoxedSlice, EntityRef, PrimaryMap};
use wasmer_types::{ExternType, FunctionIndex, ImportIndex, MemoryIndex, TableIndex};
/// Import resolver connects imports with available exported values.
pub trait Resolver: Sized {
pub trait Resolver {
/// Resolves an import a WebAssembly module to an export it's hooked up to.
///
/// The `index` provided is the index of the import in the wasm module
@@ -75,3 +75,93 @@ impl Resolver for NullResolver {
None
}
}
/// A [`Resolver`] that links two resolvers together in a chain.
pub struct NamedResolverChain<A: NamedResolver, B: NamedResolver> {
a: A,
b: B,
}
/// A trait for chaining resolvers together.
///
/// ```
/// # use wasmer_engine::{ChainableNamedResolver, NamedResolver};
/// # fn chainable_test<A, B>(imports1: A, imports2: B)
/// # where A: NamedResolver + Sized,
/// # B: NamedResolver + Sized,
/// # {
/// // override duplicates with imports from `imports2`
/// imports1.chain_front(imports2);
/// # }
/// ```
pub trait ChainableNamedResolver: NamedResolver + Sized {
/// Chain a resolver in front of the current resolver.
///
/// This will cause the second resolver to override the first.
///
/// ```
/// # use wasmer_engine::{ChainableNamedResolver, NamedResolver};
/// # fn chainable_test<A, B>(imports1: A, imports2: B)
/// # where A: NamedResolver + Sized,
/// # B: NamedResolver + Sized,
/// # {
/// // override duplicates with imports from `imports2`
/// imports1.chain_front(imports2);
/// # }
/// ```
fn chain_front<U>(self, other: U) -> NamedResolverChain<U, Self>
where
U: NamedResolver,
{
NamedResolverChain { a: other, b: self }
}
/// Chain a resolver behind the current resolver.
///
/// This will cause the first resolver to override the second.
///
/// ```
/// # use wasmer_engine::{ChainableNamedResolver, NamedResolver};
/// # fn chainable_test<A, B>(imports1: A, imports2: B)
/// # where A: NamedResolver + Sized,
/// # B: NamedResolver + Sized,
/// # {
/// // override duplicates with imports from `imports1`
/// imports1.chain_back(imports2);
/// # }
/// ```
fn chain_back<U>(self, other: U) -> NamedResolverChain<Self, U>
where
U: NamedResolver,
{
NamedResolverChain { a: self, b: other }
}
}
// We give these chain methods to all types implementing NamedResolver
impl<T: NamedResolver> ChainableNamedResolver for T {}
impl<A, B> NamedResolver for NamedResolverChain<A, B>
where
A: NamedResolver,
B: NamedResolver,
{
fn resolve_by_name(&self, module: &str, field: &str) -> Option<Export> {
self.a
.resolve_by_name(module, field)
.or_else(|| self.b.resolve_by_name(module, field))
}
}
impl<A, B> Clone for NamedResolverChain<A, B>
where
A: NamedResolver + Clone,
B: NamedResolver + Clone,
{
fn clone(&self) -> Self {
Self {
a: self.a.clone(),
b: self.b.clone(),
}
}
}