diff --git a/lib/js-api/src/export.rs b/lib/js-api/src/export.rs index b5744b866..cd7dc5fd0 100644 --- a/lib/js-api/src/export.rs +++ b/lib/js-api/src/export.rs @@ -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>>>, } impl VMFunction { - pub(crate) fn new(function: Function, environment: Option>) -> Self { + pub(crate) fn new( + function: Function, + ty: FunctionType, + environment: Option>, + ) -> 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 for Export { - fn from(val: JsValue) -> Export { - if val.is_instance_of::() { - return Export::Memory(val.unchecked_into::()); +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::() { + return Export::Memory(VMMemory::new( + val.unchecked_into::(), + memory_type, + )); + } else { + panic!("Extern type doesn't match js value type"); + } + } + ExternType::Function(function_type) => { + if val.is_instance_of::() { + return Export::Function(VMFunction::new( + val.unchecked_into::(), + function_type, + None, + )); + } else { + panic!("Extern type doesn't match js value type"); + } + } + _ => unimplemented!(), } - // Leave this last - else if val.is_instance_of::() { - return Export::Function(VMFunction::new(val.unchecked_into::(), None)); - } - unimplemented!(); } } diff --git a/lib/js-api/src/externals/function.rs b/lib/js-api/src/externals/function.rs index b8f683422..bdad35189 100644 --- a/lib/js-api/src/externals/function.rs +++ b/lib/js-api/src/externals/function.rs @@ -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 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::::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, } } diff --git a/lib/js-api/src/externals/memory.rs b/lib/js-api/src/externals/memory.rs index 5c4386fc5..caae08d64 100644 --- a/lib/js-api/src/externals/memory.rs +++ b/lib/js-api/src/externals/memory.rs @@ -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::(), pages.0).unwrap(); // let new_pages = self.vm_memory.unchecked_ref::().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, } } diff --git a/lib/js-api/src/instance.rs b/lib/js-api/src/instance.rs index 39021047c..155d527e7 100644 --- a/lib/js-api/src/instance.rs +++ b/lib/js-api/src/instance.rs @@ -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::(); diff --git a/lib/js-api/src/lib.rs b/lib/js-api/src/lib.rs index b5beec1ea..217a4a6ca 100644 --- a/lib/js-api/src/lib.rs +++ b/lib/js-api/src/lib.rs @@ -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}; diff --git a/lib/js-api/src/module.rs b/lib/js-api/src/module.rs index 24e838ce8..8be6bc6c9 100644 --- a/lib/js-api/src/module.rs +++ b/lib/js-api/src/module.rs @@ -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, + /// The type hints for the exported types + pub exports: Vec, +} + /// 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, + // WebAssembly type hints + type_hints: Option, } 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> + '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 { +// 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( +// &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( +// &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(()) +// } +// } diff --git a/lib/js-api/tests/instance.rs b/lib/js-api/tests/instance.rs index 42a1e596d..087b9e097 100644 --- a/lib/js-api/tests/instance.rs +++ b/lib/js-api/tests/instance.rs @@ -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)); } diff --git a/lib/js-api/tests/module.rs b/lib/js-api/tests/module.rs index 80603e1da..2f02a533e 100644 --- a/lib/js-api/tests/module.rs +++ b/lib/js-api/tests/module.rs @@ -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![ @@ -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![ExportType::new( "memory", - MemoryType::new(Pages(1), None, false) + MemoryType::new(Pages(2), None, false) ),] ); assert_eq!( module.exports().tables().collect::>(), vec![ExportType::new( "table", - TableType::new(Type::FuncRef, 1, None) + TableType::new(Type::FuncRef, 2, None) ),] ); assert_eq!(