Commit Graph

24 Commits

Author SHA1 Message Date
Alex Crichton
9c73a448f5 c-api: Fix wasmtime_func_call_unchecked to communicate all errors (#5262)
Change the return value of this function to a `wasmtime_error_t*`
instead of the prior `wasm_trap_t*`. This is a leftover from #5149.

Closes #5257
2022-11-14 12:30:17 -06:00
Alex Crichton
2afaac5181 Return anyhow::Error from host functions instead of Trap, redesign Trap (#5149)
* Return `anyhow::Error` from host functions instead of `Trap`

This commit refactors how errors are modeled when returned from host
functions and additionally refactors how custom errors work with `Trap`.
At a high level functions in Wasmtime that previously worked with
`Result<T, Trap>` now work with `Result<T>` instead where the error is
`anyhow::Error`. This includes functions such as:

* Host-defined functions in a `Linker<T>`
* `TypedFunc::call`
* Host-related callbacks like call hooks

Errors are now modeled primarily as `anyhow::Error` throughout Wasmtime.
This subsequently removes the need for `Trap` to have the ability to
represent all host-defined errors as it previously did. Consequently the
`From` implementations for any error into a `Trap` have been removed
here and the only embedder-defined way to create a `Trap` is to use
`Trap::new` with a custom string.

After this commit the distinction between a `Trap` and a host error is
the wasm backtrace that it contains. Previously all errors in host
functions would flow through a `Trap` and get a wasm backtrace attached
to them, but now this only happens if a `Trap` itself is created meaning
that arbitrary host-defined errors flowing from a host import to the
other side won't get backtraces attached. Some internals of Wasmtime
itself were updated or preserved to use `Trap::new` to capture a
backtrace where it seemed useful, such as when fuel runs out.

The main motivation for this commit is that it now enables hosts to
thread a concrete error type from a host function all the way through to
where a wasm function was invoked. Previously this could not be done
since the host error was wrapped in a `Trap` that didn't provide the
ability to get at the internals.

A consequence of this commit is that when a host error is returned that
isn't a `Trap` we'll capture a backtrace and then won't have a `Trap` to
attach it to. To avoid losing the contextual information this commit
uses the `Error::context` method to attach the backtrace as contextual
information to ensure that the backtrace is itself not lost.

This is a breaking change for likely all users of Wasmtime, but it's
hoped to be a relatively minor change to workaround. Most use cases can
likely change `-> Result<T, Trap>` to `-> Result<T>` and otherwise
explicit creation of a `Trap` is largely no longer necessary.

* Fix some doc links

* add some tests and make a backtrace type public (#55)

* Trap: avoid a trailing newline in the Display impl

which in turn ends up with three newlines between the end of the
backtrace and the `Caused by` in the anyhow Debug impl

* make BacktraceContext pub, and add tests showing downcasting behavior of anyhow::Error to traps or backtraces

* Remove now-unnecesary `Trap` downcasts in `Linker::module`

* Fix test output expectations

* Remove `Trap::i32_exit`

This commit removes special-handling in the `wasmtime::Trap` type for
the i32 exit code required by WASI. This is now instead modeled as a
specific `I32Exit` error type in the `wasmtime-wasi` crate which is
returned by the `proc_exit` hostcall. Embedders which previously tested
for i32 exits now downcast to the `I32Exit` value.

* Remove the `Trap::new` constructor

This commit removes the ability to create a trap with an arbitrary error
message. The purpose of this commit is to continue the prior trend of
leaning into the `anyhow::Error` type instead of trying to recreate it
with `Trap`. A subsequent simplification to `Trap` after this commit is
that `Trap` will simply be an `enum` of trap codes with no extra
information. This commit is doubly-motivated by the desire to always use
the new `BacktraceContext` type instead of sometimes using that and
sometimes using `Trap`.

Most of the changes here were around updating `Trap::new` calls to
`bail!` calls instead. Tests which assert particular error messages
additionally often needed to use the `:?` formatter instead of the `{}`
formatter because the prior formats the whole `anyhow::Error` and the
latter only formats the top-most error, which now contains the
backtrace.

* Merge `Trap` and `TrapCode`

With prior refactorings there's no more need for `Trap` to be opaque or
otherwise contain a backtrace. This commit parse down `Trap` to simply
an `enum` which was the old `TrapCode`. All various tests and such were
updated to handle this.

The main consequence of this commit is that all errors have a
`BacktraceContext` context attached to them. This unfortunately means
that the backtrace is printed first before the error message or trap
code, but given all the prior simplifications that seems worth it at
this time.

* Rename `BacktraceContext` to `WasmBacktrace`

This feels like a better name given how this has turned out, and
additionally this commit removes having both `WasmBacktrace` and
`BacktraceContext`.

* Soup up documentation for errors and traps

* Fix build of the C API

Co-authored-by: Pat Hickey <pat@moreproductive.org>
2022-11-02 16:29:31 +00:00
Alex Crichton
f4b9020913 Change wasm-to-host trampolines to take the values_vec size (#4192)
* Change wasm-to-host trampolines to take the values_vec size

This commit changes the ABI of wasm-to-host trampolines, which are
only used right now for functions created with `Func::new`, to pass
along the size of the `values_vec` argument. Previously the trampoline
simply received `*mut ValRaw` and assumed that it was the appropriate
size. By receiving a size as well we can thread through `&mut [ValRaw]`
internally instead of `*mut ValRaw`.

The original motivation for this is that I'm planning to leverage these
trampolines for the component model for host-defined functions. Out of
an abundance of caution of making sure that everything lines up I wanted
to be able to write down asserts about the size received at runtime
compared to the size expected. This overall led me to the desire to
thread this size parameter through on the assumption that it would not
impact performance all that much.

I ran two benchmarks locally from the `call.rs` benchmark and got:

* `sync/no-hook/wasm-to-host - nop - unchecked` - no change
* `sync/no-hook/wasm-to-host - nop-params-and-results - unchecked` - 5%
  slower

This is what I roughly expected in that if nothing actually reads the
new parameter (e.g. no arguments) then threading through the parameter
is effectively otherwise free. Otherwise though accesses to the `ValRaw`
storage is now bounds-checked internally in Wasmtime instead of assuming
it's valid, leading to the 5% slowdown (~9.6ns to ~10.3ns). If this
becomes a peformance bottleneck for a particular use case then we should
be fine to remove the bounds checking here or otherwise only bounds
check in debug mode, otherwise I plan on leaving this as-is.

Of particular note this also changes the C API for `*_unchecked`
functions where the C callback now receives the size of the array as
well.

* Add docs
2022-06-01 09:05:37 -05:00
Alex Crichton
0a0c232a14 Fix CI for Rust 1.61.0 (#4164)
A new version of rustc was released this morning and we have a few small
breakages on our CI which need fixing:

* A new warning was coming out of the c-api crate about an unneeded
  `unsafe` block.
* The panic message of a task in `cranelift-object` needed updating
  since the standard library changed how it formats strings with the nul
  byte.
2022-05-19 10:44:45 -05:00
Alex Crichton
7b5176baea Upgrade all crates to the Rust 2021 edition (#3991)
* Upgrade all crates to the Rust 2021 edition

I've personally started using the new format strings for things like
`panic!("some message {foo}")` or similar and have been upgrading crates
on a case-by-case basis, but I think it probably makes more sense to go
ahead and blanket upgrade everything so 2021 features are always
available.

* Fix compile of the C API

* Fix a warning

* Fix another warning
2022-04-04 12:27:12 -05:00
Alex Crichton
bfdbd10a13 Add *_unchecked variants of Func APIs for the C API (#3350)
* Add `*_unchecked` variants of `Func` APIs for the C API

This commit is what is hopefully going to be my last installment within
the saga of optimizing function calls in/out of WebAssembly modules in
the C API. This is yet another alternative approach to #3345 (sorry) but
also contains everything necessary to make the C API fast. As in #3345
the general idea is just moving checks out of the call path in the same
style of `TypedFunc`.

This new strategy takes inspiration from previously learned attempts
effectively "just" exposes how we previously passed `*mut u128` through
trampolines for arguments/results. This storage format is formalized
through a new `ValRaw` union that is exposed from the `wasmtime` crate.
By doing this it made it relatively easy to expose two new APIs:

* `Func::new_unchecked`
* `Func::call_unchecked`

These are the same as their checked equivalents except that they're
`unsafe` and they work with `*mut ValRaw` rather than safe slices of
`Val`. Working with these eschews type checks and such and requires
callers/embedders to do the right thing.

These two new functions are then exposed via the C API with new
functions, enabling C to have a fast-path of calling/defining functions.
This fast path is akin to `Func::wrap` in Rust, although that API can't
be built in C due to C not having generics in the same way that Rust
has.

For some benchmarks, the benchmarks here are:

* `nop` - Call a wasm function from the host that does nothing and
  returns nothing.
* `i64` - Call a wasm function from the host, the wasm function calls a
  host function, and the host function returns an `i64` all the way out to
  the original caller.
* `many` - Call a wasm function from the host, the wasm calls
   host function with 5 `i32` parameters, and then an `i64` result is
   returned back to the original host
* `i64` host - just the overhead of the wasm calling the host, so the
  wasm calls the host function in a loop.
* `many` host - same as `i64` host, but calling the `many` host function.

All numbers in this table are in nanoseconds, and this is just one
measurement as well so there's bound to be some variation in the precise
numbers here.

| Name      | Rust | C (before) | C (after) |
|-----------|------|------------|-----------|
| nop       | 19   | 112        | 25        |
| i64       | 22   | 207        | 32        |
| many      | 27   | 189        | 34        |
| i64 host  | 2    | 38         | 5         |
| many host | 7    | 75         | 8         |

The main conclusion here is that the C API is significantly faster than
before when using the `*_unchecked` variants of APIs. The Rust
implementation is still the ceiling (or floor I guess?) for performance
The main reason that C is slower than Rust is that a little bit more has
to travel through memory where on the Rust side of things we can
monomorphize and inline a bit more to get rid of that. Overall though
the costs are way way down from where they were originally and I don't
plan on doing a whole lot more myself at this time. There's various
things we theoretically could do I've considered but implementation-wise
I think they'll be much more weighty.

* Tweak `wasmtime_externref_t` API comments
2021-09-24 14:05:45 -05:00
Alex Crichton
bcf3544924 Optimize Func::call and its C API (#3319)
* Optimize `Func::call` and its C API

This commit is an alternative to #3298 which achieves effectively the
same goal of optimizing the `Func::call` API as well as its C API
sibling of `wasmtime_func_call`. The strategy taken here is different
than #3298 though where a new API isn't created, rather a small tweak to
an existing API is done. Specifically this commit handles the major
sources of slowness with `Func::call` with:

* Looking up the type of a function, to typecheck the arguments with and
  use to guide how the results should be loaded, no longer hits the
  rwlock in the `Engine` but instead each `Func` contains its own
  `FuncType`. This can be an unnecessary allocation for funcs not used
  with `Func::call`, so this is a downside of this implementation
  relative to #3298. A mitigating factor, though, is that instance
  exports are loaded lazily into the `Store` and in theory not too many
  funcs are active in the store as `Func` objects.

* Temporary storage is amortized with a long-lived `Vec` in the `Store`
  rather than allocating a new vector on each call. This is basically
  the same strategy as #3294 only applied to different types in
  different places. Specifically `wasmtime::Store` now retains a
  `Vec<u128>` for `Func::call`, and the C API retains a `Vec<Val>` for
  calling `Func::call`.

* Finally, an API breaking change is made to `Func::call` and its type
  signature (as well as `Func::call_async`). Instead of returning
  `Box<[Val]>` as it did before this function now takes a
  `results: &mut [Val]` parameter. This allows the caller to manage the
  allocation and we can amortize-remove it in `wasmtime_func_call` by
  using space after the parameters in the `Vec<Val>` we're passing in.
  This change is naturally a breaking change and we'll want to consider
  it carefully, but mitigating factors are that most embeddings are
  likely using `TypedFunc::call` instead and this signature taking a
  mutable slice better aligns with `Func::new` which receives a mutable
  slice for the results.

Overall this change, in the benchmark of "call a nop function from the C
API" is not quite as good as #3298. It's still a bit slower, on the
order of 15ns, because there's lots of capacity checks around vectors
and the type checks are slightly less optimized than before. Overall
though this is still significantly better than today because allocations
and the rwlock to acquire the type information are both avoided. I
personally feel that this change is the best to do because it has less
of an API impact than #3298.

* Rebase issues
2021-09-21 14:07:05 -05:00
Alex Crichton
c73673559b Avoid vector allocations in wasm->host calls (#3294)
This commit improves the runtime support for wasm-to-host invocations
for functions created with `Func::new` or `wasmtime_func_new` in the C
API. Previously a `Vec` (sometimes a `SmallVec`) would be dynamically
allocated on each host call to store the arguments that are coming from
wasm and going to the host. In the case of the `wasmtime` crate we need
to decode the `u128`-stored values, and in the case of the C API we need
to decode the `Val` into the C API's `wasmtime_val_t`.

The technique used in this commit is to store a singular `Vec<T>` inside
the "store", be it the literal `Store<T>` or within the `T` in the case
of the C API, which can be reused across wasm->host calls. This means
that we're unlikely to actually perform dynamic memory allocation and
instead we should hit a faster path where the `Vec` always has enough
capacity.

Note that this is just a mild improvement for `Func::new`-based
functions. It's still the case that `Func::wrap` is much faster, but
unfortunately the C API doesn't have access to `Func::wrap`, so the main
motivation here is accelerating the C API.
2021-09-03 15:14:21 -05:00
Alex Crichton
65378422bf Add a wasmtime_linker_define_func C API function (#3122)
This exposes the functionality of the `Linker` type where a
store-independent function can be created and inserted, allowing a
linker's functions to be used across many stores (instead of requiring
one linker-per-store).

Closes #3110
2021-07-27 18:56:52 -05:00
Alex Crichton
7a1b7cdf92 Implement RFC 11: Redesigning Wasmtime's APIs (#2897)
Implement Wasmtime's new API as designed by RFC 11. This is quite a large commit which has had lots of discussion externally, so for more information it's best to read the RFC thread and the PR thread.
2021-06-03 09:10:53 -05:00
Peter Huene
f94db6556c Update WebAssembly C API submodule to latest commit. (#2579)
* Update WebAssembly C API submodule to latest commit.

This commit updates the WebAssembly C API submodule (for `wasm.h`) to the
latest commit out of master.

This fixes the behavior of `wasm_name_new_from_string` such that it no longer
copies the null character into the name, which caused unexpected failures when
using the Wasmtime linker as imports wouldn't resolve when the null was
present.

Along with this change were breaking changes to `wasm_func_call`, the host
callback signatures, and `wasm_instance_new` to take a vector type instead of a
pointer to an unsized array.

As a result, Wasmtime language bindings based on the C API will need to be
updated once this change is pulled in.

Fixes #2211.
Fixes #2131.

* Update Doxygen comments for wasm.h changes.
2021-01-14 09:36:12 -06:00
Nick Fitzgerald
a9455a8e51 C API tweaks for wasmtime-py (#2029)
* wasmtime-c-api: Only drop non-null `*mut wasm_ref_t`s

* wasmtime-c-api: Handle null refs in `wasm_val_t` to `Val` conversion

* wasmtime-c-api: Don't unwrap and rewrap `Option`s

The `unwrap` can panic, and there isn't any point to this unwrap+rewrap.

* wasmtime-c-api: Add conversions between `funcref` and `wasm_func_t`

* wasmtime-c-api: More ownership documentation for `wasmtime.h`
2020-07-15 19:55:31 -05:00
Nick Fitzgerald
d07fdca73a wasmtime-c-api: Use a safe helper for initializing MaybeUninit out pointers 2020-07-10 13:09:08 -07:00
Nick Fitzgerald
4cdf8b7cfd wasmtime-c-api: Add support for externref values
This required that `wasm_val_t` have a `Drop` implementation, an explicit
`Clone` implementation, and no longer be `Copy`, which rippled out through the
crate a bit.

Additionally, `wasm_func_call` and friends were creating references to
uninitialized data for its out pointers and assigning to them. As soon as
`wasm_val_t` gained a `Drop` impl and tried to drop the old value of the
assignment (which is uninitialized data), then things blew up. The fix is to
properly represent the out pointers with `MaybeUninit`, and use `ptr::write` to
initialize them without dropping the old data.

Part of #929
2020-07-10 13:09:08 -07:00
Alex Crichton
cca558cd20 Remove HostRef<T> from the C API (#1926)
This commit removes `HostRef<T>` from the C API which only served the
purpose now of converting each type to a `wasm_ref_t*`. Our
implementation, however, does not guarantee that you'll get the same
`wasm_ref_t*` for each actual underlying item (e.g. if you put a func in
a table and then get the func as an export and from the table then
`same` will report `false`). Additionally the fate of `wasm_ref_t*`
seems somewhat unclear at this point.

The change here is to make the `same` and cast functions all abort
saying they're unimplemented. (similar to the host info functions). If
and when we get around to reimplementing these functions we can ensure
they're implemented uniformly and work well for all intended use cases.
2020-06-26 14:34:34 -05:00
Nick Fitzgerald
e40c039e65 wasmtime: Rip out incomplete/incorrect externref "host info" support
Better to be loud that we don't support attaching arbitrary host info to
`externref`s than to limp along and pretend we do support it. Supporting it
properly won't reuse any of this code anyways.
2020-06-25 14:00:40 -07:00
Thibault Charbonnier
8082aeaa5f C API: expose wasmtime_linker_get_one_by_name() (#1897)
* C API: expose wasmtime_linker_get_one_by_name()

* C API: remove unnecessary 'unsafe' qualifiers

* C API: avoid unnecessary mutable borrows of the Linker
2020-06-23 14:23:49 -05:00
Nick Fitzgerald
58b08b9d3a Move HostRef<T> into the C API crate
It isn't used by anything except for the C API and all of our embedder-exposed
APIs are already internally `Rc`-based, so it doesn't make sense to use with
them.
2020-06-01 15:09:51 -07:00
Nick Fitzgerald
a8ee0554a9 wasmtime: Initial, partial support for externref
This is enough to get an `externref -> externref` identity function
passing.

However, `externref`s that are dropped by compiled Wasm code are (safely)
leaked. Follow up work will leverage cranelift's stack maps to resolve this
issue.
2020-06-01 15:09:51 -07:00
Nick Fitzgerald
f28b3738ee Rename anyref to externref across the board 2020-05-20 11:58:55 -07:00
Alex Crichton
1247f2b4ae Add wasmtime-specific C APIs for tables (#1654)
This commit adds a suite of `wasmtime_funcref_table_*` APIs which mirror
the standard APIs but have a few differences:

* More errors are returned. For example error messages are communicated
  through `wasmtime_error_t` and out-of-bounds vs load of null can be
  differentiated in the `get` API.

* APIs take `wasm_func_t` instead of `wasm_ref_t`. Given the recent
  decision to remove subtyping from the anyref proposal it's not clear
  how the C API for tables will be affected, so for now these APIs are
  all specialized to only funcref tables.

* Growth now allows access to the previous size of the table, if
  desired, which mirrors the `table.grow` instruction.

This was originally motivated by bytecodealliance/wasmtime-go#5 where
the current APIs we have for working with tables don't quite work. We
don't have a great way to take an anyref constructed from a `Func` and
get the `Func` back out, so for now this sidesteps those concerns while
we sort out the anyref story.

It's intended that once the anyref story has settled and the official C
API has updated we'll likely delete these wasmtime-specific APIs or
implement them as trivial wrappers around the official ones.
2020-05-13 16:16:29 -07:00
Dan Gohman
9364eb1d98 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.
2020-04-20 15:55:33 -05:00
Alex Crichton
bd374fd6fc Add Wasmtime-specific C API functions to return errors (#1467)
* Add Wasmtime-specific C API functions to return errors

This commit adds new `wasmtime_*` symbols to the C API, many of which
mirror the existing counterparts in the `wasm.h` header. These APIs are
enhanced in a number of respects:

* Detailed error information is now available through a
  `wasmtime_error_t`. Currently this only exposes one function which is
  to extract a string version of the error.

* There is a distinction now between traps and errors during
  instantiation and function calling. Traps only happen if wasm traps,
  and errors can happen for things like runtime type errors when
  interacting with the API.

* APIs have improved safety with respect to embedders where the lengths
  of arrays are now taken as explicit parameters rather than assumed
  from other parameters.

* Handle trap updates

* Update C examples

* Fix memory.c compile on MSVC

* Update test assertions

* Refactor C slightly

* Bare-bones .NET update

* Remove bogus nul handling
2020-04-06 15:13:06 -05:00
Alex Crichton
6ef09359b0 Refactor and fill out wasmtime's C API (#1415)
* Refactor and improve safety of C API

This commit is intended to be a relatively large refactoring of the C
API which is targeted at improving the safety of our C API definitions.
Not all of the APIs have been updated yet but this is intended to be the
start.

The goal here is to make as many functions safe as we can, expressing
inputs/outputs as native Rust types rather than raw pointers wherever
possible. For example instead of `*const wasm_foo_t` we'd take
`&wasm_foo_t`. Instead of returning `*mut wasm_foo_t` we'd return
`Box<wasm_foo_t>`. No ABI/API changes are intended from this commit,
it's supposed to only change how we define all these functions
internally.

This commit also additionally implements a few more API bindings for
exposed vector types by unifying everything into one macro.

Finally, this commit moves many internal caches in the C API to the
`OnceCell` type which provides a safe interface for one-time
initialization.

* Split apart monolithic C API `lib.rs`

This commit splits the monolithic `src/lib.rs` in the C API crate into
lots of smaller files. The goal here is to make this a bit more readable
and digestable. Each module now contains only API bindings for a
particular type, roughly organized around the grouping in the wasm.h
header file already.

A few more extensions were added, such as filling out `*_as_*`
conversions with both const and non-const versions. Additionally many
APIs were made safer in the same style as the previous commit, generally
preferring Rust types rather than raw pointer types.

Overall no functional change is intended here, it should be mostly just
code movement and minor refactorings!

* Make a few wasi C bindings safer

Use safe Rust types where we can and touch up a few APIs here and there.

* Implement `wasm_*type_as_externtype*` APIs

This commit restructures `wasm_externtype_t` to be similar to
`wasm_extern_t` so type conversion between the `*_extern_*` variants to
the concrete variants are all simple casts. (checked in the case of
general to concrete, of course).

* Consistently imlpement host info functions in the API

This commit adds a small macro crate which is then used to consistently
define the various host-info-related functions in the C API. The goal
here is to try to mirror what the `wasm.h` header provides to provide a
full implementation of the header.
2020-03-27 09:50:32 -05:00