mirror of
https://github.com/mii443/wasmer.git
synced 2025-12-10 14:48:27 +00:00
Merge branch 'master' into capi-wasi-overwrite-stdin-3
This commit is contained in:
@@ -14,6 +14,7 @@ Looking for changes that affect our C API? See the [C API Changelog](lib/c-api/C
|
||||
|
||||
### Changed
|
||||
- #[3131](https://github.com/wasmerio/wasmer/pull/3131) Update migration docs for MemoryView changes
|
||||
- #[3129](https://github.com/wasmerio/wasmer/pull/3129) Fix differences between -sys and -js API
|
||||
|
||||
### Fixed
|
||||
- #[3130](https://github.com/wasmerio/wasmer/pull/3130) Remove panics from Artifact::deserialize
|
||||
|
||||
9
Cargo.lock
generated
9
Cargo.lock
generated
@@ -2923,6 +2923,7 @@ name = "wasmer"
|
||||
version = "3.0.0-beta"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"bytes",
|
||||
"cfg-if 1.0.0",
|
||||
"hashbrown 0.11.2",
|
||||
"indexmap",
|
||||
@@ -3220,11 +3221,7 @@ dependencies = [
|
||||
name = "wasmer-vbus"
|
||||
version = "3.0.0-beta"
|
||||
dependencies = [
|
||||
"libc",
|
||||
"slab",
|
||||
"thiserror",
|
||||
"tracing",
|
||||
"typetag",
|
||||
"wasmer-vfs",
|
||||
]
|
||||
|
||||
@@ -3268,11 +3265,7 @@ name = "wasmer-vnet"
|
||||
version = "3.0.0-beta"
|
||||
dependencies = [
|
||||
"bytes",
|
||||
"libc",
|
||||
"slab",
|
||||
"thiserror",
|
||||
"tracing",
|
||||
"typetag",
|
||||
"wasmer-vfs",
|
||||
]
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 }
|
||||
|
||||
@@ -4,6 +4,7 @@ use crate::js::trap::RuntimeError;
|
||||
use std::borrow::Cow;
|
||||
#[cfg(feature = "std")]
|
||||
use thiserror::Error;
|
||||
use wasmer_types::ImportError;
|
||||
|
||||
// Compilation Errors
|
||||
//
|
||||
@@ -144,6 +145,28 @@ pub enum DeserializeError {
|
||||
Compiler(CompileError),
|
||||
}
|
||||
|
||||
/// The WebAssembly.LinkError object indicates an error during
|
||||
/// module instantiation (besides traps from the start function).
|
||||
///
|
||||
/// This is based on the [link error][link-error] API.
|
||||
///
|
||||
/// [link-error]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/WebAssembly/LinkError
|
||||
#[derive(Error, Debug)]
|
||||
#[error("Link error: {0}")]
|
||||
pub enum LinkError {
|
||||
/// An error occurred when checking the import types.
|
||||
#[error("Error while importing {0:?}.{1:?}: {2}")]
|
||||
Import(String, String, ImportError),
|
||||
|
||||
#[cfg(not(target_arch = "wasm32"))]
|
||||
/// A trap ocurred during linking.
|
||||
#[error("RuntimeError occurred during linking: {0}")]
|
||||
Trap(#[source] RuntimeError),
|
||||
/// Insufficient resources available for linking.
|
||||
#[error("Insufficient resources: {0}")]
|
||||
Resource(String),
|
||||
}
|
||||
|
||||
/// An error while instantiating a module.
|
||||
///
|
||||
/// This is not a common WebAssembly error, however
|
||||
@@ -156,13 +179,18 @@ pub enum DeserializeError {
|
||||
#[cfg_attr(feature = "std", derive(Error))]
|
||||
pub enum InstantiationError {
|
||||
/// A linking ocurred during instantiation.
|
||||
#[cfg_attr(feature = "std", error("Link error: {0}"))]
|
||||
Link(String),
|
||||
#[cfg_attr(feature = "std", error(transparent))]
|
||||
Link(LinkError),
|
||||
|
||||
/// A runtime error occured while invoking the start function
|
||||
#[cfg_attr(feature = "std", error(transparent))]
|
||||
Start(RuntimeError),
|
||||
|
||||
/// The module was compiled with a CPU feature that is not available on
|
||||
/// the current host.
|
||||
#[cfg_attr(feature = "std", error("missing required CPU features: {0:?}"))]
|
||||
CpuFeature(String),
|
||||
|
||||
/// Import from a different [`Store`].
|
||||
/// This error occurs when an import from a different store is used.
|
||||
#[cfg_attr(feature = "std", error("cannot mix imports from different stores"))]
|
||||
@@ -171,6 +199,10 @@ pub enum InstantiationError {
|
||||
/// A generic error occured while invoking API functions
|
||||
#[cfg_attr(feature = "std", error(transparent))]
|
||||
Wasm(WasmError),
|
||||
|
||||
/// Insufficient resources available for execution.
|
||||
#[cfg_attr(feature = "std", error("Can't get {0} from the instance exports"))]
|
||||
NotInExports(String),
|
||||
}
|
||||
|
||||
impl From<WasmError> for InstantiationError {
|
||||
|
||||
42
lib/api/src/js/externals/function.rs
vendored
42
lib/api/src/js/externals/function.rs
vendored
@@ -1,6 +1,6 @@
|
||||
pub use self::inner::{FromToNativeWasmType, HostFunction, WasmTypeList, WithEnv, WithoutEnv};
|
||||
use crate::js::exports::{ExportError, Exportable};
|
||||
use crate::js::externals::Extern;
|
||||
use crate::js::externals::{Extern, VMExtern};
|
||||
use crate::js::function_env::FunctionEnvMut;
|
||||
use crate::js::store::{AsStoreMut, AsStoreRef, InternalStoreHandle, StoreHandle, StoreMut};
|
||||
use crate::js::types::{param_from_js, AsJs}; /* ValFuncRef */
|
||||
@@ -26,6 +26,7 @@ fn result_to_js(val: &Value) -> JsValue {
|
||||
Value::I64(i) => JsValue::from_f64(*i as _),
|
||||
Value::F32(f) => JsValue::from_f64(*f as _),
|
||||
Value::F64(f) => JsValue::from_f64(*f),
|
||||
Value::V128(f) => JsValue::from_f64(*f as _),
|
||||
val => unimplemented!(
|
||||
"The value `{:?}` is not yet supported in the JS Function API",
|
||||
val
|
||||
@@ -77,6 +78,11 @@ impl Function {
|
||||
Self::new_with_env(store, &env, ty, wrapped_func)
|
||||
}
|
||||
|
||||
/// To `VMExtern`.
|
||||
pub fn to_vm_extern(&self) -> VMExtern {
|
||||
VMExtern::Function(self.handle.internal_handle())
|
||||
}
|
||||
|
||||
/// Creates a new host `Function` (dynamic) with the provided signature.
|
||||
///
|
||||
/// If you know the signature of the host function at compile time,
|
||||
@@ -229,13 +235,13 @@ impl Function {
|
||||
note = "new_native_with_env() has been renamed to new_typed_with_env()."
|
||||
)]
|
||||
/// Creates a new host `Function` with an environment from a typed function.
|
||||
pub fn new_native_with_env<T, F, Args, Rets>(
|
||||
pub fn new_native_with_env<T: Send + 'static, F, Args, Rets>(
|
||||
store: &mut impl AsStoreMut,
|
||||
env: &FunctionEnv<T>,
|
||||
func: F,
|
||||
) -> Self
|
||||
where
|
||||
F: HostFunction<T, Args, Rets, WithEnv>,
|
||||
F: HostFunction<T, Args, Rets, WithEnv> + 'static + Send + Sync,
|
||||
Args: WasmTypeList,
|
||||
Rets: WasmTypeList,
|
||||
{
|
||||
@@ -309,8 +315,8 @@ impl Function {
|
||||
/// assert_eq!(f.ty().params(), vec![Type::I32, Type::I32]);
|
||||
/// assert_eq!(f.ty().results(), vec![Type::I32]);
|
||||
/// ```
|
||||
pub fn ty<'context>(&self, store: &'context impl AsStoreRef) -> &'context FunctionType {
|
||||
&self.handle.get(store.as_store_ref().objects()).ty
|
||||
pub fn ty(&self, store: &impl AsStoreRef) -> FunctionType {
|
||||
self.handle.get(store.as_store_ref().objects()).ty.clone()
|
||||
}
|
||||
|
||||
/// Returns the number of parameters that this function takes.
|
||||
@@ -598,7 +604,7 @@ mod inner {
|
||||
use super::RuntimeError;
|
||||
use super::VMFunctionBody;
|
||||
use crate::js::function_env::{FunctionEnvMut, VMFunctionEnvironment};
|
||||
use crate::js::store::{AsStoreMut, InternalStoreHandle, StoreHandle, StoreMut};
|
||||
use crate::js::store::{AsStoreMut, AsStoreRef, InternalStoreHandle, StoreHandle, StoreMut};
|
||||
use crate::js::FunctionEnv;
|
||||
use crate::js::NativeWasmTypeInto;
|
||||
use std::array::TryFromSliceError;
|
||||
@@ -639,6 +645,9 @@ mod inner {
|
||||
/// This method panics if `self` cannot fit in the
|
||||
/// `Self::Native` type.
|
||||
fn to_native(self) -> Self::Native;
|
||||
|
||||
/// Returns whether this native type belongs to the given store
|
||||
fn is_from_store(&self, _store: &impl AsStoreRef) -> bool;
|
||||
}
|
||||
|
||||
macro_rules! from_to_native_wasm_type {
|
||||
@@ -657,6 +666,11 @@ mod inner {
|
||||
fn to_native(self) -> Self::Native {
|
||||
self as Self::Native
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn is_from_store(&self, _store: &impl AsStoreRef) -> bool {
|
||||
true // Javascript only has one store
|
||||
}
|
||||
}
|
||||
)*
|
||||
};
|
||||
@@ -678,6 +692,11 @@ mod inner {
|
||||
fn to_native(self) -> Self::Native {
|
||||
Self::Native::from_ne_bytes(Self::to_ne_bytes(self))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn is_from_store(&self, _store: &impl AsStoreRef) -> bool {
|
||||
true // Javascript only has one store
|
||||
}
|
||||
}
|
||||
)*
|
||||
};
|
||||
@@ -887,11 +906,12 @@ mod inner {
|
||||
Args: WasmTypeList,
|
||||
Rets: WasmTypeList,
|
||||
Kind: HostFunctionKind,
|
||||
T: Sized,
|
||||
Self: Sized,
|
||||
{
|
||||
/// Get the pointer to the function body.
|
||||
fn function_body_ptr(self) -> *const VMFunctionBody;
|
||||
fn function_body_ptr(&self) -> *const VMFunctionBody;
|
||||
|
||||
// /// Get the pointer to the function call trampoline.
|
||||
// fn call_trampoline_address() -> VMTrampoline;
|
||||
}
|
||||
|
||||
/// Empty trait to specify the kind of `HostFunction`: With or
|
||||
@@ -1102,7 +1122,7 @@ mod inner {
|
||||
Func: Fn(FunctionEnvMut<'_, T>, $( $x , )*) -> RetsAsResult + 'static,
|
||||
{
|
||||
#[allow(non_snake_case)]
|
||||
fn function_body_ptr(self) -> *const VMFunctionBody {
|
||||
fn function_body_ptr(&self) -> *const VMFunctionBody {
|
||||
/// This is a function that wraps the real host
|
||||
/// function. Its address will be used inside the
|
||||
/// runtime.
|
||||
@@ -1150,7 +1170,7 @@ mod inner {
|
||||
Func: Fn($( $x , )*) -> RetsAsResult + 'static,
|
||||
{
|
||||
#[allow(non_snake_case)]
|
||||
fn function_body_ptr(self) -> *const VMFunctionBody {
|
||||
fn function_body_ptr(&self) -> *const VMFunctionBody {
|
||||
/// This is a function that wraps the real host
|
||||
/// function. Its address will be used inside the
|
||||
/// runtime.
|
||||
|
||||
16
lib/api/src/js/externals/global.rs
vendored
16
lib/api/src/js/externals/global.rs
vendored
@@ -1,6 +1,6 @@
|
||||
use crate::js::export::VMGlobal;
|
||||
use crate::js::exports::{ExportError, Exportable};
|
||||
use crate::js::externals::Extern;
|
||||
use crate::js::externals::{Extern, VMExtern};
|
||||
use crate::js::store::{AsStoreMut, AsStoreRef, InternalStoreHandle, StoreHandle};
|
||||
use crate::js::value::Value;
|
||||
use crate::js::wasm_bindgen_polyfill::Global as JSGlobal;
|
||||
@@ -55,6 +55,11 @@ impl Global {
|
||||
Self::from_value(store, val, Mutability::Var).unwrap()
|
||||
}
|
||||
|
||||
/// To `VMExtern`.
|
||||
pub(crate) fn to_vm_extern(&self) -> VMExtern {
|
||||
VMExtern::Global(self.handle.internal_handle())
|
||||
}
|
||||
|
||||
/// Create a `Global` with the initial value [`Value`] and the provided [`Mutability`].
|
||||
fn from_value(
|
||||
store: &mut impl AsStoreMut,
|
||||
@@ -135,15 +140,6 @@ impl Global {
|
||||
let ty = self.handle.get(store.as_store_ref().objects()).ty;
|
||||
Value::from_raw(store, ty.ty, raw)
|
||||
}
|
||||
/*
|
||||
match self.vm_global.ty.ty {
|
||||
ValType::I32 => Value::I32(self.vm_global.global.value().as_f64().unwrap() as _),
|
||||
ValType::I64 => Value::I64(self.vm_global.global.value().as_f64().unwrap() as _),
|
||||
ValType::F32 => Value::F32(self.vm_global.global.value().as_f64().unwrap() as _),
|
||||
ValType::F64 => Value::F64(self.vm_global.global.value().as_f64().unwrap()),
|
||||
_ => unimplemented!("The type is not yet supported in the JS Global API"),
|
||||
}
|
||||
*/
|
||||
}
|
||||
|
||||
/// Sets a custom value [`Value`] to the runtime Global.
|
||||
|
||||
13
lib/api/src/js/externals/memory.rs
vendored
13
lib/api/src/js/externals/memory.rs
vendored
@@ -1,6 +1,6 @@
|
||||
use crate::js::export::VMMemory;
|
||||
use crate::js::exports::{ExportError, Exportable};
|
||||
use crate::js::externals::Extern;
|
||||
use crate::js::externals::{Extern, VMExtern};
|
||||
use crate::js::store::{AsStoreMut, AsStoreRef, InternalStoreHandle, StoreHandle, StoreObjects};
|
||||
use crate::js::{MemoryAccessError, MemoryType};
|
||||
use std::marker::PhantomData;
|
||||
@@ -118,6 +118,11 @@ impl Memory {
|
||||
Self::from_vm_extern(new_store, handle.internal_handle())
|
||||
}
|
||||
|
||||
/// To `VMExtern`.
|
||||
pub(crate) fn to_vm_extern(&self) -> VMExtern {
|
||||
VMExtern::Memory(self.handle.internal_handle())
|
||||
}
|
||||
|
||||
/// Returns the [`MemoryType`] of the `Memory`.
|
||||
///
|
||||
/// # Example
|
||||
@@ -218,6 +223,12 @@ impl Memory {
|
||||
}
|
||||
}
|
||||
|
||||
impl std::cmp::PartialEq for Memory {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.handle == other.handle
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Exportable<'a> for Memory {
|
||||
fn get_self_from_extern(_extern: &'a Extern) -> Result<&'a Self, ExportError> {
|
||||
match _extern {
|
||||
|
||||
137
lib/api/src/js/externals/mod.rs
vendored
137
lib/api/src/js/externals/mod.rs
vendored
@@ -10,13 +10,122 @@ pub use self::memory::{Memory, MemoryError};
|
||||
pub use self::memory_view::MemoryView;
|
||||
pub use self::table::Table;
|
||||
|
||||
use crate::js::export::Export;
|
||||
use crate::js::export::{Export, VMFunction, VMGlobal, VMMemory, VMTable};
|
||||
use crate::js::exports::{ExportError, Exportable};
|
||||
use crate::js::store::StoreObject;
|
||||
use crate::js::store::{AsStoreMut, AsStoreRef};
|
||||
use crate::js::types::AsJs;
|
||||
|
||||
/*
|
||||
|
||||
|
||||
use crate::js::store::InternalStoreHandle;
|
||||
use crate::js::store::{AsStoreMut, AsStoreRef};
|
||||
use crate::js::ExternType;
|
||||
use std::fmt;
|
||||
*/
|
||||
use crate::js::error::WasmError;
|
||||
use crate::js::store::{AsStoreMut, AsStoreRef, InternalStoreHandle};
|
||||
use crate::js::wasm_bindgen_polyfill::Global as JsGlobal;
|
||||
use js_sys::Function as JsFunction;
|
||||
use js_sys::WebAssembly::{Memory as JsMemory, Table as JsTable};
|
||||
use std::fmt;
|
||||
use wasm_bindgen::{JsCast, JsValue};
|
||||
use wasmer_types::{ExternType, FunctionType, GlobalType, MemoryType, TableType};
|
||||
|
||||
/// The value of an export passed from one instance to another.
|
||||
pub enum VMExtern {
|
||||
/// A function export value.
|
||||
Function(InternalStoreHandle<VMFunction>),
|
||||
|
||||
/// A table export value.
|
||||
Table(InternalStoreHandle<VMTable>),
|
||||
|
||||
/// A memory export value.
|
||||
Memory(InternalStoreHandle<VMMemory>),
|
||||
|
||||
/// A global export value.
|
||||
Global(InternalStoreHandle<VMGlobal>),
|
||||
}
|
||||
|
||||
impl VMExtern {
|
||||
/// Return the export as a `JSValue`.
|
||||
pub fn as_jsvalue<'context>(&self, store: &'context impl AsStoreRef) -> &'context JsValue {
|
||||
match self {
|
||||
Self::Memory(js_wasm_memory) => js_wasm_memory
|
||||
.get(store.as_store_ref().objects())
|
||||
.memory
|
||||
.as_ref(),
|
||||
Self::Function(js_func) => js_func
|
||||
.get(store.as_store_ref().objects())
|
||||
.function
|
||||
.as_ref(),
|
||||
Self::Table(js_wasm_table) => js_wasm_table
|
||||
.get(store.as_store_ref().objects())
|
||||
.table
|
||||
.as_ref(),
|
||||
Self::Global(js_wasm_global) => js_wasm_global
|
||||
.get(store.as_store_ref().objects())
|
||||
.global
|
||||
.as_ref(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Convert a `JsValue` into an `Export` within a given `Context`.
|
||||
pub fn from_js_value(
|
||||
val: JsValue,
|
||||
store: &mut impl AsStoreMut,
|
||||
extern_type: ExternType,
|
||||
) -> Result<Self, WasmError> {
|
||||
match extern_type {
|
||||
ExternType::Memory(memory_type) => {
|
||||
if val.is_instance_of::<JsMemory>() {
|
||||
Ok(Self::Memory(InternalStoreHandle::new(
|
||||
&mut store.objects_mut(),
|
||||
VMMemory::new(val.unchecked_into::<JsMemory>(), memory_type),
|
||||
)))
|
||||
} else {
|
||||
Err(WasmError::TypeMismatch(
|
||||
val.js_typeof()
|
||||
.as_string()
|
||||
.map(Into::into)
|
||||
.unwrap_or("unknown".into()),
|
||||
"Memory".into(),
|
||||
))
|
||||
}
|
||||
}
|
||||
ExternType::Global(global_type) => {
|
||||
if val.is_instance_of::<JsGlobal>() {
|
||||
Ok(Self::Global(InternalStoreHandle::new(
|
||||
&mut store.objects_mut(),
|
||||
VMGlobal::new(val.unchecked_into::<JsGlobal>(), global_type),
|
||||
)))
|
||||
} else {
|
||||
panic!("Extern type doesn't match js value type");
|
||||
}
|
||||
}
|
||||
ExternType::Function(function_type) => {
|
||||
if val.is_instance_of::<JsFunction>() {
|
||||
Ok(Self::Function(InternalStoreHandle::new(
|
||||
&mut store.objects_mut(),
|
||||
VMFunction::new(val.unchecked_into::<JsFunction>(), function_type),
|
||||
)))
|
||||
} else {
|
||||
panic!("Extern type doesn't match js value type");
|
||||
}
|
||||
}
|
||||
ExternType::Table(table_type) => {
|
||||
if val.is_instance_of::<JsTable>() {
|
||||
Ok(Self::Table(InternalStoreHandle::new(
|
||||
&mut store.objects_mut(),
|
||||
VMTable::new(val.unchecked_into::<JsTable>(), table_type),
|
||||
)))
|
||||
} else {
|
||||
panic!("Extern type doesn't match js value type");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// An `Extern` is the runtime representation of an entity that
|
||||
/// can be imported or exported.
|
||||
@@ -45,13 +154,23 @@ impl Extern {
|
||||
}
|
||||
}
|
||||
|
||||
/// Create an `Extern` from an `wasmer_compiler::Export`.
|
||||
pub fn from_vm_extern(store: &mut impl AsStoreMut, export: Export) -> Self {
|
||||
match export {
|
||||
Export::Function(f) => Self::Function(Function::from_vm_extern(store, f)),
|
||||
Export::Memory(m) => Self::Memory(Memory::from_vm_extern(store, m)),
|
||||
Export::Global(g) => Self::Global(Global::from_vm_extern(store, g)),
|
||||
Export::Table(t) => Self::Table(Table::from_vm_extern(store, t)),
|
||||
/// Create an `Extern` from an `wasmer_engine::Export`.
|
||||
pub fn from_vm_extern(store: &mut impl AsStoreMut, vm_extern: VMExtern) -> Self {
|
||||
match vm_extern {
|
||||
VMExtern::Function(f) => Self::Function(Function::from_vm_extern(store, f)),
|
||||
VMExtern::Memory(m) => Self::Memory(Memory::from_vm_extern(store, m)),
|
||||
VMExtern::Global(g) => Self::Global(Global::from_vm_extern(store, g)),
|
||||
VMExtern::Table(t) => Self::Table(Table::from_vm_extern(store, t)),
|
||||
}
|
||||
}
|
||||
|
||||
/// To `VMExtern`.
|
||||
pub fn to_vm_extern(&self) -> VMExtern {
|
||||
match self {
|
||||
Self::Function(f) => f.to_vm_extern(),
|
||||
Self::Global(g) => g.to_vm_extern(),
|
||||
Self::Memory(m) => m.to_vm_extern(),
|
||||
Self::Table(t) => t.to_vm_extern(),
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
8
lib/api/src/js/externals/table.rs
vendored
8
lib/api/src/js/externals/table.rs
vendored
@@ -1,6 +1,6 @@
|
||||
use crate::js::export::{VMFunction, VMTable};
|
||||
use crate::js::exports::{ExportError, Exportable};
|
||||
use crate::js::externals::Extern;
|
||||
use crate::js::externals::{Extern, VMExtern};
|
||||
use crate::js::store::{AsStoreMut, AsStoreRef, InternalStoreHandle, StoreHandle};
|
||||
use crate::js::value::Value;
|
||||
use crate::js::RuntimeError;
|
||||
@@ -75,6 +75,11 @@ impl Table {
|
||||
})
|
||||
}
|
||||
|
||||
/// To `VMExtern`.
|
||||
pub fn to_vm_extern(&self) -> VMExtern {
|
||||
VMExtern::Table(self.handle.internal_handle())
|
||||
}
|
||||
|
||||
/// Returns the [`TableType`] of the `Table`.
|
||||
pub fn ty(&self, store: &impl AsStoreRef) -> TableType {
|
||||
self.handle.get(store.as_store_ref().objects()).ty
|
||||
@@ -143,6 +148,7 @@ impl Table {
|
||||
/// Returns an error if the range is out of bounds of either the source or
|
||||
/// destination tables.
|
||||
pub fn copy(
|
||||
_store: &mut impl AsStoreMut,
|
||||
_dst_table: &Self,
|
||||
_dst_index: u32,
|
||||
_src_table: &Self,
|
||||
|
||||
@@ -1,14 +1,17 @@
|
||||
//! The import module contains the implementation data structures and helper functions used to
|
||||
//! manipulate and access a wasm module's imports including memories, tables, globals, and
|
||||
//! functions.
|
||||
use crate::js::error::InstantiationError;
|
||||
use crate::js::error::{InstantiationError, LinkError, WasmError};
|
||||
use crate::js::export::Export;
|
||||
use crate::js::exports::Exports;
|
||||
use crate::js::module::Module;
|
||||
use crate::js::store::AsStoreRef;
|
||||
use crate::js::store::{AsStoreMut, AsStoreRef};
|
||||
use crate::js::types::AsJs;
|
||||
use crate::js::ExternType;
|
||||
use crate::Extern;
|
||||
use std::collections::HashMap;
|
||||
use std::fmt;
|
||||
use wasmer_types::ImportError;
|
||||
|
||||
/// All of the import data used when instantiating.
|
||||
///
|
||||
@@ -130,7 +133,7 @@ impl Imports {
|
||||
/// Resolve and return a vector of imports in the order they are defined in the `module`'s source code.
|
||||
///
|
||||
/// This means the returned `Vec<Extern>` might be a subset of the imports contained in `self`.
|
||||
pub fn imports_for_module(&self, module: &Module) -> Result<Vec<Extern>, InstantiationError> {
|
||||
pub fn imports_for_module(&self, module: &Module) -> Result<Vec<Extern>, LinkError> {
|
||||
let mut ret = vec![];
|
||||
for import in module.imports() {
|
||||
if let Some(imp) = self
|
||||
@@ -139,12 +142,11 @@ impl Imports {
|
||||
{
|
||||
ret.push(imp.clone());
|
||||
} else {
|
||||
return Err(InstantiationError::Link(format!(
|
||||
"Error while importing {0:?}.{1:?}: unknown import. Expected {2:?}",
|
||||
import.module(),
|
||||
import.name(),
|
||||
import.ty()
|
||||
)));
|
||||
return Err(LinkError::Import(
|
||||
import.module().to_string(),
|
||||
import.name().to_string(),
|
||||
ImportError::UnknownImport(import.ty().clone()),
|
||||
));
|
||||
}
|
||||
}
|
||||
Ok(ret)
|
||||
@@ -179,6 +181,81 @@ impl Imports {
|
||||
pub fn iter<'a>(&'a self) -> ImportsIterator<'a> {
|
||||
ImportsIterator::new(self)
|
||||
}
|
||||
|
||||
/// Create a new `Imports` from a JS Object, it receives a reference to a `Module` to
|
||||
/// map and assign the types of each import and the JS Object
|
||||
/// that contains the values of imports.
|
||||
///
|
||||
/// # Usage
|
||||
/// ```ignore
|
||||
/// let import_object = Imports::new_from_js_object(&mut store, &module, js_object);
|
||||
/// ```
|
||||
pub fn new_from_js_object(
|
||||
store: &mut impl AsStoreMut,
|
||||
module: &Module,
|
||||
object: js_sys::Object,
|
||||
) -> Result<Self, WasmError> {
|
||||
use crate::js::externals::VMExtern;
|
||||
let module_imports: HashMap<(String, String), ExternType> = module
|
||||
.imports()
|
||||
.map(|import| {
|
||||
(
|
||||
(import.module().to_string(), import.name().to_string()),
|
||||
import.ty().clone(),
|
||||
)
|
||||
})
|
||||
.collect::<HashMap<(String, String), ExternType>>();
|
||||
|
||||
let mut map: HashMap<(String, String), Extern> = HashMap::new();
|
||||
|
||||
for module_entry in js_sys::Object::entries(&object).iter() {
|
||||
let module_entry: js_sys::Array = module_entry.into();
|
||||
let module_name = module_entry.get(0).as_string().unwrap().to_string();
|
||||
let module_import_object: js_sys::Object = module_entry.get(1).into();
|
||||
for import_entry in js_sys::Object::entries(&module_import_object).iter() {
|
||||
let import_entry: js_sys::Array = import_entry.into();
|
||||
let import_name = import_entry.get(0).as_string().unwrap().to_string();
|
||||
let import_js: wasm_bindgen::JsValue = import_entry.get(1);
|
||||
let key = (module_name.clone(), import_name);
|
||||
let extern_type = module_imports.get(&key).unwrap();
|
||||
let export = VMExtern::from_js_value(import_js, store, extern_type.clone())?;
|
||||
let extern_ = Extern::from_vm_extern(store, export);
|
||||
map.insert(key, extern_);
|
||||
}
|
||||
}
|
||||
|
||||
Ok(Self { map })
|
||||
}
|
||||
}
|
||||
|
||||
impl AsJs for Imports {
|
||||
fn as_jsvalue(&self, store: &impl AsStoreRef) -> wasm_bindgen::JsValue {
|
||||
let imports_object = js_sys::Object::new();
|
||||
for (namespace, name, extern_) in self.iter() {
|
||||
let val = js_sys::Reflect::get(&imports_object, &namespace.into()).unwrap();
|
||||
if !val.is_undefined() {
|
||||
// If the namespace is already set
|
||||
js_sys::Reflect::set(
|
||||
&val,
|
||||
&name.into(),
|
||||
&extern_.as_jsvalue(&store.as_store_ref()),
|
||||
)
|
||||
.unwrap();
|
||||
} else {
|
||||
// If the namespace doesn't exist
|
||||
let import_namespace = js_sys::Object::new();
|
||||
js_sys::Reflect::set(
|
||||
&import_namespace,
|
||||
&name.into(),
|
||||
&extern_.as_jsvalue(&store.as_store_ref()),
|
||||
)
|
||||
.unwrap();
|
||||
js_sys::Reflect::set(&imports_object, &namespace.into(), &import_namespace.into())
|
||||
.unwrap();
|
||||
}
|
||||
}
|
||||
imports_object.into()
|
||||
}
|
||||
}
|
||||
|
||||
pub struct ImportsIterator<'a> {
|
||||
@@ -317,89 +394,18 @@ macro_rules! import_namespace {
|
||||
};
|
||||
}
|
||||
|
||||
/*
|
||||
#[cfg(test)]
|
||||
mod test {
|
||||
use crate::js::exports::Exportable;
|
||||
use crate::js::Type;
|
||||
use crate::js::{Global, Store, Val};
|
||||
use crate::js::{Global, Store, Value};
|
||||
|
||||
use crate::js::export::Export;
|
||||
// use wasm_bindgen::*;
|
||||
use wasm_bindgen_test::*;
|
||||
fn namespace() {
|
||||
let mut store = Store::default();
|
||||
let g1 = Global::new(&store, Val::I32(0));
|
||||
let namespace = namespace! {
|
||||
"happy" => g1
|
||||
};
|
||||
let imports1 = imports! {
|
||||
"dog" => namespace
|
||||
};
|
||||
|
||||
let happy_dog_entry = imports1.get_export("dog", "happy").unwrap();
|
||||
|
||||
assert!(
|
||||
if let Export::Global(happy_dog_global) = happy_dog_entry.to_export() {
|
||||
happy_dog_global.ty.ty == Type::I32
|
||||
} else {
|
||||
false
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
fn imports_macro_allows_trailing_comma_and_none() {
|
||||
use crate::js::Function;
|
||||
|
||||
let mut store = Default::default();
|
||||
|
||||
fn func(arg: i32) -> i32 {
|
||||
arg + 1
|
||||
}
|
||||
|
||||
let _ = imports! {
|
||||
"env" => {
|
||||
"func" => Function::new_typed(&store, func),
|
||||
},
|
||||
};
|
||||
let _ = imports! {
|
||||
"env" => {
|
||||
"func" => Function::new_typed(&store, func),
|
||||
}
|
||||
};
|
||||
let _ = imports! {
|
||||
"env" => {
|
||||
"func" => Function::new_typed(&store, func),
|
||||
},
|
||||
"abc" => {
|
||||
"def" => Function::new_typed(&store, func),
|
||||
}
|
||||
};
|
||||
let _ = imports! {
|
||||
"env" => {
|
||||
"func" => Function::new_typed(&store, func)
|
||||
},
|
||||
};
|
||||
let _ = imports! {
|
||||
"env" => {
|
||||
"func" => Function::new_typed(&store, func)
|
||||
}
|
||||
};
|
||||
let _ = imports! {
|
||||
"env" => {
|
||||
"func1" => Function::new_typed(&store, func),
|
||||
"func2" => Function::new_typed(&store, func)
|
||||
}
|
||||
};
|
||||
let _ = imports! {
|
||||
"env" => {
|
||||
"func1" => Function::new_typed(&store, func),
|
||||
"func2" => Function::new_typed(&store, func),
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
#[wasm_bindgen_test]
|
||||
fn chaining_works() {
|
||||
let mut store = Store::default();
|
||||
let g = Global::new(&store, Val::I32(0));
|
||||
|
||||
let g = Global::new(&mut store, Value::I32(0));
|
||||
|
||||
let mut imports1 = imports! {
|
||||
"dog" => {
|
||||
@@ -412,7 +418,7 @@ mod test {
|
||||
"small" => g.clone()
|
||||
},
|
||||
"cat" => {
|
||||
"small" => g.clone()
|
||||
"small" => g
|
||||
}
|
||||
};
|
||||
|
||||
@@ -426,62 +432,162 @@ mod test {
|
||||
assert!(happy.is_some());
|
||||
assert!(small.is_some());
|
||||
}
|
||||
// fn namespace() {
|
||||
// let mut store = Store::default();
|
||||
// let g1 = Global::new(&store, Val::I32(0));
|
||||
// let namespace = namespace! {
|
||||
// "happy" => g1
|
||||
// };
|
||||
// let imports1 = imports! {
|
||||
// "dog" => namespace
|
||||
// };
|
||||
|
||||
fn extending_conflict_overwrites() {
|
||||
let mut store = Store::default();
|
||||
let g1 = Global::new(&store, Val::I32(0));
|
||||
let g2 = Global::new(&store, Val::F32(0.));
|
||||
// let happy_dog_entry = imports1.get_export("dog", "happy").unwrap();
|
||||
|
||||
let mut imports1 = imports! {
|
||||
"dog" => {
|
||||
"happy" => g1,
|
||||
},
|
||||
};
|
||||
// assert!(
|
||||
// if let Export::Global(happy_dog_global) = happy_dog_entry.to_export() {
|
||||
// happy_dog_global.ty.ty == Type::I32
|
||||
// } else {
|
||||
// false
|
||||
// }
|
||||
// );
|
||||
// }
|
||||
|
||||
let imports2 = imports! {
|
||||
"dog" => {
|
||||
"happy" => g2,
|
||||
},
|
||||
};
|
||||
// fn imports_macro_allows_trailing_comma_and_none() {
|
||||
// use crate::js::Function;
|
||||
|
||||
imports1.extend(&imports2);
|
||||
let happy_dog_entry = imports1.get_export("dog", "happy").unwrap();
|
||||
// let mut store = Default::default();
|
||||
|
||||
assert!(
|
||||
if let Export::Global(happy_dog_global) = happy_dog_entry.to_export() {
|
||||
happy_dog_global.ty.ty == Type::F32
|
||||
} else {
|
||||
false
|
||||
// fn func(arg: i32) -> i32 {
|
||||
// arg + 1
|
||||
// }
|
||||
|
||||
// let _ = imports! {
|
||||
// "env" => {
|
||||
// "func" => Function::new_typed(&store, func),
|
||||
// },
|
||||
// };
|
||||
// let _ = imports! {
|
||||
// "env" => {
|
||||
// "func" => Function::new_typed(&store, func),
|
||||
// }
|
||||
// };
|
||||
// let _ = imports! {
|
||||
// "env" => {
|
||||
// "func" => Function::new_typed(&store, func),
|
||||
// },
|
||||
// "abc" => {
|
||||
// "def" => Function::new_typed(&store, func),
|
||||
// }
|
||||
// };
|
||||
// let _ = imports! {
|
||||
// "env" => {
|
||||
// "func" => Function::new_typed(&store, func)
|
||||
// },
|
||||
// };
|
||||
// let _ = imports! {
|
||||
// "env" => {
|
||||
// "func" => Function::new_typed(&store, func)
|
||||
// }
|
||||
// };
|
||||
// let _ = imports! {
|
||||
// "env" => {
|
||||
// "func1" => Function::new_typed(&store, func),
|
||||
// "func2" => Function::new_typed(&store, func)
|
||||
// }
|
||||
// };
|
||||
// let _ = imports! {
|
||||
// "env" => {
|
||||
// "func1" => Function::new_typed(&store, func),
|
||||
// "func2" => Function::new_typed(&store, func),
|
||||
// }
|
||||
// };
|
||||
// }
|
||||
|
||||
// fn chaining_works() {
|
||||
// let mut store = Store::default();
|
||||
// let g = Global::new(&store, Val::I32(0));
|
||||
|
||||
// let mut imports1 = imports! {
|
||||
// "dog" => {
|
||||
// "happy" => g.clone()
|
||||
// }
|
||||
// };
|
||||
|
||||
// let imports2 = imports! {
|
||||
// "dog" => {
|
||||
// "small" => g.clone()
|
||||
// },
|
||||
// "cat" => {
|
||||
// "small" => g.clone()
|
||||
// }
|
||||
// };
|
||||
|
||||
// imports1.extend(&imports2);
|
||||
|
||||
// let small_cat_export = imports1.get_export("cat", "small");
|
||||
// assert!(small_cat_export.is_some());
|
||||
|
||||
// let happy = imports1.get_export("dog", "happy");
|
||||
// let small = imports1.get_export("dog", "small");
|
||||
// assert!(happy.is_some());
|
||||
// assert!(small.is_some());
|
||||
// }
|
||||
|
||||
// fn extending_conflict_overwrites() {
|
||||
// let mut store = Store::default();
|
||||
// let g1 = Global::new(&store, Val::I32(0));
|
||||
// let g2 = Global::new(&store, Val::F32(0.));
|
||||
|
||||
// let mut imports1 = imports! {
|
||||
// "dog" => {
|
||||
// "happy" => g1,
|
||||
// },
|
||||
// };
|
||||
|
||||
// let imports2 = imports! {
|
||||
// "dog" => {
|
||||
// "happy" => g2,
|
||||
// },
|
||||
// };
|
||||
|
||||
// imports1.extend(&imports2);
|
||||
// let happy_dog_entry = imports1.get_export("dog", "happy").unwrap();
|
||||
|
||||
// assert!(
|
||||
// if let Export::Global(happy_dog_global) = happy_dog_entry.to_export() {
|
||||
// happy_dog_global.ty.ty == Type::F32
|
||||
// } else {
|
||||
// false
|
||||
// }
|
||||
// );
|
||||
|
||||
// // now test it in reverse
|
||||
// let mut store = Store::default();
|
||||
// let g1 = Global::new(&store, Val::I32(0));
|
||||
// let g2 = Global::new(&store, Val::F32(0.));
|
||||
|
||||
// let imports1 = imports! {
|
||||
// "dog" => {
|
||||
// "happy" => g1,
|
||||
// },
|
||||
// };
|
||||
|
||||
// let mut imports2 = imports! {
|
||||
// "dog" => {
|
||||
// "happy" => g2,
|
||||
// },
|
||||
// };
|
||||
|
||||
// imports2.extend(&imports1);
|
||||
// let happy_dog_entry = imports2.get_export("dog", "happy").unwrap();
|
||||
|
||||
// assert!(
|
||||
// if let Export::Global(happy_dog_global) = happy_dog_entry.to_export() {
|
||||
// happy_dog_global.ty.ty == Type::I32
|
||||
// } else {
|
||||
// false
|
||||
// }
|
||||
// );
|
||||
// }
|
||||
}
|
||||
);
|
||||
|
||||
// now test it in reverse
|
||||
let mut store = Store::default();
|
||||
let g1 = Global::new(&store, Val::I32(0));
|
||||
let g2 = Global::new(&store, Val::F32(0.));
|
||||
|
||||
let imports1 = imports! {
|
||||
"dog" => {
|
||||
"happy" => g1,
|
||||
},
|
||||
};
|
||||
|
||||
let mut imports2 = imports! {
|
||||
"dog" => {
|
||||
"happy" => g2,
|
||||
},
|
||||
};
|
||||
|
||||
imports2.extend(&imports1);
|
||||
let happy_dog_entry = imports2.get_export("dog", "happy").unwrap();
|
||||
|
||||
assert!(
|
||||
if let Export::Global(happy_dog_global) = happy_dog_entry.to_export() {
|
||||
happy_dog_global.ty.ty == Type::I32
|
||||
} else {
|
||||
false
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
@@ -20,8 +20,6 @@ use std::fmt;
|
||||
pub struct Instance {
|
||||
_handle: StoreHandle<WebAssembly::Instance>,
|
||||
module: Module,
|
||||
#[allow(dead_code)]
|
||||
imports: Imports,
|
||||
/// The exports for an instance.
|
||||
pub exports: Exports,
|
||||
}
|
||||
@@ -65,16 +63,37 @@ impl Instance {
|
||||
module: &Module,
|
||||
imports: &Imports,
|
||||
) -> Result<Self, InstantiationError> {
|
||||
let import_copy = imports.clone();
|
||||
let (instance, _imports): (StoreHandle<WebAssembly::Instance>, Vec<Extern>) = module
|
||||
let instance: WebAssembly::Instance = module
|
||||
.instantiate(&mut store, imports)
|
||||
.map_err(|e| InstantiationError::Start(e))?;
|
||||
|
||||
let self_instance = Self::from_module_and_instance(store, module, instance, import_copy)?;
|
||||
let self_instance = Self::from_module_and_instance(store, module, instance)?;
|
||||
//self_instance.init_envs(&imports.iter().map(Extern::to_export).collect::<Vec<_>>())?;
|
||||
Ok(self_instance)
|
||||
}
|
||||
|
||||
/// Creates a new `Instance` from a WebAssembly [`Module`] and a
|
||||
/// vector of imports.
|
||||
///
|
||||
/// ## Errors
|
||||
///
|
||||
/// The function can return [`InstantiationError`]s.
|
||||
///
|
||||
/// Those are, as defined by the spec:
|
||||
/// * Link errors that happen when plugging the imports into the instance
|
||||
/// * Runtime errors that happen when running the module `start` function.
|
||||
pub fn new_by_index(
|
||||
store: &mut impl AsStoreMut,
|
||||
module: &Module,
|
||||
externs: &[Extern],
|
||||
) -> Result<Self, InstantiationError> {
|
||||
let mut imports = Imports::new();
|
||||
for (import_ty, extern_ty) in module.imports().zip(externs.iter()) {
|
||||
imports.define(import_ty.module(), import_ty.name(), extern_ty.clone());
|
||||
}
|
||||
Self::new(store, module, &imports)
|
||||
}
|
||||
|
||||
/// Creates a Wasmer `Instance` from a Wasmer `Module` and a WebAssembly Instance
|
||||
///
|
||||
/// # Important
|
||||
@@ -87,33 +106,27 @@ impl Instance {
|
||||
pub fn from_module_and_instance(
|
||||
mut store: &mut impl AsStoreMut,
|
||||
module: &Module,
|
||||
instance: StoreHandle<WebAssembly::Instance>,
|
||||
imports: Imports,
|
||||
instance: WebAssembly::Instance,
|
||||
) -> Result<Self, InstantiationError> {
|
||||
let instance_exports = instance.get(store.as_store_ref().objects()).exports();
|
||||
use crate::js::externals::VMExtern;
|
||||
let instance_exports = instance.exports();
|
||||
let exports = module
|
||||
.exports()
|
||||
.map(|export_type| {
|
||||
let name = export_type.name();
|
||||
let extern_type = export_type.ty().clone();
|
||||
let js_export =
|
||||
js_sys::Reflect::get(&instance_exports, &name.into()).map_err(|_e| {
|
||||
InstantiationError::Link(format!(
|
||||
"Can't get {} from the instance exports",
|
||||
&name
|
||||
))
|
||||
})?;
|
||||
let export: Export =
|
||||
Export::from_js_value(js_export, &mut store, extern_type)?.into();
|
||||
let js_export = js_sys::Reflect::get(&instance_exports, &name.into())
|
||||
.map_err(|_e| InstantiationError::NotInExports(name.to_string()))?;
|
||||
let export: VMExtern =
|
||||
VMExtern::from_js_value(js_export, &mut store, extern_type)?.into();
|
||||
let extern_ = Extern::from_vm_extern(&mut store, export);
|
||||
Ok((name.to_string(), extern_))
|
||||
})
|
||||
.collect::<Result<Exports, InstantiationError>>()?;
|
||||
|
||||
let handle = StoreHandle::new(store.as_store_mut().objects_mut(), instance);
|
||||
Ok(Self {
|
||||
_handle: instance,
|
||||
_handle: handle,
|
||||
module: module.clone(),
|
||||
imports,
|
||||
exports,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -1,83 +0,0 @@
|
||||
use crate::js::error::WasmError;
|
||||
use crate::js::store::AsStoreMut;
|
||||
use crate::js::{Export, ExternType, Module};
|
||||
use std::collections::HashMap;
|
||||
|
||||
/// This struct is used in case you want to create an `Instance`
|
||||
/// of a `Module` with imports that are provided directly from
|
||||
/// Javascript with a JS Object.
|
||||
#[derive(Clone, Default)]
|
||||
pub struct JsImportObject {
|
||||
module_imports: HashMap<(String, String), ExternType>,
|
||||
object: js_sys::Object,
|
||||
}
|
||||
|
||||
/// JS Objects with wasm-bindgen are not currently Send/Sync (although they
|
||||
/// are in Javascript, since we can use them safely between webworkers).
|
||||
unsafe impl Send for JsImportObject {}
|
||||
unsafe impl Sync for JsImportObject {}
|
||||
|
||||
impl JsImportObject {
|
||||
/// Create a new `JsImportObject`, it receives a reference to a `Module` to
|
||||
/// map and assign the types of each import and the JS Object
|
||||
/// that contains the values of imports.
|
||||
///
|
||||
/// # Usage
|
||||
/// ```ignore
|
||||
/// # use wasmer::JsImportObject;
|
||||
/// let import_object = JsImportObject::new(&module, js_object);
|
||||
/// ```
|
||||
pub fn new(module: &Module, object: js_sys::Object) -> Self {
|
||||
let module_imports = module
|
||||
.imports()
|
||||
.map(|import| {
|
||||
(
|
||||
(import.module().to_string(), import.name().to_string()),
|
||||
import.ty().clone(),
|
||||
)
|
||||
})
|
||||
.collect::<HashMap<(String, String), ExternType>>();
|
||||
Self {
|
||||
module_imports,
|
||||
object,
|
||||
}
|
||||
}
|
||||
|
||||
/// Gets an export given a module and a name
|
||||
///
|
||||
/// # Usage
|
||||
/// ```ignore
|
||||
/// # use wasmer::JsImportObject;
|
||||
/// let import_object = JsImportObject::new(&module, js_object);
|
||||
/// import_object.get_export("module", "name");
|
||||
/// ```
|
||||
pub fn get_export(
|
||||
&self,
|
||||
store: &mut impl AsStoreMut,
|
||||
module: &str,
|
||||
name: &str,
|
||||
) -> Result<Export, WasmError> {
|
||||
let namespace = js_sys::Reflect::get(&self.object, &module.into())?;
|
||||
let js_export = js_sys::Reflect::get(&namespace, &name.into())?;
|
||||
match self
|
||||
.module_imports
|
||||
.get(&(module.to_string(), name.to_string()))
|
||||
{
|
||||
Some(extern_type) => Ok(Export::from_js_value(
|
||||
js_export,
|
||||
store,
|
||||
extern_type.clone(),
|
||||
)?),
|
||||
None => Err(WasmError::Generic(format!(
|
||||
"Name {} not found in module {}",
|
||||
name, module
|
||||
))),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Into<js_sys::Object> for JsImportObject {
|
||||
fn into(self) -> js_sys::Object {
|
||||
self.object
|
||||
}
|
||||
}
|
||||
@@ -197,6 +197,12 @@ impl<'a, T: ValueType> WasmSlice<'a, T> {
|
||||
self.len
|
||||
}
|
||||
|
||||
/// Return if the slice is empty.
|
||||
#[inline]
|
||||
pub fn is_empty(&self) -> bool {
|
||||
self.len == 0
|
||||
}
|
||||
|
||||
/// Get a `WasmRef` to an element in the slice.
|
||||
#[inline]
|
||||
pub fn index(self, idx: u64) -> WasmRef<'a, T> {
|
||||
|
||||
@@ -30,7 +30,6 @@ mod externals;
|
||||
mod function_env;
|
||||
mod imports;
|
||||
mod instance;
|
||||
mod js_import_object;
|
||||
mod mem_access;
|
||||
mod module;
|
||||
#[cfg(feature = "wasm-types-polyfill")]
|
||||
@@ -54,7 +53,6 @@ pub use crate::js::externals::{
|
||||
pub use crate::js::function_env::{FunctionEnv, FunctionEnvMut};
|
||||
pub use crate::js::imports::Imports;
|
||||
pub use crate::js::instance::Instance;
|
||||
pub use crate::js::js_import_object::JsImportObject;
|
||||
pub use crate::js::mem_access::{MemoryAccessError, WasmRef, WasmSlice, WasmSliceIter};
|
||||
pub use crate::js::module::{Module, ModuleTypeHints};
|
||||
pub use crate::js::native::TypedFunction;
|
||||
@@ -88,6 +86,9 @@ pub use wasmer_types::{
|
||||
#[cfg(feature = "wat")]
|
||||
pub use wat::parse_bytes as wat2wasm;
|
||||
|
||||
#[cfg(feature = "wasm-types-polyfill")]
|
||||
pub use wasmparser;
|
||||
|
||||
/// Version number of this crate.
|
||||
pub const VERSION: &str = env!("CARGO_PKG_VERSION");
|
||||
|
||||
|
||||
@@ -3,13 +3,14 @@ use crate::js::error::WasmError;
|
||||
use crate::js::error::{CompileError, InstantiationError};
|
||||
#[cfg(feature = "js-serializable-module")]
|
||||
use crate::js::error::{DeserializeError, SerializeError};
|
||||
use crate::js::externals::Extern;
|
||||
use crate::js::imports::Imports;
|
||||
use crate::js::store::{AsStoreMut, StoreHandle};
|
||||
use crate::js::store::AsStoreMut;
|
||||
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 +50,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.
|
||||
@@ -64,7 +105,7 @@ pub struct Module {
|
||||
// WebAssembly type hints
|
||||
type_hints: Option<ModuleTypeHints>,
|
||||
#[cfg(feature = "js-serializable-module")]
|
||||
raw_bytes: Option<Vec<u8>>,
|
||||
raw_bytes: Option<Bytes>,
|
||||
}
|
||||
|
||||
impl Module {
|
||||
@@ -200,7 +241,7 @@ impl Module {
|
||||
type_hints,
|
||||
name,
|
||||
#[cfg(feature = "js-serializable-module")]
|
||||
raw_bytes: Some(binary.to_vec()),
|
||||
raw_bytes: Some(binary.into_bytes()),
|
||||
})
|
||||
}
|
||||
|
||||
@@ -222,7 +263,7 @@ impl Module {
|
||||
&self,
|
||||
store: &mut impl AsStoreMut,
|
||||
imports: &Imports,
|
||||
) -> Result<(StoreHandle<WebAssembly::Instance>, Vec<Extern>), RuntimeError> {
|
||||
) -> Result<WebAssembly::Instance, RuntimeError> {
|
||||
// Ensure all imports come from the same store.
|
||||
if imports
|
||||
.into_iter()
|
||||
@@ -232,46 +273,10 @@ impl Module {
|
||||
InstantiationError::DifferentStores,
|
||||
)));
|
||||
}
|
||||
let imports_object = js_sys::Object::new();
|
||||
let mut import_externs: Vec<Extern> = vec![];
|
||||
for import_type in self.imports() {
|
||||
let resolved_import = imports.get_export(import_type.module(), import_type.name());
|
||||
if let Some(import) = resolved_import {
|
||||
let val = js_sys::Reflect::get(&imports_object, &import_type.module().into())?;
|
||||
if !val.is_undefined() {
|
||||
// If the namespace is already set
|
||||
js_sys::Reflect::set(
|
||||
&val,
|
||||
&import_type.name().into(),
|
||||
&import.as_jsvalue(&store.as_store_ref()),
|
||||
)?;
|
||||
} else {
|
||||
// If the namespace doesn't exist
|
||||
let import_namespace = js_sys::Object::new();
|
||||
js_sys::Reflect::set(
|
||||
&import_namespace,
|
||||
&import_type.name().into(),
|
||||
&import.as_jsvalue(&store.as_store_ref()),
|
||||
)?;
|
||||
js_sys::Reflect::set(
|
||||
&imports_object,
|
||||
&import_type.module().into(),
|
||||
&import_namespace.into(),
|
||||
)?;
|
||||
}
|
||||
import_externs.push(import);
|
||||
}
|
||||
// in case the import is not found, the JS Wasm VM will handle
|
||||
// the error for us, so we don't need to handle it
|
||||
}
|
||||
Ok((
|
||||
StoreHandle::new(
|
||||
store.as_store_mut().objects_mut(),
|
||||
WebAssembly::Instance::new(&self.module, &imports_object)
|
||||
.map_err(|e: JsValue| -> RuntimeError { e.into() })?,
|
||||
),
|
||||
import_externs,
|
||||
))
|
||||
|
||||
let imports_js_obj = imports.as_jsvalue(store).into();
|
||||
Ok(WebAssembly::Instance::new(&self.module, &imports_js_obj)
|
||||
.map_err(|e: JsValue| -> RuntimeError { e.into() })?)
|
||||
}
|
||||
|
||||
/// Returns the name of the current module.
|
||||
@@ -300,7 +305,7 @@ impl Module {
|
||||
/// can later process via [`Module::deserialize`].
|
||||
///
|
||||
#[cfg(feature = "js-serializable-module")]
|
||||
pub fn serialize(&self) -> Result<Vec<u8>, SerializeError> {
|
||||
pub fn serialize(&self) -> Result<Bytes, SerializeError> {
|
||||
self.raw_bytes.clone().ok_or(SerializeError::Generic(
|
||||
"Not able to serialize module".to_string(),
|
||||
))
|
||||
@@ -313,11 +318,38 @@ 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))
|
||||
}
|
||||
|
||||
#[cfg(feature = "compiler")]
|
||||
/// Deserializes a a serialized Module located in a `Path` into a `Module`.
|
||||
/// > Note: the module has to be serialized before with the `serialize` method.
|
||||
///
|
||||
/// # Safety
|
||||
///
|
||||
/// Please check [`Module::deserialize`].
|
||||
///
|
||||
/// # Usage
|
||||
///
|
||||
/// ```ignore
|
||||
/// # use wasmer::*;
|
||||
/// # let mut store = Store::default();
|
||||
/// # fn main() -> anyhow::Result<()> {
|
||||
/// let module = Module::deserialize_from_file(&store, path)?;
|
||||
/// # Ok(())
|
||||
/// # }
|
||||
/// ```
|
||||
pub unsafe fn deserialize_from_file(
|
||||
store: &impl AsStoreRef,
|
||||
path: impl AsRef<Path>,
|
||||
) -> Result<Self, DeserializeError> {
|
||||
let artifact = std::fs::read(path.as_ref())?;
|
||||
Ok(Self::new(store, bytes).map_err(|e| DeserializeError::Compiler(e)))
|
||||
}
|
||||
|
||||
/// Sets the name of the current module.
|
||||
/// This is normally useful for stacktraces and debugging.
|
||||
///
|
||||
@@ -525,16 +557,26 @@ impl Module {
|
||||
ExportsIterator::new(iter, exports.length() as usize)
|
||||
}
|
||||
|
||||
// /// Get the custom sections of the module given a `name`.
|
||||
// ///
|
||||
// /// # Important
|
||||
// ///
|
||||
// /// Following the WebAssembly spec, one name can have multiple
|
||||
// /// custom sections. That's why an iterator (rather than one element)
|
||||
// /// is returned.
|
||||
// pub fn custom_sections<'a>(&'a self, name: &'a str) -> impl Iterator<Item = Arc<[u8]>> + 'a {
|
||||
// unimplemented!();
|
||||
// }
|
||||
/// Get the custom sections of the module given a `name`.
|
||||
///
|
||||
/// # Important
|
||||
///
|
||||
/// Following the WebAssembly spec, one name can have multiple
|
||||
/// custom sections. That's why an iterator (rather than one element)
|
||||
/// is returned.
|
||||
pub fn custom_sections<'a>(&'a self, name: &'a str) -> impl Iterator<Item = Box<[u8]>> + 'a {
|
||||
// TODO: implement on JavaScript
|
||||
DefaultCustomSectionsIterator {}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct DefaultCustomSectionsIterator {}
|
||||
|
||||
impl Iterator for DefaultCustomSectionsIterator {
|
||||
type Item = Box<[u8]>;
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Debug for Module {
|
||||
|
||||
@@ -114,6 +114,28 @@ impl NativeWasmTypeInto for f64 {
|
||||
}
|
||||
}
|
||||
|
||||
impl NativeWasmTypeInto for u128 {
|
||||
#[inline]
|
||||
unsafe fn from_abi(_store: &mut impl AsStoreMut, abi: Self::Abi) -> Self {
|
||||
abi
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn into_abi(self, _store: &mut impl AsStoreMut) -> Self::Abi {
|
||||
self
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn into_raw(self, _store: &mut impl AsStoreMut) -> f64 {
|
||||
self as _
|
||||
}
|
||||
|
||||
#[inline]
|
||||
unsafe fn from_raw(_store: &mut impl AsStoreMut, raw: f64) -> Self {
|
||||
raw as _
|
||||
}
|
||||
}
|
||||
|
||||
impl NativeWasmType for Function {
|
||||
const WASM_TYPE: Type = Type::FuncRef;
|
||||
type Abi = f64;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
use crate::js::NativeWasmTypeInto;
|
||||
use crate::js::{externals::MemoryView, FromToNativeWasmType};
|
||||
use crate::js::{MemoryAccessError, WasmRef, WasmSlice};
|
||||
use crate::{js::NativeWasmTypeInto, AsStoreRef};
|
||||
use std::convert::TryFrom;
|
||||
use std::{fmt, marker::PhantomData, mem};
|
||||
pub use wasmer_types::Memory32;
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -234,6 +234,10 @@ where
|
||||
_phantom: PhantomData,
|
||||
}
|
||||
}
|
||||
#[inline]
|
||||
fn is_from_store(&self, _store: &impl AsStoreRef) -> bool {
|
||||
true // in Javascript there are no different stores
|
||||
}
|
||||
}
|
||||
|
||||
unsafe impl<T: ValueType, M: MemorySize> ValueType for WasmPtr<T, M> {
|
||||
|
||||
@@ -43,6 +43,7 @@ impl AsJs for Value {
|
||||
Self::I64(i) => JsValue::from_f64(*i as f64),
|
||||
Self::F32(f) => JsValue::from_f64(*f as f64),
|
||||
Self::F64(f) => JsValue::from_f64(*f),
|
||||
Self::V128(f) => JsValue::from_f64(*f as f64),
|
||||
Self::FuncRef(Some(func)) => func
|
||||
.handle
|
||||
.get(store.as_store_ref().objects())
|
||||
|
||||
@@ -7,7 +7,7 @@ use wasmer_types::Type;
|
||||
//use crate::ExternRef;
|
||||
use crate::js::externals::function::Function;
|
||||
|
||||
use super::store::AsStoreRef;
|
||||
use super::store::{AsStoreMut, AsStoreRef};
|
||||
|
||||
/// WebAssembly computations manipulate values of basic value types:
|
||||
/// * Integers (32 or 64 bit width)
|
||||
@@ -37,6 +37,9 @@ pub enum Value {
|
||||
|
||||
/// A first-class reference to a WebAssembly function.
|
||||
FuncRef(Option<Function>),
|
||||
|
||||
/// A 128-bit number
|
||||
V128(u128),
|
||||
}
|
||||
|
||||
macro_rules! accessors {
|
||||
@@ -76,6 +79,7 @@ impl Value {
|
||||
Self::I64(_) => Type::I64,
|
||||
Self::F32(_) => Type::F32,
|
||||
Self::F64(_) => Type::F64,
|
||||
Self::V128(_) => Type::V128,
|
||||
//Self::ExternRef(_) => Type::ExternRef,
|
||||
Self::FuncRef(_) => Type::FuncRef,
|
||||
}
|
||||
@@ -88,6 +92,7 @@ impl Value {
|
||||
Self::I64(v) => v as f64,
|
||||
Self::F32(v) => v as f64,
|
||||
Self::F64(v) => v,
|
||||
Self::V128(v) => v as f64,
|
||||
Self::FuncRef(Some(ref f)) => f
|
||||
.handle
|
||||
.get(store.as_store_ref().objects())
|
||||
@@ -107,12 +112,12 @@ impl Value {
|
||||
///
|
||||
pub unsafe fn from_raw(_store: &impl AsStoreRef, ty: Type, raw: f64) -> Self {
|
||||
match ty {
|
||||
Type::I32 => Self::I32(raw as i32),
|
||||
Type::I64 => Self::I64(raw as i64),
|
||||
Type::F32 => Self::F32(raw as f32),
|
||||
Type::I32 => Self::I32(raw as _),
|
||||
Type::I64 => Self::I64(raw as _),
|
||||
Type::F32 => Self::F32(raw as _),
|
||||
Type::F64 => Self::F64(raw),
|
||||
Type::V128 => Self::V128(raw as _),
|
||||
Type::FuncRef => todo!(),
|
||||
Type::V128 => todo!(),
|
||||
Type::ExternRef => todo!(),
|
||||
//Self::ExternRef(
|
||||
//{
|
||||
@@ -134,6 +139,7 @@ impl Value {
|
||||
| Self::I64(_)
|
||||
| Self::F32(_)
|
||||
| Self::F64(_)
|
||||
| Self::V128(_)
|
||||
//| Self::ExternRef(None)
|
||||
| Self::FuncRef(None) => true,
|
||||
//Self::ExternRef(Some(e)) => e.is_from_store(store),
|
||||
@@ -147,6 +153,7 @@ impl Value {
|
||||
(I64(i64) i64 unwrap_i64 *e)
|
||||
(F32(f32) f32 unwrap_f32 *e)
|
||||
(F64(f64) f64 unwrap_f64 *e)
|
||||
(V128(u128) v128 unwrap_v128 *e)
|
||||
//(ExternRef(&Option<ExternRef>) externref unwrap_externref e)
|
||||
(FuncRef(&Option<Function>) funcref unwrap_funcref e)
|
||||
}
|
||||
@@ -159,6 +166,7 @@ impl fmt::Debug for Value {
|
||||
Self::I64(v) => write!(f, "I64({:?})", v),
|
||||
Self::F32(v) => write!(f, "F32({:?})", v),
|
||||
Self::F64(v) => write!(f, "F64({:?})", v),
|
||||
Self::V128(v) => write!(f, "V128({:?})", v),
|
||||
//Self::ExternRef(None) => write!(f, "Null ExternRef"),
|
||||
//Self::ExternRef(Some(v)) => write!(f, "ExternRef({:?})", v),
|
||||
Self::FuncRef(None) => write!(f, "Null FuncRef"),
|
||||
@@ -174,12 +182,19 @@ impl ToString for Value {
|
||||
Self::I64(v) => v.to_string(),
|
||||
Self::F32(v) => v.to_string(),
|
||||
Self::F64(v) => v.to_string(),
|
||||
Self::V128(v) => v.to_string(),
|
||||
//Self::ExternRef(_) => "externref".to_string(),
|
||||
Self::FuncRef(_) => "funcref".to_string(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<u128> for Value {
|
||||
fn from(val: u128) -> Self {
|
||||
Self::V128(val)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<i32> for Value {
|
||||
fn from(val: i32) -> Self {
|
||||
Self::I32(val)
|
||||
@@ -246,9 +261,18 @@ const NOT_I32: &str = "Value is not of Wasm type i32";
|
||||
const NOT_I64: &str = "Value is not of Wasm type i64";
|
||||
const NOT_F32: &str = "Value is not of Wasm type f32";
|
||||
const NOT_F64: &str = "Value is not of Wasm type f64";
|
||||
const NOT_V128: &str = "Value is not of Wasm type u128";
|
||||
const NOT_FUNCREF: &str = "Value is not of Wasm type funcref";
|
||||
//const NOT_EXTERNREF: &str = "Value is not of Wasm type externref";
|
||||
|
||||
impl TryFrom<Value> for u128 {
|
||||
type Error = &'static str;
|
||||
|
||||
fn try_from(value: Value) -> Result<Self, Self::Error> {
|
||||
value.v128().ok_or(NOT_V128)
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<Value> for i32 {
|
||||
type Error = &'static str;
|
||||
|
||||
|
||||
10
lib/api/src/sys/externals/function.rs
vendored
10
lib/api/src/sys/externals/function.rs
vendored
@@ -204,6 +204,7 @@ impl Function {
|
||||
Rets: WasmTypeList,
|
||||
{
|
||||
let env = FunctionEnv::new(store, ());
|
||||
let func_ptr = func.function_body_ptr();
|
||||
let host_data = Box::new(StaticFunction {
|
||||
raw_store: store.as_store_mut().as_raw() as *mut u8,
|
||||
env,
|
||||
@@ -211,7 +212,6 @@ impl Function {
|
||||
});
|
||||
let function_type = FunctionType::new(Args::wasm_types(), Rets::wasm_types());
|
||||
|
||||
let func_ptr = <F as HostFunction<(), Args, Rets, WithoutEnv>>::function_body_ptr();
|
||||
let type_index = store
|
||||
.as_store_mut()
|
||||
.engine()
|
||||
@@ -289,6 +289,7 @@ impl Function {
|
||||
{
|
||||
// println!("new native {:p}", &new_env);
|
||||
|
||||
let func_ptr = func.function_body_ptr();
|
||||
let host_data = Box::new(StaticFunction {
|
||||
raw_store: store.as_store_mut().as_raw() as *mut u8,
|
||||
env: env.clone(),
|
||||
@@ -296,7 +297,6 @@ impl Function {
|
||||
});
|
||||
let function_type = FunctionType::new(Args::wasm_types(), Rets::wasm_types());
|
||||
|
||||
let func_ptr = <F as HostFunction<T, Args, Rets, WithEnv>>::function_body_ptr();
|
||||
let type_index = store
|
||||
.as_store_mut()
|
||||
.engine()
|
||||
@@ -1092,7 +1092,7 @@ mod inner {
|
||||
Kind: HostFunctionKind,
|
||||
{
|
||||
/// Get the pointer to the function body.
|
||||
fn function_body_ptr() -> *const VMFunctionBody;
|
||||
fn function_body_ptr(&self) -> *const VMFunctionBody;
|
||||
|
||||
/// Get the pointer to the function call trampoline.
|
||||
fn call_trampoline_address() -> VMTrampoline;
|
||||
@@ -1268,7 +1268,7 @@ mod inner {
|
||||
Func: Fn(FunctionEnvMut<T>, $( $x , )*) -> RetsAsResult + 'static,
|
||||
{
|
||||
#[allow(non_snake_case)]
|
||||
fn function_body_ptr() -> *const VMFunctionBody {
|
||||
fn function_body_ptr(&self) -> *const VMFunctionBody {
|
||||
/// This is a function that wraps the real host
|
||||
/// function. Its address will be used inside the
|
||||
/// runtime.
|
||||
@@ -1352,7 +1352,7 @@ mod inner {
|
||||
Func: Fn($( $x , )*) -> RetsAsResult + 'static,
|
||||
{
|
||||
#[allow(non_snake_case)]
|
||||
fn function_body_ptr() -> *const VMFunctionBody {
|
||||
fn function_body_ptr(&self) -> *const VMFunctionBody {
|
||||
/// This is a function that wraps the real host
|
||||
/// function. Its address will be used inside the
|
||||
/// runtime.
|
||||
|
||||
1
lib/api/src/sys/externals/memory.rs
vendored
1
lib/api/src/sys/externals/memory.rs
vendored
@@ -154,6 +154,7 @@ impl Memory {
|
||||
mem.try_clone().map(|mem| mem.into())
|
||||
}
|
||||
|
||||
/// To `VMExtern`.
|
||||
pub(crate) fn to_vm_extern(&self) -> VMExtern {
|
||||
VMExtern::Memory(self.handle.internal_handle())
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
{
|
||||
@@ -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 {
|
||||
|
||||
@@ -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<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
|
||||
@@ -124,7 +166,6 @@ impl Module {
|
||||
e
|
||||
)))
|
||||
})?;
|
||||
|
||||
Self::from_binary(store, bytes.as_ref())
|
||||
}
|
||||
|
||||
@@ -206,8 +247,8 @@ impl Module {
|
||||
/// # Ok(())
|
||||
/// # }
|
||||
/// ```
|
||||
pub fn serialize(&self) -> Result<Vec<u8>, SerializeError> {
|
||||
self.artifact.serialize()
|
||||
pub fn serialize(&self) -> Result<Bytes, SerializeError> {
|
||||
self.artifact.serialize().map(|bytes| bytes.into())
|
||||
}
|
||||
|
||||
/// Serializes a module into a file that the `Engine`
|
||||
@@ -254,9 +295,10 @@ impl Module {
|
||||
/// ```
|
||||
pub unsafe fn deserialize(
|
||||
store: &impl AsStoreRef,
|
||||
bytes: &[u8],
|
||||
bytes: impl IntoBytes,
|
||||
) -> Result<Self, DeserializeError> {
|
||||
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))
|
||||
}
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@ use wasmer_types::RawValue;
|
||||
/// A WebAssembly function that can be called natively
|
||||
/// (using the Native ABI).
|
||||
pub struct TypedFunction<Args, Rets> {
|
||||
func: Function,
|
||||
pub(crate) func: Function,
|
||||
_phantom: PhantomData<fn(Args) -> Rets>,
|
||||
}
|
||||
|
||||
@@ -45,16 +45,6 @@ impl<Args: WasmTypeList, Rets: WasmTypeList> Clone for TypedFunction<Args, Rets>
|
||||
}
|
||||
}
|
||||
|
||||
impl<Args, Rets> From<TypedFunction<Args, Rets>> for Function
|
||||
where
|
||||
Args: WasmTypeList,
|
||||
Rets: WasmTypeList,
|
||||
{
|
||||
fn from(other: TypedFunction<Args, Rets>) -> Self {
|
||||
other.func
|
||||
}
|
||||
}
|
||||
|
||||
macro_rules! impl_native_traits {
|
||||
( $( $x:ident ),* ) => {
|
||||
#[allow(unused_parens, non_snake_case)]
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
use wasmer_types::{NativeWasmType, RawValue, Type};
|
||||
use wasmer_vm::{VMExternRef, VMFuncRef};
|
||||
|
||||
use crate::{ExternRef, Function};
|
||||
use crate::{ExternRef, Function, TypedFunction, WasmTypeList};
|
||||
|
||||
use super::store::AsStoreMut;
|
||||
|
||||
@@ -165,6 +165,16 @@ impl NativeWasmTypeInto for Option<ExternRef> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<Args, Rets> From<TypedFunction<Args, Rets>> for Function
|
||||
where
|
||||
Args: WasmTypeList,
|
||||
Rets: WasmTypeList,
|
||||
{
|
||||
fn from(other: TypedFunction<Args, Rets>) -> Self {
|
||||
other.func
|
||||
}
|
||||
}
|
||||
|
||||
impl NativeWasmType for Function {
|
||||
const WASM_TYPE: Type = Type::FuncRef;
|
||||
type Abi = usize;
|
||||
|
||||
@@ -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
|
||||
}
|
||||
|
||||
|
||||
@@ -29,7 +29,7 @@ mod js {
|
||||
fn global_get() {
|
||||
let mut store = Store::default();
|
||||
let global_i32 = Global::new(&mut store, Value::I32(10));
|
||||
assert_eq!(global_i32.get(&store), Value::I32(10));
|
||||
assert_eq!(global_i32.get(&mut store), Value::I32(10));
|
||||
// 64-bit values are not yet fully supported in some versions of Node
|
||||
// Commenting this tests for now:
|
||||
|
||||
|
||||
@@ -92,6 +92,61 @@ mod js {
|
||||
assert_eq!(get_magic.call(&mut store, &[]).unwrap(), expected);
|
||||
}
|
||||
|
||||
#[wasm_bindgen_test]
|
||||
fn test_imports_from_js_object() {
|
||||
let mut store = Store::default();
|
||||
let mut module = Module::new(
|
||||
&store,
|
||||
br#"
|
||||
(module
|
||||
(func $imported (import "env" "imported") (param i32) (result i32))
|
||||
(func (export "exported") (param i32) (result i32)
|
||||
(call $imported (local.get 0))
|
||||
)
|
||||
)
|
||||
"#,
|
||||
)
|
||||
.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],
|
||||
))],
|
||||
})
|
||||
.unwrap();
|
||||
|
||||
let obj: js_sys::Object = js_sys::Function::new_with_args(
|
||||
"",
|
||||
"return {
|
||||
\"env\": {
|
||||
\"imported\": function(num) {
|
||||
console.log(\"Calling `imported`...\");
|
||||
var result = num * 2;
|
||||
console.log(\"Result of `imported`: \", result);
|
||||
return result;
|
||||
}
|
||||
}
|
||||
};",
|
||||
)
|
||||
.call0(&wasm_bindgen::JsValue::UNDEFINED)
|
||||
.unwrap()
|
||||
.into();
|
||||
|
||||
let import_object = Imports::new_from_js_object(&mut store, &module, obj)
|
||||
.expect("Can't get imports from js object");
|
||||
let instance = Instance::new(&mut store, &module, &import_object).unwrap();
|
||||
|
||||
let exported = instance.exports.get_function("exported").unwrap();
|
||||
|
||||
let expected = vec![Val::I32(6)].into_boxed_slice();
|
||||
assert_eq!(exported.call(&mut store, &[Val::I32(3)]).unwrap(), expected);
|
||||
}
|
||||
|
||||
#[wasm_bindgen_test]
|
||||
fn test_imported_function_dynamic() {
|
||||
let mut store = Store::default();
|
||||
|
||||
@@ -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)]
|
||||
|
||||
@@ -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() {
|
||||
|
||||
@@ -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);
|
||||
@@ -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)
|
||||
|
||||
@@ -7,11 +7,7 @@ license = "MIT"
|
||||
edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
libc = { version = "^0.2", default-features = false, optional = true }
|
||||
thiserror = "1"
|
||||
tracing = { version = "0.1" }
|
||||
typetag = { version = "0.1", optional = true }
|
||||
slab = { version = "0.4", optional = true }
|
||||
wasmer-vfs = { path = "../vfs", version = "=3.0.0-beta", default-features = false }
|
||||
|
||||
[features]
|
||||
|
||||
@@ -7,11 +7,7 @@ license = "MIT"
|
||||
edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
libc = { version = "^0.2", default-features = false, optional = true }
|
||||
thiserror = "1"
|
||||
tracing = { version = "0.1" }
|
||||
typetag = { version = "0.1", optional = true }
|
||||
slab = { version = "0.4", optional = true }
|
||||
wasmer-vfs = { path = "../vfs", version = "=3.0.0-beta", default-features = false }
|
||||
bytes = "1"
|
||||
|
||||
|
||||
@@ -44,8 +44,9 @@ tracing-wasm = "0.2"
|
||||
|
||||
[features]
|
||||
default = ["sys-default"]
|
||||
wasix = []
|
||||
|
||||
sys = ["wasmer/sys"]
|
||||
sys = ["wasmer/sys", "wasix"]
|
||||
sys-default = ["wasmer/wat", "wasmer/compiler", "sys", "logging", "host-fs", "sys-poll", "host-vnet" ]
|
||||
sys-poll = []
|
||||
|
||||
|
||||
@@ -47,9 +47,9 @@ pub use crate::state::{
|
||||
WasiStateCreationError, ALL_RIGHTS, VIRTUAL_ROOT_FD,
|
||||
};
|
||||
pub use crate::syscalls::types;
|
||||
pub use crate::utils::{
|
||||
get_wasi_version, get_wasi_versions, is_wasi_module, is_wasix_module, WasiVersion,
|
||||
};
|
||||
#[cfg(feature = "wasix")]
|
||||
pub use crate::utils::is_wasix_module;
|
||||
pub use crate::utils::{get_wasi_version, get_wasi_versions, is_wasi_module, WasiVersion};
|
||||
pub use wasmer_vbus::{UnsupportedVirtualBus, VirtualBus};
|
||||
#[deprecated(since = "2.1.0", note = "Please use `wasmer_vfs::FsError`")]
|
||||
pub use wasmer_vfs::FsError as WasiFsError;
|
||||
@@ -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(
|
||||
@@ -184,6 +213,7 @@ impl WasiFunctionEnv {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "wasix")]
|
||||
if is_wasix_module(module) {
|
||||
self.data_mut(store)
|
||||
.state
|
||||
@@ -394,8 +424,12 @@ pub fn generate_import_object_from_env(
|
||||
WasiVersion::Snapshot1 | WasiVersion::Latest => {
|
||||
generate_import_object_snapshot1(store, env)
|
||||
}
|
||||
#[cfg(feature = "wasix")]
|
||||
WasiVersion::Wasix32v1 => generate_import_object_wasix32_v1(store, env),
|
||||
#[cfg(feature = "wasix")]
|
||||
WasiVersion::Wasix64v1 => generate_import_object_wasix64_v1(store, env),
|
||||
#[cfg(not(feature = "wasix"))]
|
||||
_ => unimplemented!(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -537,6 +571,7 @@ fn generate_import_object_snapshot1(
|
||||
}
|
||||
|
||||
/// Combines a state generating function with the import list for snapshot 1
|
||||
#[cfg(feature = "wasix")]
|
||||
fn generate_import_object_wasix32_v1(
|
||||
mut store: &mut impl AsStoreMut,
|
||||
env: &FunctionEnv<WasiEnv>,
|
||||
@@ -655,6 +690,7 @@ fn generate_import_object_wasix32_v1(
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "wasix")]
|
||||
fn generate_import_object_wasix64_v1(
|
||||
mut store: &mut impl AsStoreMut,
|
||||
env: &FunctionEnv<WasiEnv>,
|
||||
|
||||
@@ -18,7 +18,9 @@ pub mod windows;
|
||||
|
||||
pub mod legacy;
|
||||
//pub mod wasi;
|
||||
#[cfg(feature = "wasix")]
|
||||
pub mod wasix32;
|
||||
#[cfg(feature = "wasix")]
|
||||
pub mod wasix64;
|
||||
|
||||
use self::types::*;
|
||||
|
||||
@@ -10,6 +10,7 @@ pub fn is_wasi_module(module: &Module) -> bool {
|
||||
}
|
||||
|
||||
#[allow(dead_code)]
|
||||
#[cfg(feature = "wasix")]
|
||||
/// Returns if the module is WASIX or not
|
||||
pub fn is_wasix_module(module: &Module) -> bool {
|
||||
match get_wasi_versions(module, false).ok_or(false) {
|
||||
|
||||
@@ -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::<Vec<_>>(),
|
||||
|
||||
Reference in New Issue
Block a user