Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
* 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.
  • Loading branch information
sunfishcode authored and CryZe committed Apr 25, 2020
1 parent 63c97e3 commit e37b3b0
Show file tree
Hide file tree
Showing 57 changed files with 787 additions and 874 deletions.
10 changes: 5 additions & 5 deletions cranelift/wasm/src/translation_utils.rs
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ pub struct ElemIndex(u32);
entity_impl!(ElemIndex);

/// WebAssembly global.
#[derive(Debug, Clone, Copy, Hash)]
#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq)]
pub struct Global {
/// The type of the value stored in the global.
pub ty: ir::Type,
Expand All @@ -79,7 +79,7 @@ pub struct Global {
}

/// 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 {
/// An `i32.const`.
I32Const(i32),
Expand All @@ -102,7 +102,7 @@ pub enum GlobalInit {
}

/// WebAssembly table.
#[derive(Debug, Clone, Copy, Hash)]
#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq)]
pub struct Table {
/// The type of data stored in elements of the table.
pub ty: TableElementType,
Expand All @@ -113,7 +113,7 @@ pub struct Table {
}

/// 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 {
/// A scalar type.
Val(ir::Type),
Expand All @@ -122,7 +122,7 @@ pub enum TableElementType {
}

/// WebAssembly linear memory.
#[derive(Debug, Clone, Copy, Hash)]
#[derive(Debug, Clone, Copy, Hash, Eq, PartialEq)]
pub struct Memory {
/// The minimum number of pages in the memory.
pub minimum: u32,
Expand Down
149 changes: 106 additions & 43 deletions crates/api/src/externals.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ impl Extern {
/// Returns the underlying `Func`, if this external is 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 {
Extern::Func(func) => Some(func),
_ => None,
Expand All @@ -44,7 +44,7 @@ impl Extern {
/// Returns the underlying `Global`, if this external is 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 {
Extern::Global(global) => Some(global),
_ => None,
Expand All @@ -54,7 +54,7 @@ impl Extern {
/// Returns the underlying `Table`, if this external is 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 {
Extern::Table(table) => Some(table),
_ => None,
Expand All @@ -64,7 +64,7 @@ impl Extern {
/// Returns the underlying `Memory`, if this external is 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 {
Extern::Memory(memory) => Some(memory),
_ => None,
Expand All @@ -74,10 +74,10 @@ impl Extern {
/// Returns the type associated with this `Extern`.
pub fn ty(&self) -> ExternType {
match self {
Extern::Func(ft) => ExternType::Func(ft.ty().clone()),
Extern::Memory(ft) => ExternType::Memory(ft.ty().clone()),
Extern::Table(tt) => ExternType::Table(tt.ty().clone()),
Extern::Global(gt) => ExternType::Global(gt.ty().clone()),
Extern::Func(ft) => ExternType::Func(ft.ty()),
Extern::Memory(ft) => ExternType::Memory(ft.ty()),
Extern::Table(tt) => ExternType::Table(tt.ty()),
Extern::Global(gt) => ExternType::Global(gt.ty()),
}
}

Expand All @@ -91,11 +91,11 @@ impl Extern {
}

pub(crate) fn from_wasmtime_export(
wasmtime_export: wasmtime_runtime::Export,
store: &Store,
instance_handle: InstanceHandle,
export: wasmtime_runtime::Export,
) -> Extern {
match export {
match wasmtime_export {
wasmtime_runtime::Export::Function(f) => {
Extern::Func(Func::from_wasmtime_function(f, store, instance_handle))
}
Expand Down Expand Up @@ -164,7 +164,6 @@ impl From<Table> for Extern {
#[derive(Clone)]
pub struct Global {
store: Store,
ty: GlobalType,
wasmtime_export: wasmtime_runtime::ExportGlobal,
wasmtime_handle: InstanceHandle,
}
Expand All @@ -191,27 +190,44 @@ impl Global {
let (wasmtime_handle, wasmtime_export) = generate_global_export(store, &ty, val)?;
Ok(Global {
store: store.clone(),
ty,
wasmtime_export,
wasmtime_handle,
})
}

/// Returns the underlying type of this `global`.
pub fn ty(&self) -> &GlobalType {
&self.ty
pub fn ty(&self) -> GlobalType {
// 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.
pub fn get(&self) -> Val {
unsafe {
let definition = &mut *self.wasmtime_export.definition;
match self.ty().content() {
match self.val_type() {
ValType::I32 => Val::from(*definition.as_i32()),
ValType::I64 => Val::from(*definition.as_i64()),
ValType::F32 => Val::F32(*definition.as_u32()),
ValType::F64 => Val::F64(*definition.as_u64()),
_ => unimplemented!("Global::get for {:?}", self.ty().content()),
ty => unimplemented!("Global::get for {:?}", ty),
}
}
}
Expand All @@ -223,15 +239,12 @@ impl Global {
/// Returns an error if this global has a different type than `Val`, or if
/// it's not a mutable global.
pub fn set(&self, val: Val) -> Result<()> {
if self.ty().mutability() != Mutability::Var {
if self.mutability() != Mutability::Var {
bail!("immutable global cannot be set");
}
if val.ty() != *self.ty().content() {
bail!(
"global of type {:?} cannot be set to {:?}",
self.ty().content(),
val.ty()
);
let ty = self.val_type();
if val.ty() != ty {
bail!("global of type {:?} cannot be set to {:?}", ty, val.ty());
}
if !val.comes_from_same_store(&self.store) {
bail!("cross-`Store` values are not supported");
Expand All @@ -254,13 +267,8 @@ impl Global {
store: &Store,
wasmtime_handle: InstanceHandle,
) -> 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 {
store: store.clone(),
ty: ty,
wasmtime_export,
wasmtime_handle,
}
Expand All @@ -285,7 +293,6 @@ impl Global {
#[derive(Clone)]
pub struct Table {
store: Store,
ty: TableType,
wasmtime_handle: InstanceHandle,
wasmtime_export: wasmtime_runtime::ExportTable,
}
Expand Down Expand Up @@ -326,16 +333,15 @@ impl Table {

Ok(Table {
store: store.clone(),
ty,
wasmtime_handle,
wasmtime_export,
})
}

/// Returns the underlying type of this table, including its element type as
/// well as the maximum/minimum lower bounds.
pub fn ty(&self) -> &TableType {
&self.ty
pub fn ty(&self) -> TableType {
TableType::from_wasmtime_table(&self.wasmtime_export.table.table)
}

fn wasmtime_table_index(&self) -> wasm::DefinedTableIndex {
Expand Down Expand Up @@ -368,7 +374,7 @@ impl Table {

/// Returns the current size of this table.
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
Expand Down Expand Up @@ -438,10 +444,8 @@ impl Table {
store: &Store,
wasmtime_handle: wasmtime_runtime::InstanceHandle,
) -> Table {
let ty = TableType::from_wasmtime_table(&wasmtime_export.table.table);
Table {
store: store.clone(),
ty,
wasmtime_handle,
wasmtime_export,
}
Expand Down Expand Up @@ -657,7 +661,6 @@ impl Table {
#[derive(Clone)]
pub struct Memory {
store: Store,
ty: MemoryType,
wasmtime_handle: InstanceHandle,
wasmtime_export: wasmtime_runtime::ExportMemory,
}
Expand Down Expand Up @@ -690,7 +693,6 @@ impl Memory {
generate_memory_export(store, &ty).expect("generated memory");
Memory {
store: store.clone(),
ty,
wasmtime_handle,
wasmtime_export,
}
Expand All @@ -706,14 +708,14 @@ impl Memory {
/// let store = Store::default();
/// let module = Module::new(&store, "(module (memory (export \"mem\") 1))")?;
/// 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();
/// assert_eq!(ty.limits().min(), 1);
/// # Ok(())
/// # }
/// ```
pub fn ty(&self) -> &MemoryType {
&self.ty
pub fn ty(&self) -> MemoryType {
MemoryType::from_wasmtime_memory(&self.wasmtime_export.memory.memory)
}

/// Returns this memory as a slice view that can be read natively in Rust.
Expand Down Expand Up @@ -818,7 +820,7 @@ impl Memory {
/// let store = Store::default();
/// let module = Module::new(&store, "(module (memory (export \"mem\") 1 2))")?;
/// 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.grow(1)?, 1);
Expand All @@ -844,10 +846,8 @@ impl Memory {
store: &Store,
wasmtime_handle: wasmtime_runtime::InstanceHandle,
) -> Memory {
let ty = MemoryType::from_wasmtime_memory(&wasmtime_export.memory.memory);
Memory {
store: store.clone(),
ty: ty,
wasmtime_handle,
wasmtime_export,
}
Expand Down Expand Up @@ -896,3 +896,66 @@ pub unsafe trait MemoryCreator: Send + Sync {
/// Create new LinearMemory
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()
}
}
Loading

0 comments on commit e37b3b0

Please sign in to comment.