Skip to content

Commit

Permalink
The API breaking changes from future WASIX/Network/Threading addition
Browse files Browse the repository at this point in the history
  • Loading branch information
ptitSeb committed Aug 26, 2022
1 parent cfd49c2 commit 1912373
Show file tree
Hide file tree
Showing 16 changed files with 197 additions and 62 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 2 additions & 3 deletions docs/migration_to_3.0.0.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
1 change: 1 addition & 0 deletions lib/api/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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 }
Expand Down
81 changes: 67 additions & 14 deletions lib/api/src/js/module.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -49,6 +51,46 @@ pub struct ModuleTypeHints {
pub exports: Vec<ExternType>,
}

pub trait IntoBytes {
fn into_bytes(self) -> Bytes;
}

impl IntoBytes for Bytes {
fn into_bytes(self) -> Bytes {
self
}
}

impl IntoBytes for Vec<u8> {
fn into_bytes(self) -> Bytes {
Bytes::from(self)
}
}

impl IntoBytes for &[u8] {
fn into_bytes(self) -> Bytes {
Bytes::from(self.to_vec())
}
}

impl<const N: usize> 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.
Expand Down Expand Up @@ -128,15 +170,19 @@ impl Module {
/// # }
/// ```
#[allow(unreachable_code)]
pub fn new(_store: &impl AsStoreRef, bytes: impl AsRef<[u8]>) -> Result<Self, CompileError> {
pub fn new(_store: &impl AsStoreRef, bytes: impl IntoBytes) -> Result<Self, CompileError> {
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.
Expand All @@ -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<Self, CompileError> {
pub fn from_binary(
_store: &impl AsStoreRef,
binary: impl IntoBytes,
) -> Result<Self, CompileError> {
let binary = binary.into_bytes();
//
// Self::validate(store, binary)?;
unsafe { Self::from_binary_unchecked(_store, binary) }
Expand All @@ -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<Self, CompileError> {
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
Expand Down Expand Up @@ -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())),
Expand Down Expand Up @@ -313,8 +365,9 @@ impl Module {
#[cfg(feature = "js-serializable-module")]
pub unsafe fn deserialize(
_store: &impl AsStoreRef,
bytes: &[u8],
bytes: impl IntoBytes,
) -> Result<Self, DeserializeError> {
let bytes = bytes.into_bytes();
Self::new(_store, bytes).map_err(|e| DeserializeError::Compiler(e))
}

Expand Down
2 changes: 1 addition & 1 deletion lib/api/src/js/ptr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ impl<T, M: MemorySize> WasmPtr<T, M> {

/// 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
}

Expand Down
2 changes: 1 addition & 1 deletion lib/api/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)?;
Expand Down
7 changes: 6 additions & 1 deletion lib/api/src/sys/function_env.rs
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ impl<T> FunctionEnv<T> {
}

/// 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,
{
Expand Down Expand Up @@ -105,6 +105,11 @@ impl<T: Send + 'static> FunctionEnvMut<'_, T> {
self.func_env.as_mut(&mut self.store_mut)
}

/// Borrows a new immmutable reference
pub fn as_ref(&self) -> FunctionEnv<T> {
self.func_env.clone()
}

/// Borrows a new mutable reference
pub fn as_mut(&mut self) -> FunctionEnvMut<'_, T> {
FunctionEnvMut {
Expand Down
86 changes: 69 additions & 17 deletions lib/api/src/sys/module.rs
Original file line number Diff line number Diff line change
@@ -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;
Expand Down Expand Up @@ -54,6 +56,46 @@ pub struct Module {
module_info: Arc<ModuleInfo>,
}

pub trait IntoBytes {
fn into_bytes(self) -> Bytes;
}

impl IntoBytes for Bytes {
fn into_bytes(self) -> Bytes {
self
}
}

impl IntoBytes for Vec<u8> {
fn into_bytes(self) -> Bytes {
Bytes::from(self)
}
}

impl IntoBytes for &[u8] {
fn into_bytes(self) -> Bytes {
Bytes::from(self.to_vec())
}
}

impl<const N: usize> 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
Expand Down Expand Up @@ -116,16 +158,19 @@ impl Module {
/// # }
/// ```
#[allow(unreachable_code)]
pub fn new(store: &impl AsStoreRef, bytes: impl AsRef<[u8]>) -> Result<Self, CompileError> {
pub fn new(store: &impl AsStoreRef, bytes: impl IntoBytes) -> Result<Self, CompileError> {
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")]
Expand All @@ -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();
Expand All @@ -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, CompileError> {
Self::validate(store, binary)?;
pub fn from_binary(
store: &impl AsStoreRef,
binary: impl IntoBytes,
) -> Result<Self, CompileError> {
let binary = binary.into_bytes();
Self::validate(store, binary.clone())?;
unsafe { Self::from_binary_unchecked(store, binary) }
}

Expand All @@ -166,8 +215,9 @@ impl Module {
/// beforehand.
pub unsafe fn from_binary_unchecked(
store: &impl AsStoreRef,
binary: &[u8],
binary: impl IntoBytes,
) -> Result<Self, CompileError> {
let binary = binary.into_bytes();
let module = Self::compile(store, binary)?;
Ok(module)
}
Expand All @@ -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<Self, CompileError> {
fn compile(store: &impl AsStoreRef, binary: impl IntoBytes) -> Result<Self, CompileError> {
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))
}

Expand Down
2 changes: 1 addition & 1 deletion lib/api/src/sys/ptr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,7 @@ impl<T, M: MemorySize> WasmPtr<T, M> {

/// 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
}

Expand Down
15 changes: 5 additions & 10 deletions lib/cli/src/commands/inspect.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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() {
Expand Down
4 changes: 2 additions & 2 deletions lib/cli/src/commands/run.rs
Original file line number Diff line number Diff line change
Expand Up @@ -272,7 +272,7 @@ impl Run {
let module_result: Result<Module> = 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);
Expand Down Expand Up @@ -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)
Expand Down
Loading

0 comments on commit 1912373

Please sign in to comment.