Refactor (#1524)
* Compute instance exports on demand. Instead having instances eagerly compute a Vec of Externs, and bumping the refcount for each Extern, compute Externs on demand. This also enables `Instance::get_export` to avoid doing a linear search. This also means that the closure returned by `get0` and friends now holds an `InstanceHandle` to dynamically hold the instance live rather than being scoped to a lifetime. * Compute module imports and exports on demand too. And compute Extern::ty on demand too. * Add a utility function for computing an ExternType. * Add a utility function for looking up a function's signature. * Add a utility function for computing the ValType of a Global. * Rename wasmtime_environ::Export to EntityIndex. This helps differentiate it from other Export types in the tree, and describes what it is. * Fix a typo in a comment. * Simplify module imports and exports. * Make `Instance::exports` return the export names. This significantly simplifies the public API, as it's relatively common to need the names, and this avoids the need to do a zip with `Module::exports`. This also changes `ImportType` and `ExportType` to have public members instead of private members and accessors, as I find that simplifies the usage particularly in cases where there are temporary instances. * Remove `Instance::module`. This doesn't quite remove `Instance`'s `module` member, it gets a step closer. * Use a InstanceHandle utility function. * Don't consume self in the `Func::get*` methods. Instead, just create a closure containing the instance handle and the export for them to call. * Use `ExactSizeIterator` to avoid needing separate `num_*` methods. * Rename `Extern::func()` etc. to `into_func()` etc. * Revise examples to avoid using `nth`. * Add convenience methods to instance for getting specific extern types. * Use the convenience functions in more tests and examples. * Avoid cloning strings for `ImportType` and `ExportType`. * Remove more obviated clone() calls. * Simplify `Func`'s closure state. * Make wasmtime::Export's fields private. This makes them more consistent with ExportType. * Fix compilation error. * Make a lifetime parameter explicit, and use better lifetime names. Instead of 'me, use 'instance and 'module to make it clear what the lifetime is. * More lifetime cleanups.
This commit is contained in:
@@ -68,7 +68,7 @@ pub struct ElemIndex(u32);
|
|||||||
entity_impl!(ElemIndex);
|
entity_impl!(ElemIndex);
|
||||||
|
|
||||||
/// WebAssembly global.
|
/// WebAssembly global.
|
||||||
#[derive(Debug, Clone, Copy, Hash)]
|
#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq)]
|
||||||
pub struct Global {
|
pub struct Global {
|
||||||
/// The type of the value stored in the global.
|
/// The type of the value stored in the global.
|
||||||
pub ty: ir::Type,
|
pub ty: ir::Type,
|
||||||
@@ -79,7 +79,7 @@ pub struct Global {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Globals are initialized via the `const` operators or by referring to another import.
|
/// Globals are initialized via the `const` operators or by referring to another import.
|
||||||
#[derive(Debug, Clone, Copy, Hash)]
|
#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq)]
|
||||||
pub enum GlobalInit {
|
pub enum GlobalInit {
|
||||||
/// An `i32.const`.
|
/// An `i32.const`.
|
||||||
I32Const(i32),
|
I32Const(i32),
|
||||||
@@ -102,7 +102,7 @@ pub enum GlobalInit {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// WebAssembly table.
|
/// WebAssembly table.
|
||||||
#[derive(Debug, Clone, Copy, Hash)]
|
#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq)]
|
||||||
pub struct Table {
|
pub struct Table {
|
||||||
/// The type of data stored in elements of the table.
|
/// The type of data stored in elements of the table.
|
||||||
pub ty: TableElementType,
|
pub ty: TableElementType,
|
||||||
@@ -113,7 +113,7 @@ pub struct Table {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// WebAssembly table element. Can be a function or a scalar type.
|
/// WebAssembly table element. Can be a function or a scalar type.
|
||||||
#[derive(Debug, Clone, Copy, Hash)]
|
#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq)]
|
||||||
pub enum TableElementType {
|
pub enum TableElementType {
|
||||||
/// A scalar type.
|
/// A scalar type.
|
||||||
Val(ir::Type),
|
Val(ir::Type),
|
||||||
@@ -122,7 +122,7 @@ pub enum TableElementType {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// WebAssembly linear memory.
|
/// WebAssembly linear memory.
|
||||||
#[derive(Debug, Clone, Copy, Hash)]
|
#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq)]
|
||||||
pub struct Memory {
|
pub struct Memory {
|
||||||
/// The minimum number of pages in the memory.
|
/// The minimum number of pages in the memory.
|
||||||
pub minimum: u32,
|
pub minimum: u32,
|
||||||
|
|||||||
@@ -34,7 +34,7 @@ impl Extern {
|
|||||||
/// Returns the underlying `Func`, if this external is a function.
|
/// Returns the underlying `Func`, if this external is a function.
|
||||||
///
|
///
|
||||||
/// Returns `None` if this is not a function.
|
/// Returns `None` if this is not a function.
|
||||||
pub fn func(&self) -> Option<&Func> {
|
pub fn into_func(self) -> Option<Func> {
|
||||||
match self {
|
match self {
|
||||||
Extern::Func(func) => Some(func),
|
Extern::Func(func) => Some(func),
|
||||||
_ => None,
|
_ => None,
|
||||||
@@ -44,7 +44,7 @@ impl Extern {
|
|||||||
/// Returns the underlying `Global`, if this external is a global.
|
/// Returns the underlying `Global`, if this external is a global.
|
||||||
///
|
///
|
||||||
/// Returns `None` if this is not a global.
|
/// Returns `None` if this is not a global.
|
||||||
pub fn global(&self) -> Option<&Global> {
|
pub fn into_global(self) -> Option<Global> {
|
||||||
match self {
|
match self {
|
||||||
Extern::Global(global) => Some(global),
|
Extern::Global(global) => Some(global),
|
||||||
_ => None,
|
_ => None,
|
||||||
@@ -54,7 +54,7 @@ impl Extern {
|
|||||||
/// Returns the underlying `Table`, if this external is a table.
|
/// Returns the underlying `Table`, if this external is a table.
|
||||||
///
|
///
|
||||||
/// Returns `None` if this is not a table.
|
/// Returns `None` if this is not a table.
|
||||||
pub fn table(&self) -> Option<&Table> {
|
pub fn into_table(self) -> Option<Table> {
|
||||||
match self {
|
match self {
|
||||||
Extern::Table(table) => Some(table),
|
Extern::Table(table) => Some(table),
|
||||||
_ => None,
|
_ => None,
|
||||||
@@ -64,7 +64,7 @@ impl Extern {
|
|||||||
/// Returns the underlying `Memory`, if this external is a memory.
|
/// Returns the underlying `Memory`, if this external is a memory.
|
||||||
///
|
///
|
||||||
/// Returns `None` if this is not a memory.
|
/// Returns `None` if this is not a memory.
|
||||||
pub fn memory(&self) -> Option<&Memory> {
|
pub fn into_memory(self) -> Option<Memory> {
|
||||||
match self {
|
match self {
|
||||||
Extern::Memory(memory) => Some(memory),
|
Extern::Memory(memory) => Some(memory),
|
||||||
_ => None,
|
_ => None,
|
||||||
@@ -74,10 +74,10 @@ impl Extern {
|
|||||||
/// Returns the type associated with this `Extern`.
|
/// Returns the type associated with this `Extern`.
|
||||||
pub fn ty(&self) -> ExternType {
|
pub fn ty(&self) -> ExternType {
|
||||||
match self {
|
match self {
|
||||||
Extern::Func(ft) => ExternType::Func(ft.ty().clone()),
|
Extern::Func(ft) => ExternType::Func(ft.ty()),
|
||||||
Extern::Memory(ft) => ExternType::Memory(ft.ty().clone()),
|
Extern::Memory(ft) => ExternType::Memory(ft.ty()),
|
||||||
Extern::Table(tt) => ExternType::Table(tt.ty().clone()),
|
Extern::Table(tt) => ExternType::Table(tt.ty()),
|
||||||
Extern::Global(gt) => ExternType::Global(gt.ty().clone()),
|
Extern::Global(gt) => ExternType::Global(gt.ty()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -91,11 +91,11 @@ impl Extern {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn from_wasmtime_export(
|
pub(crate) fn from_wasmtime_export(
|
||||||
|
wasmtime_export: wasmtime_runtime::Export,
|
||||||
store: &Store,
|
store: &Store,
|
||||||
instance_handle: InstanceHandle,
|
instance_handle: InstanceHandle,
|
||||||
export: wasmtime_runtime::Export,
|
|
||||||
) -> Extern {
|
) -> Extern {
|
||||||
match export {
|
match wasmtime_export {
|
||||||
wasmtime_runtime::Export::Function(f) => {
|
wasmtime_runtime::Export::Function(f) => {
|
||||||
Extern::Func(Func::from_wasmtime_function(f, store, instance_handle))
|
Extern::Func(Func::from_wasmtime_function(f, store, instance_handle))
|
||||||
}
|
}
|
||||||
@@ -164,7 +164,6 @@ impl From<Table> for Extern {
|
|||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct Global {
|
pub struct Global {
|
||||||
store: Store,
|
store: Store,
|
||||||
ty: GlobalType,
|
|
||||||
wasmtime_export: wasmtime_runtime::ExportGlobal,
|
wasmtime_export: wasmtime_runtime::ExportGlobal,
|
||||||
wasmtime_handle: InstanceHandle,
|
wasmtime_handle: InstanceHandle,
|
||||||
}
|
}
|
||||||
@@ -191,27 +190,44 @@ impl Global {
|
|||||||
let (wasmtime_handle, wasmtime_export) = generate_global_export(store, &ty, val)?;
|
let (wasmtime_handle, wasmtime_export) = generate_global_export(store, &ty, val)?;
|
||||||
Ok(Global {
|
Ok(Global {
|
||||||
store: store.clone(),
|
store: store.clone(),
|
||||||
ty,
|
|
||||||
wasmtime_export,
|
wasmtime_export,
|
||||||
wasmtime_handle,
|
wasmtime_handle,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the underlying type of this `global`.
|
/// Returns the underlying type of this `global`.
|
||||||
pub fn ty(&self) -> &GlobalType {
|
pub fn ty(&self) -> GlobalType {
|
||||||
&self.ty
|
// The original export is coming from wasmtime_runtime itself we should
|
||||||
|
// support all the types coming out of it, so assert such here.
|
||||||
|
GlobalType::from_wasmtime_global(&self.wasmtime_export.global)
|
||||||
|
.expect("core wasm global type should be supported")
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the value type of this `global`.
|
||||||
|
pub fn val_type(&self) -> ValType {
|
||||||
|
ValType::from_wasmtime_type(self.wasmtime_export.global.ty)
|
||||||
|
.expect("core wasm type should be supported")
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the underlying mutability of this `global`.
|
||||||
|
pub fn mutability(&self) -> Mutability {
|
||||||
|
if self.wasmtime_export.global.mutability {
|
||||||
|
Mutability::Var
|
||||||
|
} else {
|
||||||
|
Mutability::Const
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the current [`Val`] of this global.
|
/// Returns the current [`Val`] of this global.
|
||||||
pub fn get(&self) -> Val {
|
pub fn get(&self) -> Val {
|
||||||
unsafe {
|
unsafe {
|
||||||
let definition = &mut *self.wasmtime_export.definition;
|
let definition = &mut *self.wasmtime_export.definition;
|
||||||
match self.ty().content() {
|
match self.val_type() {
|
||||||
ValType::I32 => Val::from(*definition.as_i32()),
|
ValType::I32 => Val::from(*definition.as_i32()),
|
||||||
ValType::I64 => Val::from(*definition.as_i64()),
|
ValType::I64 => Val::from(*definition.as_i64()),
|
||||||
ValType::F32 => Val::F32(*definition.as_u32()),
|
ValType::F32 => Val::F32(*definition.as_u32()),
|
||||||
ValType::F64 => Val::F64(*definition.as_u64()),
|
ValType::F64 => Val::F64(*definition.as_u64()),
|
||||||
_ => unimplemented!("Global::get for {:?}", self.ty().content()),
|
ty => unimplemented!("Global::get for {:?}", ty),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -223,15 +239,12 @@ impl Global {
|
|||||||
/// Returns an error if this global has a different type than `Val`, or if
|
/// Returns an error if this global has a different type than `Val`, or if
|
||||||
/// it's not a mutable global.
|
/// it's not a mutable global.
|
||||||
pub fn set(&self, val: Val) -> Result<()> {
|
pub fn set(&self, val: Val) -> Result<()> {
|
||||||
if self.ty().mutability() != Mutability::Var {
|
if self.mutability() != Mutability::Var {
|
||||||
bail!("immutable global cannot be set");
|
bail!("immutable global cannot be set");
|
||||||
}
|
}
|
||||||
if val.ty() != *self.ty().content() {
|
let ty = self.val_type();
|
||||||
bail!(
|
if val.ty() != ty {
|
||||||
"global of type {:?} cannot be set to {:?}",
|
bail!("global of type {:?} cannot be set to {:?}", ty, val.ty());
|
||||||
self.ty().content(),
|
|
||||||
val.ty()
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
if !val.comes_from_same_store(&self.store) {
|
if !val.comes_from_same_store(&self.store) {
|
||||||
bail!("cross-`Store` values are not supported");
|
bail!("cross-`Store` values are not supported");
|
||||||
@@ -254,13 +267,8 @@ impl Global {
|
|||||||
store: &Store,
|
store: &Store,
|
||||||
wasmtime_handle: InstanceHandle,
|
wasmtime_handle: InstanceHandle,
|
||||||
) -> Global {
|
) -> Global {
|
||||||
// The original export is coming from wasmtime_runtime itself we should
|
|
||||||
// support all the types coming out of it, so assert such here.
|
|
||||||
let ty = GlobalType::from_wasmtime_global(&wasmtime_export.global)
|
|
||||||
.expect("core wasm global type should be supported");
|
|
||||||
Global {
|
Global {
|
||||||
store: store.clone(),
|
store: store.clone(),
|
||||||
ty: ty,
|
|
||||||
wasmtime_export,
|
wasmtime_export,
|
||||||
wasmtime_handle,
|
wasmtime_handle,
|
||||||
}
|
}
|
||||||
@@ -285,7 +293,6 @@ impl Global {
|
|||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct Table {
|
pub struct Table {
|
||||||
store: Store,
|
store: Store,
|
||||||
ty: TableType,
|
|
||||||
wasmtime_handle: InstanceHandle,
|
wasmtime_handle: InstanceHandle,
|
||||||
wasmtime_export: wasmtime_runtime::ExportTable,
|
wasmtime_export: wasmtime_runtime::ExportTable,
|
||||||
}
|
}
|
||||||
@@ -326,7 +333,6 @@ impl Table {
|
|||||||
|
|
||||||
Ok(Table {
|
Ok(Table {
|
||||||
store: store.clone(),
|
store: store.clone(),
|
||||||
ty,
|
|
||||||
wasmtime_handle,
|
wasmtime_handle,
|
||||||
wasmtime_export,
|
wasmtime_export,
|
||||||
})
|
})
|
||||||
@@ -334,8 +340,8 @@ impl Table {
|
|||||||
|
|
||||||
/// Returns the underlying type of this table, including its element type as
|
/// Returns the underlying type of this table, including its element type as
|
||||||
/// well as the maximum/minimum lower bounds.
|
/// well as the maximum/minimum lower bounds.
|
||||||
pub fn ty(&self) -> &TableType {
|
pub fn ty(&self) -> TableType {
|
||||||
&self.ty
|
TableType::from_wasmtime_table(&self.wasmtime_export.table.table)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn wasmtime_table_index(&self) -> wasm::DefinedTableIndex {
|
fn wasmtime_table_index(&self) -> wasm::DefinedTableIndex {
|
||||||
@@ -368,7 +374,7 @@ impl Table {
|
|||||||
|
|
||||||
/// Returns the current size of this table.
|
/// Returns the current size of this table.
|
||||||
pub fn size(&self) -> u32 {
|
pub fn size(&self) -> u32 {
|
||||||
unsafe { (&*self.wasmtime_export.definition).current_elements }
|
unsafe { (*self.wasmtime_export.definition).current_elements }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Grows the size of this table by `delta` more elements, initialization
|
/// Grows the size of this table by `delta` more elements, initialization
|
||||||
@@ -432,10 +438,8 @@ impl Table {
|
|||||||
store: &Store,
|
store: &Store,
|
||||||
wasmtime_handle: wasmtime_runtime::InstanceHandle,
|
wasmtime_handle: wasmtime_runtime::InstanceHandle,
|
||||||
) -> Table {
|
) -> Table {
|
||||||
let ty = TableType::from_wasmtime_table(&wasmtime_export.table.table);
|
|
||||||
Table {
|
Table {
|
||||||
store: store.clone(),
|
store: store.clone(),
|
||||||
ty,
|
|
||||||
wasmtime_handle,
|
wasmtime_handle,
|
||||||
wasmtime_export,
|
wasmtime_export,
|
||||||
}
|
}
|
||||||
@@ -651,7 +655,6 @@ impl Table {
|
|||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct Memory {
|
pub struct Memory {
|
||||||
store: Store,
|
store: Store,
|
||||||
ty: MemoryType,
|
|
||||||
wasmtime_handle: InstanceHandle,
|
wasmtime_handle: InstanceHandle,
|
||||||
wasmtime_export: wasmtime_runtime::ExportMemory,
|
wasmtime_export: wasmtime_runtime::ExportMemory,
|
||||||
}
|
}
|
||||||
@@ -684,7 +687,6 @@ impl Memory {
|
|||||||
generate_memory_export(store, &ty).expect("generated memory");
|
generate_memory_export(store, &ty).expect("generated memory");
|
||||||
Memory {
|
Memory {
|
||||||
store: store.clone(),
|
store: store.clone(),
|
||||||
ty,
|
|
||||||
wasmtime_handle,
|
wasmtime_handle,
|
||||||
wasmtime_export,
|
wasmtime_export,
|
||||||
}
|
}
|
||||||
@@ -700,14 +702,14 @@ impl Memory {
|
|||||||
/// let store = Store::default();
|
/// let store = Store::default();
|
||||||
/// let module = Module::new(&store, "(module (memory (export \"mem\") 1))")?;
|
/// let module = Module::new(&store, "(module (memory (export \"mem\") 1))")?;
|
||||||
/// let instance = Instance::new(&module, &[])?;
|
/// let instance = Instance::new(&module, &[])?;
|
||||||
/// let memory = instance.get_export("mem").unwrap().memory().unwrap();
|
/// let memory = instance.get_memory("mem").unwrap();
|
||||||
/// let ty = memory.ty();
|
/// let ty = memory.ty();
|
||||||
/// assert_eq!(ty.limits().min(), 1);
|
/// assert_eq!(ty.limits().min(), 1);
|
||||||
/// # Ok(())
|
/// # Ok(())
|
||||||
/// # }
|
/// # }
|
||||||
/// ```
|
/// ```
|
||||||
pub fn ty(&self) -> &MemoryType {
|
pub fn ty(&self) -> MemoryType {
|
||||||
&self.ty
|
MemoryType::from_wasmtime_memory(&self.wasmtime_export.memory.memory)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns this memory as a slice view that can be read natively in Rust.
|
/// Returns this memory as a slice view that can be read natively in Rust.
|
||||||
@@ -812,7 +814,7 @@ impl Memory {
|
|||||||
/// let store = Store::default();
|
/// let store = Store::default();
|
||||||
/// let module = Module::new(&store, "(module (memory (export \"mem\") 1 2))")?;
|
/// let module = Module::new(&store, "(module (memory (export \"mem\") 1 2))")?;
|
||||||
/// let instance = Instance::new(&module, &[])?;
|
/// let instance = Instance::new(&module, &[])?;
|
||||||
/// let memory = instance.get_export("mem").unwrap().memory().unwrap();
|
/// let memory = instance.get_memory("mem").unwrap();
|
||||||
///
|
///
|
||||||
/// assert_eq!(memory.size(), 1);
|
/// assert_eq!(memory.size(), 1);
|
||||||
/// assert_eq!(memory.grow(1)?, 1);
|
/// assert_eq!(memory.grow(1)?, 1);
|
||||||
@@ -838,10 +840,8 @@ impl Memory {
|
|||||||
store: &Store,
|
store: &Store,
|
||||||
wasmtime_handle: wasmtime_runtime::InstanceHandle,
|
wasmtime_handle: wasmtime_runtime::InstanceHandle,
|
||||||
) -> Memory {
|
) -> Memory {
|
||||||
let ty = MemoryType::from_wasmtime_memory(&wasmtime_export.memory.memory);
|
|
||||||
Memory {
|
Memory {
|
||||||
store: store.clone(),
|
store: store.clone(),
|
||||||
ty: ty,
|
|
||||||
wasmtime_handle,
|
wasmtime_handle,
|
||||||
wasmtime_export,
|
wasmtime_export,
|
||||||
}
|
}
|
||||||
@@ -890,3 +890,66 @@ pub unsafe trait MemoryCreator: Send + Sync {
|
|||||||
/// Create new LinearMemory
|
/// Create new LinearMemory
|
||||||
fn new_memory(&self, ty: MemoryType) -> Result<Box<dyn LinearMemory>, String>;
|
fn new_memory(&self, ty: MemoryType) -> Result<Box<dyn LinearMemory>, String>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Exports
|
||||||
|
|
||||||
|
/// An exported WebAssembly value.
|
||||||
|
///
|
||||||
|
/// This type is primarily accessed from the
|
||||||
|
/// [`Instance::exports`](crate::Instance::exports) accessor and describes what
|
||||||
|
/// names and items are exported from a wasm instance.
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct Export<'instance> {
|
||||||
|
/// The name of the export.
|
||||||
|
name: &'instance str,
|
||||||
|
|
||||||
|
/// The definition of the export.
|
||||||
|
definition: Extern,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'instance> Export<'instance> {
|
||||||
|
/// Creates a new export which is exported with the given `name` and has the
|
||||||
|
/// given `definition`.
|
||||||
|
pub(crate) fn new(name: &'instance str, definition: Extern) -> Export<'instance> {
|
||||||
|
Export { name, definition }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the name by which this export is known.
|
||||||
|
pub fn name(&self) -> &'instance str {
|
||||||
|
self.name
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Return the `ExternType` of this export.
|
||||||
|
pub fn ty(&self) -> ExternType {
|
||||||
|
self.definition.ty()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Consume this `Export` and return the contained `Extern`.
|
||||||
|
pub fn into_extern(self) -> Extern {
|
||||||
|
self.definition
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Consume this `Export` and return the contained `Func`, if it's a function,
|
||||||
|
/// or `None` otherwise.
|
||||||
|
pub fn into_func(self) -> Option<Func> {
|
||||||
|
self.definition.into_func()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Consume this `Export` and return the contained `Table`, if it's a table,
|
||||||
|
/// or `None` otherwise.
|
||||||
|
pub fn into_table(self) -> Option<Table> {
|
||||||
|
self.definition.into_table()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Consume this `Export` and return the contained `Memory`, if it's a memory,
|
||||||
|
/// or `None` otherwise.
|
||||||
|
pub fn into_memory(self) -> Option<Memory> {
|
||||||
|
self.definition.into_memory()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Consume this `Export` and return the contained `Global`, if it's a global,
|
||||||
|
/// or `None` otherwise.
|
||||||
|
pub fn into_global(self) -> Option<Global> {
|
||||||
|
self.definition.into_global()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ use wasmtime_runtime::{ExportFunction, VMTrampoline};
|
|||||||
/// let store = Store::default();
|
/// let store = Store::default();
|
||||||
/// let module = Module::new(&store, r#"(module (func (export "foo")))"#)?;
|
/// let module = Module::new(&store, r#"(module (func (export "foo")))"#)?;
|
||||||
/// let instance = Instance::new(&module, &[])?;
|
/// let instance = Instance::new(&module, &[])?;
|
||||||
/// let foo = instance.exports()[0].func().expect("export wasn't a function");
|
/// let foo = instance.get_func("foo").expect("export wasn't a function");
|
||||||
///
|
///
|
||||||
/// // Work with `foo` as a `Func` at this point, such as calling it
|
/// // Work with `foo` as a `Func` at this point, such as calling it
|
||||||
/// // dynamically...
|
/// // dynamically...
|
||||||
@@ -88,7 +88,7 @@ use wasmtime_runtime::{ExportFunction, VMTrampoline};
|
|||||||
/// "#,
|
/// "#,
|
||||||
/// )?;
|
/// )?;
|
||||||
/// let instance = Instance::new(&module, &[add.into()])?;
|
/// let instance = Instance::new(&module, &[add.into()])?;
|
||||||
/// let call_add_twice = instance.exports()[0].func().expect("export wasn't a function");
|
/// let call_add_twice = instance.get_func("call_add_twice").expect("export wasn't a function");
|
||||||
/// let call_add_twice = call_add_twice.get0::<i32>()?;
|
/// let call_add_twice = call_add_twice.get0::<i32>()?;
|
||||||
///
|
///
|
||||||
/// assert_eq!(call_add_twice()?, 10);
|
/// assert_eq!(call_add_twice()?, 10);
|
||||||
@@ -138,7 +138,6 @@ pub struct Func {
|
|||||||
store: Store,
|
store: Store,
|
||||||
instance: InstanceHandle,
|
instance: InstanceHandle,
|
||||||
export: ExportFunction,
|
export: ExportFunction,
|
||||||
ty: FuncType,
|
|
||||||
trampoline: VMTrampoline,
|
trampoline: VMTrampoline,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -149,15 +148,16 @@ macro_rules! getters {
|
|||||||
)*) => ($(
|
)*) => ($(
|
||||||
$(#[$doc])*
|
$(#[$doc])*
|
||||||
#[allow(non_snake_case)]
|
#[allow(non_snake_case)]
|
||||||
pub fn $name<'a, $($args,)* R>(&'a self)
|
pub fn $name<$($args,)* R>(&self)
|
||||||
-> anyhow::Result<impl Fn($($args,)*) -> Result<R, Trap> + 'a>
|
-> anyhow::Result<impl Fn($($args,)*) -> Result<R, Trap>>
|
||||||
where
|
where
|
||||||
$($args: WasmTy,)*
|
$($args: WasmTy,)*
|
||||||
R: WasmTy,
|
R: WasmTy,
|
||||||
{
|
{
|
||||||
// Verify all the paramers match the expected parameters, and that
|
// Verify all the paramers match the expected parameters, and that
|
||||||
// there are no extra parameters...
|
// there are no extra parameters...
|
||||||
let mut params = self.ty().params().iter().cloned();
|
let ty = self.ty();
|
||||||
|
let mut params = ty.params().iter().cloned();
|
||||||
let n = 0;
|
let n = 0;
|
||||||
$(
|
$(
|
||||||
let n = n + 1;
|
let n = n + 1;
|
||||||
@@ -167,14 +167,18 @@ macro_rules! getters {
|
|||||||
ensure!(params.next().is_none(), "Type mismatch: too many arguments (expected {})", n);
|
ensure!(params.next().is_none(), "Type mismatch: too many arguments (expected {})", n);
|
||||||
|
|
||||||
// ... then do the same for the results...
|
// ... then do the same for the results...
|
||||||
let mut results = self.ty().results().iter().cloned();
|
let mut results = ty.results().iter().cloned();
|
||||||
R::matches(&mut results)
|
R::matches(&mut results)
|
||||||
.context("Type mismatch in return type")?;
|
.context("Type mismatch in return type")?;
|
||||||
ensure!(results.next().is_none(), "Type mismatch: too many return values (expected 1)");
|
ensure!(results.next().is_none(), "Type mismatch: too many return values (expected 1)");
|
||||||
|
|
||||||
|
// Pass the instance into the closure so that we keep it live for the lifetime
|
||||||
|
// of the closure. Pass the export in so that we can call it.
|
||||||
|
let instance = self.instance.clone();
|
||||||
|
let export = self.export.clone();
|
||||||
|
|
||||||
// ... and then once we've passed the typechecks we can hand out our
|
// ... and then once we've passed the typechecks we can hand out our
|
||||||
// object since our `transmute` below should be safe!
|
// object since our `transmute` below should be safe!
|
||||||
let f = self.wasmtime_function();
|
|
||||||
Ok(move |$($args: $args),*| -> Result<R, Trap> {
|
Ok(move |$($args: $args),*| -> Result<R, Trap> {
|
||||||
unsafe {
|
unsafe {
|
||||||
let fnptr = mem::transmute::<
|
let fnptr = mem::transmute::<
|
||||||
@@ -184,12 +188,17 @@ macro_rules! getters {
|
|||||||
*mut VMContext,
|
*mut VMContext,
|
||||||
$($args,)*
|
$($args,)*
|
||||||
) -> R,
|
) -> R,
|
||||||
>(f.address);
|
>(export.address);
|
||||||
let mut ret = None;
|
let mut ret = None;
|
||||||
$(let $args = $args.into_abi();)*
|
$(let $args = $args.into_abi();)*
|
||||||
wasmtime_runtime::catch_traps(f.vmctx, || {
|
wasmtime_runtime::catch_traps(export.vmctx, || {
|
||||||
ret = Some(fnptr(f.vmctx, ptr::null_mut(), $($args,)*));
|
ret = Some(fnptr(export.vmctx, ptr::null_mut(), $($args,)*));
|
||||||
}).map_err(Trap::from_jit)?;
|
}).map_err(Trap::from_jit)?;
|
||||||
|
|
||||||
|
// We're holding this handle just to ensure that the instance stays
|
||||||
|
// live while we call into it.
|
||||||
|
drop(&instance);
|
||||||
|
|
||||||
Ok(ret.unwrap())
|
Ok(ret.unwrap())
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@@ -272,7 +281,6 @@ impl Func {
|
|||||||
crate::trampoline::generate_func_export(&ty, func, store).expect("generated func");
|
crate::trampoline::generate_func_export(&ty, func, store).expect("generated func");
|
||||||
Func {
|
Func {
|
||||||
store: store.clone(),
|
store: store.clone(),
|
||||||
ty,
|
|
||||||
instance,
|
instance,
|
||||||
export,
|
export,
|
||||||
trampoline,
|
trampoline,
|
||||||
@@ -340,7 +348,7 @@ impl Func {
|
|||||||
/// "#,
|
/// "#,
|
||||||
/// )?;
|
/// )?;
|
||||||
/// let instance = Instance::new(&module, &[add.into()])?;
|
/// let instance = Instance::new(&module, &[add.into()])?;
|
||||||
/// let foo = instance.exports()[0].func().unwrap().get2::<i32, i32, i32>()?;
|
/// let foo = instance.get_func("foo").unwrap().get2::<i32, i32, i32>()?;
|
||||||
/// assert_eq!(foo(1, 2)?, 3);
|
/// assert_eq!(foo(1, 2)?, 3);
|
||||||
/// # Ok(())
|
/// # Ok(())
|
||||||
/// # }
|
/// # }
|
||||||
@@ -371,7 +379,7 @@ impl Func {
|
|||||||
/// "#,
|
/// "#,
|
||||||
/// )?;
|
/// )?;
|
||||||
/// let instance = Instance::new(&module, &[add.into()])?;
|
/// let instance = Instance::new(&module, &[add.into()])?;
|
||||||
/// let foo = instance.exports()[0].func().unwrap().get2::<i32, i32, i32>()?;
|
/// let foo = instance.get_func("foo").unwrap().get2::<i32, i32, i32>()?;
|
||||||
/// assert_eq!(foo(1, 2)?, 3);
|
/// assert_eq!(foo(1, 2)?, 3);
|
||||||
/// assert!(foo(i32::max_value(), 1).is_err());
|
/// assert!(foo(i32::max_value(), 1).is_err());
|
||||||
/// # Ok(())
|
/// # Ok(())
|
||||||
@@ -404,7 +412,7 @@ impl Func {
|
|||||||
/// "#,
|
/// "#,
|
||||||
/// )?;
|
/// )?;
|
||||||
/// let instance = Instance::new(&module, &[debug.into()])?;
|
/// let instance = Instance::new(&module, &[debug.into()])?;
|
||||||
/// let foo = instance.exports()[0].func().unwrap().get0::<()>()?;
|
/// let foo = instance.get_func("foo").unwrap().get0::<()>()?;
|
||||||
/// foo()?;
|
/// foo()?;
|
||||||
/// # Ok(())
|
/// # Ok(())
|
||||||
/// # }
|
/// # }
|
||||||
@@ -460,7 +468,7 @@ impl Func {
|
|||||||
/// "#,
|
/// "#,
|
||||||
/// )?;
|
/// )?;
|
||||||
/// let instance = Instance::new(&module, &[log_str.into()])?;
|
/// let instance = Instance::new(&module, &[log_str.into()])?;
|
||||||
/// let foo = instance.exports()[0].func().unwrap().get0::<()>()?;
|
/// let foo = instance.get_func("foo").unwrap().get0::<()>()?;
|
||||||
/// foo()?;
|
/// foo()?;
|
||||||
/// # Ok(())
|
/// # Ok(())
|
||||||
/// # }
|
/// # }
|
||||||
@@ -470,18 +478,42 @@ impl Func {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the underlying wasm type that this `Func` has.
|
/// Returns the underlying wasm type that this `Func` has.
|
||||||
pub fn ty(&self) -> &FuncType {
|
pub fn ty(&self) -> FuncType {
|
||||||
&self.ty
|
// Signatures should always be registered in the store's registry of
|
||||||
|
// shared signatures, so we should be able to unwrap safely here.
|
||||||
|
let sig = self
|
||||||
|
.store
|
||||||
|
.compiler()
|
||||||
|
.signatures()
|
||||||
|
.lookup(self.export.signature)
|
||||||
|
.expect("failed to lookup signature");
|
||||||
|
|
||||||
|
// This is only called with `Export::Function`, and since it's coming
|
||||||
|
// from wasmtime_runtime itself we should support all the types coming
|
||||||
|
// out of it, so assert such here.
|
||||||
|
FuncType::from_wasmtime_signature(&sig).expect("core wasm signature should be supported")
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the number of parameters that this function takes.
|
/// Returns the number of parameters that this function takes.
|
||||||
pub fn param_arity(&self) -> usize {
|
pub fn param_arity(&self) -> usize {
|
||||||
self.ty.params().len()
|
let sig = self
|
||||||
|
.store
|
||||||
|
.compiler()
|
||||||
|
.signatures()
|
||||||
|
.lookup(self.export.signature)
|
||||||
|
.expect("failed to lookup signature");
|
||||||
|
sig.params.len()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the number of results this function produces.
|
/// Returns the number of results this function produces.
|
||||||
pub fn result_arity(&self) -> usize {
|
pub fn result_arity(&self) -> usize {
|
||||||
self.ty.results().len()
|
let sig = self
|
||||||
|
.store
|
||||||
|
.compiler()
|
||||||
|
.signatures()
|
||||||
|
.lookup(self.export.signature)
|
||||||
|
.expect("failed to lookup signature");
|
||||||
|
sig.returns.len()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Invokes this function with the `params` given, returning the results and
|
/// Invokes this function with the `params` given, returning the results and
|
||||||
@@ -499,18 +531,19 @@ impl Func {
|
|||||||
// this function. This involves checking to make sure we have the right
|
// this function. This involves checking to make sure we have the right
|
||||||
// number and types of arguments as well as making sure everything is
|
// number and types of arguments as well as making sure everything is
|
||||||
// from the same `Store`.
|
// from the same `Store`.
|
||||||
if self.ty.params().len() != params.len() {
|
let my_ty = self.ty();
|
||||||
|
if my_ty.params().len() != params.len() {
|
||||||
bail!(
|
bail!(
|
||||||
"expected {} arguments, got {}",
|
"expected {} arguments, got {}",
|
||||||
self.ty.params().len(),
|
my_ty.params().len(),
|
||||||
params.len()
|
params.len()
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut values_vec = vec![0; max(params.len(), self.ty.results().len())];
|
let mut values_vec = vec![0; max(params.len(), my_ty.results().len())];
|
||||||
|
|
||||||
// Store the argument values into `values_vec`.
|
// Store the argument values into `values_vec`.
|
||||||
let param_tys = self.ty.params().iter();
|
let param_tys = my_ty.params().iter();
|
||||||
for ((arg, slot), ty) in params.iter().zip(&mut values_vec).zip(param_tys) {
|
for ((arg, slot), ty) in params.iter().zip(&mut values_vec).zip(param_tys) {
|
||||||
if arg.ty() != *ty {
|
if arg.ty() != *ty {
|
||||||
bail!("argument type mismatch");
|
bail!("argument type mismatch");
|
||||||
@@ -538,8 +571,8 @@ impl Func {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Load the return values out of `values_vec`.
|
// Load the return values out of `values_vec`.
|
||||||
let mut results = Vec::with_capacity(self.ty.results().len());
|
let mut results = Vec::with_capacity(my_ty.results().len());
|
||||||
for (index, ty) in self.ty.results().iter().enumerate() {
|
for (index, ty) in my_ty.results().iter().enumerate() {
|
||||||
unsafe {
|
unsafe {
|
||||||
let ptr = values_vec.as_ptr().add(index);
|
let ptr = values_vec.as_ptr().add(index);
|
||||||
results.push(Val::read_value_from(ptr, ty));
|
results.push(Val::read_value_from(ptr, ty));
|
||||||
@@ -558,20 +591,6 @@ impl Func {
|
|||||||
store: &Store,
|
store: &Store,
|
||||||
instance: InstanceHandle,
|
instance: InstanceHandle,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
// Signatures should always be registered in the store's registry of
|
|
||||||
// shared signatures, so we should be able to unwrap safely here.
|
|
||||||
let sig = store
|
|
||||||
.compiler()
|
|
||||||
.signatures()
|
|
||||||
.lookup(export.signature)
|
|
||||||
.expect("failed to lookup signature");
|
|
||||||
|
|
||||||
// This is only called with `Export::Function`, and since it's coming
|
|
||||||
// from wasmtime_runtime itself we should support all the types coming
|
|
||||||
// out of it, so assert such here.
|
|
||||||
let ty = FuncType::from_wasmtime_signature(sig)
|
|
||||||
.expect("core wasm signature should be supported");
|
|
||||||
|
|
||||||
// Each function signature in a module should have a trampoline stored
|
// Each function signature in a module should have a trampoline stored
|
||||||
// on that module as well, so unwrap the result here since otherwise
|
// on that module as well, so unwrap the result here since otherwise
|
||||||
// it's a bug in wasmtime.
|
// it's a bug in wasmtime.
|
||||||
@@ -583,7 +602,6 @@ impl Func {
|
|||||||
instance,
|
instance,
|
||||||
export,
|
export,
|
||||||
trampoline,
|
trampoline,
|
||||||
ty,
|
|
||||||
store: store.clone(),
|
store: store.clone(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1095,7 +1113,6 @@ macro_rules! impl_into_func {
|
|||||||
.expect("failed to generate export");
|
.expect("failed to generate export");
|
||||||
Func {
|
Func {
|
||||||
store: store.clone(),
|
store: store.clone(),
|
||||||
ty,
|
|
||||||
instance,
|
instance,
|
||||||
export,
|
export,
|
||||||
trampoline,
|
trampoline,
|
||||||
|
|||||||
@@ -1,18 +1,19 @@
|
|||||||
use crate::externals::Extern;
|
use crate::externals::{Export, Extern, Global, Memory, Table};
|
||||||
|
use crate::func::Func;
|
||||||
use crate::module::Module;
|
use crate::module::Module;
|
||||||
use crate::runtime::{Config, Store};
|
use crate::runtime::{Config, Store};
|
||||||
use crate::trap::Trap;
|
use crate::trap::Trap;
|
||||||
use anyhow::{bail, Error, Result};
|
use anyhow::{bail, Error, Result};
|
||||||
use std::any::Any;
|
use std::any::Any;
|
||||||
use wasmtime_jit::{CompiledModule, Resolver};
|
use wasmtime_jit::{CompiledModule, Resolver};
|
||||||
use wasmtime_runtime::{Export, InstanceHandle, InstantiationError, SignatureRegistry};
|
use wasmtime_runtime::{InstanceHandle, InstantiationError, SignatureRegistry};
|
||||||
|
|
||||||
struct SimpleResolver<'a> {
|
struct SimpleResolver<'a> {
|
||||||
imports: &'a [Extern],
|
imports: &'a [Extern],
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Resolver for SimpleResolver<'_> {
|
impl Resolver for SimpleResolver<'_> {
|
||||||
fn resolve(&mut self, idx: u32, _name: &str, _field: &str) -> Option<Export> {
|
fn resolve(&mut self, idx: u32, _name: &str, _field: &str) -> Option<wasmtime_runtime::Export> {
|
||||||
self.imports
|
self.imports
|
||||||
.get(idx as usize)
|
.get(idx as usize)
|
||||||
.map(|i| i.get_wasmtime_export())
|
.map(|i| i.get_wasmtime_export())
|
||||||
@@ -68,7 +69,6 @@ fn instantiate(
|
|||||||
pub struct Instance {
|
pub struct Instance {
|
||||||
pub(crate) instance_handle: InstanceHandle,
|
pub(crate) instance_handle: InstanceHandle,
|
||||||
module: Module,
|
module: Module,
|
||||||
exports: Box<[Extern]>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Instance {
|
impl Instance {
|
||||||
@@ -145,20 +145,9 @@ impl Instance {
|
|||||||
Box::new(info),
|
Box::new(info),
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
let mut exports = Vec::with_capacity(module.exports().len());
|
|
||||||
for export in module.exports() {
|
|
||||||
let name = export.name().to_string();
|
|
||||||
let export = instance_handle.lookup(&name).expect("export");
|
|
||||||
exports.push(Extern::from_wasmtime_export(
|
|
||||||
store,
|
|
||||||
instance_handle.clone(),
|
|
||||||
export,
|
|
||||||
));
|
|
||||||
}
|
|
||||||
Ok(Instance {
|
Ok(Instance {
|
||||||
instance_handle,
|
instance_handle,
|
||||||
module: module.clone(),
|
module: module.clone(),
|
||||||
exports: exports.into_boxed_slice(),
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -170,24 +159,19 @@ impl Instance {
|
|||||||
self.module.store()
|
self.module.store()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the associated [`Module`] that this `Instance` instantiated.
|
|
||||||
///
|
|
||||||
/// The corresponding [`Module`] here is a static version of this `Instance`
|
|
||||||
/// which can be used to learn information such as naming information about
|
|
||||||
/// various functions.
|
|
||||||
pub fn module(&self) -> &Module {
|
|
||||||
&self.module
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns the list of exported items from this [`Instance`].
|
/// Returns the list of exported items from this [`Instance`].
|
||||||
///
|
pub fn exports<'instance>(
|
||||||
/// Note that the exports here do not have names associated with them,
|
&'instance self,
|
||||||
/// they're simply the values that are exported. To learn the value of each
|
) -> impl ExactSizeIterator<Item = Export<'instance>> + 'instance {
|
||||||
/// export you'll need to consult [`Module::exports`]. The list returned
|
let instance_handle = &self.instance_handle;
|
||||||
/// here maps 1:1 with the list that [`Module::exports`] returns, and
|
let store = self.module.store();
|
||||||
/// [`ExportType`](crate::ExportType) contains the name of each export.
|
self.instance_handle
|
||||||
pub fn exports(&self) -> &[Extern] {
|
.exports()
|
||||||
&self.exports
|
.map(move |(name, entity_index)| {
|
||||||
|
let export = instance_handle.lookup_by_declaration(entity_index);
|
||||||
|
let extern_ = Extern::from_wasmtime_export(export, store, instance_handle.clone());
|
||||||
|
Export::new(name, extern_)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Looks up an exported [`Extern`] value by name.
|
/// Looks up an exported [`Extern`] value by name.
|
||||||
@@ -196,14 +180,45 @@ impl Instance {
|
|||||||
/// the value, if found.
|
/// the value, if found.
|
||||||
///
|
///
|
||||||
/// Returns `None` if there was no export named `name`.
|
/// Returns `None` if there was no export named `name`.
|
||||||
pub fn get_export(&self, name: &str) -> Option<&Extern> {
|
pub fn get_export(&self, name: &str) -> Option<Extern> {
|
||||||
let (i, _) = self
|
let export = self.instance_handle.lookup(&name)?;
|
||||||
.module
|
Some(Extern::from_wasmtime_export(
|
||||||
.exports()
|
export,
|
||||||
.iter()
|
self.module.store(),
|
||||||
.enumerate()
|
self.instance_handle.clone(),
|
||||||
.find(|(_, e)| e.name() == name)?;
|
))
|
||||||
Some(&self.exports()[i])
|
}
|
||||||
|
|
||||||
|
/// Looks up an exported [`Func`] value by name.
|
||||||
|
///
|
||||||
|
/// Returns `None` if there was no export named `name`, or if there was but
|
||||||
|
/// it wasn't a function.
|
||||||
|
pub fn get_func(&self, name: &str) -> Option<Func> {
|
||||||
|
self.get_export(name)?.into_func()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Looks up an exported [`Table`] value by name.
|
||||||
|
///
|
||||||
|
/// Returns `None` if there was no export named `name`, or if there was but
|
||||||
|
/// it wasn't a table.
|
||||||
|
pub fn get_table(&self, name: &str) -> Option<Table> {
|
||||||
|
self.get_export(name)?.into_table()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Looks up an exported [`Memory`] value by name.
|
||||||
|
///
|
||||||
|
/// Returns `None` if there was no export named `name`, or if there was but
|
||||||
|
/// it wasn't a memory.
|
||||||
|
pub fn get_memory(&self, name: &str) -> Option<Memory> {
|
||||||
|
self.get_export(name)?.into_memory()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Looks up an exported [`Global`] value by name.
|
||||||
|
///
|
||||||
|
/// Returns `None` if there was no export named `name`, or if there was but
|
||||||
|
/// it wasn't a global.
|
||||||
|
pub fn get_global(&self, name: &str) -> Option<Global> {
|
||||||
|
self.get_export(name)?.into_global()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
|
|||||||
@@ -166,7 +166,7 @@ impl Linker {
|
|||||||
if !item.comes_from_same_store(&self.store) {
|
if !item.comes_from_same_store(&self.store) {
|
||||||
bail!("all linker items must be from the same store");
|
bail!("all linker items must be from the same store");
|
||||||
}
|
}
|
||||||
self.insert(module, name, &item.ty(), item)?;
|
self.insert(module, name, item)?;
|
||||||
Ok(self)
|
Ok(self)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -264,8 +264,8 @@ impl Linker {
|
|||||||
if !Store::same(&self.store, instance.store()) {
|
if !Store::same(&self.store, instance.store()) {
|
||||||
bail!("all linker items must be from the same store");
|
bail!("all linker items must be from the same store");
|
||||||
}
|
}
|
||||||
for (export, item) in instance.module().exports().iter().zip(instance.exports()) {
|
for export in instance.exports() {
|
||||||
self.insert(module_name, export.name(), export.ty(), item.clone())?;
|
self.insert(module_name, export.name(), export.into_extern())?;
|
||||||
}
|
}
|
||||||
Ok(self)
|
Ok(self)
|
||||||
}
|
}
|
||||||
@@ -283,7 +283,7 @@ impl Linker {
|
|||||||
let items = self
|
let items = self
|
||||||
.iter()
|
.iter()
|
||||||
.filter(|(m, _, _)| *m == module)
|
.filter(|(m, _, _)| *m == module)
|
||||||
.map(|(_, name, item)| (name.to_string(), item.clone()))
|
.map(|(_, name, item)| (name.to_string(), item))
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
for (name, item) in items {
|
for (name, item) in items {
|
||||||
self.define(as_module, &name, item)?;
|
self.define(as_module, &name, item)?;
|
||||||
@@ -291,8 +291,8 @@ impl Linker {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn insert(&mut self, module: &str, name: &str, ty: &ExternType, item: Extern) -> Result<()> {
|
fn insert(&mut self, module: &str, name: &str, item: Extern) -> Result<()> {
|
||||||
let key = self.import_key(module, name, ty);
|
let key = self.import_key(module, name, item.ty());
|
||||||
match self.map.entry(key) {
|
match self.map.entry(key) {
|
||||||
Entry::Occupied(o) if !self.allow_shadowing => bail!(
|
Entry::Occupied(o) if !self.allow_shadowing => bail!(
|
||||||
"import of `{}::{}` with kind {:?} defined twice",
|
"import of `{}::{}` with kind {:?} defined twice",
|
||||||
@@ -310,7 +310,7 @@ impl Linker {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn import_key(&mut self, module: &str, name: &str, ty: &ExternType) -> ImportKey {
|
fn import_key(&mut self, module: &str, name: &str, ty: ExternType) -> ImportKey {
|
||||||
ImportKey {
|
ImportKey {
|
||||||
module: self.intern_str(module),
|
module: self.intern_str(module),
|
||||||
name: self.intern_str(name),
|
name: self.intern_str(name),
|
||||||
@@ -318,10 +318,10 @@ impl Linker {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn import_kind(&self, ty: &ExternType) -> ImportKind {
|
fn import_kind(&self, ty: ExternType) -> ImportKind {
|
||||||
match ty {
|
match ty {
|
||||||
ExternType::Func(f) => ImportKind::Func(f.clone()),
|
ExternType::Func(f) => ImportKind::Func(f),
|
||||||
ExternType::Global(f) => ImportKind::Global(f.clone()),
|
ExternType::Global(f) => ImportKind::Global(f),
|
||||||
ExternType::Memory(_) => ImportKind::Memory,
|
ExternType::Memory(_) => ImportKind::Memory,
|
||||||
ExternType::Table(_) => ImportKind::Table,
|
ExternType::Table(_) => ImportKind::Table,
|
||||||
}
|
}
|
||||||
@@ -378,8 +378,8 @@ impl Linker {
|
|||||||
pub fn instantiate(&self, module: &Module) -> Result<Instance> {
|
pub fn instantiate(&self, module: &Module) -> Result<Instance> {
|
||||||
let mut imports = Vec::new();
|
let mut imports = Vec::new();
|
||||||
for import in module.imports() {
|
for import in module.imports() {
|
||||||
if let Some(item) = self.get(import) {
|
if let Some(item) = self.get(&import) {
|
||||||
imports.push(item.clone());
|
imports.push(item);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -429,23 +429,27 @@ impl Linker {
|
|||||||
///
|
///
|
||||||
/// Note that multiple `Extern` items may be defined for the same
|
/// Note that multiple `Extern` items may be defined for the same
|
||||||
/// module/name pair.
|
/// module/name pair.
|
||||||
pub fn iter(&self) -> impl Iterator<Item = (&str, &str, &Extern)> {
|
pub fn iter(&self) -> impl Iterator<Item = (&str, &str, Extern)> {
|
||||||
self.map
|
self.map.iter().map(move |(key, item)| {
|
||||||
.iter()
|
(
|
||||||
.map(move |(key, item)| (&*self.strings[key.module], &*self.strings[key.name], item))
|
&*self.strings[key.module],
|
||||||
|
&*self.strings[key.name],
|
||||||
|
item.clone(),
|
||||||
|
)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Looks up a value in this `Linker` which matches the `import` type
|
/// Looks up a value in this `Linker` which matches the `import` type
|
||||||
/// provided.
|
/// provided.
|
||||||
///
|
///
|
||||||
/// Returns `None` if no match was found.
|
/// Returns `None` if no match was found.
|
||||||
pub fn get(&self, import: &ImportType) -> Option<&Extern> {
|
pub fn get(&self, import: &ImportType) -> Option<Extern> {
|
||||||
let key = ImportKey {
|
let key = ImportKey {
|
||||||
module: *self.string2idx.get(import.module())?,
|
module: *self.string2idx.get(import.module())?,
|
||||||
name: *self.string2idx.get(import.name())?,
|
name: *self.string2idx.get(import.name())?,
|
||||||
kind: self.import_kind(import.ty()),
|
kind: self.import_kind(import.ty()),
|
||||||
};
|
};
|
||||||
self.map.get(&key)
|
self.map.get(&key).cloned()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns all items defined for the `module` and `name` pair.
|
/// Returns all items defined for the `module` and `name` pair.
|
||||||
@@ -468,10 +472,10 @@ impl Linker {
|
|||||||
/// Returns the single item defined for the `module` and `name` pair.
|
/// Returns the single item defined for the `module` and `name` pair.
|
||||||
///
|
///
|
||||||
/// Unlike the similar [`Linker::get_by_name`] method this function returns
|
/// Unlike the similar [`Linker::get_by_name`] method this function returns
|
||||||
/// a single `&Extern` item. If the `module` and `name` pair isn't defined
|
/// a single `Extern` item. If the `module` and `name` pair isn't defined
|
||||||
/// in this linker then an error is returned. If more than one value exists
|
/// in this linker then an error is returned. If more than one value exists
|
||||||
/// for the `module` and `name` pairs, then an error is returned as well.
|
/// for the `module` and `name` pairs, then an error is returned as well.
|
||||||
pub fn get_one_by_name(&self, module: &str, name: &str) -> Result<&Extern> {
|
pub fn get_one_by_name(&self, module: &str, name: &str) -> Result<Extern> {
|
||||||
let mut items = self.get_by_name(module, name);
|
let mut items = self.get_by_name(module, name);
|
||||||
let ret = items
|
let ret = items
|
||||||
.next()
|
.next()
|
||||||
@@ -479,6 +483,6 @@ impl Linker {
|
|||||||
if items.next().is_some() {
|
if items.next().is_some() {
|
||||||
bail!("too many items named `{}` in `{}`", name, module);
|
bail!("too many items named `{}` in `{}`", name, module);
|
||||||
}
|
}
|
||||||
Ok(ret)
|
Ok(ret.clone())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,66 +1,12 @@
|
|||||||
use crate::frame_info::GlobalFrameInfoRegistration;
|
use crate::frame_info::GlobalFrameInfoRegistration;
|
||||||
use crate::runtime::Store;
|
use crate::runtime::Store;
|
||||||
use crate::types::{
|
use crate::types::{EntityType, ExportType, ImportType};
|
||||||
ExportType, ExternType, FuncType, GlobalType, ImportType, Limits, MemoryType, Mutability,
|
use anyhow::{Error, Result};
|
||||||
TableType, ValType,
|
|
||||||
};
|
|
||||||
use anyhow::{bail, Error, Result};
|
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
use std::sync::{Arc, Mutex};
|
use std::sync::{Arc, Mutex};
|
||||||
use wasmparser::{validate, ExternalKind, ImportSectionEntryType, ModuleReader, SectionCode};
|
use wasmparser::validate;
|
||||||
use wasmtime_jit::CompiledModule;
|
use wasmtime_jit::CompiledModule;
|
||||||
|
|
||||||
fn into_memory_type(mt: wasmparser::MemoryType) -> Result<MemoryType> {
|
|
||||||
if mt.shared {
|
|
||||||
bail!("shared memories are not supported yet");
|
|
||||||
}
|
|
||||||
Ok(MemoryType::new(Limits::new(
|
|
||||||
mt.limits.initial,
|
|
||||||
mt.limits.maximum,
|
|
||||||
)))
|
|
||||||
}
|
|
||||||
|
|
||||||
fn into_global_type(gt: wasmparser::GlobalType) -> GlobalType {
|
|
||||||
let mutability = if gt.mutable {
|
|
||||||
Mutability::Var
|
|
||||||
} else {
|
|
||||||
Mutability::Const
|
|
||||||
};
|
|
||||||
GlobalType::new(into_valtype(>.content_type), mutability)
|
|
||||||
}
|
|
||||||
|
|
||||||
// `into_valtype` is used for `map` which requires `&T`.
|
|
||||||
#[allow(clippy::trivially_copy_pass_by_ref)]
|
|
||||||
fn into_valtype(ty: &wasmparser::Type) -> ValType {
|
|
||||||
use wasmparser::Type::*;
|
|
||||||
match ty {
|
|
||||||
I32 => ValType::I32,
|
|
||||||
I64 => ValType::I64,
|
|
||||||
F32 => ValType::F32,
|
|
||||||
F64 => ValType::F64,
|
|
||||||
V128 => ValType::V128,
|
|
||||||
AnyFunc => ValType::FuncRef,
|
|
||||||
AnyRef => ValType::AnyRef,
|
|
||||||
_ => unimplemented!("types in into_valtype"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn into_func_type(mt: wasmparser::FuncType) -> FuncType {
|
|
||||||
assert_eq!(mt.form, wasmparser::Type::Func);
|
|
||||||
let params = mt.params.iter().map(into_valtype).collect::<Vec<_>>();
|
|
||||||
let returns = mt.returns.iter().map(into_valtype).collect::<Vec<_>>();
|
|
||||||
FuncType::new(params.into_boxed_slice(), returns.into_boxed_slice())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn into_table_type(tt: wasmparser::TableType) -> TableType {
|
|
||||||
assert!(
|
|
||||||
tt.element_type == wasmparser::Type::AnyFunc || tt.element_type == wasmparser::Type::AnyRef
|
|
||||||
);
|
|
||||||
let ty = into_valtype(&tt.element_type);
|
|
||||||
let limits = Limits::new(tt.limits.initial, tt.limits.maximum);
|
|
||||||
TableType::new(ty, limits)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A compiled WebAssembly module, ready to be instantiated.
|
/// A compiled WebAssembly module, ready to be instantiated.
|
||||||
///
|
///
|
||||||
/// A `Module` is a compiled in-memory representation of an input WebAssembly
|
/// A `Module` is a compiled in-memory representation of an input WebAssembly
|
||||||
@@ -134,8 +80,6 @@ pub struct Module {
|
|||||||
|
|
||||||
struct ModuleInner {
|
struct ModuleInner {
|
||||||
store: Store,
|
store: Store,
|
||||||
imports: Box<[ImportType]>,
|
|
||||||
exports: Box<[ExportType]>,
|
|
||||||
compiled: CompiledModule,
|
compiled: CompiledModule,
|
||||||
frame_info_registration: Mutex<Option<Option<Arc<GlobalFrameInfoRegistration>>>>,
|
frame_info_registration: Mutex<Option<Option<Arc<GlobalFrameInfoRegistration>>>>,
|
||||||
}
|
}
|
||||||
@@ -332,9 +276,7 @@ impl Module {
|
|||||||
/// be somewhat valid for decoding purposes, and the basics of decoding can
|
/// be somewhat valid for decoding purposes, and the basics of decoding can
|
||||||
/// still fail.
|
/// still fail.
|
||||||
pub unsafe fn from_binary_unchecked(store: &Store, binary: &[u8]) -> Result<Module> {
|
pub unsafe fn from_binary_unchecked(store: &Store, binary: &[u8]) -> Result<Module> {
|
||||||
let mut ret = Module::compile(store, binary)?;
|
Module::compile(store, binary)
|
||||||
ret.read_imports_and_exports(binary)?;
|
|
||||||
Ok(ret)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Validates `binary` input data as a WebAssembly binary given the
|
/// Validates `binary` input data as a WebAssembly binary given the
|
||||||
@@ -372,8 +314,6 @@ impl Module {
|
|||||||
Ok(Module {
|
Ok(Module {
|
||||||
inner: Arc::new(ModuleInner {
|
inner: Arc::new(ModuleInner {
|
||||||
store: store.clone(),
|
store: store.clone(),
|
||||||
imports: Box::new([]),
|
|
||||||
exports: Box::new([]),
|
|
||||||
compiled,
|
compiled,
|
||||||
frame_info_registration: Mutex::new(None),
|
frame_info_registration: Mutex::new(None),
|
||||||
}),
|
}),
|
||||||
@@ -451,7 +391,7 @@ impl Module {
|
|||||||
/// "#;
|
/// "#;
|
||||||
/// let module = Module::new(&store, wat)?;
|
/// let module = Module::new(&store, wat)?;
|
||||||
/// assert_eq!(module.imports().len(), 1);
|
/// assert_eq!(module.imports().len(), 1);
|
||||||
/// let import = &module.imports()[0];
|
/// let import = module.imports().next().unwrap();
|
||||||
/// assert_eq!(import.module(), "host");
|
/// assert_eq!(import.module(), "host");
|
||||||
/// assert_eq!(import.name(), "foo");
|
/// assert_eq!(import.name(), "foo");
|
||||||
/// match import.ty() {
|
/// match import.ty() {
|
||||||
@@ -461,8 +401,17 @@ impl Module {
|
|||||||
/// # Ok(())
|
/// # Ok(())
|
||||||
/// # }
|
/// # }
|
||||||
/// ```
|
/// ```
|
||||||
pub fn imports(&self) -> &[ImportType] {
|
pub fn imports<'module>(
|
||||||
&self.inner.imports
|
&'module self,
|
||||||
|
) -> impl ExactSizeIterator<Item = ImportType<'module>> + 'module {
|
||||||
|
let module = self.inner.compiled.module_ref();
|
||||||
|
module
|
||||||
|
.imports
|
||||||
|
.iter()
|
||||||
|
.map(move |(module_name, name, entity_index)| {
|
||||||
|
let r#type = EntityType::new(entity_index, module);
|
||||||
|
ImportType::new(module_name, name, r#type)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the list of exports that this [`Module`] has and will be
|
/// Returns the list of exports that this [`Module`] has and will be
|
||||||
@@ -482,7 +431,7 @@ impl Module {
|
|||||||
/// # fn main() -> anyhow::Result<()> {
|
/// # fn main() -> anyhow::Result<()> {
|
||||||
/// # let store = Store::default();
|
/// # let store = Store::default();
|
||||||
/// let module = Module::new(&store, "(module)")?;
|
/// let module = Module::new(&store, "(module)")?;
|
||||||
/// assert!(module.exports().is_empty());
|
/// assert!(module.exports().next().is_none());
|
||||||
/// # Ok(())
|
/// # Ok(())
|
||||||
/// # }
|
/// # }
|
||||||
/// ```
|
/// ```
|
||||||
@@ -502,14 +451,15 @@ impl Module {
|
|||||||
/// let module = Module::new(&store, wat)?;
|
/// let module = Module::new(&store, wat)?;
|
||||||
/// assert_eq!(module.exports().len(), 2);
|
/// assert_eq!(module.exports().len(), 2);
|
||||||
///
|
///
|
||||||
/// let foo = &module.exports()[0];
|
/// let mut exports = module.exports();
|
||||||
|
/// let foo = exports.next().unwrap();
|
||||||
/// assert_eq!(foo.name(), "foo");
|
/// assert_eq!(foo.name(), "foo");
|
||||||
/// match foo.ty() {
|
/// match foo.ty() {
|
||||||
/// ExternType::Func(_) => { /* ... */ }
|
/// ExternType::Func(_) => { /* ... */ }
|
||||||
/// _ => panic!("unexpected export type!"),
|
/// _ => panic!("unexpected export type!"),
|
||||||
/// }
|
/// }
|
||||||
///
|
///
|
||||||
/// let memory = &module.exports()[1];
|
/// let memory = exports.next().unwrap();
|
||||||
/// assert_eq!(memory.name(), "memory");
|
/// assert_eq!(memory.name(), "memory");
|
||||||
/// match memory.ty() {
|
/// match memory.ty() {
|
||||||
/// ExternType::Memory(_) => { /* ... */ }
|
/// ExternType::Memory(_) => { /* ... */ }
|
||||||
@@ -518,8 +468,14 @@ impl Module {
|
|||||||
/// # Ok(())
|
/// # Ok(())
|
||||||
/// # }
|
/// # }
|
||||||
/// ```
|
/// ```
|
||||||
pub fn exports(&self) -> &[ExportType] {
|
pub fn exports<'module>(
|
||||||
&self.inner.exports
|
&'module self,
|
||||||
|
) -> impl ExactSizeIterator<Item = ExportType<'module>> + 'module {
|
||||||
|
let module = self.inner.compiled.module_ref();
|
||||||
|
module.exports.iter().map(move |(name, entity_index)| {
|
||||||
|
let r#type = EntityType::new(entity_index, module);
|
||||||
|
ExportType::new(name, r#type)
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the [`Store`] that this [`Module`] was compiled into.
|
/// Returns the [`Store`] that this [`Module`] was compiled into.
|
||||||
@@ -527,141 +483,6 @@ impl Module {
|
|||||||
&self.inner.store
|
&self.inner.store
|
||||||
}
|
}
|
||||||
|
|
||||||
fn read_imports_and_exports(&mut self, binary: &[u8]) -> Result<()> {
|
|
||||||
let inner = Arc::get_mut(&mut self.inner).unwrap();
|
|
||||||
let mut reader = ModuleReader::new(binary)?;
|
|
||||||
let mut imports = Vec::new();
|
|
||||||
let mut exports = Vec::new();
|
|
||||||
let mut memories = Vec::new();
|
|
||||||
let mut tables = Vec::new();
|
|
||||||
let mut func_sig = Vec::new();
|
|
||||||
let mut sigs = Vec::new();
|
|
||||||
let mut globals = Vec::new();
|
|
||||||
while !reader.eof() {
|
|
||||||
let section = reader.read()?;
|
|
||||||
match section.code {
|
|
||||||
SectionCode::Memory => {
|
|
||||||
let section = section.get_memory_section_reader()?;
|
|
||||||
memories.reserve_exact(section.get_count() as usize);
|
|
||||||
for entry in section {
|
|
||||||
memories.push(into_memory_type(entry?)?);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
SectionCode::Type => {
|
|
||||||
let section = section.get_type_section_reader()?;
|
|
||||||
sigs.reserve_exact(section.get_count() as usize);
|
|
||||||
for entry in section {
|
|
||||||
sigs.push(into_func_type(entry?));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
SectionCode::Function => {
|
|
||||||
let section = section.get_function_section_reader()?;
|
|
||||||
func_sig.reserve_exact(section.get_count() as usize);
|
|
||||||
for entry in section {
|
|
||||||
func_sig.push(entry?);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
SectionCode::Global => {
|
|
||||||
let section = section.get_global_section_reader()?;
|
|
||||||
globals.reserve_exact(section.get_count() as usize);
|
|
||||||
for entry in section {
|
|
||||||
globals.push(into_global_type(entry?.ty));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
SectionCode::Table => {
|
|
||||||
let section = section.get_table_section_reader()?;
|
|
||||||
tables.reserve_exact(section.get_count() as usize);
|
|
||||||
for entry in section {
|
|
||||||
tables.push(into_table_type(entry?))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
SectionCode::Import => {
|
|
||||||
let section = section.get_import_section_reader()?;
|
|
||||||
imports.reserve_exact(section.get_count() as usize);
|
|
||||||
for entry in section {
|
|
||||||
let entry = entry?;
|
|
||||||
let r#type = match entry.ty {
|
|
||||||
ImportSectionEntryType::Function(index) => {
|
|
||||||
func_sig.push(index);
|
|
||||||
let sig = &sigs[index as usize];
|
|
||||||
ExternType::Func(sig.clone())
|
|
||||||
}
|
|
||||||
ImportSectionEntryType::Table(tt) => {
|
|
||||||
let table = into_table_type(tt);
|
|
||||||
tables.push(table.clone());
|
|
||||||
ExternType::Table(table)
|
|
||||||
}
|
|
||||||
ImportSectionEntryType::Memory(mt) => {
|
|
||||||
let memory = into_memory_type(mt)?;
|
|
||||||
memories.push(memory.clone());
|
|
||||||
ExternType::Memory(memory)
|
|
||||||
}
|
|
||||||
ImportSectionEntryType::Global(gt) => {
|
|
||||||
let global = into_global_type(gt);
|
|
||||||
globals.push(global.clone());
|
|
||||||
ExternType::Global(global)
|
|
||||||
}
|
|
||||||
};
|
|
||||||
imports.push(ImportType::new(entry.module, entry.field, r#type));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
SectionCode::Export => {
|
|
||||||
let section = section.get_export_section_reader()?;
|
|
||||||
exports.reserve_exact(section.get_count() as usize);
|
|
||||||
for entry in section {
|
|
||||||
let entry = entry?;
|
|
||||||
let r#type = match entry.kind {
|
|
||||||
ExternalKind::Function => {
|
|
||||||
let sig_index = func_sig[entry.index as usize] as usize;
|
|
||||||
let sig = &sigs[sig_index];
|
|
||||||
ExternType::Func(sig.clone())
|
|
||||||
}
|
|
||||||
ExternalKind::Table => {
|
|
||||||
ExternType::Table(tables[entry.index as usize].clone())
|
|
||||||
}
|
|
||||||
ExternalKind::Memory => {
|
|
||||||
ExternType::Memory(memories[entry.index as usize].clone())
|
|
||||||
}
|
|
||||||
ExternalKind::Global => {
|
|
||||||
ExternType::Global(globals[entry.index as usize].clone())
|
|
||||||
}
|
|
||||||
};
|
|
||||||
exports.push(ExportType::new(entry.field, r#type));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
SectionCode::Custom {
|
|
||||||
name: "webidl-bindings",
|
|
||||||
..
|
|
||||||
}
|
|
||||||
| SectionCode::Custom {
|
|
||||||
name: "wasm-interface-types",
|
|
||||||
..
|
|
||||||
} => {
|
|
||||||
bail!(
|
|
||||||
"\
|
|
||||||
support for interface types has temporarily been removed from `wasmtime`
|
|
||||||
|
|
||||||
for more information about this temoprary you can read on the issue online:
|
|
||||||
|
|
||||||
https://github.com/bytecodealliance/wasmtime/issues/1271
|
|
||||||
|
|
||||||
and for re-adding support for interface types you can see this issue:
|
|
||||||
|
|
||||||
https://github.com/bytecodealliance/wasmtime/issues/677
|
|
||||||
"
|
|
||||||
);
|
|
||||||
}
|
|
||||||
_ => {
|
|
||||||
// skip other sections
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
inner.imports = imports.into();
|
|
||||||
inner.exports = exports.into();
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Register this module's stack frame information into the global scope.
|
/// Register this module's stack frame information into the global scope.
|
||||||
///
|
///
|
||||||
/// This is required to ensure that any traps can be properly symbolicated.
|
/// This is required to ensure that any traps can be properly symbolicated.
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ use std::mem;
|
|||||||
use std::panic::{self, AssertUnwindSafe};
|
use std::panic::{self, AssertUnwindSafe};
|
||||||
use wasmtime_environ::entity::PrimaryMap;
|
use wasmtime_environ::entity::PrimaryMap;
|
||||||
use wasmtime_environ::isa::TargetIsa;
|
use wasmtime_environ::isa::TargetIsa;
|
||||||
use wasmtime_environ::{ir, settings, CompiledFunction, Export, Module};
|
use wasmtime_environ::{ir, settings, CompiledFunction, EntityIndex, Module};
|
||||||
use wasmtime_jit::trampoline::ir::{
|
use wasmtime_jit::trampoline::ir::{
|
||||||
ExternalName, Function, InstBuilder, MemFlags, StackSlotData, StackSlotKind,
|
ExternalName, Function, InstBuilder, MemFlags, StackSlotData, StackSlotKind,
|
||||||
};
|
};
|
||||||
@@ -212,7 +212,7 @@ pub fn create_handle_with_function(
|
|||||||
|
|
||||||
let pointer_type = isa.pointer_type();
|
let pointer_type = isa.pointer_type();
|
||||||
let sig = match ft.get_wasmtime_signature(pointer_type) {
|
let sig = match ft.get_wasmtime_signature(pointer_type) {
|
||||||
Some(sig) => sig.clone(),
|
Some(sig) => sig,
|
||||||
None => bail!("not a supported core wasm signature {:?}", ft),
|
None => bail!("not a supported core wasm signature {:?}", ft),
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -228,7 +228,7 @@ pub fn create_handle_with_function(
|
|||||||
let func_id = module.local.functions.push(sig_id);
|
let func_id = module.local.functions.push(sig_id);
|
||||||
module
|
module
|
||||||
.exports
|
.exports
|
||||||
.insert("trampoline".to_string(), Export::Function(func_id));
|
.insert("trampoline".to_string(), EntityIndex::Function(func_id));
|
||||||
let trampoline = make_trampoline(isa.as_ref(), &mut code_memory, &mut fn_builder_ctx, &sig);
|
let trampoline = make_trampoline(isa.as_ref(), &mut code_memory, &mut fn_builder_ctx, &sig);
|
||||||
finished_functions.push(trampoline);
|
finished_functions.push(trampoline);
|
||||||
|
|
||||||
@@ -276,7 +276,7 @@ pub unsafe fn create_handle_with_raw_function(
|
|||||||
|
|
||||||
let pointer_type = isa.pointer_type();
|
let pointer_type = isa.pointer_type();
|
||||||
let sig = match ft.get_wasmtime_signature(pointer_type) {
|
let sig = match ft.get_wasmtime_signature(pointer_type) {
|
||||||
Some(sig) => sig.clone(),
|
Some(sig) => sig,
|
||||||
None => bail!("not a supported core wasm signature {:?}", ft),
|
None => bail!("not a supported core wasm signature {:?}", ft),
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -288,7 +288,7 @@ pub unsafe fn create_handle_with_raw_function(
|
|||||||
let func_id = module.local.functions.push(sig_id);
|
let func_id = module.local.functions.push(sig_id);
|
||||||
module
|
module
|
||||||
.exports
|
.exports
|
||||||
.insert("trampoline".to_string(), Export::Function(func_id));
|
.insert("trampoline".to_string(), EntityIndex::Function(func_id));
|
||||||
finished_functions.push(func);
|
finished_functions.push(func);
|
||||||
let sig_id = store.compiler().signatures().register(&sig);
|
let sig_id = store.compiler().signatures().register(&sig);
|
||||||
trampolines.insert(sig_id, trampoline);
|
trampolines.insert(sig_id, trampoline);
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ use crate::Store;
|
|||||||
use crate::{GlobalType, Mutability, Val};
|
use crate::{GlobalType, Mutability, Val};
|
||||||
use anyhow::{bail, Result};
|
use anyhow::{bail, Result};
|
||||||
use wasmtime_environ::entity::PrimaryMap;
|
use wasmtime_environ::entity::PrimaryMap;
|
||||||
use wasmtime_environ::{wasm, Module};
|
use wasmtime_environ::{wasm, EntityIndex, Module};
|
||||||
use wasmtime_runtime::InstanceHandle;
|
use wasmtime_runtime::InstanceHandle;
|
||||||
|
|
||||||
pub fn create_global(store: &Store, gt: &GlobalType, val: Val) -> Result<InstanceHandle> {
|
pub fn create_global(store: &Store, gt: &GlobalType, val: Val) -> Result<InstanceHandle> {
|
||||||
@@ -26,10 +26,9 @@ pub fn create_global(store: &Store, gt: &GlobalType, val: Val) -> Result<Instanc
|
|||||||
};
|
};
|
||||||
let mut module = Module::new();
|
let mut module = Module::new();
|
||||||
let global_id = module.local.globals.push(global);
|
let global_id = module.local.globals.push(global);
|
||||||
module.exports.insert(
|
module
|
||||||
"global".to_string(),
|
.exports
|
||||||
wasmtime_environ::Export::Global(global_id),
|
.insert("global".to_string(), EntityIndex::Global(global_id));
|
||||||
);
|
|
||||||
let handle = create_handle(
|
let handle = create_handle(
|
||||||
module,
|
module,
|
||||||
store,
|
store,
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ use crate::Store;
|
|||||||
use crate::{Limits, MemoryType};
|
use crate::{Limits, MemoryType};
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use wasmtime_environ::entity::PrimaryMap;
|
use wasmtime_environ::entity::PrimaryMap;
|
||||||
use wasmtime_environ::{wasm, MemoryPlan, Module, WASM_PAGE_SIZE};
|
use wasmtime_environ::{wasm, EntityIndex, MemoryPlan, Module, WASM_PAGE_SIZE};
|
||||||
use wasmtime_runtime::{
|
use wasmtime_runtime::{
|
||||||
InstanceHandle, RuntimeLinearMemory, RuntimeMemoryCreator, VMMemoryDefinition,
|
InstanceHandle, RuntimeLinearMemory, RuntimeMemoryCreator, VMMemoryDefinition,
|
||||||
};
|
};
|
||||||
@@ -23,10 +23,9 @@ pub fn create_handle_with_memory(store: &Store, memory: &MemoryType) -> Result<I
|
|||||||
|
|
||||||
let memory_plan = wasmtime_environ::MemoryPlan::for_memory(memory, &tunable);
|
let memory_plan = wasmtime_environ::MemoryPlan::for_memory(memory, &tunable);
|
||||||
let memory_id = module.local.memory_plans.push(memory_plan);
|
let memory_id = module.local.memory_plans.push(memory_plan);
|
||||||
module.exports.insert(
|
module
|
||||||
"memory".to_string(),
|
.exports
|
||||||
wasmtime_environ::Export::Memory(memory_id),
|
.insert("memory".to_string(), EntityIndex::Memory(memory_id));
|
||||||
);
|
|
||||||
|
|
||||||
create_handle(
|
create_handle(
|
||||||
module,
|
module,
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ use crate::Store;
|
|||||||
use crate::{TableType, ValType};
|
use crate::{TableType, ValType};
|
||||||
use anyhow::{bail, Result};
|
use anyhow::{bail, Result};
|
||||||
use wasmtime_environ::entity::PrimaryMap;
|
use wasmtime_environ::entity::PrimaryMap;
|
||||||
use wasmtime_environ::{wasm, Module};
|
use wasmtime_environ::{wasm, EntityIndex, Module};
|
||||||
use wasmtime_runtime::InstanceHandle;
|
use wasmtime_runtime::InstanceHandle;
|
||||||
|
|
||||||
pub fn create_handle_with_table(store: &Store, table: &TableType) -> Result<InstanceHandle> {
|
pub fn create_handle_with_table(store: &Store, table: &TableType) -> Result<InstanceHandle> {
|
||||||
@@ -21,10 +21,9 @@ pub fn create_handle_with_table(store: &Store, table: &TableType) -> Result<Inst
|
|||||||
|
|
||||||
let table_plan = wasmtime_environ::TablePlan::for_table(table, &tunable);
|
let table_plan = wasmtime_environ::TablePlan::for_table(table, &tunable);
|
||||||
let table_id = module.local.table_plans.push(table_plan);
|
let table_id = module.local.table_plans.push(table_plan);
|
||||||
module.exports.insert(
|
module
|
||||||
"table".to_string(),
|
.exports
|
||||||
wasmtime_environ::Export::Table(table_id),
|
.insert("table".to_string(), EntityIndex::Table(table_id));
|
||||||
);
|
|
||||||
|
|
||||||
create_handle(
|
create_handle(
|
||||||
module,
|
module,
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
use wasmtime_environ::{ir, wasm};
|
use std::fmt;
|
||||||
|
use wasmtime_environ::{ir, wasm, EntityIndex};
|
||||||
|
|
||||||
// Type Representations
|
// Type Representations
|
||||||
|
|
||||||
@@ -247,7 +248,7 @@ impl FuncType {
|
|||||||
/// Returns `None` if any types in the signature can't be converted to the
|
/// Returns `None` if any types in the signature can't be converted to the
|
||||||
/// types in this crate, but that should very rarely happen and largely only
|
/// types in this crate, but that should very rarely happen and largely only
|
||||||
/// indicate a bug in our cranelift integration.
|
/// indicate a bug in our cranelift integration.
|
||||||
pub(crate) fn from_wasmtime_signature(signature: ir::Signature) -> Option<FuncType> {
|
pub(crate) fn from_wasmtime_signature(signature: &ir::Signature) -> Option<FuncType> {
|
||||||
let params = signature
|
let params = signature
|
||||||
.params
|
.params
|
||||||
.iter()
|
.iter()
|
||||||
@@ -382,6 +383,53 @@ impl MemoryType {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Entity Types
|
||||||
|
|
||||||
|
#[derive(Clone, Hash, Eq, PartialEq)]
|
||||||
|
pub(crate) enum EntityType<'module> {
|
||||||
|
Function(&'module ir::Signature),
|
||||||
|
Table(&'module wasm::Table),
|
||||||
|
Memory(&'module wasm::Memory),
|
||||||
|
Global(&'module wasm::Global),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'module> EntityType<'module> {
|
||||||
|
/// Translate from a `EntityIndex` into an `ExternType`.
|
||||||
|
pub(crate) fn new(
|
||||||
|
entity_index: &EntityIndex,
|
||||||
|
module: &'module wasmtime_environ::Module,
|
||||||
|
) -> EntityType<'module> {
|
||||||
|
match entity_index {
|
||||||
|
EntityIndex::Function(func_index) => {
|
||||||
|
let sig = module.local.func_signature(*func_index);
|
||||||
|
EntityType::Function(&sig)
|
||||||
|
}
|
||||||
|
EntityIndex::Table(table_index) => {
|
||||||
|
EntityType::Table(&module.local.table_plans[*table_index].table)
|
||||||
|
}
|
||||||
|
EntityIndex::Memory(memory_index) => {
|
||||||
|
EntityType::Memory(&module.local.memory_plans[*memory_index].memory)
|
||||||
|
}
|
||||||
|
EntityIndex::Global(global_index) => {
|
||||||
|
EntityType::Global(&module.local.globals[*global_index])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn extern_type(&self) -> ExternType {
|
||||||
|
match self {
|
||||||
|
EntityType::Function(sig) => FuncType::from_wasmtime_signature(sig)
|
||||||
|
.expect("core wasm function type should be supported")
|
||||||
|
.into(),
|
||||||
|
EntityType::Table(table) => TableType::from_wasmtime_table(table).into(),
|
||||||
|
EntityType::Memory(memory) => MemoryType::from_wasmtime_memory(memory).into(),
|
||||||
|
EntityType::Global(global) => GlobalType::from_wasmtime_global(global)
|
||||||
|
.expect("core wasm global type should be supported")
|
||||||
|
.into(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Import Types
|
// Import Types
|
||||||
|
|
||||||
/// A descriptor for an imported value into a wasm module.
|
/// A descriptor for an imported value into a wasm module.
|
||||||
@@ -390,38 +438,53 @@ impl MemoryType {
|
|||||||
/// [`Module::imports`](crate::Module::imports) API. Each [`ImportType`]
|
/// [`Module::imports`](crate::Module::imports) API. Each [`ImportType`]
|
||||||
/// describes an import into the wasm module with the module/name that it's
|
/// describes an import into the wasm module with the module/name that it's
|
||||||
/// imported from as well as the type of item that's being imported.
|
/// imported from as well as the type of item that's being imported.
|
||||||
#[derive(Debug, Clone, Hash, Eq, PartialEq)]
|
#[derive(Clone, Hash, Eq, PartialEq)]
|
||||||
pub struct ImportType {
|
pub struct ImportType<'module> {
|
||||||
module: String,
|
/// The module of the import.
|
||||||
name: String,
|
module: &'module str,
|
||||||
ty: ExternType,
|
|
||||||
|
/// The field of the import.
|
||||||
|
name: &'module str,
|
||||||
|
|
||||||
|
/// The type of the import.
|
||||||
|
ty: EntityType<'module>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ImportType {
|
impl<'module> ImportType<'module> {
|
||||||
/// Creates a new import descriptor which comes from `module` and `name` and
|
/// Creates a new import descriptor which comes from `module` and `name` and
|
||||||
/// is of type `ty`.
|
/// is of type `ty`.
|
||||||
pub fn new(module: &str, name: &str, ty: ExternType) -> ImportType {
|
pub(crate) fn new(
|
||||||
ImportType {
|
module: &'module str,
|
||||||
module: module.to_string(),
|
name: &'module str,
|
||||||
name: name.to_string(),
|
ty: EntityType<'module>,
|
||||||
ty,
|
) -> ImportType<'module> {
|
||||||
}
|
ImportType { module, name, ty }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the module name that this import is expected to come from.
|
/// Returns the module name that this import is expected to come from.
|
||||||
pub fn module(&self) -> &str {
|
pub fn module(&self) -> &'module str {
|
||||||
&self.module
|
self.module
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the field name of the module that this import is expected to
|
/// Returns the field name of the module that this import is expected to
|
||||||
/// come from.
|
/// come from.
|
||||||
pub fn name(&self) -> &str {
|
pub fn name(&self) -> &'module str {
|
||||||
&self.name
|
self.name
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the expected type of this import.
|
/// Returns the expected type of this import.
|
||||||
pub fn ty(&self) -> &ExternType {
|
pub fn ty(&self) -> ExternType {
|
||||||
&self.ty
|
self.ty.extern_type()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'module> fmt::Debug for ImportType<'module> {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
f.debug_struct("ImportType")
|
||||||
|
.field("module", &self.module().to_owned())
|
||||||
|
.field("name", &self.name().to_owned())
|
||||||
|
.field("ty", &self.ty())
|
||||||
|
.finish()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -433,29 +496,38 @@ impl ImportType {
|
|||||||
/// [`Module::exports`](crate::Module::exports) accessor and describes what
|
/// [`Module::exports`](crate::Module::exports) accessor and describes what
|
||||||
/// names are exported from a wasm module and the type of the item that is
|
/// names are exported from a wasm module and the type of the item that is
|
||||||
/// exported.
|
/// exported.
|
||||||
#[derive(Debug, Clone, Hash, Eq, PartialEq)]
|
#[derive(Clone, Hash, Eq, PartialEq)]
|
||||||
pub struct ExportType {
|
pub struct ExportType<'module> {
|
||||||
name: String,
|
/// The name of the export.
|
||||||
ty: ExternType,
|
name: &'module str,
|
||||||
|
|
||||||
|
/// The type of the export.
|
||||||
|
ty: EntityType<'module>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ExportType {
|
impl<'module> ExportType<'module> {
|
||||||
/// Creates a new export which is exported with the given `name` and has the
|
/// Creates a new export which is exported with the given `name` and has the
|
||||||
/// given `ty`.
|
/// given `ty`.
|
||||||
pub fn new(name: &str, ty: ExternType) -> ExportType {
|
pub(crate) fn new(name: &'module str, ty: EntityType<'module>) -> ExportType<'module> {
|
||||||
ExportType {
|
ExportType { name, ty }
|
||||||
name: name.to_string(),
|
|
||||||
ty,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the name by which this export is known by.
|
/// Returns the name by which this export is known.
|
||||||
pub fn name(&self) -> &str {
|
pub fn name(&self) -> &'module str {
|
||||||
&self.name
|
self.name
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the type of this export.
|
/// Returns the type of this export.
|
||||||
pub fn ty(&self) -> &ExternType {
|
pub fn ty(&self) -> ExternType {
|
||||||
&self.ty
|
self.ty.extern_type()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'module> fmt::Debug for ExportType<'module> {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
f.debug_struct("ExportType")
|
||||||
|
.field("name", &self.name().to_owned())
|
||||||
|
.field("ty", &self.ty())
|
||||||
|
.finish()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -41,10 +41,10 @@ pub extern "C" fn wasm_extern_kind(e: &wasm_extern_t) -> wasm_externkind_t {
|
|||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub extern "C" fn wasm_extern_type(e: &wasm_extern_t) -> Box<wasm_externtype_t> {
|
pub extern "C" fn wasm_extern_type(e: &wasm_extern_t) -> Box<wasm_externtype_t> {
|
||||||
let ty = match &e.which {
|
let ty = match &e.which {
|
||||||
ExternHost::Func(f) => ExternType::Func(f.borrow().ty().clone()),
|
ExternHost::Func(f) => ExternType::Func(f.borrow().ty()),
|
||||||
ExternHost::Global(f) => ExternType::Global(f.borrow().ty().clone()),
|
ExternHost::Global(f) => ExternType::Global(f.borrow().ty()),
|
||||||
ExternHost::Table(f) => ExternType::Table(f.borrow().ty().clone()),
|
ExternHost::Table(f) => ExternType::Table(f.borrow().ty()),
|
||||||
ExternHost::Memory(f) => ExternType::Memory(f.borrow().ty().clone()),
|
ExternHost::Memory(f) => ExternType::Memory(f.borrow().ty()),
|
||||||
};
|
};
|
||||||
Box::new(wasm_externtype_t::new(ty))
|
Box::new(wasm_externtype_t::new(ty))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -246,7 +246,7 @@ fn _wasmtime_func_call(
|
|||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub extern "C" fn wasm_func_type(f: &wasm_func_t) -> Box<wasm_functype_t> {
|
pub extern "C" fn wasm_func_type(f: &wasm_func_t) -> Box<wasm_functype_t> {
|
||||||
Box::new(wasm_functype_t::new(f.func().borrow().ty().clone()))
|
Box::new(wasm_functype_t::new(f.func().borrow().ty()))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
@@ -272,10 +272,10 @@ pub unsafe extern "C" fn wasmtime_caller_export_get(
|
|||||||
let name = str::from_utf8(name.as_slice()).ok()?;
|
let name = str::from_utf8(name.as_slice()).ok()?;
|
||||||
let export = caller.caller.get_export(name)?;
|
let export = caller.caller.get_export(name)?;
|
||||||
let which = match export {
|
let which = match export {
|
||||||
Extern::Func(f) => ExternHost::Func(HostRef::new(f.clone())),
|
Extern::Func(f) => ExternHost::Func(HostRef::new(f)),
|
||||||
Extern::Global(g) => ExternHost::Global(HostRef::new(g.clone())),
|
Extern::Global(g) => ExternHost::Global(HostRef::new(g)),
|
||||||
Extern::Memory(m) => ExternHost::Memory(HostRef::new(m.clone())),
|
Extern::Memory(m) => ExternHost::Memory(HostRef::new(m)),
|
||||||
Extern::Table(t) => ExternHost::Table(HostRef::new(t.clone())),
|
Extern::Table(t) => ExternHost::Table(HostRef::new(t)),
|
||||||
};
|
};
|
||||||
Some(Box::new(wasm_extern_t { which }))
|
Some(Box::new(wasm_extern_t { which }))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -71,7 +71,7 @@ pub extern "C" fn wasm_global_as_extern(g: &wasm_global_t) -> &wasm_extern_t {
|
|||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub extern "C" fn wasm_global_type(g: &wasm_global_t) -> Box<wasm_globaltype_t> {
|
pub extern "C" fn wasm_global_type(g: &wasm_global_t) -> Box<wasm_globaltype_t> {
|
||||||
let globaltype = g.global().borrow().ty().clone();
|
let globaltype = g.global().borrow().ty();
|
||||||
Box::new(wasm_globaltype_t::new(globaltype))
|
Box::new(wasm_globaltype_t::new(globaltype))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -145,12 +145,11 @@ pub extern "C" fn wasm_instance_exports(instance: &wasm_instance_t, out: &mut wa
|
|||||||
let instance = &instance.instance.borrow();
|
let instance = &instance.instance.borrow();
|
||||||
instance
|
instance
|
||||||
.exports()
|
.exports()
|
||||||
.iter()
|
.map(|e| match e.into_extern() {
|
||||||
.map(|e| match e {
|
Extern::Func(f) => ExternHost::Func(HostRef::new(f)),
|
||||||
Extern::Func(f) => ExternHost::Func(HostRef::new(f.clone())),
|
Extern::Global(f) => ExternHost::Global(HostRef::new(f)),
|
||||||
Extern::Global(f) => ExternHost::Global(HostRef::new(f.clone())),
|
Extern::Memory(f) => ExternHost::Memory(HostRef::new(f)),
|
||||||
Extern::Memory(f) => ExternHost::Memory(HostRef::new(f.clone())),
|
Extern::Table(f) => ExternHost::Table(HostRef::new(f)),
|
||||||
Extern::Table(f) => ExternHost::Table(HostRef::new(f.clone())),
|
|
||||||
})
|
})
|
||||||
.collect()
|
.collect()
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -51,7 +51,7 @@ pub extern "C" fn wasm_memory_as_extern(m: &wasm_memory_t) -> &wasm_extern_t {
|
|||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub extern "C" fn wasm_memory_type(m: &wasm_memory_t) -> Box<wasm_memorytype_t> {
|
pub extern "C" fn wasm_memory_type(m: &wasm_memory_t) -> Box<wasm_memorytype_t> {
|
||||||
let ty = m.memory().borrow().ty().clone();
|
let ty = m.memory().borrow().ty();
|
||||||
Box::new(wasm_memorytype_t::new(ty))
|
Box::new(wasm_memorytype_t::new(ty))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -46,13 +46,11 @@ pub extern "C" fn wasmtime_module_new(
|
|||||||
handle_result(Module::from_binary(store, binary), |module| {
|
handle_result(Module::from_binary(store, binary), |module| {
|
||||||
let imports = module
|
let imports = module
|
||||||
.imports()
|
.imports()
|
||||||
.iter()
|
.map(|i| wasm_importtype_t::new(i.module().to_owned(), i.name().to_owned(), i.ty()))
|
||||||
.map(|i| wasm_importtype_t::new(i.clone()))
|
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
let exports = module
|
let exports = module
|
||||||
.exports()
|
.exports()
|
||||||
.iter()
|
.map(|e| wasm_exporttype_t::new(e.name().to_owned(), e.ty()))
|
||||||
.map(|e| wasm_exporttype_t::new(e.clone()))
|
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
let module = Box::new(wasm_module_t {
|
let module = Box::new(wasm_module_t {
|
||||||
module: HostRef::new(module),
|
module: HostRef::new(module),
|
||||||
|
|||||||
@@ -54,7 +54,7 @@ pub unsafe extern "C" fn wasm_table_new(
|
|||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub extern "C" fn wasm_table_type(t: &wasm_table_t) -> Box<wasm_tabletype_t> {
|
pub extern "C" fn wasm_table_type(t: &wasm_table_t) -> Box<wasm_tabletype_t> {
|
||||||
let ty = t.table().borrow().ty().clone();
|
let ty = t.table().borrow().ty();
|
||||||
Box::new(wasm_tabletype_t::new(ty))
|
Box::new(wasm_tabletype_t::new(ty))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,12 +1,12 @@
|
|||||||
use crate::{wasm_externtype_t, wasm_name_t};
|
use crate::{wasm_externtype_t, wasm_name_t};
|
||||||
use once_cell::unsync::OnceCell;
|
use once_cell::unsync::OnceCell;
|
||||||
use std::str;
|
use wasmtime::ExternType;
|
||||||
use wasmtime::ExportType;
|
|
||||||
|
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct wasm_exporttype_t {
|
pub struct wasm_exporttype_t {
|
||||||
ty: ExportType,
|
name: String,
|
||||||
|
ty: ExternType,
|
||||||
name_cache: OnceCell<wasm_name_t>,
|
name_cache: OnceCell<wasm_name_t>,
|
||||||
type_cache: OnceCell<wasm_externtype_t>,
|
type_cache: OnceCell<wasm_externtype_t>,
|
||||||
}
|
}
|
||||||
@@ -14,8 +14,9 @@ pub struct wasm_exporttype_t {
|
|||||||
wasmtime_c_api_macros::declare_ty!(wasm_exporttype_t);
|
wasmtime_c_api_macros::declare_ty!(wasm_exporttype_t);
|
||||||
|
|
||||||
impl wasm_exporttype_t {
|
impl wasm_exporttype_t {
|
||||||
pub(crate) fn new(ty: ExportType) -> wasm_exporttype_t {
|
pub(crate) fn new(name: String, ty: ExternType) -> wasm_exporttype_t {
|
||||||
wasm_exporttype_t {
|
wasm_exporttype_t {
|
||||||
|
name,
|
||||||
ty,
|
ty,
|
||||||
name_cache: OnceCell::new(),
|
name_cache: OnceCell::new(),
|
||||||
type_cache: OnceCell::new(),
|
type_cache: OnceCell::new(),
|
||||||
@@ -29,19 +30,18 @@ pub extern "C" fn wasm_exporttype_new(
|
|||||||
ty: Box<wasm_externtype_t>,
|
ty: Box<wasm_externtype_t>,
|
||||||
) -> Option<Box<wasm_exporttype_t>> {
|
) -> Option<Box<wasm_exporttype_t>> {
|
||||||
let name = name.take();
|
let name = name.take();
|
||||||
let name = str::from_utf8(&name).ok()?;
|
let name = String::from_utf8(name).ok()?;
|
||||||
let ty = ExportType::new(name, ty.ty());
|
Some(Box::new(wasm_exporttype_t::new(name, ty.ty())))
|
||||||
Some(Box::new(wasm_exporttype_t::new(ty)))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub extern "C" fn wasm_exporttype_name(et: &wasm_exporttype_t) -> &wasm_name_t {
|
pub extern "C" fn wasm_exporttype_name(et: &wasm_exporttype_t) -> &wasm_name_t {
|
||||||
et.name_cache
|
et.name_cache
|
||||||
.get_or_init(|| wasm_name_t::from_name(&et.ty.name()))
|
.get_or_init(|| wasm_name_t::from_name(et.name.clone()))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub extern "C" fn wasm_exporttype_type(et: &wasm_exporttype_t) -> &wasm_externtype_t {
|
pub extern "C" fn wasm_exporttype_type(et: &wasm_exporttype_t) -> &wasm_externtype_t {
|
||||||
et.type_cache
|
et.type_cache
|
||||||
.get_or_init(|| wasm_externtype_t::new(et.ty.ty().clone()))
|
.get_or_init(|| wasm_externtype_t::new(et.ty.clone()))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,12 +1,13 @@
|
|||||||
use crate::{wasm_externtype_t, wasm_name_t};
|
use crate::{wasm_externtype_t, wasm_name_t};
|
||||||
use once_cell::unsync::OnceCell;
|
use once_cell::unsync::OnceCell;
|
||||||
use std::str;
|
use wasmtime::ExternType;
|
||||||
use wasmtime::ImportType;
|
|
||||||
|
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct wasm_importtype_t {
|
pub struct wasm_importtype_t {
|
||||||
pub(crate) ty: ImportType,
|
pub(crate) module: String,
|
||||||
|
pub(crate) name: String,
|
||||||
|
pub(crate) ty: ExternType,
|
||||||
module_cache: OnceCell<wasm_name_t>,
|
module_cache: OnceCell<wasm_name_t>,
|
||||||
name_cache: OnceCell<wasm_name_t>,
|
name_cache: OnceCell<wasm_name_t>,
|
||||||
type_cache: OnceCell<wasm_externtype_t>,
|
type_cache: OnceCell<wasm_externtype_t>,
|
||||||
@@ -15,8 +16,10 @@ pub struct wasm_importtype_t {
|
|||||||
wasmtime_c_api_macros::declare_ty!(wasm_importtype_t);
|
wasmtime_c_api_macros::declare_ty!(wasm_importtype_t);
|
||||||
|
|
||||||
impl wasm_importtype_t {
|
impl wasm_importtype_t {
|
||||||
pub(crate) fn new(ty: ImportType) -> wasm_importtype_t {
|
pub(crate) fn new(module: String, name: String, ty: ExternType) -> wasm_importtype_t {
|
||||||
wasm_importtype_t {
|
wasm_importtype_t {
|
||||||
|
module,
|
||||||
|
name,
|
||||||
ty,
|
ty,
|
||||||
module_cache: OnceCell::new(),
|
module_cache: OnceCell::new(),
|
||||||
name_cache: OnceCell::new(),
|
name_cache: OnceCell::new(),
|
||||||
@@ -33,26 +36,25 @@ pub extern "C" fn wasm_importtype_new(
|
|||||||
) -> Option<Box<wasm_importtype_t>> {
|
) -> Option<Box<wasm_importtype_t>> {
|
||||||
let module = module.take();
|
let module = module.take();
|
||||||
let name = name.take();
|
let name = name.take();
|
||||||
let module = str::from_utf8(&module).ok()?;
|
let module = String::from_utf8(module).ok()?;
|
||||||
let name = str::from_utf8(&name).ok()?;
|
let name = String::from_utf8(name).ok()?;
|
||||||
let ty = ImportType::new(module, name, ty.ty());
|
Some(Box::new(wasm_importtype_t::new(module, name, ty.ty())))
|
||||||
Some(Box::new(wasm_importtype_t::new(ty)))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub extern "C" fn wasm_importtype_module(it: &wasm_importtype_t) -> &wasm_name_t {
|
pub extern "C" fn wasm_importtype_module(it: &wasm_importtype_t) -> &wasm_name_t {
|
||||||
it.module_cache
|
it.module_cache
|
||||||
.get_or_init(|| wasm_name_t::from_name(&it.ty.module()))
|
.get_or_init(|| wasm_name_t::from_name(it.module.clone()))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub extern "C" fn wasm_importtype_name(it: &wasm_importtype_t) -> &wasm_name_t {
|
pub extern "C" fn wasm_importtype_name(it: &wasm_importtype_t) -> &wasm_name_t {
|
||||||
it.name_cache
|
it.name_cache
|
||||||
.get_or_init(|| wasm_name_t::from_name(&it.ty.name()))
|
.get_or_init(|| wasm_name_t::from_name(it.name.clone()))
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub extern "C" fn wasm_importtype_type(it: &wasm_importtype_t) -> &wasm_externtype_t {
|
pub extern "C" fn wasm_importtype_type(it: &wasm_importtype_t) -> &wasm_externtype_t {
|
||||||
it.type_cache
|
it.type_cache
|
||||||
.get_or_init(|| wasm_externtype_t::new(it.ty.ty().clone()))
|
.get_or_init(|| wasm_externtype_t::new(it.ty.clone()))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,8 +9,8 @@ use std::slice;
|
|||||||
pub type wasm_name_t = wasm_byte_vec_t;
|
pub type wasm_name_t = wasm_byte_vec_t;
|
||||||
|
|
||||||
impl wasm_name_t {
|
impl wasm_name_t {
|
||||||
pub(crate) fn from_name(name: &str) -> wasm_name_t {
|
pub(crate) fn from_name(name: String) -> wasm_name_t {
|
||||||
name.to_string().into_bytes().into()
|
name.into_bytes().into()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ use std::fs::File;
|
|||||||
use std::os::raw::{c_char, c_int};
|
use std::os::raw::{c_char, c_int};
|
||||||
use std::path::{Path, PathBuf};
|
use std::path::{Path, PathBuf};
|
||||||
use std::slice;
|
use std::slice;
|
||||||
|
use std::str;
|
||||||
use wasi_common::{
|
use wasi_common::{
|
||||||
old::snapshot_0::WasiCtxBuilder as WasiSnapshot0CtxBuilder, preopen_dir,
|
old::snapshot_0::WasiCtxBuilder as WasiSnapshot0CtxBuilder, preopen_dir,
|
||||||
WasiCtxBuilder as WasiPreview1CtxBuilder,
|
WasiCtxBuilder as WasiPreview1CtxBuilder,
|
||||||
@@ -296,7 +297,7 @@ pub unsafe extern "C" fn wasi_instance_new(
|
|||||||
})),
|
})),
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
*trap = Box::into_raw(Box::new(wasm_trap_t {
|
*trap = Box::into_raw(Box::new(wasm_trap_t {
|
||||||
trap: HostRef::new(Trap::new(e.to_string())),
|
trap: HostRef::new(Trap::new(e)),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
None
|
None
|
||||||
@@ -312,26 +313,26 @@ pub extern "C" fn wasi_instance_bind_import<'a>(
|
|||||||
instance: &'a mut wasi_instance_t,
|
instance: &'a mut wasi_instance_t,
|
||||||
import: &wasm_importtype_t,
|
import: &wasm_importtype_t,
|
||||||
) -> Option<&'a wasm_extern_t> {
|
) -> Option<&'a wasm_extern_t> {
|
||||||
let module = import.ty.module();
|
let module = &import.module;
|
||||||
let name = import.ty.name();
|
let name = str::from_utf8(import.name.as_bytes()).ok()?;
|
||||||
|
|
||||||
let export = match &instance.wasi {
|
let export = match &instance.wasi {
|
||||||
WasiInstance::Preview1(wasi) => {
|
WasiInstance::Preview1(wasi) => {
|
||||||
if module != "wasi_snapshot_preview1" {
|
if module != "wasi_snapshot_preview1" {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
wasi.get_export(name)?
|
wasi.get_export(&name)?
|
||||||
}
|
}
|
||||||
WasiInstance::Snapshot0(wasi) => {
|
WasiInstance::Snapshot0(wasi) => {
|
||||||
if module != "wasi_unstable" {
|
if module != "wasi_unstable" {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
wasi.get_export(name)?
|
wasi.get_export(&name)?
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
if export.ty() != import.ty.ty().func()? {
|
if &export.ty() != import.ty.func()? {
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -10,6 +10,6 @@ pub extern "C" fn wasmtime_wat2wasm(
|
|||||||
Err(_) => return bad_utf8(),
|
Err(_) => return bad_utf8(),
|
||||||
};
|
};
|
||||||
handle_result(wat::parse_str(wat).map_err(|e| e.into()), |bytes| {
|
handle_result(wat::parse_str(wat).map_err(|e| e.into()), |bytes| {
|
||||||
ret.set_buffer(bytes.into())
|
ret.set_buffer(bytes)
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -203,7 +203,7 @@ fn compile(env: CompileEnv<'_>) -> Result<ModuleCacheDataTupleType, CompileError
|
|||||||
let func_index = env.local.func_index(*i);
|
let func_index = env.local.func_index(*i);
|
||||||
let mut context = Context::new();
|
let mut context = Context::new();
|
||||||
context.func.name = get_func_name(func_index);
|
context.func.name = get_func_name(func_index);
|
||||||
context.func.signature = env.local.signatures[env.local.functions[func_index]].clone();
|
context.func.signature = env.local.func_signature(func_index).clone();
|
||||||
if env.tunables.debug_info {
|
if env.tunables.debug_info {
|
||||||
context.func.collect_debug_info();
|
context.func.collect_debug_info();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -906,8 +906,8 @@ impl<'module_environment> cranelift_wasm::FuncEnvironment for FuncEnvironment<'m
|
|||||||
func: &mut ir::Function,
|
func: &mut ir::Function,
|
||||||
index: FuncIndex,
|
index: FuncIndex,
|
||||||
) -> WasmResult<ir::FuncRef> {
|
) -> WasmResult<ir::FuncRef> {
|
||||||
let sigidx = self.module.functions[index];
|
let sig = self.module.func_signature(index);
|
||||||
let signature = func.import_signature(self.module.signatures[sigidx].clone());
|
let signature = func.import_signature(sig.clone());
|
||||||
let name = get_func_name(index);
|
let name = get_func_name(index);
|
||||||
Ok(func.import_function(ir::ExtFuncData {
|
Ok(func.import_function(ir::ExtFuncData {
|
||||||
name,
|
name,
|
||||||
|
|||||||
@@ -55,7 +55,7 @@ pub use crate::func_environ::BuiltinFunctionIndex;
|
|||||||
#[cfg(feature = "lightbeam")]
|
#[cfg(feature = "lightbeam")]
|
||||||
pub use crate::lightbeam::Lightbeam;
|
pub use crate::lightbeam::Lightbeam;
|
||||||
pub use crate::module::{
|
pub use crate::module::{
|
||||||
Export, MemoryPlan, MemoryStyle, Module, ModuleLocal, TableElements, TablePlan, TableStyle,
|
EntityIndex, MemoryPlan, MemoryStyle, Module, ModuleLocal, TableElements, TablePlan, TableStyle,
|
||||||
};
|
};
|
||||||
pub use crate::module_environ::{
|
pub use crate::module_environ::{
|
||||||
translate_signature, DataInitializer, DataInitializerLocation, FunctionBodyData,
|
translate_signature, DataInitializer, DataInitializerLocation, FunctionBodyData,
|
||||||
|
|||||||
@@ -30,16 +30,16 @@ pub struct TableElements {
|
|||||||
pub elements: Box<[FuncIndex]>,
|
pub elements: Box<[FuncIndex]>,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// An entity to export.
|
/// An index of an entity.
|
||||||
#[derive(Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)]
|
#[derive(Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)]
|
||||||
pub enum Export {
|
pub enum EntityIndex {
|
||||||
/// Function export.
|
/// Function index.
|
||||||
Function(FuncIndex),
|
Function(FuncIndex),
|
||||||
/// Table export.
|
/// Table index.
|
||||||
Table(TableIndex),
|
Table(TableIndex),
|
||||||
/// Memory export.
|
/// Memory index.
|
||||||
Memory(MemoryIndex),
|
Memory(MemoryIndex),
|
||||||
/// Global export.
|
/// Global index.
|
||||||
Global(GlobalIndex),
|
Global(GlobalIndex),
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -150,21 +150,11 @@ pub struct Module {
|
|||||||
/// function.
|
/// function.
|
||||||
pub local: ModuleLocal,
|
pub local: ModuleLocal,
|
||||||
|
|
||||||
/// Names of imported functions, as well as the index of the import that
|
/// All import records, in the order they are declared in the module.
|
||||||
/// performed this import.
|
pub imports: Vec<(String, String, EntityIndex)>,
|
||||||
pub imported_funcs: PrimaryMap<FuncIndex, (String, String, u32)>,
|
|
||||||
|
|
||||||
/// Names of imported tables.
|
|
||||||
pub imported_tables: PrimaryMap<TableIndex, (String, String, u32)>,
|
|
||||||
|
|
||||||
/// Names of imported memories.
|
|
||||||
pub imported_memories: PrimaryMap<MemoryIndex, (String, String, u32)>,
|
|
||||||
|
|
||||||
/// Names of imported globals.
|
|
||||||
pub imported_globals: PrimaryMap<GlobalIndex, (String, String, u32)>,
|
|
||||||
|
|
||||||
/// Exported entities.
|
/// Exported entities.
|
||||||
pub exports: IndexMap<String, Export>,
|
pub exports: IndexMap<String, EntityIndex>,
|
||||||
|
|
||||||
/// The module "start" function, if present.
|
/// The module "start" function, if present.
|
||||||
pub start_func: Option<FuncIndex>,
|
pub start_func: Option<FuncIndex>,
|
||||||
@@ -226,10 +216,7 @@ impl Module {
|
|||||||
Self {
|
Self {
|
||||||
id: NEXT_ID.fetch_add(1, SeqCst),
|
id: NEXT_ID.fetch_add(1, SeqCst),
|
||||||
name: None,
|
name: None,
|
||||||
imported_funcs: PrimaryMap::new(),
|
imports: Vec::new(),
|
||||||
imported_tables: PrimaryMap::new(),
|
|
||||||
imported_memories: PrimaryMap::new(),
|
|
||||||
imported_globals: PrimaryMap::new(),
|
|
||||||
exports: IndexMap::new(),
|
exports: IndexMap::new(),
|
||||||
start_func: None,
|
start_func: None,
|
||||||
table_elements: Vec::new(),
|
table_elements: Vec::new(),
|
||||||
@@ -344,4 +331,9 @@ impl ModuleLocal {
|
|||||||
pub fn is_imported_global(&self, index: GlobalIndex) -> bool {
|
pub fn is_imported_global(&self, index: GlobalIndex) -> bool {
|
||||||
index.index() < self.num_imported_globals
|
index.index() < self.num_imported_globals
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Convenience method for looking up the signature of a function.
|
||||||
|
pub fn func_signature(&self, func_index: FuncIndex) -> &ir::Signature {
|
||||||
|
&self.signatures[self.functions[func_index]]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
use crate::func_environ::FuncEnvironment;
|
use crate::func_environ::FuncEnvironment;
|
||||||
use crate::module::{Export, MemoryPlan, Module, TableElements, TablePlan};
|
use crate::module::{EntityIndex, MemoryPlan, Module, TableElements, TablePlan};
|
||||||
use crate::tunables::Tunables;
|
use crate::tunables::Tunables;
|
||||||
use cranelift_codegen::ir;
|
use cranelift_codegen::ir;
|
||||||
use cranelift_codegen::ir::{AbiParam, ArgumentPurpose};
|
use cranelift_codegen::ir::{AbiParam, ArgumentPurpose};
|
||||||
@@ -8,7 +8,7 @@ use cranelift_entity::PrimaryMap;
|
|||||||
use cranelift_wasm::{
|
use cranelift_wasm::{
|
||||||
self, translate_module, DataIndex, DefinedFuncIndex, ElemIndex, FuncIndex, Global, GlobalIndex,
|
self, translate_module, DataIndex, DefinedFuncIndex, ElemIndex, FuncIndex, Global, GlobalIndex,
|
||||||
Memory, MemoryIndex, ModuleTranslationState, SignatureIndex, Table, TableIndex,
|
Memory, MemoryIndex, ModuleTranslationState, SignatureIndex, Table, TableIndex,
|
||||||
TargetEnvironment, WasmResult,
|
TargetEnvironment, WasmError, WasmResult,
|
||||||
};
|
};
|
||||||
use std::convert::TryFrom;
|
use std::convert::TryFrom;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
@@ -57,7 +57,6 @@ impl<'data> ModuleTranslation<'data> {
|
|||||||
pub struct ModuleEnvironment<'data> {
|
pub struct ModuleEnvironment<'data> {
|
||||||
/// The result to be filled in.
|
/// The result to be filled in.
|
||||||
result: ModuleTranslation<'data>,
|
result: ModuleTranslation<'data>,
|
||||||
imports: u32,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'data> ModuleEnvironment<'data> {
|
impl<'data> ModuleEnvironment<'data> {
|
||||||
@@ -72,7 +71,6 @@ impl<'data> ModuleEnvironment<'data> {
|
|||||||
tunables: tunables.clone(),
|
tunables: tunables.clone(),
|
||||||
module_translation: None,
|
module_translation: None,
|
||||||
},
|
},
|
||||||
imports: 0,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -89,7 +87,7 @@ impl<'data> ModuleEnvironment<'data> {
|
|||||||
Ok(self.result)
|
Ok(self.result)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn declare_export(&mut self, export: Export, name: &str) -> WasmResult<()> {
|
fn declare_export(&mut self, export: EntityIndex, name: &str) -> WasmResult<()> {
|
||||||
self.result
|
self.result
|
||||||
.module
|
.module
|
||||||
.exports
|
.exports
|
||||||
@@ -123,6 +121,14 @@ impl<'data> cranelift_wasm::ModuleEnvironment<'data> for ModuleEnvironment<'data
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn reserve_imports(&mut self, num: u32) -> WasmResult<()> {
|
||||||
|
Ok(self
|
||||||
|
.result
|
||||||
|
.module
|
||||||
|
.imports
|
||||||
|
.reserve_exact(usize::try_from(num).unwrap()))
|
||||||
|
}
|
||||||
|
|
||||||
fn declare_func_import(
|
fn declare_func_import(
|
||||||
&mut self,
|
&mut self,
|
||||||
sig_index: SignatureIndex,
|
sig_index: SignatureIndex,
|
||||||
@@ -131,37 +137,33 @@ impl<'data> cranelift_wasm::ModuleEnvironment<'data> for ModuleEnvironment<'data
|
|||||||
) -> WasmResult<()> {
|
) -> WasmResult<()> {
|
||||||
debug_assert_eq!(
|
debug_assert_eq!(
|
||||||
self.result.module.local.functions.len(),
|
self.result.module.local.functions.len(),
|
||||||
self.result.module.imported_funcs.len(),
|
self.result.module.local.num_imported_funcs,
|
||||||
"Imported functions must be declared first"
|
"Imported functions must be declared first"
|
||||||
);
|
);
|
||||||
self.result.module.local.functions.push(sig_index);
|
let func_index = self.result.module.local.functions.push(sig_index);
|
||||||
|
self.result.module.imports.push((
|
||||||
self.result.module.imported_funcs.push((
|
module.to_owned(),
|
||||||
String::from(module),
|
field.to_owned(),
|
||||||
String::from(field),
|
EntityIndex::Function(func_index),
|
||||||
self.imports,
|
|
||||||
));
|
));
|
||||||
self.result.module.local.num_imported_funcs += 1;
|
self.result.module.local.num_imported_funcs += 1;
|
||||||
self.imports += 1;
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn declare_table_import(&mut self, table: Table, module: &str, field: &str) -> WasmResult<()> {
|
fn declare_table_import(&mut self, table: Table, module: &str, field: &str) -> WasmResult<()> {
|
||||||
debug_assert_eq!(
|
debug_assert_eq!(
|
||||||
self.result.module.local.table_plans.len(),
|
self.result.module.local.table_plans.len(),
|
||||||
self.result.module.imported_tables.len(),
|
self.result.module.local.num_imported_tables,
|
||||||
"Imported tables must be declared first"
|
"Imported tables must be declared first"
|
||||||
);
|
);
|
||||||
let plan = TablePlan::for_table(table, &self.result.tunables);
|
let plan = TablePlan::for_table(table, &self.result.tunables);
|
||||||
self.result.module.local.table_plans.push(plan);
|
let table_index = self.result.module.local.table_plans.push(plan);
|
||||||
|
self.result.module.imports.push((
|
||||||
self.result.module.imported_tables.push((
|
module.to_owned(),
|
||||||
String::from(module),
|
field.to_owned(),
|
||||||
String::from(field),
|
EntityIndex::Table(table_index),
|
||||||
self.imports,
|
|
||||||
));
|
));
|
||||||
self.result.module.local.num_imported_tables += 1;
|
self.result.module.local.num_imported_tables += 1;
|
||||||
self.imports += 1;
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -173,19 +175,20 @@ impl<'data> cranelift_wasm::ModuleEnvironment<'data> for ModuleEnvironment<'data
|
|||||||
) -> WasmResult<()> {
|
) -> WasmResult<()> {
|
||||||
debug_assert_eq!(
|
debug_assert_eq!(
|
||||||
self.result.module.local.memory_plans.len(),
|
self.result.module.local.memory_plans.len(),
|
||||||
self.result.module.imported_memories.len(),
|
self.result.module.local.num_imported_memories,
|
||||||
"Imported memories must be declared first"
|
"Imported memories must be declared first"
|
||||||
);
|
);
|
||||||
|
if memory.shared {
|
||||||
|
return Err(WasmError::Unsupported("shared memories".to_owned()));
|
||||||
|
}
|
||||||
let plan = MemoryPlan::for_memory(memory, &self.result.tunables);
|
let plan = MemoryPlan::for_memory(memory, &self.result.tunables);
|
||||||
self.result.module.local.memory_plans.push(plan);
|
let memory_index = self.result.module.local.memory_plans.push(plan);
|
||||||
|
self.result.module.imports.push((
|
||||||
self.result.module.imported_memories.push((
|
module.to_owned(),
|
||||||
String::from(module),
|
field.to_owned(),
|
||||||
String::from(field),
|
EntityIndex::Memory(memory_index),
|
||||||
self.imports,
|
|
||||||
));
|
));
|
||||||
self.result.module.local.num_imported_memories += 1;
|
self.result.module.local.num_imported_memories += 1;
|
||||||
self.imports += 1;
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -197,26 +200,16 @@ impl<'data> cranelift_wasm::ModuleEnvironment<'data> for ModuleEnvironment<'data
|
|||||||
) -> WasmResult<()> {
|
) -> WasmResult<()> {
|
||||||
debug_assert_eq!(
|
debug_assert_eq!(
|
||||||
self.result.module.local.globals.len(),
|
self.result.module.local.globals.len(),
|
||||||
self.result.module.imported_globals.len(),
|
self.result.module.local.num_imported_globals,
|
||||||
"Imported globals must be declared first"
|
"Imported globals must be declared first"
|
||||||
);
|
);
|
||||||
self.result.module.local.globals.push(global);
|
let global_index = self.result.module.local.globals.push(global);
|
||||||
|
self.result.module.imports.push((
|
||||||
self.result.module.imported_globals.push((
|
module.to_owned(),
|
||||||
String::from(module),
|
field.to_owned(),
|
||||||
String::from(field),
|
EntityIndex::Global(global_index),
|
||||||
self.imports,
|
|
||||||
));
|
));
|
||||||
self.result.module.local.num_imported_globals += 1;
|
self.result.module.local.num_imported_globals += 1;
|
||||||
self.imports += 1;
|
|
||||||
Ok(())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn finish_imports(&mut self) -> WasmResult<()> {
|
|
||||||
self.result.module.imported_funcs.shrink_to_fit();
|
|
||||||
self.result.module.imported_tables.shrink_to_fit();
|
|
||||||
self.result.module.imported_memories.shrink_to_fit();
|
|
||||||
self.result.module.imported_globals.shrink_to_fit();
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -262,6 +255,9 @@ impl<'data> cranelift_wasm::ModuleEnvironment<'data> for ModuleEnvironment<'data
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn declare_memory(&mut self, memory: Memory) -> WasmResult<()> {
|
fn declare_memory(&mut self, memory: Memory) -> WasmResult<()> {
|
||||||
|
if memory.shared {
|
||||||
|
return Err(WasmError::Unsupported("shared memories".to_owned()));
|
||||||
|
}
|
||||||
let plan = MemoryPlan::for_memory(memory, &self.result.tunables);
|
let plan = MemoryPlan::for_memory(memory, &self.result.tunables);
|
||||||
self.result.module.local.memory_plans.push(plan);
|
self.result.module.local.memory_plans.push(plan);
|
||||||
Ok(())
|
Ok(())
|
||||||
@@ -290,19 +286,19 @@ impl<'data> cranelift_wasm::ModuleEnvironment<'data> for ModuleEnvironment<'data
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn declare_func_export(&mut self, func_index: FuncIndex, name: &str) -> WasmResult<()> {
|
fn declare_func_export(&mut self, func_index: FuncIndex, name: &str) -> WasmResult<()> {
|
||||||
self.declare_export(Export::Function(func_index), name)
|
self.declare_export(EntityIndex::Function(func_index), name)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn declare_table_export(&mut self, table_index: TableIndex, name: &str) -> WasmResult<()> {
|
fn declare_table_export(&mut self, table_index: TableIndex, name: &str) -> WasmResult<()> {
|
||||||
self.declare_export(Export::Table(table_index), name)
|
self.declare_export(EntityIndex::Table(table_index), name)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn declare_memory_export(&mut self, memory_index: MemoryIndex, name: &str) -> WasmResult<()> {
|
fn declare_memory_export(&mut self, memory_index: MemoryIndex, name: &str) -> WasmResult<()> {
|
||||||
self.declare_export(Export::Memory(memory_index), name)
|
self.declare_export(EntityIndex::Memory(memory_index), name)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn declare_global_export(&mut self, global_index: GlobalIndex, name: &str) -> WasmResult<()> {
|
fn declare_global_export(&mut self, global_index: GlobalIndex, name: &str) -> WasmResult<()> {
|
||||||
self.declare_export(Export::Global(global_index), name)
|
self.declare_export(EntityIndex::Global(global_index), name)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn declare_start_func(&mut self, func_index: FuncIndex) -> WasmResult<()> {
|
fn declare_start_func(&mut self, func_index: FuncIndex) -> WasmResult<()> {
|
||||||
@@ -421,6 +417,27 @@ impl<'data> cranelift_wasm::ModuleEnvironment<'data> for ModuleEnvironment<'data
|
|||||||
.insert(func_index, name.to_string());
|
.insert(func_index, name.to_string());
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn custom_section(&mut self, name: &'data str, _data: &'data [u8]) -> WasmResult<()> {
|
||||||
|
match name {
|
||||||
|
"webidl-bindings" | "wasm-interface-types" => Err(WasmError::Unsupported(
|
||||||
|
"\
|
||||||
|
Support for interface types has temporarily been removed from `wasmtime`.
|
||||||
|
|
||||||
|
For more information about this temoprary you can read on the issue online:
|
||||||
|
|
||||||
|
https://github.com/bytecodealliance/wasmtime/issues/1271
|
||||||
|
|
||||||
|
and for re-adding support for interface types you can see this issue:
|
||||||
|
|
||||||
|
https://github.com/bytecodealliance/wasmtime/issues/677
|
||||||
|
"
|
||||||
|
.to_owned(),
|
||||||
|
)),
|
||||||
|
// skip other sections
|
||||||
|
_ => Ok(()),
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Add environment-specific function parameters.
|
/// Add environment-specific function parameters.
|
||||||
|
|||||||
@@ -169,31 +169,14 @@ pub fn differential_execution(
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let funcs = module
|
for (name, f) in instance.exports().filter_map(|e| {
|
||||||
.exports()
|
let name = e.name();
|
||||||
.iter()
|
e.into_func().map(|f| (name, f))
|
||||||
.filter_map(|e| {
|
}) {
|
||||||
if let ExternType::Func(_) = e.ty() {
|
|
||||||
Some(e.name())
|
|
||||||
} else {
|
|
||||||
None
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.collect::<Vec<_>>();
|
|
||||||
|
|
||||||
for name in funcs {
|
|
||||||
// Always call the hang limit initializer first, so that we don't
|
// Always call the hang limit initializer first, so that we don't
|
||||||
// infinite loop when calling another export.
|
// infinite loop when calling another export.
|
||||||
init_hang_limit(&instance);
|
init_hang_limit(&instance);
|
||||||
|
|
||||||
let f = match instance
|
|
||||||
.get_export(&name)
|
|
||||||
.expect("instance should have export from module")
|
|
||||||
{
|
|
||||||
Extern::Func(f) => f.clone(),
|
|
||||||
_ => panic!("export should be a function"),
|
|
||||||
};
|
|
||||||
|
|
||||||
let ty = f.ty();
|
let ty = f.ty();
|
||||||
let params = match dummy::dummy_values(ty.params()) {
|
let params = match dummy::dummy_values(ty.params()) {
|
||||||
Ok(p) => p,
|
Ok(p) => p,
|
||||||
@@ -378,8 +361,7 @@ pub fn make_api_calls(api: crate::generators::api::ApiCalls) {
|
|||||||
|
|
||||||
let funcs = instance
|
let funcs = instance
|
||||||
.exports()
|
.exports()
|
||||||
.iter()
|
.filter_map(|e| match e.into_extern() {
|
||||||
.filter_map(|e| match e {
|
|
||||||
Extern::Func(f) => Some(f.clone()),
|
Extern::Func(f) => Some(f.clone()),
|
||||||
_ => None,
|
_ => None,
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -6,19 +6,20 @@ use wasmtime::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
/// Create a set of dummy functions/globals/etc for the given imports.
|
/// Create a set of dummy functions/globals/etc for the given imports.
|
||||||
pub fn dummy_imports(store: &Store, import_tys: &[ImportType]) -> Result<Vec<Extern>, Trap> {
|
pub fn dummy_imports<'module>(
|
||||||
let mut imports = Vec::with_capacity(import_tys.len());
|
store: &Store,
|
||||||
for imp in import_tys {
|
import_tys: impl Iterator<Item = ImportType<'module>>,
|
||||||
imports.push(match imp.ty() {
|
) -> Result<Vec<Extern>, Trap> {
|
||||||
ExternType::Func(func_ty) => Extern::Func(dummy_func(&store, func_ty.clone())),
|
import_tys
|
||||||
ExternType::Global(global_ty) => {
|
.map(|imp| {
|
||||||
Extern::Global(dummy_global(&store, global_ty.clone())?)
|
Ok(match imp.ty() {
|
||||||
}
|
ExternType::Func(func_ty) => Extern::Func(dummy_func(&store, func_ty)),
|
||||||
ExternType::Table(table_ty) => Extern::Table(dummy_table(&store, table_ty.clone())?),
|
ExternType::Global(global_ty) => Extern::Global(dummy_global(&store, global_ty)?),
|
||||||
ExternType::Memory(mem_ty) => Extern::Memory(dummy_memory(&store, mem_ty.clone())),
|
ExternType::Table(table_ty) => Extern::Table(dummy_table(&store, table_ty)?),
|
||||||
});
|
ExternType::Memory(mem_ty) => Extern::Memory(dummy_memory(&store, mem_ty)),
|
||||||
}
|
})
|
||||||
Ok(imports)
|
})
|
||||||
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Construct a dummy function for the given function type
|
/// Construct a dummy function for the given function type
|
||||||
|
|||||||
@@ -3,9 +3,10 @@
|
|||||||
use crate::resolver::Resolver;
|
use crate::resolver::Resolver;
|
||||||
use more_asserts::assert_ge;
|
use more_asserts::assert_ge;
|
||||||
use std::collections::HashSet;
|
use std::collections::HashSet;
|
||||||
|
use std::convert::TryInto;
|
||||||
use wasmtime_environ::entity::PrimaryMap;
|
use wasmtime_environ::entity::PrimaryMap;
|
||||||
use wasmtime_environ::wasm::{Global, GlobalInit, Memory, Table, TableElementType};
|
use wasmtime_environ::wasm::{Global, GlobalInit, Memory, Table, TableElementType};
|
||||||
use wasmtime_environ::{MemoryPlan, MemoryStyle, Module, TablePlan};
|
use wasmtime_environ::{EntityIndex, MemoryPlan, MemoryStyle, Module, TablePlan};
|
||||||
use wasmtime_runtime::{
|
use wasmtime_runtime::{
|
||||||
Export, Imports, InstanceHandle, LinkError, SignatureRegistry, VMFunctionImport,
|
Export, Imports, InstanceHandle, LinkError, SignatureRegistry, VMFunctionImport,
|
||||||
VMGlobalImport, VMMemoryImport, VMTableImport,
|
VMGlobalImport, VMMemoryImport, VMTableImport,
|
||||||
@@ -22,12 +23,18 @@ pub fn resolve_imports(
|
|||||||
) -> Result<Imports, LinkError> {
|
) -> Result<Imports, LinkError> {
|
||||||
let mut dependencies = HashSet::new();
|
let mut dependencies = HashSet::new();
|
||||||
|
|
||||||
let mut function_imports = PrimaryMap::with_capacity(module.imported_funcs.len());
|
let mut function_imports = PrimaryMap::with_capacity(module.local.num_imported_funcs);
|
||||||
for (index, (module_name, field, import_idx)) in module.imported_funcs.iter() {
|
let mut table_imports = PrimaryMap::with_capacity(module.local.num_imported_tables);
|
||||||
match resolver.resolve(*import_idx, module_name, field) {
|
let mut memory_imports = PrimaryMap::with_capacity(module.local.num_imported_memories);
|
||||||
Some(export_value) => match export_value {
|
let mut global_imports = PrimaryMap::with_capacity(module.local.num_imported_globals);
|
||||||
Export::Function(f) => {
|
|
||||||
let import_signature = &module.local.signatures[module.local.functions[index]];
|
for (import_idx, (module_name, field_name, import)) in module.imports.iter().enumerate() {
|
||||||
|
let import_idx = import_idx.try_into().unwrap();
|
||||||
|
let export = resolver.resolve(import_idx, module_name, field_name);
|
||||||
|
|
||||||
|
match (import, &export) {
|
||||||
|
(EntityIndex::Function(func_index), Some(Export::Function(f))) => {
|
||||||
|
let import_signature = module.local.func_signature(*func_index);
|
||||||
let signature = signatures.lookup(f.signature).unwrap();
|
let signature = signatures.lookup(f.signature).unwrap();
|
||||||
if signature != *import_signature {
|
if signature != *import_signature {
|
||||||
// TODO: If the difference is in the calling convention,
|
// TODO: If the difference is in the calling convention,
|
||||||
@@ -35,7 +42,7 @@ pub fn resolve_imports(
|
|||||||
return Err(LinkError(format!(
|
return Err(LinkError(format!(
|
||||||
"{}/{}: incompatible import type: exported function with signature {} \
|
"{}/{}: incompatible import type: exported function with signature {} \
|
||||||
incompatible with function import with signature {}",
|
incompatible with function import with signature {}",
|
||||||
module_name, field, signature, import_signature
|
module_name, field_name, signature, import_signature
|
||||||
)));
|
)));
|
||||||
}
|
}
|
||||||
dependencies.insert(unsafe { InstanceHandle::from_vmctx(f.vmctx) });
|
dependencies.insert(unsafe { InstanceHandle::from_vmctx(f.vmctx) });
|
||||||
@@ -44,33 +51,26 @@ pub fn resolve_imports(
|
|||||||
vmctx: f.vmctx,
|
vmctx: f.vmctx,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
Export::Table(_) | Export::Memory(_) | Export::Global(_) => {
|
(EntityIndex::Function(_), Some(_)) => {
|
||||||
return Err(LinkError(format!(
|
return Err(LinkError(format!(
|
||||||
"{}/{}: incompatible import type: export incompatible with function import",
|
"{}/{}: incompatible import type: export incompatible with function import",
|
||||||
module_name, field
|
module_name, field_name
|
||||||
)));
|
)));
|
||||||
}
|
}
|
||||||
},
|
(EntityIndex::Function(_), None) => {
|
||||||
None => {
|
|
||||||
return Err(LinkError(format!(
|
return Err(LinkError(format!(
|
||||||
"{}/{}: unknown import function: function not provided",
|
"{}/{}: unknown import function: function not provided",
|
||||||
module_name, field
|
module_name, field_name
|
||||||
)));
|
)));
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut table_imports = PrimaryMap::with_capacity(module.imported_tables.len());
|
(EntityIndex::Table(table_index), Some(Export::Table(t))) => {
|
||||||
for (index, (module_name, field, import_idx)) in module.imported_tables.iter() {
|
let import_table = &module.local.table_plans[*table_index];
|
||||||
match resolver.resolve(*import_idx, module_name, field) {
|
|
||||||
Some(export_value) => match export_value {
|
|
||||||
Export::Table(t) => {
|
|
||||||
let import_table = &module.local.table_plans[index];
|
|
||||||
if !is_table_compatible(&t.table, import_table) {
|
if !is_table_compatible(&t.table, import_table) {
|
||||||
return Err(LinkError(format!(
|
return Err(LinkError(format!(
|
||||||
"{}/{}: incompatible import type: exported table incompatible with \
|
"{}/{}: incompatible import type: exported table incompatible with \
|
||||||
table import",
|
table import",
|
||||||
module_name, field,
|
module_name, field_name,
|
||||||
)));
|
)));
|
||||||
}
|
}
|
||||||
dependencies.insert(unsafe { InstanceHandle::from_vmctx(t.vmctx) });
|
dependencies.insert(unsafe { InstanceHandle::from_vmctx(t.vmctx) });
|
||||||
@@ -79,33 +79,26 @@ pub fn resolve_imports(
|
|||||||
vmctx: t.vmctx,
|
vmctx: t.vmctx,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
Export::Global(_) | Export::Memory(_) | Export::Function(_) => {
|
(EntityIndex::Table(_), Some(_)) => {
|
||||||
return Err(LinkError(format!(
|
return Err(LinkError(format!(
|
||||||
"{}/{}: incompatible import type: export incompatible with table import",
|
"{}/{}: incompatible import type: export incompatible with table import",
|
||||||
module_name, field
|
module_name, field_name
|
||||||
)));
|
)));
|
||||||
}
|
}
|
||||||
},
|
(EntityIndex::Table(_), None) => {
|
||||||
None => {
|
|
||||||
return Err(LinkError(format!(
|
return Err(LinkError(format!(
|
||||||
"unknown import: no provided import table for {}/{}",
|
"{}/{}: unknown import table: table not provided",
|
||||||
module_name, field
|
module_name, field_name
|
||||||
)));
|
)));
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut memory_imports = PrimaryMap::with_capacity(module.imported_memories.len());
|
(EntityIndex::Memory(memory_index), Some(Export::Memory(m))) => {
|
||||||
for (index, (module_name, field, import_idx)) in module.imported_memories.iter() {
|
let import_memory = &module.local.memory_plans[*memory_index];
|
||||||
match resolver.resolve(*import_idx, module_name, field) {
|
|
||||||
Some(export_value) => match export_value {
|
|
||||||
Export::Memory(m) => {
|
|
||||||
let import_memory = &module.local.memory_plans[index];
|
|
||||||
if !is_memory_compatible(&m.memory, import_memory) {
|
if !is_memory_compatible(&m.memory, import_memory) {
|
||||||
return Err(LinkError(format!(
|
return Err(LinkError(format!(
|
||||||
"{}/{}: incompatible import type: exported memory incompatible with \
|
"{}/{}: incompatible import type: exported memory incompatible with \
|
||||||
memory import",
|
memory import",
|
||||||
module_name, field
|
module_name, field_name
|
||||||
)));
|
)));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -116,9 +109,9 @@ pub fn resolve_imports(
|
|||||||
MemoryStyle::Static {
|
MemoryStyle::Static {
|
||||||
bound: import_bound,
|
bound: import_bound,
|
||||||
},
|
},
|
||||||
) = (m.memory.style, &import_memory.style)
|
) = (&m.memory.style, &import_memory.style)
|
||||||
{
|
{
|
||||||
assert_ge!(bound, *import_bound);
|
assert_ge!(*bound, *import_bound);
|
||||||
}
|
}
|
||||||
assert_ge!(m.memory.offset_guard_size, import_memory.offset_guard_size);
|
assert_ge!(m.memory.offset_guard_size, import_memory.offset_guard_size);
|
||||||
|
|
||||||
@@ -128,50 +121,41 @@ pub fn resolve_imports(
|
|||||||
vmctx: m.vmctx,
|
vmctx: m.vmctx,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
Export::Table(_) | Export::Global(_) | Export::Function(_) => {
|
(EntityIndex::Memory(_), Some(_)) => {
|
||||||
return Err(LinkError(format!(
|
return Err(LinkError(format!(
|
||||||
"{}/{}: incompatible import type: export incompatible with memory import",
|
"{}/{}: incompatible import type: export incompatible with memory import",
|
||||||
module_name, field
|
module_name, field_name
|
||||||
)));
|
)));
|
||||||
}
|
}
|
||||||
},
|
(EntityIndex::Memory(_), None) => {
|
||||||
None => {
|
|
||||||
return Err(LinkError(format!(
|
return Err(LinkError(format!(
|
||||||
"unknown import: no provided import memory for {}/{}",
|
"{}/{}: unknown import memory: memory not provided",
|
||||||
module_name, field
|
module_name, field_name
|
||||||
)));
|
)));
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
let mut global_imports = PrimaryMap::with_capacity(module.imported_globals.len());
|
(EntityIndex::Global(global_index), Some(Export::Global(g))) => {
|
||||||
for (index, (module_name, field, import_idx)) in module.imported_globals.iter() {
|
let imported_global = module.local.globals[*global_index];
|
||||||
match resolver.resolve(*import_idx, module_name, field) {
|
|
||||||
Some(export_value) => match export_value {
|
|
||||||
Export::Table(_) | Export::Memory(_) | Export::Function(_) => {
|
|
||||||
return Err(LinkError(format!(
|
|
||||||
"{}/{}: incompatible import type: exported global incompatible with \
|
|
||||||
global import",
|
|
||||||
module_name, field
|
|
||||||
)));
|
|
||||||
}
|
|
||||||
Export::Global(g) => {
|
|
||||||
let imported_global = module.local.globals[index];
|
|
||||||
if !is_global_compatible(&g.global, &imported_global) {
|
if !is_global_compatible(&g.global, &imported_global) {
|
||||||
return Err(LinkError(format!(
|
return Err(LinkError(format!(
|
||||||
"{}/{}: incompatible import type: exported global incompatible with \
|
"{}/{}: incompatible import type: exported global incompatible with \
|
||||||
global import",
|
global import",
|
||||||
module_name, field
|
module_name, field_name
|
||||||
)));
|
)));
|
||||||
}
|
}
|
||||||
dependencies.insert(unsafe { InstanceHandle::from_vmctx(g.vmctx) });
|
dependencies.insert(unsafe { InstanceHandle::from_vmctx(g.vmctx) });
|
||||||
global_imports.push(VMGlobalImport { from: g.definition });
|
global_imports.push(VMGlobalImport { from: g.definition });
|
||||||
}
|
}
|
||||||
},
|
(EntityIndex::Global(_), Some(_)) => {
|
||||||
None => {
|
|
||||||
return Err(LinkError(format!(
|
return Err(LinkError(format!(
|
||||||
"unknown import: no provided import global for {}/{}",
|
"{}/{}: incompatible import type: export incompatible with global import",
|
||||||
module_name, field
|
module_name, field_name
|
||||||
|
)));
|
||||||
|
}
|
||||||
|
(EntityIndex::Global(_), None) => {
|
||||||
|
return Err(LinkError(format!(
|
||||||
|
"{}/{}: unknown import global: global not provided",
|
||||||
|
module_name, field_name
|
||||||
)));
|
)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -42,7 +42,7 @@ pub fn layout_vmcontext(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let num_tables_imports = module.imported_tables.len();
|
let num_tables_imports = module.local.num_imported_tables;
|
||||||
let mut table_relocs = Vec::with_capacity(module.local.table_plans.len() - num_tables_imports);
|
let mut table_relocs = Vec::with_capacity(module.local.table_plans.len() - num_tables_imports);
|
||||||
for (index, table) in module.local.table_plans.iter().skip(num_tables_imports) {
|
for (index, table) in module.local.table_plans.iter().skip(num_tables_imports) {
|
||||||
let def_index = module.local.defined_table_index(index).unwrap();
|
let def_index = module.local.defined_table_index(index).unwrap();
|
||||||
@@ -66,7 +66,7 @@ pub fn layout_vmcontext(
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
let num_globals_imports = module.imported_globals.len();
|
let num_globals_imports = module.local.num_imported_globals;
|
||||||
for (index, global) in module.local.globals.iter().skip(num_globals_imports) {
|
for (index, global) in module.local.globals.iter().skip(num_globals_imports) {
|
||||||
let def_index = module.local.defined_global_index(index).unwrap();
|
let def_index = module.local.defined_global_index(index).unwrap();
|
||||||
let offset = ofs.vmctx_vmglobal_definition(def_index) as usize;
|
let offset = ofs.vmctx_vmglobal_definition(def_index) as usize;
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ pub fn declare_functions(
|
|||||||
module: &Module,
|
module: &Module,
|
||||||
relocations: &Relocations,
|
relocations: &Relocations,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
for i in 0..module.imported_funcs.len() {
|
for i in 0..module.local.num_imported_funcs {
|
||||||
let string_name = format!("_wasm_function_{}", i);
|
let string_name = format!("_wasm_function_{}", i);
|
||||||
obj.declare(string_name, Decl::function_import())?;
|
obj.declare(string_name, Decl::function_import())?;
|
||||||
}
|
}
|
||||||
@@ -32,7 +32,7 @@ pub fn emit_functions(
|
|||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
debug_assert!(
|
debug_assert!(
|
||||||
module.start_func.is_none()
|
module.start_func.is_none()
|
||||||
|| module.start_func.unwrap().index() >= module.imported_funcs.len(),
|
|| module.start_func.unwrap().index() >= module.local.num_imported_funcs,
|
||||||
"imported start functions not supported yet"
|
"imported start functions not supported yet"
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ pub unsafe extern "C" fn resolve_vmctx_memory_ptr(p: *const u32) -> *const u8 {
|
|||||||
);
|
);
|
||||||
let handle = InstanceHandle::from_vmctx(VMCTX_AND_MEMORY.0);
|
let handle = InstanceHandle::from_vmctx(VMCTX_AND_MEMORY.0);
|
||||||
assert!(
|
assert!(
|
||||||
VMCTX_AND_MEMORY.1 < handle.instance().module().local.memory_plans.len(),
|
VMCTX_AND_MEMORY.1 < handle.module().local.memory_plans.len(),
|
||||||
"memory index for debugger is out of bounds"
|
"memory index for debugger is out of bounds"
|
||||||
);
|
);
|
||||||
let index = MemoryIndex::new(VMCTX_AND_MEMORY.1);
|
let index = MemoryIndex::new(VMCTX_AND_MEMORY.1);
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ use wasmtime_environ::wasm::{
|
|||||||
DataIndex, DefinedFuncIndex, DefinedGlobalIndex, DefinedMemoryIndex, DefinedTableIndex,
|
DataIndex, DefinedFuncIndex, DefinedGlobalIndex, DefinedMemoryIndex, DefinedTableIndex,
|
||||||
ElemIndex, FuncIndex, GlobalIndex, GlobalInit, MemoryIndex, SignatureIndex, TableIndex,
|
ElemIndex, FuncIndex, GlobalIndex, GlobalInit, MemoryIndex, SignatureIndex, TableIndex,
|
||||||
};
|
};
|
||||||
use wasmtime_environ::{ir, DataInitializer, Module, TableElements, VMOffsets};
|
use wasmtime_environ::{ir, DataInitializer, EntityIndex, Module, TableElements, VMOffsets};
|
||||||
|
|
||||||
cfg_if::cfg_if! {
|
cfg_if::cfg_if! {
|
||||||
if #[cfg(unix)] {
|
if #[cfg(unix)] {
|
||||||
@@ -296,9 +296,9 @@ impl Instance {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Lookup an export with the given export declaration.
|
/// Lookup an export with the given export declaration.
|
||||||
pub fn lookup_by_declaration(&self, export: &wasmtime_environ::Export) -> Export {
|
pub fn lookup_by_declaration(&self, export: &EntityIndex) -> Export {
|
||||||
match export {
|
match export {
|
||||||
wasmtime_environ::Export::Function(index) => {
|
EntityIndex::Function(index) => {
|
||||||
let signature = self.signature_id(self.module.local.functions[*index]);
|
let signature = self.signature_id(self.module.local.functions[*index]);
|
||||||
let (address, vmctx) =
|
let (address, vmctx) =
|
||||||
if let Some(def_index) = self.module.local.defined_func_index(*index) {
|
if let Some(def_index) = self.module.local.defined_func_index(*index) {
|
||||||
@@ -317,7 +317,7 @@ impl Instance {
|
|||||||
}
|
}
|
||||||
.into()
|
.into()
|
||||||
}
|
}
|
||||||
wasmtime_environ::Export::Table(index) => {
|
EntityIndex::Table(index) => {
|
||||||
let (definition, vmctx) =
|
let (definition, vmctx) =
|
||||||
if let Some(def_index) = self.module.local.defined_table_index(*index) {
|
if let Some(def_index) = self.module.local.defined_table_index(*index) {
|
||||||
(self.table_ptr(def_index), self.vmctx_ptr())
|
(self.table_ptr(def_index), self.vmctx_ptr())
|
||||||
@@ -332,7 +332,7 @@ impl Instance {
|
|||||||
}
|
}
|
||||||
.into()
|
.into()
|
||||||
}
|
}
|
||||||
wasmtime_environ::Export::Memory(index) => {
|
EntityIndex::Memory(index) => {
|
||||||
let (definition, vmctx) =
|
let (definition, vmctx) =
|
||||||
if let Some(def_index) = self.module.local.defined_memory_index(*index) {
|
if let Some(def_index) = self.module.local.defined_memory_index(*index) {
|
||||||
(self.memory_ptr(def_index), self.vmctx_ptr())
|
(self.memory_ptr(def_index), self.vmctx_ptr())
|
||||||
@@ -347,7 +347,7 @@ impl Instance {
|
|||||||
}
|
}
|
||||||
.into()
|
.into()
|
||||||
}
|
}
|
||||||
wasmtime_environ::Export::Global(index) => ExportGlobal {
|
EntityIndex::Global(index) => ExportGlobal {
|
||||||
definition: if let Some(def_index) = self.module.local.defined_global_index(*index)
|
definition: if let Some(def_index) = self.module.local.defined_global_index(*index)
|
||||||
{
|
{
|
||||||
self.global_ptr(def_index)
|
self.global_ptr(def_index)
|
||||||
@@ -363,10 +363,10 @@ impl Instance {
|
|||||||
|
|
||||||
/// Return an iterator over the exports of this instance.
|
/// Return an iterator over the exports of this instance.
|
||||||
///
|
///
|
||||||
/// Specifically, it provides access to the key-value pairs, where they keys
|
/// Specifically, it provides access to the key-value pairs, where the keys
|
||||||
/// are export names, and the values are export declarations which can be
|
/// are export names, and the values are export declarations which can be
|
||||||
/// resolved `lookup_by_declaration`.
|
/// resolved `lookup_by_declaration`.
|
||||||
pub fn exports(&self) -> indexmap::map::Iter<String, wasmtime_environ::Export> {
|
pub fn exports(&self) -> indexmap::map::Iter<String, EntityIndex> {
|
||||||
self.module.exports.iter()
|
self.module.exports.iter()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -383,8 +383,13 @@ impl Instance {
|
|||||||
None => return Ok(()),
|
None => return Ok(()),
|
||||||
};
|
};
|
||||||
|
|
||||||
let (callee_address, callee_vmctx) = match self.module.local.defined_func_index(start_index)
|
self.invoke_function_index(start_index)
|
||||||
{
|
.map_err(InstantiationError::StartTrap)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn invoke_function_index(&self, callee_index: FuncIndex) -> Result<(), Trap> {
|
||||||
|
let (callee_address, callee_vmctx) =
|
||||||
|
match self.module.local.defined_func_index(callee_index) {
|
||||||
Some(defined_index) => {
|
Some(defined_index) => {
|
||||||
let body = *self
|
let body = *self
|
||||||
.finished_functions
|
.finished_functions
|
||||||
@@ -393,12 +398,20 @@ impl Instance {
|
|||||||
(body as *const _, self.vmctx_ptr())
|
(body as *const _, self.vmctx_ptr())
|
||||||
}
|
}
|
||||||
None => {
|
None => {
|
||||||
assert_lt!(start_index.index(), self.module.imported_funcs.len());
|
assert_lt!(callee_index.index(), self.module.local.num_imported_funcs);
|
||||||
let import = self.imported_function(start_index);
|
let import = self.imported_function(callee_index);
|
||||||
(import.body, import.vmctx)
|
(import.body, import.vmctx)
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
self.invoke_function(callee_vmctx, callee_address)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn invoke_function(
|
||||||
|
&self,
|
||||||
|
callee_vmctx: *mut VMContext,
|
||||||
|
callee_address: *const VMFunctionBody,
|
||||||
|
) -> Result<(), Trap> {
|
||||||
// Make the call.
|
// Make the call.
|
||||||
unsafe {
|
unsafe {
|
||||||
catch_traps(callee_vmctx, || {
|
catch_traps(callee_vmctx, || {
|
||||||
@@ -407,7 +420,6 @@ impl Instance {
|
|||||||
unsafe extern "C" fn(*mut VMContext, *mut VMContext),
|
unsafe extern "C" fn(*mut VMContext, *mut VMContext),
|
||||||
>(callee_address)(callee_vmctx, self.vmctx_ptr())
|
>(callee_address)(callee_vmctx, self.vmctx_ptr())
|
||||||
})
|
})
|
||||||
.map_err(InstantiationError::StartTrap)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1019,7 +1031,7 @@ impl InstanceHandle {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Lookup an export with the given export declaration.
|
/// Lookup an export with the given export declaration.
|
||||||
pub fn lookup_by_declaration(&self, export: &wasmtime_environ::Export) -> Export {
|
pub fn lookup_by_declaration(&self, export: &EntityIndex) -> Export {
|
||||||
self.instance().lookup_by_declaration(export)
|
self.instance().lookup_by_declaration(export)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1028,7 +1040,7 @@ impl InstanceHandle {
|
|||||||
/// Specifically, it provides access to the key-value pairs, where the keys
|
/// Specifically, it provides access to the key-value pairs, where the keys
|
||||||
/// are export names, and the values are export declarations which can be
|
/// are export names, and the values are export declarations which can be
|
||||||
/// resolved `lookup_by_declaration`.
|
/// resolved `lookup_by_declaration`.
|
||||||
pub fn exports(&self) -> indexmap::map::Iter<String, wasmtime_environ::Export> {
|
pub fn exports(&self) -> indexmap::map::Iter<String, EntityIndex> {
|
||||||
self.instance().exports()
|
self.instance().exports()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1204,7 +1216,7 @@ fn check_memory_init_bounds(
|
|||||||
|
|
||||||
/// Allocate memory for just the tables of the current module.
|
/// Allocate memory for just the tables of the current module.
|
||||||
fn create_tables(module: &Module) -> BoxedSlice<DefinedTableIndex, Table> {
|
fn create_tables(module: &Module) -> BoxedSlice<DefinedTableIndex, Table> {
|
||||||
let num_imports = module.imported_tables.len();
|
let num_imports = module.local.num_imported_tables;
|
||||||
let mut tables: PrimaryMap<DefinedTableIndex, _> =
|
let mut tables: PrimaryMap<DefinedTableIndex, _> =
|
||||||
PrimaryMap::with_capacity(module.local.table_plans.len() - num_imports);
|
PrimaryMap::with_capacity(module.local.table_plans.len() - num_imports);
|
||||||
for table in &module.local.table_plans.values().as_slice()[num_imports..] {
|
for table in &module.local.table_plans.values().as_slice()[num_imports..] {
|
||||||
@@ -1291,7 +1303,7 @@ fn create_memories(
|
|||||||
module: &Module,
|
module: &Module,
|
||||||
mem_creator: &dyn RuntimeMemoryCreator,
|
mem_creator: &dyn RuntimeMemoryCreator,
|
||||||
) -> Result<BoxedSlice<DefinedMemoryIndex, Box<dyn RuntimeLinearMemory>>, InstantiationError> {
|
) -> Result<BoxedSlice<DefinedMemoryIndex, Box<dyn RuntimeLinearMemory>>, InstantiationError> {
|
||||||
let num_imports = module.imported_memories.len();
|
let num_imports = module.local.num_imported_memories;
|
||||||
let mut memories: PrimaryMap<DefinedMemoryIndex, _> =
|
let mut memories: PrimaryMap<DefinedMemoryIndex, _> =
|
||||||
PrimaryMap::with_capacity(module.local.memory_plans.len() - num_imports);
|
PrimaryMap::with_capacity(module.local.memory_plans.len() - num_imports);
|
||||||
for plan in &module.local.memory_plans.values().as_slice()[num_imports..] {
|
for plan in &module.local.memory_plans.values().as_slice()[num_imports..] {
|
||||||
@@ -1336,7 +1348,7 @@ fn initialize_memories(
|
|||||||
/// Allocate memory for just the globals of the current module,
|
/// Allocate memory for just the globals of the current module,
|
||||||
/// with initializers applied.
|
/// with initializers applied.
|
||||||
fn create_globals(module: &Module) -> BoxedSlice<DefinedGlobalIndex, VMGlobalDefinition> {
|
fn create_globals(module: &Module) -> BoxedSlice<DefinedGlobalIndex, VMGlobalDefinition> {
|
||||||
let num_imports = module.imported_globals.len();
|
let num_imports = module.local.num_imported_globals;
|
||||||
let mut vmctx_globals = PrimaryMap::with_capacity(module.local.globals.len() - num_imports);
|
let mut vmctx_globals = PrimaryMap::with_capacity(module.local.globals.len() - num_imports);
|
||||||
|
|
||||||
for _ in &module.local.globals.values().as_slice()[num_imports..] {
|
for _ in &module.local.globals.values().as_slice()[num_imports..] {
|
||||||
@@ -1348,7 +1360,7 @@ fn create_globals(module: &Module) -> BoxedSlice<DefinedGlobalIndex, VMGlobalDef
|
|||||||
|
|
||||||
fn initialize_globals(instance: &Instance) {
|
fn initialize_globals(instance: &Instance) {
|
||||||
let module = Arc::clone(&instance.module);
|
let module = Arc::clone(&instance.module);
|
||||||
let num_imports = module.imported_globals.len();
|
let num_imports = module.local.num_imported_globals;
|
||||||
for (index, global) in module.local.globals.iter().skip(num_imports) {
|
for (index, global) in module.local.globals.iter().skip(num_imports) {
|
||||||
let def_index = module.local.defined_global_index(index).unwrap();
|
let def_index = module.local.defined_global_index(index).unwrap();
|
||||||
unsafe {
|
unsafe {
|
||||||
@@ -1394,7 +1406,7 @@ pub enum InstantiationError {
|
|||||||
#[error("Trap occurred during instantiation")]
|
#[error("Trap occurred during instantiation")]
|
||||||
Trap(Trap),
|
Trap(Trap),
|
||||||
|
|
||||||
/// A compilation error occured.
|
/// A trap occurred while running the wasm start function.
|
||||||
#[error("Trap occurred while invoking start function")]
|
#[error("Trap occurred while invoking start function")]
|
||||||
StartTrap(Trap),
|
StartTrap(Trap),
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -51,7 +51,6 @@ pub fn instantiate(
|
|||||||
let module = Module::new(&store, &data).context("failed to create wasm module")?;
|
let module = Module::new(&store, &data).context("failed to create wasm module")?;
|
||||||
let imports = module
|
let imports = module
|
||||||
.imports()
|
.imports()
|
||||||
.iter()
|
|
||||||
.map(|i| {
|
.map(|i| {
|
||||||
let field_name = i.name();
|
let field_name = i.name();
|
||||||
if let Some(export) = snapshot1.get_export(field_name) {
|
if let Some(export) = snapshot1.get_export(field_name) {
|
||||||
@@ -60,7 +59,7 @@ pub fn instantiate(
|
|||||||
bail!(
|
bail!(
|
||||||
"import {} was not found in module {}",
|
"import {} was not found in module {}",
|
||||||
field_name,
|
field_name,
|
||||||
i.module(),
|
i.module()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
@@ -71,13 +70,10 @@ pub fn instantiate(
|
|||||||
bin_name,
|
bin_name,
|
||||||
))?;
|
))?;
|
||||||
|
|
||||||
let export = instance
|
instance
|
||||||
.get_export("_start")
|
.get_export("_start")
|
||||||
.context("expected a _start export")?
|
.context("expected a _start export")?
|
||||||
.clone();
|
.into_func()
|
||||||
|
|
||||||
export
|
|
||||||
.func()
|
|
||||||
.context("expected export to be a func")?
|
.context("expected export to be a func")?
|
||||||
.call(&[])?;
|
.call(&[])?;
|
||||||
|
|
||||||
|
|||||||
@@ -66,7 +66,7 @@ impl WastContext {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_export(&self, module: Option<&str>, name: &str) -> Result<&Extern> {
|
fn get_export(&self, module: Option<&str>, name: &str) -> Result<Extern> {
|
||||||
match module {
|
match module {
|
||||||
Some(module) => self.linker.get_one_by_name(module, name),
|
Some(module) => self.linker.get_one_by_name(module, name),
|
||||||
None => self
|
None => self
|
||||||
@@ -156,7 +156,7 @@ impl WastContext {
|
|||||||
) -> Result<Outcome> {
|
) -> Result<Outcome> {
|
||||||
let func = self
|
let func = self
|
||||||
.get_export(instance_name, field)?
|
.get_export(instance_name, field)?
|
||||||
.func()
|
.into_func()
|
||||||
.ok_or_else(|| anyhow!("no function named `{}`", field))?;
|
.ok_or_else(|| anyhow!("no function named `{}`", field))?;
|
||||||
Ok(match func.call(args) {
|
Ok(match func.call(args) {
|
||||||
Ok(result) => Outcome::Ok(result.into()),
|
Ok(result) => Outcome::Ok(result.into()),
|
||||||
@@ -168,7 +168,7 @@ impl WastContext {
|
|||||||
fn get(&mut self, instance_name: Option<&str>, field: &str) -> Result<Outcome> {
|
fn get(&mut self, instance_name: Option<&str>, field: &str) -> Result<Outcome> {
|
||||||
let global = self
|
let global = self
|
||||||
.get_export(instance_name, field)?
|
.get_export(instance_name, field)?
|
||||||
.global()
|
.into_global()
|
||||||
.ok_or_else(|| anyhow!("no global named `{}`", field))?;
|
.ok_or_else(|| anyhow!("no global named `{}`", field))?;
|
||||||
Ok(Outcome::Ok(vec![global.get()]))
|
Ok(Outcome::Ok(vec![global.get()]))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -74,10 +74,8 @@ fn main() -> Result<(), Box<dyn Error>> {
|
|||||||
// The `Instance` gives us access to various exported functions and items,
|
// The `Instance` gives us access to various exported functions and items,
|
||||||
// which we access here to pull out our `answer` exported function and
|
// which we access here to pull out our `answer` exported function and
|
||||||
// run it.
|
// run it.
|
||||||
let answer = instance.get_export("answer")
|
let answer = instance.get_func("answer")
|
||||||
.expect("export named `answer` not found")
|
.expect("`answer` was not an exported function");
|
||||||
.func()
|
|
||||||
.expect("export `answer` was not a function");
|
|
||||||
|
|
||||||
// There's a few ways we can call the `answer` `Func` value. The easiest
|
// There's a few ways we can call the `answer` `Func` value. The easiest
|
||||||
// is to statically assert its signature with `get0` (in this case asserting
|
// is to statically assert its signature with `get0` (in this case asserting
|
||||||
|
|||||||
@@ -47,7 +47,7 @@ let wat = r#"
|
|||||||
"#;
|
"#;
|
||||||
let module = Module::new(&store, wat)?;
|
let module = Module::new(&store, wat)?;
|
||||||
let instance = Instance::new(&module, &[])?;
|
let instance = Instance::new(&module, &[])?;
|
||||||
let add = instance.get_export("add").and_then(|f| f.func()).unwrap();
|
let add = instance.get_func("add").unwrap();
|
||||||
let add = add.get2::<i32, i32, i32>()?;
|
let add = add.get2::<i32, i32, i32>()?;
|
||||||
println!("1 + 2 = {}", add(1, 2)?);
|
println!("1 + 2 = {}", add(1, 2)?);
|
||||||
# Ok(())
|
# Ok(())
|
||||||
|
|||||||
@@ -22,8 +22,7 @@ fn main() -> Result<()> {
|
|||||||
|
|
||||||
// Invoke `fib` export
|
// Invoke `fib` export
|
||||||
let fib = instance
|
let fib = instance
|
||||||
.get_export("fib")
|
.get_func("fib")
|
||||||
.and_then(|e| e.func())
|
|
||||||
.ok_or(anyhow::format_err!("failed to find `fib` function export"))?
|
.ok_or(anyhow::format_err!("failed to find `fib` function export"))?
|
||||||
.get1::<i32, i32>()?;
|
.get1::<i32, i32>()?;
|
||||||
println!("fib(6) = {}", fib(6)?);
|
println!("fib(6) = {}", fib(6)?);
|
||||||
|
|||||||
@@ -16,8 +16,7 @@ fn main() -> Result<()> {
|
|||||||
|
|
||||||
// Invoke `gcd` export
|
// Invoke `gcd` export
|
||||||
let gcd = instance
|
let gcd = instance
|
||||||
.get_export("gcd")
|
.get_func("gcd")
|
||||||
.and_then(|e| e.func())
|
|
||||||
.ok_or(anyhow::format_err!("failed to find `gcd` function export"))?
|
.ok_or(anyhow::format_err!("failed to find `gcd` function export"))?
|
||||||
.get2::<i32, i32, i32>()?;
|
.get2::<i32, i32, i32>()?;
|
||||||
|
|
||||||
|
|||||||
@@ -35,8 +35,7 @@ fn main() -> Result<()> {
|
|||||||
// Next we poke around a bit to extract the `run` function from the module.
|
// Next we poke around a bit to extract the `run` function from the module.
|
||||||
println!("Extracting export...");
|
println!("Extracting export...");
|
||||||
let run = instance
|
let run = instance
|
||||||
.get_export("run")
|
.get_func("run")
|
||||||
.and_then(|e| e.func())
|
|
||||||
.ok_or(anyhow::format_err!("failed to find `run` function export"))?
|
.ok_or(anyhow::format_err!("failed to find `run` function export"))?
|
||||||
.get0::<()>()?;
|
.get0::<()>()?;
|
||||||
|
|
||||||
|
|||||||
@@ -26,7 +26,7 @@ fn main() -> Result<()> {
|
|||||||
|
|
||||||
// And with that we can perform the final link and the execute the module.
|
// And with that we can perform the final link and the execute the module.
|
||||||
let linking1 = linker.instantiate(&linking1)?;
|
let linking1 = linker.instantiate(&linking1)?;
|
||||||
let run = linking1.get_export("run").and_then(|e| e.func()).unwrap();
|
let run = linking1.get_func("run").unwrap();
|
||||||
let run = run.get0::<()>()?;
|
let run = run.get0::<()>()?;
|
||||||
run()?;
|
run()?;
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|||||||
@@ -18,22 +18,18 @@ fn main() -> Result<()> {
|
|||||||
|
|
||||||
// Load up our exports from the instance
|
// Load up our exports from the instance
|
||||||
let memory = instance
|
let memory = instance
|
||||||
.get_export("memory")
|
.get_memory("memory")
|
||||||
.and_then(|e| e.memory())
|
|
||||||
.ok_or(anyhow::format_err!("failed to find `memory` export"))?;
|
.ok_or(anyhow::format_err!("failed to find `memory` export"))?;
|
||||||
let size = instance
|
let size = instance
|
||||||
.get_export("size")
|
.get_func("size")
|
||||||
.and_then(|e| e.func())
|
|
||||||
.ok_or(anyhow::format_err!("failed to find `size` export"))?
|
.ok_or(anyhow::format_err!("failed to find `size` export"))?
|
||||||
.get0::<i32>()?;
|
.get0::<i32>()?;
|
||||||
let load = instance
|
let load = instance
|
||||||
.get_export("load")
|
.get_func("load")
|
||||||
.and_then(|e| e.func())
|
|
||||||
.ok_or(anyhow::format_err!("failed to find `load` export"))?
|
.ok_or(anyhow::format_err!("failed to find `load` export"))?
|
||||||
.get1::<i32, i32>()?;
|
.get1::<i32, i32>()?;
|
||||||
let store = instance
|
let store = instance
|
||||||
.get_export("store")
|
.get_func("store")
|
||||||
.and_then(|e| e.func())
|
|
||||||
.ok_or(anyhow::format_err!("failed to find `store` export"))?
|
.ok_or(anyhow::format_err!("failed to find `store` export"))?
|
||||||
.get2::<i32, i32, ()>()?;
|
.get2::<i32, i32, ()>()?;
|
||||||
|
|
||||||
|
|||||||
@@ -43,8 +43,7 @@ fn main() -> Result<()> {
|
|||||||
// Extract exports.
|
// Extract exports.
|
||||||
println!("Extracting export...");
|
println!("Extracting export...");
|
||||||
let g = instance
|
let g = instance
|
||||||
.get_export("g")
|
.get_func("g")
|
||||||
.and_then(|e| e.func())
|
|
||||||
.ok_or(format_err!("failed to find export `g`"))?;
|
.ok_or(format_err!("failed to find export `g`"))?;
|
||||||
|
|
||||||
// Call `$g`.
|
// Call `$g`.
|
||||||
@@ -60,8 +59,7 @@ fn main() -> Result<()> {
|
|||||||
// Call `$round_trip_many`.
|
// Call `$round_trip_many`.
|
||||||
println!("Calling export \"round_trip_many\"...");
|
println!("Calling export \"round_trip_many\"...");
|
||||||
let round_trip_many = instance
|
let round_trip_many = instance
|
||||||
.get_export("round_trip_many")
|
.get_func("round_trip_many")
|
||||||
.and_then(|e| e.func())
|
|
||||||
.ok_or(format_err!("failed to find export `round_trip_many`"))?;
|
.ok_or(format_err!("failed to find export `round_trip_many`"))?;
|
||||||
let args = vec![
|
let args = vec![
|
||||||
Val::I64(0),
|
Val::I64(0),
|
||||||
|
|||||||
@@ -33,10 +33,7 @@ fn main() -> Result<()> {
|
|||||||
// Instance our module with the imports we've created, then we can run the
|
// Instance our module with the imports we've created, then we can run the
|
||||||
// standard wasi `_start` function.
|
// standard wasi `_start` function.
|
||||||
let instance = Instance::new(&module, &imports)?;
|
let instance = Instance::new(&module, &imports)?;
|
||||||
let start = instance
|
let start = instance.get_func("_start").unwrap();
|
||||||
.get_export("_start")
|
|
||||||
.and_then(|e| e.func())
|
|
||||||
.unwrap();
|
|
||||||
let start = start.get0::<()>()?;
|
let start = start.get0::<()>()?;
|
||||||
start()?;
|
start()?;
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|||||||
@@ -190,7 +190,7 @@ impl RunCommand {
|
|||||||
store: &Store,
|
store: &Store,
|
||||||
module_registry: &ModuleRegistry,
|
module_registry: &ModuleRegistry,
|
||||||
path: &Path,
|
path: &Path,
|
||||||
) -> Result<(Instance, Module)> {
|
) -> Result<Instance> {
|
||||||
// Read the wasm module binary either as `*.wat` or a raw binary
|
// Read the wasm module binary either as `*.wat` or a raw binary
|
||||||
let data = wat::parse_file(path)?;
|
let data = wat::parse_file(path)?;
|
||||||
|
|
||||||
@@ -199,7 +199,6 @@ impl RunCommand {
|
|||||||
// Resolve import using module_registry.
|
// Resolve import using module_registry.
|
||||||
let imports = module
|
let imports = module
|
||||||
.imports()
|
.imports()
|
||||||
.iter()
|
|
||||||
.map(|i| {
|
.map(|i| {
|
||||||
let export = match i.module() {
|
let export = match i.module() {
|
||||||
"wasi_snapshot_preview1" => {
|
"wasi_snapshot_preview1" => {
|
||||||
@@ -222,20 +221,16 @@ impl RunCommand {
|
|||||||
let instance = Instance::new(&module, &imports)
|
let instance = Instance::new(&module, &imports)
|
||||||
.context(format!("failed to instantiate {:?}", path))?;
|
.context(format!("failed to instantiate {:?}", path))?;
|
||||||
|
|
||||||
Ok((instance, module))
|
Ok(instance)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_module(&self, store: &Store, module_registry: &ModuleRegistry) -> Result<()> {
|
fn handle_module(&self, store: &Store, module_registry: &ModuleRegistry) -> Result<()> {
|
||||||
let (instance, module) = Self::instantiate_module(store, module_registry, &self.module)?;
|
let instance = Self::instantiate_module(store, module_registry, &self.module)?;
|
||||||
|
|
||||||
// If a function to invoke was given, invoke it.
|
// If a function to invoke was given, invoke it.
|
||||||
if let Some(name) = self.invoke.as_ref() {
|
if let Some(name) = self.invoke.as_ref() {
|
||||||
self.invoke_export(instance, name)?;
|
self.invoke_export(instance, name)?;
|
||||||
} else if module
|
} else if instance.exports().any(|export| export.name().is_empty()) {
|
||||||
.exports()
|
|
||||||
.iter()
|
|
||||||
.any(|export| export.name().is_empty())
|
|
||||||
{
|
|
||||||
// Launch the default command export.
|
// Launch the default command export.
|
||||||
self.invoke_export(instance, "")?;
|
self.invoke_export(instance, "")?;
|
||||||
} else {
|
} else {
|
||||||
@@ -248,19 +243,16 @@ impl RunCommand {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn invoke_export(&self, instance: Instance, name: &str) -> Result<()> {
|
fn invoke_export(&self, instance: Instance, name: &str) -> Result<()> {
|
||||||
let pos = instance
|
let func = if let Some(export) = instance.get_export(name) {
|
||||||
.module()
|
if let Some(func) = export.into_func() {
|
||||||
.exports()
|
func
|
||||||
.iter()
|
} else {
|
||||||
.enumerate()
|
bail!("export of `{}` wasn't a function", name)
|
||||||
.find(|(_, e)| e.name() == name);
|
}
|
||||||
let (ty, export) = match pos {
|
} else {
|
||||||
Some((i, ty)) => match (ty.ty(), &instance.exports()[i]) {
|
bail!("failed to find export of `{}` in module", name)
|
||||||
(wasmtime::ExternType::Func(ty), wasmtime::Extern::Func(f)) => (ty, f),
|
|
||||||
_ => bail!("export of `{}` wasn't a function", name),
|
|
||||||
},
|
|
||||||
None => bail!("failed to find export of `{}` in module", name),
|
|
||||||
};
|
};
|
||||||
|
let ty = func.ty();
|
||||||
if ty.params().len() > 0 {
|
if ty.params().len() > 0 {
|
||||||
eprintln!(
|
eprintln!(
|
||||||
"warning: using `--invoke` with a function that takes arguments \
|
"warning: using `--invoke` with a function that takes arguments \
|
||||||
@@ -288,7 +280,7 @@ impl RunCommand {
|
|||||||
|
|
||||||
// Invoke the function and then afterwards print all the results that came
|
// Invoke the function and then afterwards print all the results that came
|
||||||
// out, if there are any.
|
// out, if there are any.
|
||||||
let results = export
|
let results = func
|
||||||
.call(&values)
|
.call(&values)
|
||||||
.with_context(|| format!("failed to invoke `{}`", name))?;
|
.with_context(|| format!("failed to invoke `{}`", name))?;
|
||||||
if !results.is_empty() {
|
if !results.is_empty() {
|
||||||
|
|||||||
@@ -38,18 +38,13 @@ mod tests {
|
|||||||
"#;
|
"#;
|
||||||
|
|
||||||
fn invoke_export(instance: &Instance, func_name: &str) -> Result<Box<[Val]>> {
|
fn invoke_export(instance: &Instance, func_name: &str) -> Result<Box<[Val]>> {
|
||||||
let ret = instance
|
let ret = instance.get_func(func_name).unwrap().call(&[])?;
|
||||||
.get_export(func_name)
|
|
||||||
.unwrap()
|
|
||||||
.func()
|
|
||||||
.unwrap()
|
|
||||||
.call(&[])?;
|
|
||||||
Ok(ret)
|
Ok(ret)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Locate "memory" export, get base address and size and set memory protection to PROT_NONE
|
// Locate "memory" export, get base address and size and set memory protection to PROT_NONE
|
||||||
fn set_up_memory(instance: &Instance) -> (*mut u8, usize) {
|
fn set_up_memory(instance: &Instance) -> (*mut u8, usize) {
|
||||||
let mem_export = instance.get_export("memory").unwrap().memory().unwrap();
|
let mem_export = instance.get_memory("memory").unwrap();
|
||||||
let base = mem_export.data_ptr();
|
let base = mem_export.data_ptr();
|
||||||
let length = mem_export.data_size();
|
let length = mem_export.data_size();
|
||||||
|
|
||||||
@@ -105,9 +100,6 @@ mod tests {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
let exports = instance.exports();
|
|
||||||
assert!(!exports.is_empty());
|
|
||||||
|
|
||||||
// these invoke wasmtime_call_trampoline from action.rs
|
// these invoke wasmtime_call_trampoline from action.rs
|
||||||
{
|
{
|
||||||
println!("calling read...");
|
println!("calling read...");
|
||||||
@@ -130,8 +122,8 @@ mod tests {
|
|||||||
|
|
||||||
// these invoke wasmtime_call_trampoline from callable.rs
|
// these invoke wasmtime_call_trampoline from callable.rs
|
||||||
{
|
{
|
||||||
let read_func = exports[0]
|
let read_func = instance
|
||||||
.func()
|
.get_func("read")
|
||||||
.expect("expected a 'read' func in the module");
|
.expect("expected a 'read' func in the module");
|
||||||
println!("calling read...");
|
println!("calling read...");
|
||||||
let result = read_func.call(&[]).expect("expected function not to trap");
|
let result = read_func.call(&[]).expect("expected function not to trap");
|
||||||
@@ -139,8 +131,8 @@ mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
let read_out_of_bounds_func = exports[1]
|
let read_out_of_bounds_func = instance
|
||||||
.func()
|
.get_func("read_out_of_bounds")
|
||||||
.expect("expected a 'read_out_of_bounds' func in the module");
|
.expect("expected a 'read_out_of_bounds' func in the module");
|
||||||
println!("calling read_out_of_bounds...");
|
println!("calling read_out_of_bounds...");
|
||||||
let trap = read_out_of_bounds_func
|
let trap = read_out_of_bounds_func
|
||||||
@@ -216,8 +208,8 @@ mod tests {
|
|||||||
|
|
||||||
// First instance1
|
// First instance1
|
||||||
{
|
{
|
||||||
let exports1 = instance1.exports();
|
let mut exports1 = instance1.exports();
|
||||||
assert!(!exports1.is_empty());
|
assert!(exports1.next().is_some());
|
||||||
|
|
||||||
println!("calling instance1.read...");
|
println!("calling instance1.read...");
|
||||||
let result = invoke_export(&instance1, "read").expect("read succeeded");
|
let result = invoke_export(&instance1, "read").expect("read succeeded");
|
||||||
@@ -231,8 +223,8 @@ mod tests {
|
|||||||
|
|
||||||
// And then instance2
|
// And then instance2
|
||||||
{
|
{
|
||||||
let exports2 = instance2.exports();
|
let mut exports2 = instance2.exports();
|
||||||
assert!(!exports2.is_empty());
|
assert!(exports2.next().is_some());
|
||||||
|
|
||||||
println!("calling instance2.read...");
|
println!("calling instance2.read...");
|
||||||
let result = invoke_export(&instance2, "read").expect("read succeeded");
|
let result = invoke_export(&instance2, "read").expect("read succeeded");
|
||||||
@@ -262,13 +254,12 @@ mod tests {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
let instance1_exports = instance1.exports();
|
let mut instance1_exports = instance1.exports();
|
||||||
assert!(!instance1_exports.is_empty());
|
let instance1_read = instance1_exports.next().unwrap();
|
||||||
let instance1_read = instance1_exports[0].clone();
|
|
||||||
|
|
||||||
// instance2 wich calls 'instance1.read'
|
// instance2 which calls 'instance1.read'
|
||||||
let module2 = Module::new(&store, WAT2)?;
|
let module2 = Module::new(&store, WAT2)?;
|
||||||
let instance2 = Instance::new(&module2, &[instance1_read])?;
|
let instance2 = Instance::new(&module2, &[instance1_read.into_extern()])?;
|
||||||
// since 'instance2.run' calls 'instance1.read' we need to set up the signal handler to handle
|
// since 'instance2.run' calls 'instance1.read' we need to set up the signal handler to handle
|
||||||
// SIGSEGV originating from within the memory of instance1
|
// SIGSEGV originating from within the memory of instance1
|
||||||
unsafe {
|
unsafe {
|
||||||
|
|||||||
@@ -269,14 +269,14 @@ fn get_from_module() -> anyhow::Result<()> {
|
|||||||
"#,
|
"#,
|
||||||
)?;
|
)?;
|
||||||
let instance = Instance::new(&module, &[])?;
|
let instance = Instance::new(&module, &[])?;
|
||||||
let f0 = instance.get_export("f0").unwrap().func().unwrap();
|
let f0 = instance.get_func("f0").unwrap();
|
||||||
assert!(f0.get0::<()>().is_ok());
|
assert!(f0.get0::<()>().is_ok());
|
||||||
assert!(f0.get0::<i32>().is_err());
|
assert!(f0.get0::<i32>().is_err());
|
||||||
let f1 = instance.get_export("f1").unwrap().func().unwrap();
|
let f1 = instance.get_func("f1").unwrap();
|
||||||
assert!(f1.get0::<()>().is_err());
|
assert!(f1.get0::<()>().is_err());
|
||||||
assert!(f1.get1::<i32, ()>().is_ok());
|
assert!(f1.get1::<i32, ()>().is_ok());
|
||||||
assert!(f1.get1::<i32, f32>().is_err());
|
assert!(f1.get1::<i32, f32>().is_err());
|
||||||
let f2 = instance.get_export("f2").unwrap().func().unwrap();
|
let f2 = instance.get_func("f2").unwrap();
|
||||||
assert!(f2.get0::<()>().is_err());
|
assert!(f2.get0::<()>().is_err());
|
||||||
assert!(f2.get0::<i32>().is_ok());
|
assert!(f2.get0::<i32>().is_ok());
|
||||||
assert!(f2.get1::<i32, ()>().is_err());
|
assert!(f2.get1::<i32, ()>().is_err());
|
||||||
|
|||||||
@@ -70,7 +70,7 @@ fn use_after_drop() -> anyhow::Result<()> {
|
|||||||
"#,
|
"#,
|
||||||
)?;
|
)?;
|
||||||
let instance = Instance::new(&module, &[])?;
|
let instance = Instance::new(&module, &[])?;
|
||||||
let g = instance.exports()[0].global().unwrap().clone();
|
let g = instance.get_global("foo").unwrap();
|
||||||
assert_eq!(g.get().i32(), Some(100));
|
assert_eq!(g.get().i32(), Some(100));
|
||||||
g.set(101.into())?;
|
g.set(101.into())?;
|
||||||
drop(instance);
|
drop(instance);
|
||||||
|
|||||||
@@ -40,18 +40,14 @@ fn test_import_calling_export() {
|
|||||||
let instance =
|
let instance =
|
||||||
Instance::new(&module, imports.as_slice()).expect("failed to instantiate module");
|
Instance::new(&module, imports.as_slice()).expect("failed to instantiate module");
|
||||||
|
|
||||||
let exports = instance.exports();
|
let run_func = instance
|
||||||
assert!(!exports.is_empty());
|
.get_func("run")
|
||||||
|
|
||||||
let run_func = exports[0]
|
|
||||||
.func()
|
|
||||||
.expect("expected a run func in the module");
|
.expect("expected a run func in the module");
|
||||||
|
|
||||||
*other.borrow_mut() = Some(
|
*other.borrow_mut() = Some(
|
||||||
exports[1]
|
instance
|
||||||
.func()
|
.get_func("other")
|
||||||
.expect("expected an other func in the module")
|
.expect("expected an other func in the module"),
|
||||||
.clone(),
|
|
||||||
);
|
);
|
||||||
|
|
||||||
run_func.call(&[]).expect("expected function not to trap");
|
run_func.call(&[]).expect("expected function not to trap");
|
||||||
@@ -84,11 +80,8 @@ fn test_returns_incorrect_type() -> Result<()> {
|
|||||||
let imports = vec![callback_func.into()];
|
let imports = vec![callback_func.into()];
|
||||||
let instance = Instance::new(&module, imports.as_slice())?;
|
let instance = Instance::new(&module, imports.as_slice())?;
|
||||||
|
|
||||||
let exports = instance.exports();
|
let run_func = instance
|
||||||
assert!(!exports.is_empty());
|
.get_func("run")
|
||||||
|
|
||||||
let run_func = exports[0]
|
|
||||||
.func()
|
|
||||||
.expect("expected a run func in the module");
|
.expect("expected a run func in the module");
|
||||||
|
|
||||||
let trap = run_func
|
let trap = run_func
|
||||||
|
|||||||
@@ -43,7 +43,7 @@ fn same_import_names_still_distinct() -> anyhow::Result<()> {
|
|||||||
];
|
];
|
||||||
let instance = Instance::new(&module, &imports)?;
|
let instance = Instance::new(&module, &imports)?;
|
||||||
|
|
||||||
let func = instance.get_export("foo").unwrap().func().unwrap();
|
let func = instance.get_func("foo").unwrap();
|
||||||
let results = func.call(&[])?;
|
let results = func.call(&[])?;
|
||||||
assert_eq!(results.len(), 1);
|
assert_eq!(results.len(), 1);
|
||||||
match results[0] {
|
match results[0] {
|
||||||
|
|||||||
@@ -17,9 +17,7 @@ fn test_invoke_func_via_table() -> Result<()> {
|
|||||||
let instance = Instance::new(&module, &[]).context("> Error instantiating module!")?;
|
let instance = Instance::new(&module, &[]).context("> Error instantiating module!")?;
|
||||||
|
|
||||||
let f = instance
|
let f = instance
|
||||||
.get_export("table")
|
.get_table("table")
|
||||||
.unwrap()
|
|
||||||
.table()
|
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.get(0)
|
.get(0)
|
||||||
.unwrap()
|
.unwrap()
|
||||||
|
|||||||
@@ -90,7 +90,7 @@ fn interposition() -> Result<()> {
|
|||||||
)?;
|
)?;
|
||||||
}
|
}
|
||||||
let instance = linker.instantiate(&module)?;
|
let instance = linker.instantiate(&module)?;
|
||||||
let func = instance.get_export("export").unwrap().func().unwrap();
|
let func = instance.get_func("export").unwrap();
|
||||||
let func = func.get0::<i32>()?;
|
let func = func.get0::<i32>()?;
|
||||||
assert_eq!(func()?, 112);
|
assert_eq!(func()?, 112);
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|||||||
@@ -169,15 +169,7 @@ mod not_for_windows {
|
|||||||
|
|
||||||
assert_eq!(*mem_creator.num_created_memories.lock().unwrap(), 2);
|
assert_eq!(*mem_creator.num_created_memories.lock().unwrap(), 2);
|
||||||
|
|
||||||
assert_eq!(
|
assert_eq!(instance2.get_memory("memory").unwrap().size(), 2);
|
||||||
instance2
|
|
||||||
.get_export("memory")
|
|
||||||
.unwrap()
|
|
||||||
.memory()
|
|
||||||
.unwrap()
|
|
||||||
.size(),
|
|
||||||
2
|
|
||||||
);
|
|
||||||
|
|
||||||
// we take the lock outside the assert, so it won't get poisoned on assert failure
|
// we take the lock outside the assert, so it won't get poisoned on assert failure
|
||||||
let tot_pages = *mem_creator.num_total_pages.lock().unwrap();
|
let tot_pages = *mem_creator.num_total_pages.lock().unwrap();
|
||||||
|
|||||||
@@ -17,9 +17,7 @@ fn test_trap_return() -> Result<()> {
|
|||||||
let hello_func = Func::new(&store, hello_type, |_, _, _| Err(Trap::new("test 123")));
|
let hello_func = Func::new(&store, hello_type, |_, _, _| Err(Trap::new("test 123")));
|
||||||
|
|
||||||
let instance = Instance::new(&module, &[hello_func.into()])?;
|
let instance = Instance::new(&module, &[hello_func.into()])?;
|
||||||
let run_func = instance.exports()[0]
|
let run_func = instance.get_func("run").expect("expected function export");
|
||||||
.func()
|
|
||||||
.expect("expected function export");
|
|
||||||
|
|
||||||
let e = run_func
|
let e = run_func
|
||||||
.call(&[])
|
.call(&[])
|
||||||
@@ -44,9 +42,7 @@ fn test_trap_trace() -> Result<()> {
|
|||||||
|
|
||||||
let module = Module::new(&store, wat)?;
|
let module = Module::new(&store, wat)?;
|
||||||
let instance = Instance::new(&module, &[])?;
|
let instance = Instance::new(&module, &[])?;
|
||||||
let run_func = instance.exports()[0]
|
let run_func = instance.get_func("run").expect("expected function export");
|
||||||
.func()
|
|
||||||
.expect("expected function export");
|
|
||||||
|
|
||||||
let e = run_func
|
let e = run_func
|
||||||
.call(&[])
|
.call(&[])
|
||||||
@@ -91,9 +87,7 @@ fn test_trap_trace_cb() -> Result<()> {
|
|||||||
|
|
||||||
let module = Module::new(&store, wat)?;
|
let module = Module::new(&store, wat)?;
|
||||||
let instance = Instance::new(&module, &[fn_func.into()])?;
|
let instance = Instance::new(&module, &[fn_func.into()])?;
|
||||||
let run_func = instance.exports()[0]
|
let run_func = instance.get_func("run").expect("expected function export");
|
||||||
.func()
|
|
||||||
.expect("expected function export");
|
|
||||||
|
|
||||||
let e = run_func
|
let e = run_func
|
||||||
.call(&[])
|
.call(&[])
|
||||||
@@ -123,9 +117,7 @@ fn test_trap_stack_overflow() -> Result<()> {
|
|||||||
|
|
||||||
let module = Module::new(&store, wat)?;
|
let module = Module::new(&store, wat)?;
|
||||||
let instance = Instance::new(&module, &[])?;
|
let instance = Instance::new(&module, &[])?;
|
||||||
let run_func = instance.exports()[0]
|
let run_func = instance.get_func("run").expect("expected function export");
|
||||||
.func()
|
|
||||||
.expect("expected function export");
|
|
||||||
|
|
||||||
let e = run_func
|
let e = run_func
|
||||||
.call(&[])
|
.call(&[])
|
||||||
@@ -159,9 +151,7 @@ fn trap_display_pretty() -> Result<()> {
|
|||||||
|
|
||||||
let module = Module::new(&store, wat)?;
|
let module = Module::new(&store, wat)?;
|
||||||
let instance = Instance::new(&module, &[])?;
|
let instance = Instance::new(&module, &[])?;
|
||||||
let run_func = instance.exports()[0]
|
let run_func = instance.get_func("bar").expect("expected function export");
|
||||||
.func()
|
|
||||||
.expect("expected function export");
|
|
||||||
|
|
||||||
let e = run_func.call(&[]).err().expect("error calling function");
|
let e = run_func.call(&[]).err().expect("error calling function");
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
@@ -192,7 +182,7 @@ fn trap_display_multi_module() -> Result<()> {
|
|||||||
|
|
||||||
let module = Module::new(&store, wat)?;
|
let module = Module::new(&store, wat)?;
|
||||||
let instance = Instance::new(&module, &[])?;
|
let instance = Instance::new(&module, &[])?;
|
||||||
let bar = instance.exports()[0].clone();
|
let bar = instance.get_export("bar").unwrap();
|
||||||
|
|
||||||
let wat = r#"
|
let wat = r#"
|
||||||
(module $b
|
(module $b
|
||||||
@@ -203,9 +193,7 @@ fn trap_display_multi_module() -> Result<()> {
|
|||||||
"#;
|
"#;
|
||||||
let module = Module::new(&store, wat)?;
|
let module = Module::new(&store, wat)?;
|
||||||
let instance = Instance::new(&module, &[bar])?;
|
let instance = Instance::new(&module, &[bar])?;
|
||||||
let bar2 = instance.exports()[0]
|
let bar2 = instance.get_func("bar2").expect("expected function export");
|
||||||
.func()
|
|
||||||
.expect("expected function export");
|
|
||||||
|
|
||||||
let e = bar2.call(&[]).err().expect("error calling function");
|
let e = bar2.call(&[]).err().expect("error calling function");
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
@@ -268,14 +256,14 @@ fn rust_panic_import() -> Result<()> {
|
|||||||
Func::wrap(&store, || panic!("this is another panic")).into(),
|
Func::wrap(&store, || panic!("this is another panic")).into(),
|
||||||
],
|
],
|
||||||
)?;
|
)?;
|
||||||
let func = instance.exports()[0].func().unwrap().clone();
|
let func = instance.get_func("foo").unwrap();
|
||||||
let err = panic::catch_unwind(AssertUnwindSafe(|| {
|
let err = panic::catch_unwind(AssertUnwindSafe(|| {
|
||||||
drop(func.call(&[]));
|
drop(func.call(&[]));
|
||||||
}))
|
}))
|
||||||
.unwrap_err();
|
.unwrap_err();
|
||||||
assert_eq!(err.downcast_ref::<&'static str>(), Some(&"this is a panic"));
|
assert_eq!(err.downcast_ref::<&'static str>(), Some(&"this is a panic"));
|
||||||
|
|
||||||
let func = instance.exports()[1].func().unwrap().clone();
|
let func = instance.get_func("bar").unwrap();
|
||||||
let err = panic::catch_unwind(AssertUnwindSafe(|| {
|
let err = panic::catch_unwind(AssertUnwindSafe(|| {
|
||||||
drop(func.call(&[]));
|
drop(func.call(&[]));
|
||||||
}))
|
}))
|
||||||
@@ -333,7 +321,7 @@ fn mismatched_arguments() -> Result<()> {
|
|||||||
|
|
||||||
let module = Module::new(&store, &binary)?;
|
let module = Module::new(&store, &binary)?;
|
||||||
let instance = Instance::new(&module, &[])?;
|
let instance = Instance::new(&module, &[])?;
|
||||||
let func = instance.exports()[0].func().unwrap().clone();
|
let func = instance.get_func("foo").unwrap();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
func.call(&[]).unwrap_err().to_string(),
|
func.call(&[]).unwrap_err().to_string(),
|
||||||
"expected 1 arguments, got 0"
|
"expected 1 arguments, got 0"
|
||||||
@@ -417,7 +405,7 @@ fn present_after_module_drop() -> Result<()> {
|
|||||||
let store = Store::default();
|
let store = Store::default();
|
||||||
let module = Module::new(&store, r#"(func (export "foo") unreachable)"#)?;
|
let module = Module::new(&store, r#"(func (export "foo") unreachable)"#)?;
|
||||||
let instance = Instance::new(&module, &[])?;
|
let instance = Instance::new(&module, &[])?;
|
||||||
let func = instance.exports()[0].func().unwrap().clone();
|
let func = instance.get_func("foo").unwrap();
|
||||||
|
|
||||||
println!("asserting before we drop modules");
|
println!("asserting before we drop modules");
|
||||||
assert_trap(func.call(&[]).unwrap_err().downcast()?);
|
assert_trap(func.call(&[]).unwrap_err().downcast()?);
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
(assert_invalid (module (memory 1 1 shared)) "not supported")
|
(assert_invalid (module (memory 1 1 shared)) "Unsupported feature: shared memories")
|
||||||
|
|||||||
Reference in New Issue
Block a user