Improved type reflection

This commit is contained in:
Syrus Akbary
2021-07-12 20:54:20 -07:00
parent d25b2cb008
commit 2c75468c9e
8 changed files with 710 additions and 76 deletions

View File

@@ -9,18 +9,36 @@ use std::fmt;
use std::sync::Arc;
use wasm_bindgen::JsCast;
use wasm_bindgen::JsValue;
use wasmer_types::{ExternType, FunctionType, MemoryType};
#[derive(Clone, Debug, PartialEq)]
pub struct VMMemory {
pub(crate) memory: Memory,
pub(crate) ty: MemoryType,
}
impl VMMemory {
pub(crate) fn new(memory: Memory, ty: MemoryType) -> Self {
Self { memory, ty }
}
}
pub type VMMemory = Memory;
#[derive(Clone)]
pub struct VMFunction {
pub(crate) function: Function,
pub(crate) ty: FunctionType,
pub(crate) environment: Option<Arc<RefCell<Box<dyn WasmerEnv>>>>,
}
impl VMFunction {
pub(crate) fn new(function: Function, environment: Option<Box<dyn WasmerEnv>>) -> Self {
pub(crate) fn new(
function: Function,
ty: FunctionType,
environment: Option<Box<dyn WasmerEnv>>,
) -> Self {
Self {
function,
ty,
environment: environment.map(|env| Arc::new(RefCell::new(env))),
}
}
@@ -63,22 +81,38 @@ pub enum Export {
impl Export {
pub fn as_jsvalue(&self) -> &JsValue {
match self {
Export::Memory(js_wasm_memory) => js_wasm_memory.as_ref(),
Export::Memory(js_wasm_memory) => js_wasm_memory.memory.as_ref(),
Export::Function(js_func) => js_func.function.as_ref(),
_ => unimplemented!(),
}
}
}
impl From<JsValue> for Export {
fn from(val: JsValue) -> Export {
if val.is_instance_of::<Memory>() {
return Export::Memory(val.unchecked_into::<Memory>());
impl From<(JsValue, ExternType)> for Export {
fn from((val, extern_type): (JsValue, ExternType)) -> Export {
match extern_type {
ExternType::Memory(memory_type) => {
if val.is_instance_of::<Memory>() {
return Export::Memory(VMMemory::new(
val.unchecked_into::<Memory>(),
memory_type,
));
} else {
panic!("Extern type doesn't match js value type");
}
}
ExternType::Function(function_type) => {
if val.is_instance_of::<Function>() {
return Export::Function(VMFunction::new(
val.unchecked_into::<Function>(),
function_type,
None,
));
} else {
panic!("Extern type doesn't match js value type");
}
}
_ => unimplemented!(),
}
// Leave this last
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::exports::{ExportError, Exportable};
use crate::externals::Extern;
use crate::store::Store;
use crate::types::{AsJs /* ValFuncRef */, Val};
use crate::FunctionType;
use crate::{FunctionType, ValType};
use core::any::Any;
use wasm_bindgen::prelude::*;
use wasm_bindgen::{JsCast, __rt::WasmRefCell};
@@ -45,7 +45,6 @@ pub struct VMFunctionBody(u8);
// #[derive(PartialEq)]
pub struct Function {
pub(crate) store: Store,
ty: FunctionType,
pub(crate) exported: VMFunction,
}
@@ -175,8 +174,7 @@ impl Function {
// let environment: Option<Arc>
Self {
store: store.clone(),
ty: ty.into(),
exported: VMFunction::new(func, None),
exported: VMFunction::new(func, ty.into(), None),
}
// Function::new
// let wrapped_func =
@@ -314,8 +312,7 @@ impl Function {
let ty = FunctionType::new(Args::wasm_types(), Rets::wasm_types());
Self {
store: store.clone(),
ty,
exported: VMFunction::new(binded_func, None),
exported: VMFunction::new(binded_func, ty, None),
}
// let vmctx = VMFunctionEnvironment {
@@ -396,8 +393,7 @@ impl Function {
// panic!("Function env {:?}", environment.type_id());
Self {
store: store.clone(),
ty,
exported: VMFunction::new(binded_func, Some(environment)),
exported: VMFunction::new(binded_func, ty, Some(environment)),
}
// let function = inner::Function::<Args, Rets>::new(func);
@@ -443,8 +439,7 @@ impl Function {
/// assert_eq!(f.ty().results(), vec![Type::I32]);
/// ```
pub fn ty(&self) -> &FunctionType {
unimplemented!();
// &self.exported.vm_function.signature
&self.exported.ty
}
/// Returns the [`Store`] where the `Function` belongs.
@@ -599,8 +594,25 @@ impl Function {
}
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([]))
let result_types = self.exported.ty.results();
match result_types.len() {
0 => Ok(Box::new([])),
1 => {
let num_value = result.unwrap().as_f64().unwrap();
let value = match result_types[0] {
ValType::I32 => Val::I32(num_value as _),
ValType::I64 => Val::I64(num_value as _),
ValType::F32 => Val::F32(num_value as _),
ValType::F64 => Val::F64(num_value),
_ => unimplemented!(),
};
Ok(vec![value].into_boxed_slice())
}
_ => unimplemented!(),
}
//
// 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)?;
@@ -613,7 +625,6 @@ impl Function {
pub(crate) fn from_vm_export(store: &Store, wasmer_export: VMFunction) -> Self {
Self {
store: store.clone(),
ty: FunctionType::new(vec![], vec![]),
exported: wasmer_export,
}
}

View File

@@ -49,7 +49,6 @@ extern "C" {
#[derive(Debug, Clone)]
pub struct Memory {
store: Store,
ty: MemoryType,
vm_memory: VMMemory,
}
@@ -75,11 +74,11 @@ impl Memory {
}
js_sys::Reflect::set(&descriptor, &"shared".into(), &ty.shared.into());
let memory = VMMemory::new(&descriptor).unwrap();
// unimplemented!();
let js_memory = js_sys::WebAssembly::Memory::new(&descriptor).unwrap();
let memory = VMMemory::new(js_memory, ty);
Ok(Self {
store: store.clone(),
ty,
vm_memory: memory,
})
}
@@ -98,9 +97,7 @@ impl Memory {
/// assert_eq!(m.ty(), mt);
/// ```
pub fn ty(&self) -> MemoryType {
self.ty.clone()
// unimplemented!();
// self.vm_memory.from.ty()
self.vm_memory.ty.clone()
}
/// Returns the [`Store`] where the `Memory` belongs.
@@ -158,7 +155,7 @@ impl Memory {
/// Returns the size (in bytes) of the `Memory`.
pub fn data_size(&self) -> u64 {
let bytes = js_sys::Reflect::get(&self.vm_memory.buffer(), &"byteLength".into())
let bytes = js_sys::Reflect::get(&self.vm_memory.memory.buffer(), &"byteLength".into())
.unwrap()
.as_f64()
.unwrap() as u64;
@@ -180,7 +177,7 @@ impl Memory {
/// assert_eq!(m.size(), Pages(1));
/// ```
pub fn size(&self) -> Pages {
let bytes = js_sys::Reflect::get(&self.vm_memory.buffer(), &"byteLength".into())
let bytes = js_sys::Reflect::get(&self.vm_memory.memory.buffer(), &"byteLength".into())
.unwrap()
.as_f64()
.unwrap() as u64;
@@ -225,7 +222,7 @@ impl Memory {
let pages = delta.into();
// let new_pages = js_memory_grow(&self.vm_memory.unchecked_into::<JSMemory>(), pages.0).unwrap();
// let new_pages = self.vm_memory.unchecked_ref::<JSMemory>().grow(pages.0);
let new_pages = self.vm_memory.grow(pages.0);
let new_pages = self.vm_memory.memory.grow(pages.0);
Ok(Pages(new_pages))
}
@@ -271,13 +268,12 @@ impl Memory {
/// example view
pub fn uint8view(&self) -> js_sys::Uint8Array {
js_sys::Uint8Array::new(&self.vm_memory.buffer())
js_sys::Uint8Array::new(&self.vm_memory.memory.buffer())
}
pub(crate) fn from_vm_export(store: &Store, vm_memory: VMMemory) -> Self {
Self {
store: store.clone(),
ty: MemoryType::new(Pages(1), None, false),
vm_memory,
}
}

View File

@@ -1,3 +1,4 @@
use crate::export::Export;
use crate::exports::Exports;
use crate::externals::Extern;
use crate::module::Module;
@@ -117,8 +118,10 @@ impl Instance {
.exports()
.map(|export_type| {
let name = export_type.name();
let export = js_sys::Reflect::get(&instance_exports, &name.into()).unwrap();
let extern_ = Extern::from_vm_export(store, export.into());
let extern_type = export_type.ty().clone();
let js_export = js_sys::Reflect::get(&instance_exports, &name.into()).unwrap();
let export: Export = (js_export, extern_type).into();
let extern_ = Extern::from_vm_export(store, export);
(name.to_string(), extern_)
})
.collect::<Exports>();

View File

@@ -313,7 +313,7 @@ pub use crate::externals::{
};
pub use crate::import_object::{ImportObject, ImportObjectIterator, LikeNamespace};
pub use crate::instance::{Instance, InstantiationError};
pub use crate::module::Module;
pub use crate::module::{Module, ModuleTypeHints};
pub use wasm_bindgen::JsValue as RuntimeError;
// pub use crate::native::NativeFunc;
pub use crate::ptr::{Array, Item, WasmPtr};

View File

@@ -30,6 +30,23 @@ pub enum IoCompileError {
Compile(#[from] CompileError),
}
/// WebAssembly in the browser doesn't yet output the descriptor/types
/// corresponding to each extern (import and export).
///
/// This should be fixed once the JS-Types Wasm proposal is adopted
/// by the browsers:
/// https://github.com/WebAssembly/js-types/blob/master/proposals/js-types/Overview.md
///
/// Until that happens, we annotate the module with the expected
/// types so we can built on top of them at runtime.
#[derive(Clone)]
pub struct ModuleTypeHints {
/// The type hints for the imported types
pub imports: Vec<ExternType>,
/// The type hints for the exported types
pub exports: Vec<ExternType>,
}
/// A WebAssembly Module contains stateless WebAssembly
/// code that has already been compiled and can be instantiated
/// multiple times.
@@ -43,6 +60,8 @@ pub struct Module {
store: Store,
module: WebAssembly::Module,
name: Option<String>,
// WebAssembly type hints
type_hints: Option<ModuleTypeHints>,
}
impl Module {
@@ -148,6 +167,7 @@ impl Module {
Ok(Self {
store: store.clone(),
module,
type_hints: None,
name: None,
})
}
@@ -352,6 +372,37 @@ impl Module {
}
}
/// Set the type hints for this module.
///
/// Returns an error if the hints doesn't match the shape of
/// import or export types of the module.
pub fn set_type_hints(&mut self, type_hints: ModuleTypeHints) -> Result<(), String> {
let exports = WebAssembly::Module::exports(&self.module);
// Check exports
if exports.length() as usize != type_hints.exports.len() {
return Err("The exports length must match the type hints lenght".to_owned());
}
for (i, val) in exports.iter().enumerate() {
let kind = Reflect::get(val.as_ref(), &"kind".into())
.unwrap()
.as_string()
.unwrap();
// It is safe to unwrap as we have already checked for the exports length
let type_hint = type_hints.exports.get(i).unwrap();
let expected_kind = match type_hint {
ExternType::Function(_) => "function",
ExternType::Global(_) => "global",
ExternType::Memory(_) => "memory",
ExternType::Table(_) => "table",
};
if expected_kind != kind.as_str() {
return Err(format!("The provided type hint for the export {} is {} which doesn't match the expected kind: {}", i, kind.as_str(), expected_kind));
}
}
self.type_hints = Some(type_hints);
Ok(())
}
// /// Get the custom sections of the module given a `name`.
// pub fn custom_sections<'a>(&'a self, name: &'a str) -> impl Iterator<Item = Arc<[u8]>> + 'a {
// self.custom_sections
@@ -391,7 +442,8 @@ impl Module {
let exports = WebAssembly::Module::exports(&self.module);
let iter = exports
.iter()
.map(move |val| {
.enumerate()
.map(move |(i, val)| {
let field = Reflect::get(val.as_ref(), &"name".into())
.unwrap()
.as_string()
@@ -400,24 +452,33 @@ impl Module {
.unwrap()
.as_string()
.unwrap();
let extern_type = match kind.as_str() {
"function" => {
let func_type = FunctionType::new(vec![], vec![]);
ExternType::Function(func_type)
let type_hint = self
.type_hints
.as_ref()
.map(|hints| hints.exports.get(i).unwrap().clone());
let extern_type = if let Some(hint) = type_hint {
hint
} else {
// The default types
match kind.as_str() {
"function" => {
let func_type = FunctionType::new(vec![], vec![]);
ExternType::Function(func_type)
}
"global" => {
let global_type = GlobalType::new(Type::I32, Mutability::Const);
ExternType::Global(global_type)
}
"memory" => {
let memory_type = MemoryType::new(Pages(1), None, false);
ExternType::Memory(memory_type)
}
"table" => {
let table_type = TableType::new(Type::FuncRef, 1, None);
ExternType::Table(table_type)
}
_ => unimplemented!(),
}
"global" => {
let global_type = GlobalType::new(Type::I32, Mutability::Const);
ExternType::Global(global_type)
}
"memory" => {
let memory_type = MemoryType::new(Pages(1), None, false);
ExternType::Memory(memory_type)
}
"table" => {
let table_type = TableType::new(Type::FuncRef, 1, None);
ExternType::Table(table_type)
}
_ => unimplemented!(),
};
ExportType::new(&field, extern_type)
})
@@ -454,3 +515,472 @@ impl fmt::Debug for Module {
.finish()
}
}
// use anyhow::{bail, Result};
// use std::fmt::Write;
// use wasmparser::*;
// pub fn wasm_types(bytes: &[u8]) -> Result<ModuleTypes> {
// let mut d = ModuleTypes::new(bytes);
// d.parse()?;
// Ok(d.dst)
// }
// struct ModuleTypes<'a> {
// bytes: &'a [u8],
// cur: usize,
// }
// #[derive(Default)]
// struct ModuleTypesIndices {
// funcs: u32,
// globals: u32,
// tables: u32,
// memories: u32,
// }
// const NBYTES: usize = 4;
// impl<'a> ModuleTypes<'a> {
// fn new(bytes: &'a [u8]) -> Dump<'a> {
// Dump {
// bytes,
// cur: 0,
// nesting: 0,
// state: String::new(),
// dst: String::new(),
// }
// }
// fn run(&mut self) -> Result<()> {
// self.print_module()?;
// assert_eq!(self.cur, self.bytes.len());
// Ok(())
// }
// fn print_module(&mut self) -> Result<()> {
// let mut stack = Vec::new();
// let mut i = ModuleTypesIndices::default();
// self.nesting += 1;
// for item in Parser::new(0).parse_all(self.bytes) {
// match item? {
// Payload::Version { num, range } => {
// write!(self.state, "version {}", num)?;
// self.print(range.end)?;
// }
// Payload::TypeSection(s) => self.section(s, "type", |me, end, t| {
// write!(me.state, "[type {}] {:?}", i.types, t)?;
// i.types += 1;
// me.print(end)
// })?,
// Payload::ImportSection(s) => self.section(s, "import", |me, end, imp| {
// write!(me.state, "import ")?;
// match imp.ty {
// ImportSectionEntryType::Function(_) => {
// write!(me.state, "[func {}]", i.funcs)?;
// i.funcs += 1;
// }
// ImportSectionEntryType::Memory(_) => {
// write!(me.state, "[memory {}]", i.memories)?;
// i.memories += 1;
// }
// ImportSectionEntryType::Tag(_) => {
// write!(me.state, "[tag {}]", i.tags)?;
// i.tags += 1;
// }
// ImportSectionEntryType::Table(_) => {
// write!(me.state, "[table {}]", i.tables)?;
// i.tables += 1;
// }
// ImportSectionEntryType::Global(_) => {
// write!(me.state, "[global {}]", i.globals)?;
// i.globals += 1;
// }
// ImportSectionEntryType::Instance(_) => {
// write!(me.state, "[instance {}]", i.instances)?;
// i.instances += 1;
// }
// ImportSectionEntryType::Module(_) => {
// write!(me.state, "[module {}]", i.modules)?;
// i.modules += 1;
// }
// }
// write!(me.state, " {:?}", imp)?;
// me.print(end)
// })?,
// Payload::FunctionSection(s) => {
// let mut cnt = 0;
// self.section(s, "func", |me, end, f| {
// write!(me.state, "[func {}] type {:?}", cnt + i.funcs, f)?;
// cnt += 1;
// me.print(end)
// })?
// }
// Payload::TableSection(s) => self.section(s, "table", |me, end, t| {
// write!(me.state, "[table {}] {:?}", i.tables, t)?;
// i.tables += 1;
// me.print(end)
// })?,
// Payload::MemorySection(s) => self.section(s, "memory", |me, end, m| {
// write!(me.state, "[memory {}] {:?}", i.memories, m)?;
// i.memories += 1;
// me.print(end)
// })?,
// Payload::TagSection(s) => self.section(s, "tag", |me, end, m| {
// write!(me.state, "[tag {}] {:?}", i.tags, m)?;
// i.tags += 1;
// me.print(end)
// })?,
// Payload::ExportSection(s) => self.section(s, "export", |me, end, e| {
// write!(me.state, "export {:?}", e)?;
// me.print(end)
// })?,
// Payload::GlobalSection(s) => self.section(s, "global", |me, _end, g| {
// write!(me.state, "[global {}] {:?}", i.globals, g.ty)?;
// i.globals += 1;
// me.print(g.init_expr.get_binary_reader().original_position())?;
// me.print_ops(g.init_expr.get_operators_reader())
// })?,
// Payload::AliasSection(s) => self.section(s, "alias", |me, end, a| {
// write!(me.state, "[alias] {:?}", a)?;
// match a {
// Alias::InstanceExport { kind, .. } => match kind {
// ExternalKind::Function => i.funcs += 1,
// ExternalKind::Global => i.globals += 1,
// ExternalKind::Module => i.modules += 1,
// ExternalKind::Table => i.tables += 1,
// ExternalKind::Instance => i.instances += 1,
// ExternalKind::Memory => i.memories += 1,
// ExternalKind::Tag => i.tags += 1,
// ExternalKind::Type => i.types += 1,
// },
// Alias::OuterType { .. } => i.types += 1,
// Alias::OuterModule { .. } => i.modules += 1,
// }
// me.print(end)
// })?,
// Payload::InstanceSection(s) => {
// self.section(s, "instance", |me, _end, instance| {
// write!(
// me.state,
// "[instance {}] instantiate module:{}",
// i.instances,
// instance.module()
// )?;
// me.print(instance.original_position())?;
// i.instances += 1;
// me.print_iter(instance.args()?, |me, end, arg| {
// write!(me.state, "[instantiate arg] {:?}", arg)?;
// me.print(end)
// })
// })?
// }
// Payload::StartSection { func, range } => {
// write!(self.state, "start section")?;
// self.print(range.start)?;
// write!(self.state, "start function {}", func)?;
// self.print(range.end)?;
// }
// Payload::DataCountSection { count, range } => {
// write!(self.state, "data count section")?;
// self.print(range.start)?;
// write!(self.state, "data count {}", count)?;
// self.print(range.end)?;
// }
// Payload::ElementSection(s) => self.section(s, "element", |me, _end, i| {
// write!(me.state, "element {:?}", i.ty)?;
// let mut items = i.items.get_items_reader()?;
// match i.kind {
// ElementKind::Passive => {
// write!(me.state, " passive, {} items", items.get_count())?;
// }
// ElementKind::Active {
// table_index,
// init_expr,
// } => {
// write!(me.state, " table[{}]", table_index)?;
// me.print(init_expr.get_binary_reader().original_position())?;
// me.print_ops(init_expr.get_operators_reader())?;
// write!(me.state, "{} items", items.get_count())?;
// }
// ElementKind::Declared => {
// write!(me.state, " declared {} items", items.get_count())?;
// }
// }
// me.print(items.original_position())?;
// for _ in 0..items.get_count() {
// let item = items.read()?;
// write!(me.state, "item {:?}", item)?;
// me.print(items.original_position())?;
// }
// Ok(())
// })?,
// Payload::DataSection(s) => self.section(s, "data", |me, end, i| {
// match i.kind {
// DataKind::Passive => {
// write!(me.state, "data passive")?;
// me.print(end - i.data.len())?;
// }
// DataKind::Active {
// memory_index,
// init_expr,
// } => {
// write!(me.state, "data memory[{}]", memory_index)?;
// me.print(init_expr.get_binary_reader().original_position())?;
// me.print_ops(init_expr.get_operators_reader())?;
// }
// }
// write!(me.dst, "0x{:04x} |", me.cur)?;
// for _ in 0..NBYTES {
// write!(me.dst, "---")?;
// }
// write!(me.dst, "-| ... {} bytes of data\n", i.data.len())?;
// me.cur = end;
// Ok(())
// })?,
// Payload::CodeSectionStart { count, range, size } => {
// write!(self.state, "code section")?;
// self.print(range.start)?;
// write!(self.state, "{} count", count)?;
// self.print(range.end - size as usize)?;
// }
// Payload::CodeSectionEntry(body) => {
// write!(
// self.dst,
// "============== func {} ====================\n",
// i.funcs
// )?;
// i.funcs += 1;
// write!(self.state, "size of function")?;
// self.print(body.get_binary_reader().original_position())?;
// let mut locals = body.get_locals_reader()?;
// write!(self.state, "{} local blocks", locals.get_count())?;
// self.print(locals.original_position())?;
// for _ in 0..locals.get_count() {
// let (amt, ty) = locals.read()?;
// write!(self.state, "{} locals of type {:?}", amt, ty)?;
// self.print(locals.original_position())?;
// }
// self.print_ops(body.get_operators_reader()?)?;
// }
// Payload::ModuleSectionStart { count, range, size } => {
// write!(self.state, "module section")?;
// self.print(range.start)?;
// write!(self.state, "{} count", count)?;
// self.print(range.end - size as usize)?;
// }
// Payload::ModuleSectionEntry { parser: _, range } => {
// write!(self.state, "inline module size")?;
// self.print(range.start)?;
// self.nesting += 1;
// stack.push(i);
// i = Indices::default();
// }
// Payload::CustomSection {
// name,
// data_offset,
// data,
// range,
// } => {
// write!(self.state, "custom section")?;
// self.print(range.start)?;
// write!(self.state, "name: {:?}", name)?;
// self.print(data_offset)?;
// if name == "name" {
// let mut iter = NameSectionReader::new(data, data_offset)?;
// while !iter.eof() {
// self.print_custom_name_section(iter.read()?, iter.original_position())?;
// }
// } else {
// write!(self.dst, "0x{:04x} |", self.cur)?;
// for _ in 0..NBYTES {
// write!(self.dst, "---")?;
// }
// write!(self.dst, "-| ... {} bytes of data\n", data.len())?;
// self.cur += data.len();
// }
// }
// Payload::UnknownSection {
// id,
// range,
// contents,
// } => {
// write!(self.state, "unknown section: {}", id)?;
// self.print(range.start)?;
// write!(self.dst, "0x{:04x} |", self.cur)?;
// for _ in 0..NBYTES {
// write!(self.dst, "---")?;
// }
// write!(self.dst, "-| ... {} bytes of data\n", contents.len())?;
// self.cur += contents.len();
// }
// Payload::End => {
// self.nesting -= 1;
// if self.nesting > 0 {
// i = stack.pop().unwrap();
// }
// }
// }
// }
// Ok(())
// }
// fn print_name_map(&mut self, thing: &str, n: NameMap<'_>) -> Result<()> {
// write!(self.state, "{} names", thing)?;
// self.print(n.original_position())?;
// let mut map = n.get_map()?;
// write!(self.state, "{} count", map.get_count())?;
// self.print(map.original_position())?;
// for _ in 0..map.get_count() {
// write!(self.state, "{:?}", map.read()?)?;
// self.print(map.original_position())?;
// }
// Ok(())
// }
// fn print_indirect_name_map(
// &mut self,
// thing_a: &str,
// thing_b: &str,
// n: IndirectNameMap<'_>,
// ) -> Result<()> {
// write!(self.state, "{} names", thing_b)?;
// self.print(n.original_position())?;
// let mut outer_map = n.get_indirect_map()?;
// write!(self.state, "{} count", outer_map.get_indirect_count())?;
// self.print(outer_map.original_position())?;
// for _ in 0..outer_map.get_indirect_count() {
// let inner = outer_map.read()?;
// write!(
// self.state,
// "{} {} {}s",
// thing_a, inner.indirect_index, thing_b,
// )?;
// self.print(inner.original_position())?;
// let mut map = inner.get_map()?;
// write!(self.state, "{} count", map.get_count())?;
// self.print(map.original_position())?;
// for _ in 0..map.get_count() {
// write!(self.state, "{:?}", map.read()?)?;
// self.print(map.original_position())?;
// }
// }
// Ok(())
// }
// fn print_custom_name_section(&mut self, name: Name<'_>, end: usize) -> Result<()> {
// match name {
// Name::Module(n) => {
// write!(self.state, "module name")?;
// self.print(n.original_position())?;
// write!(self.state, "{:?}", n.get_name()?)?;
// self.print(end)?;
// }
// Name::Function(n) => self.print_name_map("function", n)?,
// Name::Local(n) => self.print_indirect_name_map("function", "local", n)?,
// Name::Label(n) => self.print_indirect_name_map("function", "label", n)?,
// Name::Type(n) => self.print_name_map("type", n)?,
// Name::Table(n) => self.print_name_map("table", n)?,
// Name::Memory(n) => self.print_name_map("memory", n)?,
// Name::Global(n) => self.print_name_map("global", n)?,
// Name::Element(n) => self.print_name_map("element", n)?,
// Name::Data(n) => self.print_name_map("data", n)?,
// Name::Unknown { ty, range, .. } => {
// write!(self.state, "unknown names: {}", ty)?;
// self.print(range.start)?;
// self.print(end)?;
// }
// }
// Ok(())
// }
// fn section<T>(
// &mut self,
// iter: T,
// name: &str,
// print: impl FnMut(&mut Self, usize, T::Item) -> Result<()>,
// ) -> Result<()>
// where
// T: SectionReader + SectionWithLimitedItems,
// {
// write!(self.state, "{} section", name)?;
// self.print(iter.range().start)?;
// self.print_iter(iter, print)
// }
// fn print_iter<T>(
// &mut self,
// mut iter: T,
// mut print: impl FnMut(&mut Self, usize, T::Item) -> Result<()>,
// ) -> Result<()>
// where
// T: SectionReader + SectionWithLimitedItems,
// {
// write!(self.state, "{} count", iter.get_count())?;
// self.print(iter.original_position())?;
// for _ in 0..iter.get_count() {
// let item = iter.read()?;
// print(self, iter.original_position(), item)?;
// }
// if !iter.eof() {
// bail!("too many bytes in section");
// }
// Ok(())
// }
// fn print_ops(&mut self, mut i: OperatorsReader) -> Result<()> {
// while !i.eof() {
// match i.read() {
// Ok(op) => write!(self.state, "{:?}", op)?,
// Err(_) => write!(self.state, "??")?,
// }
// self.print(i.original_position())?;
// }
// Ok(())
// }
// fn print(&mut self, end: usize) -> Result<()> {
// assert!(
// self.cur < end,
// "{:#x} >= {:#x}\ntrying to print: {}\n{}",
// self.cur,
// end,
// self.state,
// self.dst
// );
// let bytes = &self.bytes[self.cur..end];
// for _ in 0..self.nesting - 1 {
// write!(self.dst, " ")?;
// }
// write!(self.dst, "0x{:04x} |", self.cur)?;
// for (i, chunk) in bytes.chunks(NBYTES).enumerate() {
// if i > 0 {
// for _ in 0..self.nesting - 1 {
// write!(self.dst, " ")?;
// }
// self.dst.push_str(" |");
// }
// for j in 0..NBYTES {
// match chunk.get(j) {
// Some(b) => write!(self.dst, " {:02x}", b)?,
// None => write!(self.dst, " ")?,
// }
// }
// if i == 0 {
// self.dst.push_str(" | ");
// self.dst.push_str(&self.state);
// self.state.truncate(0);
// }
// self.dst.push_str("\n");
// }
// self.cur = end;
// Ok(())
// }
// }

View File

@@ -67,7 +67,7 @@ fn test_exported_memory() {
#[wasm_bindgen_test]
fn test_exported_function() {
let store = Store::default();
let module = Module::new(
let mut module = Module::new(
&store,
br#"
(module
@@ -78,6 +78,13 @@ fn test_exported_function() {
"#,
)
.unwrap();
module.set_type_hints(ModuleTypeHints {
imports: vec![],
exports: vec![ExternType::Function(FunctionType::new(
vec![],
vec![Type::I32],
))],
});
let import_object = imports! {};
let instance = Instance::new(&module, &import_object).unwrap();
@@ -87,8 +94,12 @@ fn test_exported_function() {
// assert_eq!(memory.data_size(), 65536);
let get_magic = instance.exports.get_function("get_magic").unwrap();
assert_eq!(
get_magic.ty().clone(),
FunctionType::new(vec![], vec![Type::I32])
);
let expected = vec![Val::F64(42.0)].into_boxed_slice();
let expected = vec![Val::I32(42)].into_boxed_slice();
assert_eq!(get_magic.call(&[]), Ok(expected));
}
@@ -122,7 +133,7 @@ fn test_exported_function() {
#[wasm_bindgen_test]
fn test_imported_function_dynamic() {
let store = Store::default();
let module = Module::new(
let mut module = Module::new(
&store,
br#"
(module
@@ -134,6 +145,16 @@ fn test_imported_function_dynamic() {
"#,
)
.unwrap();
module.set_type_hints(ModuleTypeHints {
imports: vec![ExternType::Function(FunctionType::new(
vec![Type::I32],
vec![Type::I32],
))],
exports: vec![ExternType::Function(FunctionType::new(
vec![Type::I32],
vec![Type::I32],
))],
});
let imported_signature = FunctionType::new(vec![Type::I32], vec![Type::I32]);
let imported = Function::new(&store, &imported_signature, |args| {
@@ -156,14 +177,14 @@ fn test_imported_function_dynamic() {
let exported = instance.exports.get_function("exported").unwrap();
let expected = vec![Val::F64(5.0)].into_boxed_slice();
let expected = vec![Val::I32(5)].into_boxed_slice();
assert_eq!(exported.call(&[Val::I32(4)]), Ok(expected));
}
#[wasm_bindgen_test]
fn test_imported_function_native() {
let store = Store::default();
let module = Module::new(
let mut module = Module::new(
&store,
br#"
(module
@@ -175,6 +196,16 @@ fn test_imported_function_native() {
"#,
)
.unwrap();
module.set_type_hints(ModuleTypeHints {
imports: vec![ExternType::Function(FunctionType::new(
vec![Type::I32],
vec![Type::I32],
))],
exports: vec![ExternType::Function(FunctionType::new(
vec![Type::I32],
vec![Type::I32],
))],
});
fn imported_fn(arg: u32) -> u32 {
return arg + 1;
@@ -195,14 +226,14 @@ fn test_imported_function_native() {
let exported = instance.exports.get_function("exported").unwrap();
let expected = vec![Val::F64(5.0)].into_boxed_slice();
let expected = vec![Val::I32(5)].into_boxed_slice();
assert_eq!(exported.call(&[Val::I32(4)]), Ok(expected));
}
#[wasm_bindgen_test]
fn test_imported_function_native_with_env() {
let store = Store::default();
let module = Module::new(
let mut module = Module::new(
&store,
br#"
(module
@@ -214,6 +245,16 @@ fn test_imported_function_native_with_env() {
"#,
)
.unwrap();
module.set_type_hints(ModuleTypeHints {
imports: vec![ExternType::Function(FunctionType::new(
vec![Type::I32],
vec![Type::I32],
))],
exports: vec![ExternType::Function(FunctionType::new(
vec![Type::I32],
vec![Type::I32],
))],
});
#[derive(WasmerEnv, Clone)]
struct Env {
@@ -239,14 +280,14 @@ fn test_imported_function_native_with_env() {
let exported = instance.exports.get_function("exported").unwrap();
let expected = vec![Val::F64(12.0)].into_boxed_slice();
let expected = vec![Val::I32(12)].into_boxed_slice();
assert_eq!(exported.call(&[Val::I32(4)]), Ok(expected));
}
#[wasm_bindgen_test]
fn test_imported_function_native_with_wasmer_env() {
let store = Store::default();
let module = Module::new(
let mut module = Module::new(
&store,
br#"
(module
@@ -259,6 +300,16 @@ fn test_imported_function_native_with_wasmer_env() {
"#,
)
.unwrap();
module.set_type_hints(ModuleTypeHints {
imports: vec![ExternType::Function(FunctionType::new(
vec![Type::I32],
vec![Type::I32],
))],
exports: vec![
ExternType::Function(FunctionType::new(vec![Type::I32], vec![Type::I32])),
ExternType::Memory(MemoryType::new(Pages(1), None, false)),
],
});
#[derive(WasmerEnv, Clone)]
struct Env {
@@ -301,11 +352,11 @@ fn test_imported_function_native_with_wasmer_env() {
let exported = instance.exports.get_function("exported").unwrap();
/// It with the provided memory
let expected = vec![Val::F64(24.0)].into_boxed_slice();
let expected = vec![Val::I32(24)].into_boxed_slice();
assert_eq!(exported.call(&[Val::I32(4)]), Ok(expected));
/// It works if we update the memory
memory.uint8view().set_index(0, 3);
let expected = vec![Val::F64(36.0)].into_boxed_slice();
let expected = vec![Val::I32(36)].into_boxed_slice();
assert_eq!(exported.call(&[Val::I32(4)]), Ok(expected));
}

View File

@@ -101,11 +101,20 @@ fn exports() {
let store = Store::default();
let wat = r#"(module
(func (export "func") nop)
(memory (export "memory") 1)
(table (export "table") 1 funcref)
(memory (export "memory") 2)
(table (export "table") 2 funcref)
(global (export "global") i32 (i32.const 0))
)"#;
let module = Module::new(&store, wat).unwrap();
let mut module = Module::new(&store, wat).unwrap();
module.set_type_hints(ModuleTypeHints {
exports: vec![
ExternType::Function(FunctionType::new(vec![], vec![])),
ExternType::Memory(MemoryType::new(Pages(2), None, false)),
ExternType::Table(TableType::new(Type::FuncRef, 2, None)),
ExternType::Global(GlobalType::new(Type::I32, Mutability::Const)),
],
imports: vec![],
});
assert_eq!(
module.exports().collect::<Vec<_>>(),
vec![
@@ -115,11 +124,11 @@ fn exports() {
),
ExportType::new(
"memory",
ExternType::Memory(MemoryType::new(Pages(1), None, false))
ExternType::Memory(MemoryType::new(Pages(2), None, false))
),
ExportType::new(
"table",
ExternType::Table(TableType::new(Type::FuncRef, 1, None))
ExternType::Table(TableType::new(Type::FuncRef, 2, None))
),
ExportType::new(
"global",
@@ -137,14 +146,14 @@ fn exports() {
module.exports().memories().collect::<Vec<_>>(),
vec![ExportType::new(
"memory",
MemoryType::new(Pages(1), None, false)
MemoryType::new(Pages(2), None, false)
),]
);
assert_eq!(
module.exports().tables().collect::<Vec<_>>(),
vec![ExportType::new(
"table",
TableType::new(Type::FuncRef, 1, None)
TableType::new(Type::FuncRef, 2, None)
),]
);
assert_eq!(