Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion RELEASES.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,10 @@ Unreleased

### Added

### Changed
* The [Commands and Reactors ABI] is now supported in the Rust API. `Linker::module`
loads a module and automatically handles Commands and Reactors semantics.

[Commands and Reactors ABI]: https://github.com/WebAssembly/WASI/blob/master/design/application-abi.md#current-unstable-abi

### Fixed

Expand Down
12 changes: 12 additions & 0 deletions crates/c-api/include/wasmtime.h
Original file line number Diff line number Diff line change
Expand Up @@ -117,6 +117,18 @@ WASM_API_EXTERN own wasmtime_error_t* wasmtime_linker_instantiate(
own wasm_trap_t **trap
);

WASM_API_EXTERN own wasmtime_error_t* wasmtime_linker_module(
const wasmtime_linker_t *linker,
const wasm_name_t *name,
const wasm_module_t *module
);

WASM_API_EXTERN own wasmtime_error_t* wasmtime_linker_get_default(
const wasmtime_linker_t *linker,
const wasm_name_t *name,
own wasm_func_t **func
);

///////////////////////////////////////////////////////////////////////////////
//
// wasmtime_caller_t extension, binding the `Caller` type in the Rust API
Expand Down
34 changes: 32 additions & 2 deletions crates/c-api/src/linker.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
use crate::{bad_utf8, handle_result, wasmtime_error_t};
use crate::{wasm_extern_t, wasm_store_t, ExternHost};
use crate::{wasm_instance_t, wasm_module_t, wasm_name_t, wasm_trap_t};
use crate::{wasm_func_t, wasm_instance_t, wasm_module_t, wasm_name_t, wasm_trap_t};
use std::str;
use wasmtime::{Extern, Linker};
use wasmtime::{Extern, HostRef, Linker};

#[repr(C)]
pub struct wasmtime_linker_t {
Expand Down Expand Up @@ -89,3 +89,33 @@ pub unsafe extern "C" fn wasmtime_linker_instantiate(
let result = linker.linker.instantiate(&module.module.borrow());
super::instance::handle_instantiate(result, instance_ptr, trap_ptr)
}

#[no_mangle]
pub unsafe extern "C" fn wasmtime_linker_module(
linker: &mut wasmtime_linker_t,
name: &wasm_name_t,
module: &wasm_module_t,
) -> Option<Box<wasmtime_error_t>> {
let linker = &mut linker.linker;
let name = match str::from_utf8(name.as_slice()) {
Ok(s) => s,
Err(_) => return bad_utf8(),
};
handle_result(linker.module(name, &module.module.borrow()), |_linker| ())
}

#[no_mangle]
pub unsafe extern "C" fn wasmtime_linker_get_default(
linker: &mut wasmtime_linker_t,
name: &wasm_name_t,
func: &mut *mut wasm_func_t,
) -> Option<Box<wasmtime_error_t>> {
let linker = &mut linker.linker;
let name = match str::from_utf8(name.as_slice()) {
Ok(s) => s,
Err(_) => return bad_utf8(),
};
handle_result(linker.get_default(name), |f| {
*func = Box::into_raw(Box::new(HostRef::new(f).into()))
})
}
4 changes: 0 additions & 4 deletions crates/runtime/src/instance.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1330,8 +1330,4 @@ pub enum InstantiationError {
/// A trap ocurred during instantiation, after linking.
#[error("Trap occurred during instantiation")]
Trap(Trap),

/// A trap occurred while running the wasm start function.
#[error("Trap occurred while invoking start function")]
StartTrap(Trap),
}
41 changes: 12 additions & 29 deletions crates/test-programs/tests/wasm_tests/runtime.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
use anyhow::{bail, Context};
use anyhow::Context;
use std::fs::File;
use std::path::Path;
use wasi_common::VirtualDirEntry;
use wasmtime::{Instance, Module, Store};
use wasmtime::{Linker, Module, Store};

#[derive(Clone, Copy, Debug)]
pub enum PreopenType {
Expand Down Expand Up @@ -48,36 +48,19 @@ pub fn instantiate(
let (reader, _writer) = os_pipe::pipe()?;
builder.stdin(reader_to_file(reader));
let snapshot1 = wasmtime_wasi::Wasi::new(&store, builder.build()?);
let module = Module::new(&store, &data).context("failed to create wasm module")?;
let imports = module
.imports()
.map(|i| {
let field_name = i.name();
if let Some(export) = snapshot1.get_export(field_name) {
Ok(export.clone().into())
} else {
bail!(
"import {} was not found in module {}",
field_name,
i.module()
)
}
})
.collect::<Result<Vec<_>, _>>()?;

let instance = Instance::new(&module, &imports).context(format!(
"error while instantiating Wasm module '{}'",
bin_name,
))?;
let mut linker = Linker::new(&store);

instance
.get_export("_start")
.context("expected a _start export")?
.into_func()
.context("expected export to be a func")?
.call(&[])?;
snapshot1.add_to_linker(&mut linker)?;

let module = Module::new(&store, &data).context("failed to create wasm module")?;

Ok(())
linker
.module("", &module)
.and_then(|m| m.get_default(""))
.and_then(|f| f.get0::<()>())
.and_then(|f| f().map_err(Into::into))
.context(format!("error while testing Wasm module '{}'", bin_name,))
}

#[cfg(unix)]
Expand Down
2 changes: 2 additions & 0 deletions crates/wasi-common/wig/src/wasi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,7 @@ pub fn define_struct(args: TokenStream) -> TokenStream {
let memory = match caller.get_export("memory") {
Some(wasmtime::Extern::Memory(m)) => m,
_ => {
log::warn!("callee does not export a memory as \"memory\"");
let e = wasi_common::old::snapshot_0::wasi::__WASI_ERRNO_INVAL;
#handle_early_error
}
Expand Down Expand Up @@ -463,6 +464,7 @@ pub fn define_struct_for_wiggle(args: TokenStream) -> TokenStream {
let mem = match caller.get_export("memory") {
Some(wasmtime::Extern::Memory(m)) => m,
_ => {
log::warn!("callee does not export a memory as \"memory\"");
let e = wasi_common::wasi::Errno::Inval;
#handle_early_error
}
Expand Down
83 changes: 49 additions & 34 deletions crates/wasmtime/src/instance.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,25 @@ fn instantiate(
sig_registry: &SignatureRegistry,
host: Box<dyn Any>,
) -> Result<StoreInstanceHandle, Error> {
// For now we have a restriction that the `Store` that we're working
// with is the same for everything involved here.
for import in imports {
if !import.comes_from_same_store(store) {
bail!("cross-`Store` instantiation is not currently supported");
}
}

if imports.len() != compiled_module.module().imports.len() {
bail!(
"wrong number of imports provided, {} != {}",
imports.len(),
compiled_module.module().imports.len()
);
}

let mut resolver = SimpleResolver { imports };
unsafe {
let config = store.engine().config();
let config = store.engine().config();
let instance = unsafe {
let instance = compiled_module.instantiate(
&mut resolver,
sig_registry,
Expand All @@ -51,31 +67,38 @@ fn instantiate(
)
.map_err(|e| -> Error {
match e {
InstantiationError::StartTrap(trap) | InstantiationError::Trap(trap) => {
Trap::from_runtime(trap).into()
}
InstantiationError::Trap(trap) => Trap::from_runtime(trap).into(),
other => other.into(),
}
})?;

// If a start function is present, now that we've got our compiled
// instance we can invoke it. Make sure we use all the trap-handling
// configuration in `store` as well.
if let Some(start) = instance.module().start_func {
let f = match instance.lookup_by_declaration(&EntityIndex::Function(start)) {
wasmtime_runtime::Export::Function(f) => f,
_ => unreachable!(), // valid modules shouldn't hit this
};
super::func::catch_traps(instance.vmctx_ptr(), store, || {
instance
};

let start_func = instance.handle.module().start_func;

// If a start function is present, invoke it. Make sure we use all the
// trap-handling configuration in `store` as well.
if let Some(start) = start_func {
let f = match instance
.handle
.lookup_by_declaration(&EntityIndex::Function(start))
{
wasmtime_runtime::Export::Function(f) => f,
_ => unreachable!(), // valid modules shouldn't hit this
};
let vmctx_ptr = instance.handle.vmctx_ptr();
unsafe {
super::func::catch_traps(vmctx_ptr, store, || {
mem::transmute::<
*const VMFunctionBody,
unsafe extern "C" fn(*mut VMContext, *mut VMContext),
>(f.address)(f.vmctx, instance.vmctx_ptr())
>(f.address)(f.vmctx, vmctx_ptr)
})?;
}

Ok(instance)
}

Ok(instance)
}

/// An instantiated WebAssembly module.
Expand Down Expand Up @@ -111,6 +134,15 @@ impl Instance {
/// automatically run (if provided) 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 performance 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 `imports` array here is a bit tricky. The entries in the list of
Expand Down Expand Up @@ -147,23 +179,6 @@ impl Instance {
/// [`ExternType`]: crate::ExternType
pub fn new(module: &Module, imports: &[Extern]) -> Result<Instance, Error> {
let store = module.store();

// For now we have a restriction that the `Store` that we're working
// with is the same for everything involved here.
for import in imports {
if !import.comes_from_same_store(store) {
bail!("cross-`Store` instantiation is not currently supported");
}
}

if imports.len() != module.imports().len() {
bail!(
"wrong number of imports provided, {} != {}",
imports.len(),
module.imports().len()
);
}

let info = module.register_frame_info();
let handle = instantiate(
store,
Expand Down
Loading