Added partial support for tables

This commit is contained in:
Syrus Akbary
2021-07-13 00:20:59 -07:00
parent f46b01c260
commit a55f157c50
6 changed files with 133 additions and 105 deletions

View File

@@ -1,13 +1,13 @@
use crate::instance::Instance;
use crate::WasmerEnv;
use js_sys::Function;
use js_sys::WebAssembly::Memory;
use js_sys::WebAssembly::{Memory, Table};
use std::cell::RefCell;
use std::fmt;
use std::sync::Arc;
use wasm_bindgen::JsCast;
use wasm_bindgen::JsValue;
use wasmer_types::{ExternType, FunctionType, MemoryType};
use wasmer_types::{ExternType, FunctionType, MemoryType, TableType};
#[derive(Clone, Debug, PartialEq)]
pub struct VMMemory {
@@ -21,6 +21,18 @@ impl VMMemory {
}
}
#[derive(Clone, Debug, PartialEq)]
pub struct VMTable {
pub(crate) table: Table,
pub(crate) ty: TableType,
}
impl VMTable {
pub(crate) fn new(table: Table, ty: TableType) -> Self {
Self { table, ty }
}
}
#[derive(Clone)]
pub struct VMFunction {
pub(crate) function: Function,
@@ -68,8 +80,9 @@ pub enum Export {
/// A function export value.
Function(VMFunction),
// /// A table export value.
// Table(VMTable),
/// A table export value.
Table(VMTable),
/// A memory export value.
Memory(VMMemory),
// /// A global export value.
@@ -81,6 +94,7 @@ impl Export {
match self {
Export::Memory(js_wasm_memory) => js_wasm_memory.memory.as_ref(),
Export::Function(js_func) => js_func.function.as_ref(),
Export::Table(js_wasm_table) => js_wasm_table.table.as_ref(),
_ => unimplemented!(),
}
}
@@ -110,6 +124,13 @@ impl From<(JsValue, ExternType)> for Export {
panic!("Extern type doesn't match js value type");
}
}
ExternType::Table(table_type) => {
if val.is_instance_of::<Table>() {
return Export::Table(VMTable::new(val.unchecked_into::<Table>(), table_type));
} else {
panic!("Extern type doesn't match js value type");
}
}
_ => unimplemented!(),
}
}

View File

@@ -1,7 +1,7 @@
pub(crate) mod function;
// mod global;
mod memory;
// mod table;
mod table;
pub use self::function::{
FromToNativeWasmType, Function, HostFunction, WasmTypeList, WithEnv, WithoutEnv,
@@ -9,7 +9,7 @@ pub use self::function::{
// pub use self::global::Global;
pub use self::memory::Memory;
// pub use self::table::Table;
pub use self::table::Table;
use crate::export::Export;
use crate::exports::{ExportError, Exportable};
@@ -28,7 +28,7 @@ pub enum Extern {
// /// A external [`Global`].
// Global(Global),
/// A external [`Table`].
// Table(Table),
Table(Table),
/// A external [`Memory`].
Memory(Memory),
}
@@ -39,7 +39,7 @@ impl Extern {
match self {
Self::Function(ft) => ExternType::Function(ft.ty().clone()),
Self::Memory(ft) => ExternType::Memory(ft.ty()),
// Self::Table(tt) => ExternType::Table(*tt.ty()),
Self::Table(tt) => ExternType::Table(*tt.ty()),
// Self::Global(gt) => ExternType::Global(*gt.ty()),
}
}
@@ -50,7 +50,7 @@ impl Extern {
Export::Function(f) => Self::Function(Function::from_vm_export(store, f)),
Export::Memory(m) => Self::Memory(Memory::from_vm_export(store, m)),
// Export::Global(g) => Self::Global(Global::from_vm_export(store, g)),
// Export::Table(t) => Self::Table(Table::from_vm_export(store, t)),
Export::Table(t) => Self::Table(Table::from_vm_export(store, t)),
}
}
}
@@ -61,7 +61,7 @@ impl<'a> Exportable<'a> for Extern {
Self::Function(f) => f.to_export(),
// Self::Global(g) => g.to_export(),
Self::Memory(m) => m.to_export(),
// Self::Table(t) => t.to_export(),
Self::Table(t) => t.to_export(),
}
}
@@ -82,7 +82,7 @@ impl fmt::Debug for Extern {
Self::Function(_) => "Function(...)",
// Self::Global(_) => "Global(...)",
Self::Memory(_) => "Memory(...)",
// Self::Table(_) => "Table(...)",
Self::Table(_) => "Table(...)",
}
)
}
@@ -106,8 +106,8 @@ impl From<Memory> for Extern {
}
}
// impl From<Table> for Extern {
// fn from(r: Table) -> Self {
// Self::Table(r)
// }
// }
impl From<Table> for Extern {
fn from(r: Table) -> Self {
Self::Table(r)
}
}

View File

@@ -1,13 +1,13 @@
use crate::export::VMFunction;
use crate::export::{Export, VMTable};
use crate::exports::{ExportError, Exportable};
use crate::externals::Extern;
use crate::externals::{Extern, Function as WasmerFunction};
use crate::store::Store;
use crate::types::{Val, ValFuncRef};
use crate::types::Val;
use crate::RuntimeError;
use crate::TableType;
use loupe::MemoryUsage;
use std::sync::Arc;
use wasmer_engine::Export;
use wasmer_vm::{Table as RuntimeTable, TableElement, VMTable};
use js_sys::Function;
use wasmer_types::FunctionType;
/// A WebAssembly `table` instance.
///
@@ -18,18 +18,22 @@ use wasmer_vm::{Table as RuntimeTable, TableElement, VMTable};
/// mutable from both host and WebAssembly.
///
/// Spec: <https://webassembly.github.io/spec/core/exec/runtime.html#table-instances>
#[derive(MemoryUsage)]
#[derive(Debug, Clone, PartialEq)]
pub struct Table {
store: Store,
vm_table: VMTable,
}
fn set_table_item(
table: &dyn RuntimeTable,
item_index: u32,
item: TableElement,
) -> Result<(), RuntimeError> {
table.set(item_index, item).map_err(|e| e.into())
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(val: Val) -> Result<Function, RuntimeError> {
match val {
Val::FuncRef(func) => Ok(func.as_ref().unwrap().exported.function.clone().into()),
// Only funcrefs is supported by the spec atm
_ => unimplemented!(),
}
}
impl Table {
@@ -40,30 +44,38 @@ impl Table {
/// This function will construct the `Table` using the store
/// [`BaseTunables`][crate::tunables::BaseTunables].
pub fn new(store: &Store, ty: TableType, init: Val) -> Result<Self, RuntimeError> {
let item = init.into_table_reference(store)?;
let tunables = store.tunables();
let style = tunables.table_style(&ty);
let table = tunables
.create_host_table(&ty, &style)
.map_err(RuntimeError::new)?;
// let item = init.into_table_reference(store)?;
// let tunables = store.tunables();
// let style = tunables.table_style(&ty);
// let table = tunables
// .create_host_table(&ty, &style)
// .map_err(RuntimeError::new)?;
let num_elements = table.size();
let descriptor = js_sys::Object::new();
js_sys::Reflect::set(&descriptor, &"initial".into(), &ty.minimum.into());
if let Some(max) = ty.maximum {
js_sys::Reflect::set(&descriptor, &"maximum".into(), &max.into());
}
js_sys::Reflect::set(&descriptor, &"element".into(), &"anyfunc".into());
let js_table = js_sys::WebAssembly::Table::new(&descriptor).unwrap();
let table = VMTable::new(js_table, ty);
let num_elements = table.table.length();
let func = get_function(init)?;
for i in 0..num_elements {
set_table_item(table.as_ref(), i, item.clone())?;
set_table_item(&table, i, &func)?;
}
Ok(Self {
store: store.clone(),
vm_table: VMTable {
from: table,
instance_ref: None,
},
vm_table: table,
})
}
/// Returns the [`TableType`] of the `Table`.
pub fn ty(&self) -> &TableType {
self.vm_table.from.ty()
&self.vm_table.ty
}
/// Returns the [`Store`] where the `Table` belongs.
@@ -73,19 +85,24 @@ impl Table {
/// Retrieves an element of the table at the provided `index`.
pub fn get(&self, index: u32) -> Option<Val> {
let item = self.vm_table.from.get(index)?;
Some(ValFuncRef::from_table_reference(item, &self.store))
let func = self.vm_table.table.get(index).ok()?;
let ty = FunctionType::new(vec![], vec![]);
Some(Val::FuncRef(Some(WasmerFunction::from_vm_export(
&self.store,
VMFunction::new(func, ty, None),
))))
}
/// Sets an element `val` in the Table at the provided `index`.
pub fn set(&self, index: u32, val: Val) -> Result<(), RuntimeError> {
let item = val.into_table_reference(&self.store)?;
set_table_item(self.vm_table.from.as_ref(), index, item)
let func = get_function(val)?;
set_table_item(&self.vm_table, index, &func)?;
Ok(())
}
/// Retrieves the size of the `Table` (in elements)
pub fn size(&self) -> u32 {
self.vm_table.from.size()
self.vm_table.table.length()
}
/// Grows the size of the `Table` by `delta`, initializating
@@ -98,11 +115,12 @@ impl Table {
///
/// Returns an error if the `delta` is out of bounds for the table.
pub fn grow(&self, delta: u32, init: Val) -> Result<u32, RuntimeError> {
let item = init.into_table_reference(&self.store)?;
self.vm_table
.from
.grow(delta, item)
.ok_or_else(|| RuntimeError::new(format!("failed to grow table by `{}`", delta)))
unimplemented!();
// let item = init.into_table_reference(&self.store)?;
// self.vm_table
// .from
// .grow(delta, item)
// .ok_or_else(|| RuntimeError::new(format!("failed to grow table by `{}`", delta)))
}
/// Copies the `len` elements of `src_table` starting at `src_index`
@@ -119,20 +137,21 @@ impl Table {
src_index: u32,
len: u32,
) -> Result<(), RuntimeError> {
if !Store::same(&dst_table.store, &src_table.store) {
return Err(RuntimeError::new(
"cross-`Store` table copies are not supported",
));
}
RuntimeTable::copy(
dst_table.vm_table.from.as_ref(),
src_table.vm_table.from.as_ref(),
dst_index,
src_index,
len,
)
.map_err(RuntimeError::from_trap)?;
Ok(())
unimplemented!();
// if !Store::same(&dst_table.store, &src_table.store) {
// return Err(RuntimeError::new(
// "cross-`Store` table copies are not supported",
// ));
// }
// RuntimeTable::copy(
// dst_table.vm_table.from.as_ref(),
// src_table.vm_table.from.as_ref(),
// dst_index,
// src_index,
// len,
// )
// .map_err(RuntimeError::from_trap)?;
// Ok(())
}
pub(crate) fn from_vm_export(store: &Store, vm_table: VMTable) -> Self {
@@ -144,7 +163,7 @@ impl Table {
/// Returns whether or not these two tables refer to the same data.
pub fn same(&self, other: &Self) -> bool {
Arc::ptr_eq(&self.vm_table.from, &other.vm_table.from)
self.vm_table == other.vm_table
}
/// Get access to the backing VM value for this extern. This function is for
@@ -160,21 +179,10 @@ impl Table {
}
}
impl Clone for Table {
fn clone(&self) -> Self {
let mut vm_table = self.vm_table.clone();
vm_table.upgrade_instance_ref().unwrap();
Self {
store: self.store.clone(),
vm_table,
}
}
}
impl<'a> Exportable<'a> for Table {
fn to_export(&self) -> Export {
self.vm_table.clone().into()
// self.vm_table.clone().into()
unimplemented!();
}
fn get_self_from_extern(_extern: &'a Extern) -> Result<&'a Self, ExportError> {
@@ -183,5 +191,4 @@ impl<'a> Exportable<'a> for Table {
_ => Err(ExportError::IncompatibleType),
}
}
}

View File

@@ -308,8 +308,8 @@ pub use crate::cell::WasmCell;
pub use crate::env::{HostEnvInitError, LazyInit, WasmerEnv};
pub use crate::exports::{ExportError, Exportable, Exports, ExportsIterator};
pub use crate::externals::{
Extern, FromToNativeWasmType, Function, HostFunction, Memory,
/* Global, Table, */
Extern, FromToNativeWasmType, Function, HostFunction, Memory, Table,
/* Global, */
WasmTypeList,
};
pub use crate::import_object::{ImportObject, ImportObjectIterator, LikeNamespace};

View File

@@ -29,6 +29,7 @@ impl AsJs for Val {
Self::I64(i) => JsValue::from_f64(*i as f64),
Self::F32(f) => JsValue::from_f64(*f as f64),
Self::F64(f) => JsValue::from_f64(*f),
Self::FuncRef(func) => func.as_ref().unwrap().exported.function.clone().into(),
_ => unimplemented!(),
}
}