#[repr(transparent)]pub struct Instance(_);Expand description
An instantiated WebAssembly module.
This type represents the instantiation of a Module. Once instantiated
you can access the exports which are of type
Extern and provide the ability to call functions, set globals, read
memory, etc. When interacting with any wasm code you’ll want to make an
Instance to call any code or execute anything.
Instances are owned by a Store which is passed in at
creation time. It’s recommended to create instances with
Linker::instantiate or similar
Linker methods, but a more low-level constructor is also
available as Instance::new.
Implementations§
source§impl Instance
impl Instance
sourcepub fn new(
store: impl AsContextMut,
module: &Module,
imports: &[Extern]
) -> Result<Instance>
pub fn new(
store: impl AsContextMut,
module: &Module,
imports: &[Extern]
) -> Result<Instance>
Creates a new Instance from the previously compiled Module and
list of imports specified.
This method instantiates the module provided with the imports,
following the procedure in the core specification to
instantiate. Instantiation can fail for a number of reasons (many
specified below), but if successful the start function will be
automatically run (if specified in the module) and then the
Instance will be returned.
Per the WebAssembly spec, instantiation includes running the module’s
start function, if it has one (not to be confused with the _start
function, which is not run).
Note that this is a low-level function that just performs an
instantiation. See the Linker struct for an API which
provides a convenient way to link imports and provides automatic Command
and Reactor behavior.
Providing Imports
The entries in the list of imports are intended to correspond 1:1
with the list of imports returned by Module::imports. Before
calling Instance::new you’ll want to inspect the return value of
Module::imports and, for each import type, create an Extern
which corresponds to that type. These Extern values are all then
collected into a list and passed to this function.
Note that this function is intentionally relatively low level. For an
easier time passing imports by doing name-based resolution it’s
recommended to instead use the Linker type.
Errors
This function can fail for a number of reasons, including, but not limited to:
- The number of
importsprovided doesn’t match the number of imports returned by themodule’sModule::importsmethod. - The type of any
Externdoesn’t match the correspondingExternTypeentry that it maps to. - The
startfunction in the instance, if present, traps. - Module/instance resource limits are exceeded.
When instantiation fails it’s recommended to inspect the return value to
see why it failed, or bubble it upwards. If you’d like to specifically
check for trap errors, you can use error.downcast::<Trap>(). For more
about error handling see the Trap documentation.
Panics
This function will panic if called with a store associated with a
asynchronous config. This function
will also panic if any Extern supplied is not owned by store.
sourcepub async fn new_async<T>(
store: impl AsContextMut<Data = T>,
module: &Module,
imports: &[Extern]
) -> Result<Instance>where
T: Send,
Available on crate feature async only.
pub async fn new_async<T>(
store: impl AsContextMut<Data = T>,
module: &Module,
imports: &[Extern]
) -> Result<Instance>where
T: Send,
async only.Same as Instance::new, except for usage in [asynchronous stores].
For more details about this function see the documentation on
Instance::new. The only difference between these two methods is that
this one will asynchronously invoke the wasm start function in case it
calls any imported function which is an asynchronous host function (e.g.
created with Func::new_async.
Panics
This function will panic if called with a store associated with a
synchronous config. This is only compatible with
stores associated with an asynchronous config.
This function will also panic, like Instance::new, if any Extern
specified does not belong to store.
sourcepub fn exports<'a, T: 'a>(
&'a self,
store: impl Into<StoreContextMut<'a, T>>
) -> impl ExactSizeIterator<Item = Export<'a>> + 'a
pub fn exports<'a, T: 'a>(
&'a self,
store: impl Into<StoreContextMut<'a, T>>
) -> impl ExactSizeIterator<Item = Export<'a>> + 'a
Returns the list of exported items from this Instance.
Panics
Panics if store does not own this instance.
Examples found in repository?
544 545 546 547 548 549 550 551 552 553 554 555
pub fn instance(
&mut self,
mut store: impl AsContextMut<Data = T>,
module_name: &str,
instance: Instance,
) -> Result<&mut Self> {
for export in instance.exports(store.as_context_mut()) {
let key = self.import_key(module_name, Some(export.name()));
self.insert(key, Definition::Extern(export.into_extern()))?;
}
Ok(self)
}sourcepub fn get_export(&self, store: impl AsContextMut, name: &str) -> Option<Extern>
pub fn get_export(&self, store: impl AsContextMut, name: &str) -> Option<Extern>
Looks up an exported Extern value by name.
This method will search the module for an export named name and return
the value, if found.
Returns None if there was no export named name.
Panics
Panics if store does not own this instance.
Why does get_export take a mutable context?
This method requires a mutable context because an instance’s exports are lazily populated, and we cache them as they are accessed. This makes instantiating a module faster, but also means this method requires a mutable context.
Examples found in repository?
438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521
pub fn get_func(&self, store: impl AsContextMut, name: &str) -> Option<Func> {
self.get_export(store, name)?.into_func()
}
/// Looks up an exported [`Func`] value by name and with its type.
///
/// This function is a convenience wrapper over [`Instance::get_func`] and
/// [`Func::typed`]. For more information see the linked documentation.
///
/// Returns an error if `name` isn't a function export or if the export's
/// type did not match `Params` or `Results`
///
/// # Panics
///
/// Panics if `store` does not own this instance.
pub fn get_typed_func<Params, Results>(
&self,
mut store: impl AsContextMut,
name: &str,
) -> Result<TypedFunc<Params, Results>>
where
Params: crate::WasmParams,
Results: crate::WasmResults,
{
let f = self
.get_export(store.as_context_mut(), name)
.and_then(|f| f.into_func())
.ok_or_else(|| anyhow!("failed to find function export `{}`", name))?;
Ok(f.typed::<Params, Results>(store)
.with_context(|| format!("failed to convert function `{}` to given type", name))?)
}
/// 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.
///
/// # Panics
///
/// Panics if `store` does not own this instance.
pub fn get_table(&self, store: impl AsContextMut, name: &str) -> Option<Table> {
self.get_export(store, 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.
///
/// # Panics
///
/// Panics if `store` does not own this instance.
pub fn get_memory(&self, store: impl AsContextMut, name: &str) -> Option<Memory> {
self.get_export(store, name)?.into_memory()
}
/// Looks up an exported [`SharedMemory`] value by name.
///
/// Returns `None` if there was no export named `name`, or if there was but
/// it wasn't a shared memory.
///
/// # Panics
///
/// Panics if `store` does not own this instance.
pub fn get_shared_memory(
&self,
mut store: impl AsContextMut,
name: &str,
) -> Option<SharedMemory> {
let mut store = store.as_context_mut();
self.get_export(&mut store, name)?.into_shared_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.
///
/// # Panics
///
/// Panics if `store` does not own this instance.
pub fn get_global(&self, store: impl AsContextMut, name: &str) -> Option<Global> {
self.get_export(store, name)?.into_global()
}More examples
675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807
pub fn module(
&mut self,
mut store: impl AsContextMut<Data = T>,
module_name: &str,
module: &Module,
) -> Result<&mut Self>
where
T: 'static,
{
// NB: this is intended to function the same as `Linker::module_async`,
// they should be kept in sync.
// This assert isn't strictly necessary since it'll bottom out in the
// `HostFunc::to_func` method anyway. This is placed earlier for this
// function though to prevent the functions created here from delaying
// the panic until they're called.
assert!(
Engine::same(&self.engine, store.as_context().engine()),
"different engines for this linker and the store provided"
);
match ModuleKind::categorize(module)? {
ModuleKind::Command => {
self.command(
store,
module_name,
module,
|store, func_ty, export_name, instance_pre| {
Func::new(
store,
func_ty.clone(),
move |mut caller, params, results| {
// Create a new instance for this command execution.
let instance = instance_pre.instantiate(&mut caller)?;
// `unwrap()` everything here because we know the instance contains a
// function export with the given name and signature because we're
// iterating over the module it was instantiated from.
instance
.get_export(&mut caller, &export_name)
.unwrap()
.into_func()
.unwrap()
.call(&mut caller, params, results)?;
Ok(())
},
)
},
)
}
ModuleKind::Reactor => {
let instance = self.instantiate(&mut store, &module)?;
if let Some(export) = instance.get_export(&mut store, "_initialize") {
if let Extern::Func(func) = export {
func.typed::<(), ()>(&store)
.and_then(|f| f.call(&mut store, ()).map_err(Into::into))
.context("calling the Reactor initialization function")?;
}
}
self.instance(store, module_name, instance)
}
}
}
/// Define automatic instantiations of a [`Module`] in this linker.
///
/// This is the same as [`Linker::module`], except for async `Store`s.
#[cfg(all(feature = "async", feature = "cranelift"))]
#[cfg_attr(nightlydoc, doc(cfg(all(feature = "async", feature = "cranelift"))))]
pub async fn module_async(
&mut self,
mut store: impl AsContextMut<Data = T>,
module_name: &str,
module: &Module,
) -> Result<&mut Self>
where
T: Send + 'static,
{
// NB: this is intended to function the same as `Linker::module`, they
// should be kept in sync.
assert!(
Engine::same(&self.engine, store.as_context().engine()),
"different engines for this linker and the store provided"
);
match ModuleKind::categorize(module)? {
ModuleKind::Command => self.command(
store,
module_name,
module,
|store, func_ty, export_name, instance_pre| {
let upvars = Arc::new((instance_pre, export_name));
Func::new_async(
store,
func_ty.clone(),
move |mut caller, params, results| {
let upvars = upvars.clone();
Box::new(async move {
let (instance_pre, export_name) = &*upvars;
let instance = instance_pre.instantiate_async(&mut caller).await?;
instance
.get_export(&mut caller, &export_name)
.unwrap()
.into_func()
.unwrap()
.call_async(&mut caller, params, results)
.await?;
Ok(())
})
},
)
},
),
ModuleKind::Reactor => {
let instance = self.instantiate_async(&mut store, &module).await?;
if let Some(export) = instance.get_export(&mut store, "_initialize") {
if let Extern::Func(func) = export {
let func = func
.typed::<(), ()>(&store)
.context("loading the Reactor initialization function")?;
func.call_async(&mut store, ())
.await
.context("calling the Reactor initialization function")?;
}
}
self.instance(store, module_name, instance)
}
}
}sourcepub fn get_typed_func<Params, Results>(
&self,
store: impl AsContextMut,
name: &str
) -> Result<TypedFunc<Params, Results>>where
Params: WasmParams,
Results: WasmResults,
pub fn get_typed_func<Params, Results>(
&self,
store: impl AsContextMut,
name: &str
) -> Result<TypedFunc<Params, Results>>where
Params: WasmParams,
Results: WasmResults,
Looks up an exported Func value by name and with its type.
This function is a convenience wrapper over Instance::get_func and
Func::typed. For more information see the linked documentation.
Returns an error if name isn’t a function export or if the export’s
type did not match Params or Results
Panics
Panics if store does not own this instance.
sourcepub fn get_memory(&self, store: impl AsContextMut, name: &str) -> Option<Memory>
pub fn get_memory(&self, store: impl AsContextMut, name: &str) -> Option<Memory>
Looks up an exported SharedMemory value by name.
Returns None if there was no export named name, or if there was but
it wasn’t a shared memory.
Panics
Panics if store does not own this instance.