From 1912373e1f5916c29adfb604b7dabf8b69c858e8 Mon Sep 17 00:00:00 2001 From: ptitSeb Date: Fri, 26 Aug 2022 10:46:56 +0200 Subject: [PATCH 1/5] The API breaking changes from future WASIX/Network/Threading addition --- Cargo.lock | 1 + docs/migration_to_3.0.0.md | 5 +- lib/api/Cargo.toml | 1 + lib/api/src/js/module.rs | 81 ++++++++++++++++++++++++------ lib/api/src/js/ptr.rs | 2 +- lib/api/src/lib.rs | 2 +- lib/api/src/sys/function_env.rs | 7 ++- lib/api/src/sys/module.rs | 86 +++++++++++++++++++++++++------- lib/api/src/sys/ptr.rs | 2 +- lib/cli/src/commands/inspect.rs | 15 ++---- lib/cli/src/commands/run.rs | 4 +- lib/cli/src/commands/validate.rs | 2 +- lib/wasi/src/lib.rs | 33 +++++++++++- tests/compilers/imports.rs | 6 +-- tests/compilers/traps.rs | 10 ++-- tests/lib/wast/src/wasi_wast.rs | 2 +- 16 files changed, 197 insertions(+), 62 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 69a3e6b50cc..8867bdf3879 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2923,6 +2923,7 @@ name = "wasmer" version = "3.0.0-beta" dependencies = [ "anyhow", + "bytes", "cfg-if 1.0.0", "hashbrown 0.11.2", "indexmap", diff --git a/docs/migration_to_3.0.0.md b/docs/migration_to_3.0.0.md index c115578cd5c..02a613c6732 100644 --- a/docs/migration_to_3.0.0.md +++ b/docs/migration_to_3.0.0.md @@ -195,14 +195,13 @@ import_object.define("env", "host_function", host_function); let instance = Instance::new(&mut store, &module, &import_object).expect("Could not instantiate module."); ``` -For WASI, don't forget to import memory to `WasiEnv` +For WASI, don't forget to initialize the `WasiEnv` (it will import the memory) ```rust let mut wasi_env = WasiState::new("hello").finalize()?; let import_object = wasi_env.import_object(&mut store, &module)?; let instance = Instance::new(&mut store, &module, &import_object).expect("Could not instantiate module."); -let memory = instance.exports.get_memory("memory")?; -wasi_env.data_mut(&mut store).set_memory(memory.clone()); +wasi_env.initialize(&mut store, &instance).unwrap(); ``` #### `ChainableNamedResolver` is removed diff --git a/lib/api/Cargo.toml b/lib/api/Cargo.toml index 36a6fb7eaa3..9bcb2c9b0a1 100644 --- a/lib/api/Cargo.toml +++ b/lib/api/Cargo.toml @@ -26,6 +26,7 @@ indexmap = { version = "1.6" } cfg-if = "1.0" thiserror = "1.0" more-asserts = "0.2" +bytes = "1" # - Optional shared dependencies. wat = { version = "1.0", optional = true } tracing = { version = "0.1", optional = true } diff --git a/lib/api/src/js/module.rs b/lib/api/src/js/module.rs index 975d1bee5d5..7a614ee7506 100644 --- a/lib/api/src/js/module.rs +++ b/lib/api/src/js/module.rs @@ -9,7 +9,9 @@ use crate::js::store::{AsStoreMut, StoreHandle}; use crate::js::types::{AsJs, ExportType, ImportType}; use crate::js::RuntimeError; use crate::AsStoreRef; +use bytes::Bytes; use js_sys::{Reflect, Uint8Array, WebAssembly}; +use std::borrow::Cow; use std::fmt; use std::io; use std::path::Path; @@ -49,6 +51,46 @@ pub struct ModuleTypeHints { pub exports: Vec, } +pub trait IntoBytes { + fn into_bytes(self) -> Bytes; +} + +impl IntoBytes for Bytes { + fn into_bytes(self) -> Bytes { + self + } +} + +impl IntoBytes for Vec { + fn into_bytes(self) -> Bytes { + Bytes::from(self) + } +} + +impl IntoBytes for &[u8] { + fn into_bytes(self) -> Bytes { + Bytes::from(self.to_vec()) + } +} + +impl IntoBytes for &[u8; N] { + fn into_bytes(self) -> Bytes { + Bytes::from(self.to_vec()) + } +} + +impl IntoBytes for &str { + fn into_bytes(self) -> Bytes { + Bytes::from(self.as_bytes().to_vec()) + } +} + +impl IntoBytes for Cow<'_, [u8]> { + fn into_bytes(self) -> Bytes { + Bytes::from(self.to_vec()) + } +} + /// A WebAssembly Module contains stateless WebAssembly /// code that has already been compiled and can be instantiated /// multiple times. @@ -128,15 +170,19 @@ impl Module { /// # } /// ``` #[allow(unreachable_code)] - pub fn new(_store: &impl AsStoreRef, bytes: impl AsRef<[u8]>) -> Result { + pub fn new(_store: &impl AsStoreRef, bytes: impl IntoBytes) -> Result { + let mut bytes = bytes.into_bytes(); #[cfg(feature = "wat")] - let bytes = wat::parse_bytes(bytes.as_ref()).map_err(|e| { - CompileError::Wasm(WasmError::Generic(format!( - "Error when converting wat: {}", - e - ))) - })?; - Self::from_binary(_store, bytes.as_ref()) + if bytes.starts_with(b"\0asm") == false { + let parsed_bytes = wat::parse_bytes(bytes.as_ref()).map_err(|e| { + CompileError::Wasm(WasmError::Generic(format!( + "Error when converting wat: {}", + e + ))) + })?; + bytes = Bytes::from(parsed_bytes.to_vec()); + } + Self::from_binary(_store, bytes) } /// Creates a new WebAssembly module from a file path. @@ -152,7 +198,11 @@ impl Module { /// Opposed to [`Module::new`], this function is not compatible with /// the WebAssembly text format (if the "wat" feature is enabled for /// this crate). - pub fn from_binary(_store: &impl AsStoreRef, binary: &[u8]) -> Result { + pub fn from_binary( + _store: &impl AsStoreRef, + binary: impl IntoBytes, + ) -> Result { + let binary = binary.into_bytes(); // // Self::validate(store, binary)?; unsafe { Self::from_binary_unchecked(_store, binary) } @@ -166,9 +216,10 @@ impl Module { /// We maintain the `unsafe` to preserve the same API as Wasmer pub unsafe fn from_binary_unchecked( _store: &impl AsStoreRef, - binary: &[u8], + binary: impl IntoBytes, ) -> Result { - let js_bytes = Uint8Array::view(binary); + let binary = binary.into_bytes(); + let js_bytes = Uint8Array::view(&binary[..]); let module = WebAssembly::Module::new(&js_bytes.into()).unwrap(); // The module is now validated, so we can safely parse it's types @@ -210,8 +261,9 @@ impl Module { /// This validation is normally pretty fast and checks the enabled /// WebAssembly features in the Store Engine to assure deterministic /// validation of the Module. - pub fn validate(_store: &impl AsStoreRef, binary: &[u8]) -> Result<(), CompileError> { - let js_bytes = unsafe { Uint8Array::view(binary) }; + pub fn validate(_store: &impl AsStoreRef, binary: impl IntoBytes) -> Result<(), CompileError> { + let binary = binary.into_bytes(); + let js_bytes = unsafe { Uint8Array::view(&binary[..]) }; match WebAssembly::validate(&js_bytes.into()) { Ok(true) => Ok(()), _ => Err(CompileError::Validate("Invalid Wasm file".to_owned())), @@ -313,8 +365,9 @@ impl Module { #[cfg(feature = "js-serializable-module")] pub unsafe fn deserialize( _store: &impl AsStoreRef, - bytes: &[u8], + bytes: impl IntoBytes, ) -> Result { + let bytes = bytes.into_bytes(); Self::new(_store, bytes).map_err(|e| DeserializeError::Compiler(e)) } diff --git a/lib/api/src/js/ptr.rs b/lib/api/src/js/ptr.rs index b7b812c434a..cdcb19f1f22 100644 --- a/lib/api/src/js/ptr.rs +++ b/lib/api/src/js/ptr.rs @@ -71,7 +71,7 @@ impl WasmPtr { /// Get the offset into Wasm linear memory for this `WasmPtr`. #[inline] - pub fn offset(self) -> M::Offset { + pub fn offset(&self) -> M::Offset { self.offset } diff --git a/lib/api/src/lib.rs b/lib/api/src/lib.rs index 663903104ba..ccb647175b9 100644 --- a/lib/api/src/lib.rs +++ b/lib/api/src/lib.rs @@ -55,7 +55,7 @@ //! "#; //! //! let mut store = Store::default(); -//! let module = Module::new(&store, &module_wat)?; +//! let module = Module::new(&store, module_wat)?; //! // The module doesn't import anything, so we create an empty import object. //! let import_object = imports! {}; //! let instance = Instance::new(&mut store, &module, &import_object)?; diff --git a/lib/api/src/sys/function_env.rs b/lib/api/src/sys/function_env.rs index deb5c0b4304..6ef7b48a3c9 100644 --- a/lib/api/src/sys/function_env.rs +++ b/lib/api/src/sys/function_env.rs @@ -29,7 +29,7 @@ impl FunctionEnv { } /// Get the data as reference - pub fn as_ref<'a>(&self, store: &'a impl AsStoreMut) -> &'a T + pub fn as_ref<'a>(&self, store: &'a impl AsStoreRef) -> &'a T where T: Any + Send + 'static + Sized, { @@ -105,6 +105,11 @@ impl FunctionEnvMut<'_, T> { self.func_env.as_mut(&mut self.store_mut) } + /// Borrows a new immmutable reference + pub fn as_ref(&self) -> FunctionEnv { + self.func_env.clone() + } + /// Borrows a new mutable reference pub fn as_mut(&mut self) -> FunctionEnvMut<'_, T> { FunctionEnvMut { diff --git a/lib/api/src/sys/module.rs b/lib/api/src/sys/module.rs index b730a19b9dd..72f1b414a9e 100644 --- a/lib/api/src/sys/module.rs +++ b/lib/api/src/sys/module.rs @@ -1,6 +1,8 @@ use crate::sys::InstantiationError; use crate::AsStoreMut; use crate::AsStoreRef; +use bytes::Bytes; +use std::borrow::Cow; use std::fmt; use std::io; use std::path::Path; @@ -54,6 +56,46 @@ pub struct Module { module_info: Arc, } +pub trait IntoBytes { + fn into_bytes(self) -> Bytes; +} + +impl IntoBytes for Bytes { + fn into_bytes(self) -> Bytes { + self + } +} + +impl IntoBytes for Vec { + fn into_bytes(self) -> Bytes { + Bytes::from(self) + } +} + +impl IntoBytes for &[u8] { + fn into_bytes(self) -> Bytes { + Bytes::from(self.to_vec()) + } +} + +impl IntoBytes for &[u8; N] { + fn into_bytes(self) -> Bytes { + Bytes::from(self.to_vec()) + } +} + +impl IntoBytes for &str { + fn into_bytes(self) -> Bytes { + Bytes::from(self.as_bytes().to_vec()) + } +} + +impl IntoBytes for Cow<'_, [u8]> { + fn into_bytes(self) -> Bytes { + Bytes::from(self.to_vec()) + } +} + impl Module { #[cfg(feature = "compiler")] /// Creates a new WebAssembly Module given the configuration @@ -116,16 +158,19 @@ impl Module { /// # } /// ``` #[allow(unreachable_code)] - pub fn new(store: &impl AsStoreRef, bytes: impl AsRef<[u8]>) -> Result { + pub fn new(store: &impl AsStoreRef, bytes: impl IntoBytes) -> Result { + let mut bytes = bytes.into_bytes(); #[cfg(feature = "wat")] - let bytes = wat::parse_bytes(bytes.as_ref()).map_err(|e| { - CompileError::Wasm(WasmError::Generic(format!( - "Error when converting wat: {}", - e - ))) - })?; - - Self::from_binary(store, bytes.as_ref()) + if !bytes.starts_with(b"\0asm") { + let parsed_bytes = wat::parse_bytes(&bytes[..]).map_err(|e| { + CompileError::Wasm(WasmError::Generic(format!( + "Error when converting wat: {}", + e + ))) + })?; + bytes = Bytes::from(parsed_bytes.to_vec()); + } + Self::from_binary(store, bytes) } #[cfg(feature = "compiler")] @@ -137,7 +182,7 @@ impl Module { let file_ref = file.as_ref(); let canonical = file_ref.canonicalize()?; let wasm_bytes = std::fs::read(file_ref)?; - let mut module = Self::new(store, &wasm_bytes)?; + let mut module = Self::new(store, wasm_bytes)?; // Set the module name to the absolute path of the filename. // This is useful for debugging the stack traces. let filename = canonical.as_path().to_str().unwrap(); @@ -151,8 +196,12 @@ impl Module { /// Opposed to [`Module::new`], this function is not compatible with /// the WebAssembly text format (if the "wat" feature is enabled for /// this crate). - pub fn from_binary(store: &impl AsStoreRef, binary: &[u8]) -> Result { - Self::validate(store, binary)?; + pub fn from_binary( + store: &impl AsStoreRef, + binary: impl IntoBytes, + ) -> Result { + let binary = binary.into_bytes(); + Self::validate(store, binary.clone())?; unsafe { Self::from_binary_unchecked(store, binary) } } @@ -166,8 +215,9 @@ impl Module { /// beforehand. pub unsafe fn from_binary_unchecked( store: &impl AsStoreRef, - binary: &[u8], + binary: impl IntoBytes, ) -> Result { + let binary = binary.into_bytes(); let module = Self::compile(store, binary)?; Ok(module) } @@ -179,16 +229,18 @@ impl Module { /// This validation is normally pretty fast and checks the enabled /// WebAssembly features in the Store Engine to assure deterministic /// validation of the Module. - pub fn validate(store: &impl AsStoreRef, binary: &[u8]) -> Result<(), CompileError> { - store.as_store_ref().engine().validate(binary) + pub fn validate(store: &impl AsStoreRef, binary: impl IntoBytes) -> Result<(), CompileError> { + let binary = binary.into_bytes(); + store.as_store_ref().engine().validate(&binary[..]) } #[cfg(feature = "compiler")] - fn compile(store: &impl AsStoreRef, binary: &[u8]) -> Result { + fn compile(store: &impl AsStoreRef, binary: impl IntoBytes) -> Result { + let binary = binary.into_bytes(); let artifact = store .as_store_ref() .engine() - .compile(binary, store.as_store_ref().tunables())?; + .compile(&binary[..], store.as_store_ref().tunables())?; Ok(Self::from_artifact(artifact)) } diff --git a/lib/api/src/sys/ptr.rs b/lib/api/src/sys/ptr.rs index f14383946d1..1f51c203094 100644 --- a/lib/api/src/sys/ptr.rs +++ b/lib/api/src/sys/ptr.rs @@ -76,7 +76,7 @@ impl WasmPtr { /// Get the offset into Wasm linear memory for this `WasmPtr`. #[inline] - pub fn offset(self) -> M::Offset { + pub fn offset(&self) -> M::Offset { self.offset } diff --git a/lib/cli/src/commands/inspect.rs b/lib/cli/src/commands/inspect.rs index b21b96bbb1a..4d56faa6136 100644 --- a/lib/cli/src/commands/inspect.rs +++ b/lib/cli/src/commands/inspect.rs @@ -25,16 +25,11 @@ impl Inspect { fn inner_execute(&self) -> Result<()> { let (store, _compiler_type) = self.store.get_store()?; let module_contents = std::fs::read(&self.path)?; - let module = Module::new(&store, &module_contents)?; - println!( - "Type: {}", - if !is_wasm(&module_contents) { - "wat" - } else { - "wasm" - } - ); - println!("Size: {}", ByteSize(module_contents.len() as _)); + let iswasm = is_wasm(&module_contents); + let module_len = module_contents.len(); + let module = Module::new(&store, module_contents)?; + println!("Type: {}", if !iswasm { "wat" } else { "wasm" }); + println!("Size: {}", ByteSize(module_len as _)); println!("Imports:"); println!(" Functions:"); for f in module.imports().functions() { diff --git a/lib/cli/src/commands/run.rs b/lib/cli/src/commands/run.rs index 4c742306e00..c6e0fde6ee8 100644 --- a/lib/cli/src/commands/run.rs +++ b/lib/cli/src/commands/run.rs @@ -272,7 +272,7 @@ impl Run { let module_result: Result = if !self.disable_cache && contents.len() > 0x1000 { self.get_module_from_cache(&store, &contents, &compiler_type) } else { - Module::new(&store, &contents).map_err(|e| e.into()) + Module::new(&store, contents).map_err(|e| e.into()) }; #[cfg(not(feature = "cache"))] let module_result = Module::new(&store, &contents); @@ -319,7 +319,7 @@ impl Run { warning!("cached module is corrupted: {}", err); } } - let module = Module::new(store, &contents)?; + let module = Module::new(store, contents)?; // Store the compiled Module in cache cache.store(hash, &module)?; Ok(module) diff --git a/lib/cli/src/commands/validate.rs b/lib/cli/src/commands/validate.rs index 4f620ecc3d2..2e1aa59ec37 100644 --- a/lib/cli/src/commands/validate.rs +++ b/lib/cli/src/commands/validate.rs @@ -27,7 +27,7 @@ impl Validate { if !is_wasm(&module_contents) { bail!("`wasmer validate` only validates WebAssembly files"); } - Module::validate(&store, &module_contents)?; + Module::validate(&store, module_contents)?; eprintln!("Validation passed for `{}`.", self.path.display()); Ok(()) } diff --git a/lib/wasi/src/lib.rs b/lib/wasi/src/lib.rs index 4daeb25a47d..2ad3b767d51 100644 --- a/lib/wasi/src/lib.rs +++ b/lib/wasi/src/lib.rs @@ -62,9 +62,11 @@ use wasmer_wasi_types::__WASI_CLOCK_MONOTONIC; use derivative::*; use std::ops::Deref; use thiserror::Error; +use tracing::trace; use wasmer::{ - imports, namespace, AsStoreMut, AsStoreRef, Exports, Function, FunctionEnv, Imports, Memory, - Memory32, MemoryAccessError, MemorySize, MemoryView, Module, TypedFunction, + imports, namespace, AsStoreMut, AsStoreRef, ExportError, Exports, Function, FunctionEnv, + Imports, Instance, Memory, Memory32, MemoryAccessError, MemorySize, MemoryView, Module, + TypedFunction, }; pub use runtime::{ @@ -166,6 +168,33 @@ impl WasiFunctionEnv { self.env.as_mut(store) } + /// Initializes the WasiEnv using the instance exports + /// (this must be executed before attempting to use it) + /// (as the stores can not by themselves be passed between threads we can store the module + /// in a thread-local variables and use it later - for multithreading) + pub fn initialize( + &mut self, + store: &mut impl AsStoreMut, + instance: &Instance, + ) -> Result<(), ExportError> { + // List all the exports and imports + for ns in instance.module().exports() { + //trace!("module::export - {} ({:?})", ns.name(), ns.ty()); + trace!("module::export - {}", ns.name()); + } + for ns in instance.module().imports() { + trace!("module::import - {}::{}", ns.module(), ns.name()); + } + + // First we get the malloc function which if it exists will be used to + // create the pthread_self structure + let memory = instance.exports.get_memory("memory")?.clone(); + let env = self.data_mut(store); + env.set_memory(memory); + + Ok(()) + } + /// Like `import_object` but containing all the WASI versions detected in /// the module. pub fn import_object_for_all_wasi_versions( diff --git a/tests/compilers/imports.rs b/tests/compilers/imports.rs index 60d452ac62f..a14273dd4ff 100644 --- a/tests/compilers/imports.rs +++ b/tests/compilers/imports.rs @@ -40,7 +40,7 @@ fn get_module(store: &Store) -> Result { (start $foo) "#; - let module = Module::new(store, &wat)?; + let module = Module::new(store, wat)?; Ok(module) } @@ -339,7 +339,7 @@ fn static_function_that_fails(config: crate::Config) -> Result<()> { (start $foo) "#; - let module = Module::new(&store, &wat)?; + let module = Module::new(&store, wat)?; let f0 = Function::new_typed(&mut store, || -> Result { Err(RuntimeError::new("oops")) }); @@ -375,7 +375,7 @@ fn get_module2(store: &Store) -> Result { (call 0)) "#; - let module = Module::new(store, &wat)?; + let module = Module::new(store, wat)?; Ok(module) } diff --git a/tests/compilers/traps.rs b/tests/compilers/traps.rs index 5c0e6a20d08..6bf18c27f83 100644 --- a/tests/compilers/traps.rs +++ b/tests/compilers/traps.rs @@ -262,7 +262,7 @@ fn trap_start_function_import(config: crate::Config) -> Result<()> { ) "#; - let module = Module::new(&store, &binary)?; + let module = Module::new(&store, binary)?; let sig = FunctionType::new(vec![], vec![]); let func = Function::new(&mut store, &sig, |_| Err(RuntimeError::new("user trap"))); let err = Instance::new( @@ -302,7 +302,7 @@ fn rust_panic_import(config: crate::Config) -> Result<()> { ) "#; - let module = Module::new(&store, &binary)?; + let module = Module::new(&store, binary)?; let sig = FunctionType::new(vec![], vec![]); let func = Function::new(&mut store, &sig, |_| panic!("this is a panic")); let f0 = Function::new_typed(&mut store, || panic!("this is another panic")); @@ -347,7 +347,7 @@ fn rust_panic_start_function(config: crate::Config) -> Result<()> { ) "#; - let module = Module::new(&store, &binary)?; + let module = Module::new(&store, binary)?; let sig = FunctionType::new(vec![], vec![]); let func = Function::new(&mut store, &sig, |_| panic!("this is a panic")); let err = panic::catch_unwind(AssertUnwindSafe(|| { @@ -393,7 +393,7 @@ fn mismatched_arguments(config: crate::Config) -> Result<()> { ) "#; - let module = Module::new(&store, &binary)?; + let module = Module::new(&store, binary)?; let instance = Instance::new(&mut store, &module, &imports! {})?; let func: &Function = instance.exports.get("foo")?; assert_eq!( @@ -432,7 +432,7 @@ fn call_signature_mismatch(config: crate::Config) -> Result<()> { ) "#; - let module = Module::new(&store, &binary)?; + let module = Module::new(&store, binary)?; let err = Instance::new(&mut store, &module, &imports! {}) .err() .expect("expected error"); diff --git a/tests/lib/wast/src/wasi_wast.rs b/tests/lib/wast/src/wasi_wast.rs index 6b2e13aac4c..beb11456c73 100644 --- a/tests/lib/wast/src/wasi_wast.rs +++ b/tests/lib/wast/src/wasi_wast.rs @@ -82,7 +82,7 @@ impl<'a> WasiTest<'a> { wasm_module.read_to_end(&mut out)?; out }; - let module = Module::new(store, &wasm_bytes)?; + let module = Module::new(store, wasm_bytes)?; let (env, _tempdirs, stdout_rx, stderr_rx) = self.create_wasi_env(store, filesystem_kind)?; let imports = self.get_imports(store, &env.env, &module)?; From 436bec735bc532f608a49fdf2e32b5d69b7b15dd Mon Sep 17 00:00:00 2001 From: ptitSeb Date: Thu, 1 Sep 2022 13:52:53 +0200 Subject: [PATCH 2/5] Using IntoBytes only for Module::deserialise (both sys and js) --- lib/api/src/js/module.rs | 31 ++++++++-------------- lib/api/src/sys/module.rs | 45 +++++++++++++------------------- lib/cli/src/commands/validate.rs | 2 +- tests/compilers/serialize.rs | 2 +- 4 files changed, 31 insertions(+), 49 deletions(-) diff --git a/lib/api/src/js/module.rs b/lib/api/src/js/module.rs index 48fa0b80ffd..27f9d66867e 100644 --- a/lib/api/src/js/module.rs +++ b/lib/api/src/js/module.rs @@ -169,19 +169,15 @@ impl Module { /// # } /// ``` #[allow(unreachable_code)] - pub fn new(_store: &impl AsStoreRef, bytes: impl IntoBytes) -> Result { - let mut bytes = bytes.into_bytes(); + pub fn new(_store: &impl AsStoreRef, bytes: impl AsRef<[u8]>) -> Result { #[cfg(feature = "wat")] - if bytes.starts_with(b"\0asm") == false { - let parsed_bytes = wat::parse_bytes(bytes.as_ref()).map_err(|e| { - CompileError::Wasm(WasmError::Generic(format!( - "Error when converting wat: {}", - e - ))) - })?; - bytes = Bytes::from(parsed_bytes.to_vec()); - } - Self::from_binary(_store, bytes) + let bytes = wat::parse_bytes(bytes.as_ref()).map_err(|e| { + CompileError::Wasm(WasmError::Generic(format!( + "Error when converting wat: {}", + e + ))) + })?; + Self::from_binary(_store, bytes.as_ref()) } /// Creates a new WebAssembly module from a file path. @@ -197,11 +193,7 @@ impl Module { /// Opposed to [`Module::new`], this function is not compatible with /// the WebAssembly text format (if the "wat" feature is enabled for /// this crate). - pub fn from_binary( - _store: &impl AsStoreRef, - binary: impl IntoBytes, - ) -> Result { - let binary = binary.into_bytes(); + pub fn from_binary(_store: &impl AsStoreRef, binary: &[u8]) -> Result { // // Self::validate(store, binary)?; unsafe { Self::from_binary_unchecked(_store, binary) } @@ -215,9 +207,8 @@ impl Module { /// We maintain the `unsafe` to preserve the same API as Wasmer pub unsafe fn from_binary_unchecked( _store: &impl AsStoreRef, - binary: impl IntoBytes, + binary: &[u8], ) -> Result { - let binary = binary.into_bytes(); let js_bytes = Uint8Array::view(&binary[..]); let module = WebAssembly::Module::new(&js_bytes.into()).unwrap(); @@ -260,7 +251,7 @@ impl Module { /// This validation is normally pretty fast and checks the enabled /// WebAssembly features in the Store Engine to assure deterministic /// validation of the Module. - pub fn validate(_store: &impl AsStoreRef, binary: impl IntoBytes) -> Result<(), CompileError> { + pub fn validate(_store: &impl AsStoreRef, binary: &[u8]) -> Result<(), CompileError> { let binary = binary.into_bytes(); let js_bytes = unsafe { Uint8Array::view(&binary[..]) }; match WebAssembly::validate(&js_bytes.into()) { diff --git a/lib/api/src/sys/module.rs b/lib/api/src/sys/module.rs index 72f1b414a9e..bc4257ab08c 100644 --- a/lib/api/src/sys/module.rs +++ b/lib/api/src/sys/module.rs @@ -158,19 +158,15 @@ impl Module { /// # } /// ``` #[allow(unreachable_code)] - pub fn new(store: &impl AsStoreRef, bytes: impl IntoBytes) -> Result { - let mut bytes = bytes.into_bytes(); + pub fn new(store: &impl AsStoreRef, bytes: impl AsRef<[u8]>) -> Result { #[cfg(feature = "wat")] - if !bytes.starts_with(b"\0asm") { - let parsed_bytes = wat::parse_bytes(&bytes[..]).map_err(|e| { - CompileError::Wasm(WasmError::Generic(format!( - "Error when converting wat: {}", - e - ))) - })?; - bytes = Bytes::from(parsed_bytes.to_vec()); - } - Self::from_binary(store, bytes) + let bytes = wat::parse_bytes(bytes.as_ref()).map_err(|e| { + CompileError::Wasm(WasmError::Generic(format!( + "Error when converting wat: {}", + e + ))) + })?; + Self::from_binary(store, bytes.as_ref()) } #[cfg(feature = "compiler")] @@ -182,7 +178,7 @@ impl Module { let file_ref = file.as_ref(); let canonical = file_ref.canonicalize()?; let wasm_bytes = std::fs::read(file_ref)?; - let mut module = Self::new(store, wasm_bytes)?; + let mut module = Self::new(store, &wasm_bytes)?; // Set the module name to the absolute path of the filename. // This is useful for debugging the stack traces. let filename = canonical.as_path().to_str().unwrap(); @@ -196,12 +192,8 @@ impl Module { /// Opposed to [`Module::new`], this function is not compatible with /// the WebAssembly text format (if the "wat" feature is enabled for /// this crate). - pub fn from_binary( - store: &impl AsStoreRef, - binary: impl IntoBytes, - ) -> Result { - let binary = binary.into_bytes(); - Self::validate(store, binary.clone())?; + pub fn from_binary(store: &impl AsStoreRef, binary: &[u8]) -> Result { + Self::validate(store, binary)?; unsafe { Self::from_binary_unchecked(store, binary) } } @@ -215,9 +207,8 @@ impl Module { /// beforehand. pub unsafe fn from_binary_unchecked( store: &impl AsStoreRef, - binary: impl IntoBytes, + binary: &[u8], ) -> Result { - let binary = binary.into_bytes(); let module = Self::compile(store, binary)?; Ok(module) } @@ -229,13 +220,12 @@ impl Module { /// This validation is normally pretty fast and checks the enabled /// WebAssembly features in the Store Engine to assure deterministic /// validation of the Module. - pub fn validate(store: &impl AsStoreRef, binary: impl IntoBytes) -> Result<(), CompileError> { - let binary = binary.into_bytes(); - store.as_store_ref().engine().validate(&binary[..]) + pub fn validate(store: &impl AsStoreRef, binary: &[u8]) -> Result<(), CompileError> { + store.as_store_ref().engine().validate(binary) } #[cfg(feature = "compiler")] - fn compile(store: &impl AsStoreRef, binary: impl IntoBytes) -> Result { + fn compile(store: &impl AsStoreRef, binary: &[u8]) -> Result { let binary = binary.into_bytes(); let artifact = store .as_store_ref() @@ -306,9 +296,10 @@ impl Module { /// ``` pub unsafe fn deserialize( store: &impl AsStoreRef, - bytes: &[u8], + bytes: impl IntoBytes, ) -> Result { - let artifact = store.as_store_ref().engine().deserialize(bytes)?; + let bytes = bytes.into_bytes(); + let artifact = store.as_store_ref().engine().deserialize(&bytes)?; Ok(Self::from_artifact(artifact)) } diff --git a/lib/cli/src/commands/validate.rs b/lib/cli/src/commands/validate.rs index 2e1aa59ec37..4f620ecc3d2 100644 --- a/lib/cli/src/commands/validate.rs +++ b/lib/cli/src/commands/validate.rs @@ -27,7 +27,7 @@ impl Validate { if !is_wasm(&module_contents) { bail!("`wasmer validate` only validates WebAssembly files"); } - Module::validate(&store, module_contents)?; + Module::validate(&store, &module_contents)?; eprintln!("Validation passed for `{}`.", self.path.display()); Ok(()) } diff --git a/tests/compilers/serialize.rs b/tests/compilers/serialize.rs index 4bca9000fb9..48997f0e484 100644 --- a/tests/compilers/serialize.rs +++ b/tests/compilers/serialize.rs @@ -45,7 +45,7 @@ fn test_deserialize(config: crate::Config) -> Result<()> { let serialized_bytes = module.serialize()?; let headless_store = config.headless_store(); - let deserialized_module = unsafe { Module::deserialize(&headless_store, &serialized_bytes)? }; + let deserialized_module = unsafe { Module::deserialize(&headless_store, serialized_bytes)? }; assert_eq!(deserialized_module.name(), Some("name")); assert_eq!( deserialized_module.exports().collect::>(), From 35285558694bc3f6e050bb962e17d6225b2800cc Mon Sep 17 00:00:00 2001 From: ptitSeb Date: Thu, 1 Sep 2022 17:18:13 +0200 Subject: [PATCH 3/5] Made Module::serialize to gives Bytes instead of Vec --- lib/api/src/js/module.rs | 11 +++++------ lib/api/src/sys/module.rs | 7 +++---- lib/c-api/src/wasm_c_api/module.rs | 2 +- 3 files changed, 9 insertions(+), 11 deletions(-) diff --git a/lib/api/src/js/module.rs b/lib/api/src/js/module.rs index 27f9d66867e..38ac279a792 100644 --- a/lib/api/src/js/module.rs +++ b/lib/api/src/js/module.rs @@ -105,7 +105,7 @@ pub struct Module { // WebAssembly type hints type_hints: Option, #[cfg(feature = "js-serializable-module")] - raw_bytes: Option>, + raw_bytes: Option, } impl Module { @@ -209,7 +209,7 @@ impl Module { _store: &impl AsStoreRef, binary: &[u8], ) -> Result { - let js_bytes = Uint8Array::view(&binary[..]); + let js_bytes = Uint8Array::view(binary); let module = WebAssembly::Module::new(&js_bytes.into()).unwrap(); // The module is now validated, so we can safely parse it's types @@ -241,7 +241,7 @@ impl Module { type_hints, name, #[cfg(feature = "js-serializable-module")] - raw_bytes: Some(binary.to_vec()), + raw_bytes: Some(binary), }) } @@ -252,8 +252,7 @@ impl Module { /// WebAssembly features in the Store Engine to assure deterministic /// validation of the Module. pub fn validate(_store: &impl AsStoreRef, binary: &[u8]) -> Result<(), CompileError> { - let binary = binary.into_bytes(); - let js_bytes = unsafe { Uint8Array::view(&binary[..]) }; + let js_bytes = unsafe { Uint8Array::view(binary) }; match WebAssembly::validate(&js_bytes.into()) { Ok(true) => Ok(()), _ => Err(CompileError::Validate("Invalid Wasm file".to_owned())), @@ -306,7 +305,7 @@ impl Module { /// can later process via [`Module::deserialize`]. /// #[cfg(feature = "js-serializable-module")] - pub fn serialize(&self) -> Result, SerializeError> { + pub fn serialize(&self) -> Result { self.raw_bytes.clone().ok_or(SerializeError::Generic( "Not able to serialize module".to_string(), )) diff --git a/lib/api/src/sys/module.rs b/lib/api/src/sys/module.rs index bc4257ab08c..24e372663bb 100644 --- a/lib/api/src/sys/module.rs +++ b/lib/api/src/sys/module.rs @@ -226,11 +226,10 @@ impl Module { #[cfg(feature = "compiler")] fn compile(store: &impl AsStoreRef, binary: &[u8]) -> Result { - let binary = binary.into_bytes(); let artifact = store .as_store_ref() .engine() - .compile(&binary[..], store.as_store_ref().tunables())?; + .compile(binary, store.as_store_ref().tunables())?; Ok(Self::from_artifact(artifact)) } @@ -248,8 +247,8 @@ impl Module { /// # Ok(()) /// # } /// ``` - pub fn serialize(&self) -> Result, SerializeError> { - self.artifact.serialize() + pub fn serialize(&self) -> Result { + self.artifact.serialize().map(|bytes| bytes.into()) } /// Serializes a module into a file that the `Engine` diff --git a/lib/c-api/src/wasm_c_api/module.rs b/lib/c-api/src/wasm_c_api/module.rs index 26cbfd3fcb5..4afa7760cb6 100644 --- a/lib/c-api/src/wasm_c_api/module.rs +++ b/lib/c-api/src/wasm_c_api/module.rs @@ -475,7 +475,7 @@ pub unsafe extern "C" fn wasm_module_deserialize( #[no_mangle] pub unsafe extern "C" fn wasm_module_serialize(module: &wasm_module_t, out: &mut wasm_byte_vec_t) { let byte_vec = c_try!(module.inner.serialize(); otherwise ()); - out.set_buffer(byte_vec); + out.set_buffer(byte_vec.to_vec()); } #[cfg(test)] From cc9fb4693d6d340a93c3b5c9d0fe0562bfb8aee8 Mon Sep 17 00:00:00 2001 From: ptitSeb Date: Thu, 1 Sep 2022 17:39:18 +0200 Subject: [PATCH 4/5] Fixed js build --- lib/api/src/js/module.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/api/src/js/module.rs b/lib/api/src/js/module.rs index 38ac279a792..4bad30fea04 100644 --- a/lib/api/src/js/module.rs +++ b/lib/api/src/js/module.rs @@ -241,7 +241,7 @@ impl Module { type_hints, name, #[cfg(feature = "js-serializable-module")] - raw_bytes: Some(binary), + raw_bytes: Some(binary.into_bytes()), }) } From 2752f7d3908c87fbcac0c6c374a0b5b2eeea12c5 Mon Sep 17 00:00:00 2001 From: ptitSeb Date: Thu, 1 Sep 2022 18:02:14 +0200 Subject: [PATCH 5/5] More rollback fixes --- lib/api/src/lib.rs | 2 +- tests/compilers/imports.rs | 6 +++--- tests/compilers/traps.rs | 10 +++++----- tests/lib/wast/src/wasi_wast.rs | 2 +- 4 files changed, 10 insertions(+), 10 deletions(-) diff --git a/lib/api/src/lib.rs b/lib/api/src/lib.rs index ccb647175b9..663903104ba 100644 --- a/lib/api/src/lib.rs +++ b/lib/api/src/lib.rs @@ -55,7 +55,7 @@ //! "#; //! //! let mut store = Store::default(); -//! let module = Module::new(&store, module_wat)?; +//! let module = Module::new(&store, &module_wat)?; //! // The module doesn't import anything, so we create an empty import object. //! let import_object = imports! {}; //! let instance = Instance::new(&mut store, &module, &import_object)?; diff --git a/tests/compilers/imports.rs b/tests/compilers/imports.rs index a14273dd4ff..60d452ac62f 100644 --- a/tests/compilers/imports.rs +++ b/tests/compilers/imports.rs @@ -40,7 +40,7 @@ fn get_module(store: &Store) -> Result { (start $foo) "#; - let module = Module::new(store, wat)?; + let module = Module::new(store, &wat)?; Ok(module) } @@ -339,7 +339,7 @@ fn static_function_that_fails(config: crate::Config) -> Result<()> { (start $foo) "#; - let module = Module::new(&store, wat)?; + let module = Module::new(&store, &wat)?; let f0 = Function::new_typed(&mut store, || -> Result { Err(RuntimeError::new("oops")) }); @@ -375,7 +375,7 @@ fn get_module2(store: &Store) -> Result { (call 0)) "#; - let module = Module::new(store, wat)?; + let module = Module::new(store, &wat)?; Ok(module) } diff --git a/tests/compilers/traps.rs b/tests/compilers/traps.rs index 6bf18c27f83..5c0e6a20d08 100644 --- a/tests/compilers/traps.rs +++ b/tests/compilers/traps.rs @@ -262,7 +262,7 @@ fn trap_start_function_import(config: crate::Config) -> Result<()> { ) "#; - let module = Module::new(&store, binary)?; + let module = Module::new(&store, &binary)?; let sig = FunctionType::new(vec![], vec![]); let func = Function::new(&mut store, &sig, |_| Err(RuntimeError::new("user trap"))); let err = Instance::new( @@ -302,7 +302,7 @@ fn rust_panic_import(config: crate::Config) -> Result<()> { ) "#; - let module = Module::new(&store, binary)?; + let module = Module::new(&store, &binary)?; let sig = FunctionType::new(vec![], vec![]); let func = Function::new(&mut store, &sig, |_| panic!("this is a panic")); let f0 = Function::new_typed(&mut store, || panic!("this is another panic")); @@ -347,7 +347,7 @@ fn rust_panic_start_function(config: crate::Config) -> Result<()> { ) "#; - let module = Module::new(&store, binary)?; + let module = Module::new(&store, &binary)?; let sig = FunctionType::new(vec![], vec![]); let func = Function::new(&mut store, &sig, |_| panic!("this is a panic")); let err = panic::catch_unwind(AssertUnwindSafe(|| { @@ -393,7 +393,7 @@ fn mismatched_arguments(config: crate::Config) -> Result<()> { ) "#; - let module = Module::new(&store, binary)?; + let module = Module::new(&store, &binary)?; let instance = Instance::new(&mut store, &module, &imports! {})?; let func: &Function = instance.exports.get("foo")?; assert_eq!( @@ -432,7 +432,7 @@ fn call_signature_mismatch(config: crate::Config) -> Result<()> { ) "#; - let module = Module::new(&store, binary)?; + let module = Module::new(&store, &binary)?; let err = Instance::new(&mut store, &module, &imports! {}) .err() .expect("expected error"); diff --git a/tests/lib/wast/src/wasi_wast.rs b/tests/lib/wast/src/wasi_wast.rs index beb11456c73..6b2e13aac4c 100644 --- a/tests/lib/wast/src/wasi_wast.rs +++ b/tests/lib/wast/src/wasi_wast.rs @@ -82,7 +82,7 @@ impl<'a> WasiTest<'a> { wasm_module.read_to_end(&mut out)?; out }; - let module = Module::new(store, wasm_bytes)?; + let module = Module::new(store, &wasm_bytes)?; let (env, _tempdirs, stdout_rx, stderr_rx) = self.create_wasi_env(store, filesystem_kind)?; let imports = self.get_imports(store, &env.env, &module)?;