|
Revision tags: dev, v36.0.9, v44.0.1, v43.0.2, v36.0.8, v24.0.8, v44.0.0, v43.0.1, v42.0.2, v36.0.7, v24.0.7, v43.0.0, v42.0.1, v41.0.4, v42.0.0, v40.0.4, v36.0.6, v24.0.6, v41.0.3, v41.0.2 |
|
| #
aedc5480 |
| 28-Jan-2026 |
Ohad Ravid <[email protected]> |
Added a thread_local guard to trigger dtor hook before fibers are used (#12426)
* Added a thread_local guard to trigger dtor hook before fibers are used
* Add a test for async function that use a t
Added a thread_local guard to trigger dtor hook before fibers are used (#12426)
* Added a thread_local guard to trigger dtor hook before fibers are used
* Add a test for async function that use a tls variable with a destructor
show more ...
|
|
Revision tags: v41.0.1, v36.0.5, v40.0.3 |
|
| #
cc8d04f4 |
| 23-Jan-2026 |
Alex Crichton <[email protected]> |
Remove need for explicit `Config::async_support` knob (#12371)
* Refactor component model host function definitions
Push the `async`-ness down one layer.
* Remove need for explicit `Config::async
Remove need for explicit `Config::async_support` knob (#12371)
* Refactor component model host function definitions
Push the `async`-ness down one layer.
* Remove need for explicit `Config::async_support` knob
This commit is an attempt to step towards reconciling "old async" and "new async" in Wasmtime. The old async style is the original async support in Wasmtime with `call_async`, `func_wrap_async`, etc, where the main property is that the store is "locked" during an async operation. Put another way, a store can only execute at most one async operation at a time. This is in contrast to "new async" support in Wasmtime with the component-model-async (WASIp3) support, where stores can have more than one async operation in flight at once.
This commit does not fully reconcile these differences, but it does remove one hurdle along the way: `Config::async_support`. Since the beginning of Wasmtime this configuration knob has existed to explicitly demarcate a config/engine/store as "this thing requires `async` stuff internally." This has started to make less and less sense over time where the line between sync and async has become more murky with WASIp3 where the two worlds comingle. The goal of this commit is to deprecate `Config::async_support` and make the function not actually do anything.
In isolation this can't simply be done, however, because there are many load-bearing aspects of Wasmtime that rely on this `async_support` knob. For example once epochs + yielding are enabled it's required that all Wasm is executed on a fiber lest it hit an epoch and not know how to yield. That means that this commit is not a simple removal of `async_support` but instead a refactoring/rearchitecting of how async is used internally within Wasmtime. The high-level ideas within Wasmtime now are:
* A `Store` has a "requires async" boolean stored within it. * All configuration options which end up requiring async, such as yielding with epochs, turn this boolean on. * Creation of host functions which use async (e.g. `func_wrap_{async,concurrent}`) will also turn this option on. * Synchronous API entrypoints into Wasmtime ensure that this boolean is disabled. * Asynchronous APIs are usable at any time.
This means that the concept of an async store vs a sync store is now gone. All stores are equally capable of executing sync/async, and the change now is that dynamically some stores will require that async is used with certain configuration. Additionally all panicking conditions around `async_support` have been converted to errors instead. All relevant APIs already returned an error and things are murky enough now that it's not necessarily trivial to get this right at the embedder level. In the interest of avoiding panics all detected async mismatches are now first-class `wasmtime::Error` values.
The end result of this commit is that `Config::async_support` is a deprecated `#[doc(hidden)]` function that does nothing. While many internal changes happened as well as having new tests for all this sort of behavior this is not expected to have a great impact on external consumers. In general a deletion of `async_support(true)` is in theory all that's required. This is intended to make it easier to think about async/sync/etc in the future with WASIp3 and eventually reconcile `func_wrap_async` and `func_wrap_concurrent` for example. That's left for future refactorings however.
prtest:full
* Review comments
* Fix CI failures
show more ...
|
|
Revision tags: v41.0.0, v36.0.4, v39.0.2, v40.0.2 |
|
| #
94740588 |
| 09-Jan-2026 |
Nick Fitzgerald <[email protected]> |
Migrate the Wasmtime CLI to `wasmtime::error` (#12295)
* Migrate wasmtime-cli to `wasmtime::error`
* migrate benches to `wasmtime::error` as well
* Remove new usage of anyhow that snuck in
|
|
Revision tags: v40.0.1, v40.0.0, v39.0.1, v39.0.0, v38.0.4, v37.0.3, v36.0.3, v24.0.5, v38.0.3, v38.0.2, v38.0.1, v37.0.2, v37.0.1, v37.0.0, v36.0.2, v36.0.1, v36.0.0, v35.0.0, v24.0.4, v33.0.2, v34.0.2, v34.0.1, v33.0.1, v24.0.3, v32.0.1, v34.0.0 |
|
| #
3d67b75e |
| 11-Jun-2025 |
Alex Crichton <[email protected]> |
Add a dummy impl of fibers for Miri (#11009)
* Add a dummy impl of fibers for Miri
This commit extends the `wasmtime-internal-fiber` crate with an implementation for Miri. Previously this was entir
Add a dummy impl of fibers for Miri (#11009)
* Add a dummy impl of fibers for Miri
This commit extends the `wasmtime-internal-fiber` crate with an implementation for Miri. Previously this was entirely unsupported because fibers use inline assembly. The implementation with Miri spawns a separate thread and keeps it in a suspended state with locks to model a suspended stack. This technically isn't correct because TLS variables will be wrong, but it's "correct enough" for our usage in Wasmtime. In the end this enables running more tests in Miri which is always a good thing, and a number of loose odds and ends were cleaned up relate to our unsafe management of async state.
* Apply suggestions from code review
Co-authored-by: Pat Hickey <[email protected]>
---------
Co-authored-by: Pat Hickey <[email protected]>
show more ...
|
| #
d41b0a71 |
| 22-May-2025 |
Alex Crichton <[email protected]> |
Use `Waker::noop` from Rust 1.85 (#10804)
Now possible after #10785
|
|
Revision tags: v33.0.0 |
|
| #
f81c0dc0 |
| 13-May-2025 |
Alex Crichton <[email protected]> |
Add `T: 'static` to `Store<T>` (#10760)
* Add `T: 'static` to `Store<T>
Since the beginning the `T` type parameter on `Store<T>` has had no bounds on it. This was intended for maximal flexibility i
Add `T: 'static` to `Store<T>` (#10760)
* Add `T: 'static` to `Store<T>
Since the beginning the `T` type parameter on `Store<T>` has had no bounds on it. This was intended for maximal flexibility in terms of what embedders place within a `Store<T>` and I've personally advocated that we need to keep it this way. In the development of the WASIp3 work, however, I've at least personally reached the conclusion that this is no longer tenable and proceeding will require adding a `'static` bound to data within a store.
Wasmtime today [already] carries unsafe `transmute`s to work around this lack of `'static` bound, and while the number of `unsafe` parts is relatively small right now we're still fundamentally lying to the compiler about lifetime bounds internally. With the WASIp3 async work this degree of "lying" has become even worse. Joel has written up some examples [on Zulip] about how the Rust compiler is requiring `'static` bounds in surprising ways. These patterns are cropping up quite frequently in the WASIp3 work and it's becoming particularly onerous maintaining all of the `unsafe` and ensuring that everything is in sync.
In the WASIp3 repository I've additionally [prototyped a change] which would additionally practically require `T: 'static` in more locations. This change is one I plan on landing in Wasmtime in the near future and while its main motivations are for enabling WASIp3 work it is also a much nicer system than what we have today, in my opinion.
Overall the cost of not having `T: 'static` on `Store<T>` is effectively becoming quite costly, in particular with respect to WASIp3 work. This is coupled with all known embedders already using `T: 'static` data within a `Store<T>` so the expectation of the impact of this change is not large. The main downside of this change as a result is that when and where to place `'static` bounds is sort of a game of whack-a-mole with the compiler. For example I changed `Store<T>` to require `'static` here, but the rest of the change is basically "hit compile until rustc says it's ok". There's not necessarily a huge amount of rhyme-or-reason to where `'static` bounds crop up, which can be surprising or difficult to work with for users.
In the end I feel that this change is necessary and one we can't shy away from. If problems crop up we'll need to figure out how to thread that needle at that time, but I'm coming around to thinking that `T: 'static` is just a fundamental constraint we'll have to take on at this time. Maybe a future version of Rust that fixes some of Joel's examples (if they can be fixed, we're not sure of that) we could consider relaxing this but that's left for future work.
[already]: https://github.com/bytecodealliance/wasmtime/blob/35053d6d8d1a5d4692cf636cba0c920b4a79a44b/crates/wasmtime/src/runtime/store.rs#L602-L611 [on Zulip]: https://rust-lang.zulipchat.com/#narrow/channel/122651-general/topic/.22type.20may.20not.20live.20long.20enough.22.20for.20generic.20closure/near/473862072 [prototyped a change]: https://github.com/bytecodealliance/wasip3-prototyping/pull/158
* Remove a no-longer-necessary `unsafe` block
* Update test expectations
* Fix gc-disabled builds
show more ...
|
|
Revision tags: v32.0.0 |
|
| #
c22b3cb9 |
| 11-Apr-2025 |
Nick Fitzgerald <[email protected]> |
Reuse Wasm linear memories code for GC heaps (#10503)
* Reuse code for Wasm linear memories for GC heaps
Instead of bespoke code paths and structures for Wasm GC, this commit makes it so that we no
Reuse Wasm linear memories code for GC heaps (#10503)
* Reuse code for Wasm linear memories for GC heaps
Instead of bespoke code paths and structures for Wasm GC, this commit makes it so that we now reuse VM structures like `VMMemoryDefinition` and bounds-checking logic. Notably, we also reuse all the associated bounds-checking optimizations and, when possible, virtual-memory techniques to completely elide them.
Furthermore, this commit adds support for growing GC heaps, reusing the machinery for growing memories, and makes it so that GC heaps always start out empty. This allows us to properly delay allocating the GC heap's storage until a GC object is actually allocated.
Fixes #9350
* fix c api compilation
* use assert_contains
* remove no-longer-necessary extra memory config from limiter tests
* Helper for retry-after-maybe-async-gc in libcalls
* Clean up some comments
* fix wasmtime-fuzzing and no-gc compilation
* fix examples
* fix no-gc+compiler build
* fix build without pooling allocator
* fix +cranelift +gc-drc -gc-null builds
* fix table hash key stability test
* fix oracle usage of `ExternRef::new`
* fix +gc -gc-null -gc-drc build
* fix wasmtime-fuzzing
* make `StorePtr` wrap a `NonNull`
* Fix some doc tests
* Remove some unnecessary retry helpers now that `FooRef::new` will auto-gc
* fix things after rebase
* Reorganize collection/growth methods for GC heap
* rename BoundsCheck variants
* fix cfg'ing of gc only code
* Fix doc tests
* fix one more gc cfg
* disable GC heap OOM test on non-64-bit targets
show more ...
|
| #
07c71ab5 |
| 10-Apr-2025 |
Nick Fitzgerald <[email protected]> |
Automatically trigger GC in `{Array,Extern,Struct}Ref` allocation functions (#10560)
* Automatically trigger GC in `{Array,Extern,Struct}Ref` allocation functions
Rather than forcing all callers to
Automatically trigger GC in `{Array,Extern,Struct}Ref` allocation functions (#10560)
* Automatically trigger GC in `{Array,Extern,Struct}Ref` allocation functions
Rather than forcing all callers to check for `GcHeapOutOfMemory`, trigger a GC, and then try again. This does force us to define `*_async` variations for when async is enabled, however; it's ultimately worth it.
* cargo fmt
* review feedback and fix tests
* fix +runtime -gc build
* more feedback and build cfg fixes
* remove copy-paste assertion that doesn't apply to this method
* move assertion into retry methods
show more ...
|
|
Revision tags: v31.0.0, v30.0.2, v30.0.1, v30.0.0, v29.0.1, v29.0.0, v28.0.1, v28.0.0, v27.0.0, v26.0.1, v25.0.3, v24.0.2 |
|
| #
7a28a5b9 |
| 05-Nov-2024 |
Alex Crichton <[email protected]> |
Remove static/dynamic memories from public docs (#9545)
* Remove static/dynamic memories from public docs
This commit removes the terminology of "static" and "dynamic" memories from the public-faci
Remove static/dynamic memories from public docs (#9545)
* Remove static/dynamic memories from public docs
This commit removes the terminology of "static" and "dynamic" memories from the public-facing documentation of Wasmtime, notably on the `Config` structure and its various configuration settings. The goal of this commit is in the same vein as #9543 which is to simplify the memory settings of Wasmtime for users in this case.
This change doesn't actually have any code changes beyond renames (and handling now-deprecated CLI options). The goal of this commit is to basically rewrite how we document the effect of various settings of Wasmtime. Notably:
* `Config::static_memory_maximum_size` is now `memory_reservation`. * `Config::static_memory_forced` is now `memory_reservation_is_maximum`. * `Config::dynamic_memory_reserved_for_growth` is now `memory_reservation_for_growth`.
Documentation for all of these options has been rewritten and updated to take into account the removal of "dynamic" and "static" terminology. Additionally more words have been written about the various effects of each setting and how things related to wasm features such as index type sizes and custom page sizes.
The rewritten documentation is intended to basically already match what Wasmtime does today. I believe that all of these settings are useful in one form or another so none have been dropped but the updated documentation is intended to help simplify the mental model for how they're processed internally and how they affect allocations and such.
* Fix how the setting is flipped
* Review comments
show more ...
|
| #
48d5338b |
| 01-Nov-2024 |
Alex Crichton <[email protected]> |
Merge static/dynamic guard size options (#9528)
* Merge static/dynamic guard size options
This commit is the first of what will likely be a few to refactor the memory-related configuration options
Merge static/dynamic guard size options (#9528)
* Merge static/dynamic guard size options
This commit is the first of what will likely be a few to refactor the memory-related configuration options in Wasmtime. The end goal of these refactorings is to fix some preexisting issues and additionally make the configuration easier to understand for both users and implementors alike. First on the chopping block here is to merge the `dynamic_memory_guard_size` and `static_memory_guard_size` options into one option. AFAIK there's not a strong reason to have separate configuration options for these so it's hopefully simpler to have a single `memory_guard_size` option which applies to all linear memories equally.
I'll note that the old CLI options are preserved but are documented as deprecated. We don't currently warn on using "deprecated options" so for now the old options are just documented as deprecated and are otherwise silently accepted.
* Fix compilation of C API
* Fix build of fuzzers
show more ...
|
|
Revision tags: v26.0.0 |
|
| #
12c20b22 |
| 10-Oct-2024 |
Nick Fitzgerald <[email protected]> |
Implement the Wasm GC instructions for converting between `anyref` and `externref` (#9435)
* Implement the Wasm GC instructions for converting between `anyref` and `externref`
This commit implement
Implement the Wasm GC instructions for converting between `anyref` and `externref` (#9435)
* Implement the Wasm GC instructions for converting between `anyref` and `externref`
This commit implements two instructions:
1. `any.convert_extern` 2. `extern.convert_any`
These instructions are used to convert between `anyref` and `externref` values. The `any.convert_extern` instruction takes an `anyref` value and converts it to an `externref` value. The `extern.convert_any` instruction takes an `externref` value and converts it to an `anyref` value.
Rather than implementing wrapper objects -- for example an `struct AnyOfExtern(ExternRef)` type that is a subtype of `AnyRef` -- we instead reuse the same representation converted references as their unconverted reference. For example, `(any.convert_extern my_externref)` is identical to the original `my_externref` value. This means that we don't actually emit any clif instructions to implement these Wasm instructions; they are no-ops!
Wasm code remains none-the-wiser because it cannot directly test for the difference between, for example, a `my_anyref` and the result of `(extern.convert_any my_anyref)` because they are in two different type hierarchies, so any direct `ref.test` would be invalid. The Wasm code would have to convert one into the other's type hierarchy, at which point it doesn't know whether wrapping/unwrapping took place.
We did need some changes at the host API and host API implementation levels, however:
* We needed to relax the requirement that a `wasmtime::AnyRef` only wraps a `VMGcRef` that points to an object that is a subtype of `anyref` and similar for `wasmtime::ExternRef`.
* We needed to make the `wasmtime::ExternRef::data[_mut]` methods return an option of their associated host data, since any `externref` resulting from `(extern.convert_any ...)` does not have any associated host data. (This change would have been required either way, even if we used wrapper objects.)
* fix tests
* fix wasmtime-environ tests
show more ...
|
|
Revision tags: v21.0.2, v22.0.1, v23.0.3, v25.0.2, v24.0.1, v25.0.1, v25.0.0, v24.0.0, v23.0.2, v23.0.1, v23.0.0, v22.0.0 |
|
| #
05fe6282 |
| 03-Jun-2024 |
Shane Snover <[email protected]> |
Refactor wasmtime::Func to "unsplat" arguments for the async API (#8732)
* Complete implementation in wasmtime
* Get the impl of IntoFunc to point at the new HostContext from_closure method to tie
Refactor wasmtime::Func to "unsplat" arguments for the async API (#8732)
* Complete implementation in wasmtime
* Get the impl of IntoFunc to point at the new HostContext from_closure method to tie it back to the new implementation
* A little bit of cleanup to comments and naming
* Update doc comment for Func wrap_async
show more ...
|
|
Revision tags: v21.0.1, v21.0.0 |
|
| #
906ea017 |
| 17-May-2024 |
Alex Crichton <[email protected]> |
Use bytes for maximum size of linear memory with pooling (#8628)
* Use bytes for maximum size of linear memory with pooling
This commit changes configuration of the pooling allocator to use a byte-
Use bytes for maximum size of linear memory with pooling (#8628)
* Use bytes for maximum size of linear memory with pooling
This commit changes configuration of the pooling allocator to use a byte-based unit rather than a page based unit. The previous `PoolingAllocatorConfig::memory_pages` configuration option configures the maximum size that a linear memory may grow to at runtime. This is an important factor in calculation of stripes for MPK and is also a coarse-grained knob apart from `StoreLimiter` to limit memory consumption. This configuration option has been renamed to `max_memory_size` and documented that it's in terms of bytes rather than pages as before.
Additionally the documented constraint of `max_memory_size` must be smaller than `static_memory_bound` is now additionally enforced as a minor clean-up as part of this PR as well.
* Review comments
* Fix benchmark build
show more ...
|
|
Revision tags: v20.0.2, v20.0.1, v20.0.0 |
|
| #
f3c2a0bb |
| 22-Apr-2024 |
Alex Crichton <[email protected]> |
Fix a panic calling host functions with refs in async mode (#8434)
This commit fixes a panic when a host function defined with `Func::new` returned GC references and was called in async mode. The lo
Fix a panic calling host functions with refs in async mode (#8434)
This commit fixes a panic when a host function defined with `Func::new` returned GC references and was called in async mode. The logic to auto-gc before the return values go to wasm asserted that a synchronous GC was possible but the context this function is called in could be either async or sync. The fix applied in this commit is to remove the auto-gc. This means that hosts will need to explicitly GC in these situations until auto-gc is re-added back to Wasmtime.
cc #8433 as this will make the behavior consistent, but we'll want to re-add the gc behavior.
show more ...
|
|
Revision tags: v17.0.3, v19.0.2, v18.0.4 |
|
| #
0fa13013 |
| 04-Apr-2024 |
Nick Fitzgerald <[email protected]> |
Add `GcRuntime` and `GcCompiler` traits; `i31ref` support (#8196)
\### The `GcRuntime` and `GcCompiler` Traits
This commit factors out the details of the garbage collector away from the rest of the
Add `GcRuntime` and `GcCompiler` traits; `i31ref` support (#8196)
\### The `GcRuntime` and `GcCompiler` Traits
This commit factors out the details of the garbage collector away from the rest of the runtime and the compiler. It does this by introducing two new traits, very similar to a subset of [those proposed in the Wasm GC RFC], although not all equivalent functionality has been added yet because Wasmtime doesn't support, for example, GC structs yet:
[those proposed in the Wasm GC RFC]: https://github.com/bytecodealliance/rfcs/blob/main/accepted/wasm-gc.md#defining-the-pluggable-gc-interface
1. The `GcRuntime` trait: This trait defines how to create new GC heaps, run collections within them, and execute the various GC barriers the collector requires.
Rather than monomorphize all of Wasmtime on this trait, we use it as a dynamic trait object. This does imply some virtual call overhead and missing some inlining (and resulting post-inlining) optimization opportunities. However, it is *much* less disruptive to the existing embedder API, results in a cleaner embedder API anyways, and we don't believe that VM runtime/embedder code is on the hot path for working with the GC at this time anyways (that would be the actual Wasm code, which has inlined GC barriers and direct calls and all of that). In the future, once we have optimized enough of the GC that such code is ever hot, we have options we can investigate at that time to avoid these dynamic virtual calls, like only enabling one single collector at build time and then creating a static type alias like `type TheOneGcImpl = ...;` based on the compile time configuration, and using this type alias in the runtime rather than a dynamic trait object.
The `GcRuntime` trait additionally defines a method to reset a GC heap, for use by the pooling allocator. This allows reuse of GC heaps across different stores. This integration is very rudimentary at the moment, and is missing all kinds of configuration knobs that we should have before deploying Wasm GC in production. This commit is large enough as it is already! Ideally, in the future, I'd like to make it so that GC heaps receive their memory region, rather than allocate/reserve it themselves, and let each slot in the pooling allocator's memory pool be *either* a linear memory or a GC heap. This would unask various capacity planning questions such as "what percent of memory capacity should we dedicate to linear memories vs GC heaps?". It also seems like basically all the same configuration knobs we have for linear memories apply equally to GC heaps (see also the "Indexed Heaps" section below).
2. The `GcCompiler` trait: This trait defines how to emit CLIF that implements GC barriers for various operations on GC-managed references. The Rust code calls into this trait dynamically via a trait object, but since it is customizing the CLIF that is generated for Wasm code, the Wasm code itself is not making dynamic, indirect calls for GC barriers. The `GcCompiler` implementation can inline the parts of GC barrier that it believes should be inline, and leave out-of-line calls to rare slow paths.
All that said, there is still only a single implementation of each of these traits: the existing deferred reference-counting (DRC) collector. So there is a bunch of code motion in this commit as the DRC collector was further isolated from the rest of the runtime and moved to its own submodule. That said, this was not *purely* code motion (see "Indexed Heaps" below) so it is worth not simply skipping over the DRC collector's code in review.
\### Indexed Heaps
This commit does bake in a couple assumptions that must be shared across all collector implementations, such as a shared `VMGcHeader` that all objects allocated within a GC heap must begin with, but the most notable and far-reaching of these assumptions is that all collectors will use "indexed heaps".
What we are calling indexed heaps are basically the three following invariants:
1. All GC heaps will be a single contiguous region of memory, and all GC objects will be allocated within this region of memory. The collector may ask the system allocator for additional memory, e.g. to maintain its free lists, but GC objects themselves will never be allocated via `malloc`.
2. A pointer to a GC-managed object (i.e. a `VMGcRef`) is a 32-bit offset into the GC heap's contiguous region of memory. We never hold raw pointers to GC objects (although, of course, we have to compute them and use them temporarily when actually accessing objects). This means that deref'ing GC pointers is equivalent to deref'ing linear memory pointers: we need to add a base and we also check that the GC pointer/index is within the bounds of the GC heap. Furthermore, compressing 64-bit pointers into 32 bits is a fairly common technique among high-performance GC implementations[^compressed-oops][^v8-ptr-compression] so we are in good company.
3. Anything stored inside the GC heap is untrusted. Even each GC reference that is an element of an `(array (ref any))` is untrusted, and bounds checked on access. This means that, for example, we do not store the raw pointer to an `externref`'s host object inside the GC heap. Instead an `externref` now stores an ID that can be used to index into a side table in the store that holds the actual `Box<dyn Any>` host object, and accessing that side table is always checked.
[^compressed-oops]: See ["Compressed OOPs" in OpenJDK.](https://wiki.openjdk.org/display/HotSpot/CompressedOops)
[^v8-ptr-compression]: See [V8's pointer compression](https://v8.dev/blog/pointer-compression).
The good news with regards to all the bounds checking that this scheme implies is that we can use all the same virtual memory tricks that linear memories use to omit explicit bounds checks. Additionally, (2) means that the sizes of GC objects is that much smaller (and therefore that much more cache friendly) because they are only holding onto 32-bit, rather than 64-bit, references to other GC objects. (We can, in the future, support GC heaps up to 16GiB in size without losing 32-bit GC pointers by taking advantage of `VMGcHeader` alignment and storing aligned indices rather than byte indices, while still leaving the bottom bit available for tagging as an `i31ref` discriminant. Should we ever need to support even larger GC heap capacities, we could go to full 64-bit references, but we would need explicit bounds checks.)
The biggest benefit of indexed heaps is that, because we are (explicitly or implicitly) bounds checking GC heap accesses, and because we are not otherwise trusting any data from inside the GC heap, we greatly reduce how badly things can go wrong in the face of collector bugs and GC heap corruption. We are essentially sandboxing the GC heap region, the same way that linear memory is a sandbox. GC bugs could lead to the guest program accessing the wrong GC object, or getting garbage data from within the GC heap. But only garbage data from within the GC heap, never outside it. The worse that could happen would be if we decided not to zero out GC heaps between reuse across stores (which is a valid trade off to make, since zeroing a GC heap is a defense-in-depth technique similar to zeroing a Wasm stack and not semantically visible in the absence of GC bugs) and then a GC bug would allow the current Wasm guest to read old GC data from the old Wasm guest that previously used this GC heap. But again, it could never access host data.
Taken altogether, this allows for collector implementations that are nearly free from `unsafe` code, and unsafety can otherwise be targeted and limited in scope, such as interactions with JIT code. Most importantly, we do not have to maintain critical invariants across the whole system -- invariants which can't be nicely encapsulated or abstracted -- to preserve memory safety. Such holistic invariants that refuse encapsulation are otherwise generally a huge safety problem with GC implementations.
\### `VMGcRef` is *NOT* `Clone` or `Copy` Anymore
`VMGcRef` used to be `Clone` and `Copy`. It is not anymore. The motivation here was to be sure that I was actually calling GC barriers at all the correct places. I couldn't be sure before. Now, you can still explicitly copy a raw GC reference without running GC barriers if you need to and understand why that's okay (aka you are implementing the collector), but that is something you have to opt into explicitly by calling `unchecked_copy`. The default now is that you can't just copy the reference, and instead call an explicit `clone` method (not *the* `Clone` trait, because we need to pass in the GC heap context to run the GC barriers) and it is hard to forget to do that accidentally. This resulted in a pretty big amount of churn, but I am wayyyyyy more confident that the correct GC barriers are called at the correct times now than I was before.
\### `i31ref`
I started this commit by trying to add `i31ref` support. And it grew into the whole traits interface because I found that I needed to abstract GC barriers into helpers anyways to avoid running them for `i31ref`s, so I figured that I might as well add the whole traits interface. In comparison, `i31ref` support is much easier and smaller than that other part! But it was also difficult to pull apart from this commit, sorry about that!
---------------------
Overall, I know this is a very large commit. I am super happy to have some synchronous meetings to walk through this all, give an overview of the architecture, answer questions directly, etc... to make review easier!
prtest:full
show more ...
|
|
Revision tags: v19.0.1, v19.0.0, v18.0.3 |
|
| #
bd2ea901 |
| 06-Mar-2024 |
Nick Fitzgerald <[email protected]> |
Define garbage collection rooting APIs (#8011)
* Define garbage collection rooting APIs
Rooting prevents GC objects from being collected while they are actively being used.
We have a few sometimes
Define garbage collection rooting APIs (#8011)
* Define garbage collection rooting APIs
Rooting prevents GC objects from being collected while they are actively being used.
We have a few sometimes-conflicting goals with our GC rooting APIs:
1. Safety: It should never be possible to get a use-after-free bug because the user misused the rooting APIs, the collector "mistakenly" determined an object was unreachable and collected it, and then the user tried to access the object. This is our highest priority.
2. Moving GC: Our rooting APIs should moving collectors (such as generational and compacting collectors) where an object might get relocated after a collection and we need to update the GC root's pointer to the moved object. This means we either need cooperation and internal mutability from individual GC roots as well as the ability to enumerate all GC roots on the native Rust stack, or we need a level of indirection.
3. Performance: Our rooting APIs should generally be as low-overhead as possible. They definitely shouldn't require synchronization and locking to create, access, and drop GC roots.
4. Ergonomics: Our rooting APIs should be, if not a pleasure, then at least not a burden for users. Additionally, the API's types should be `Sync` and `Send` so that they work well with async Rust.
For example, goals (3) and (4) are in conflict when we think about how to support (2). Ideally, for ergonomics, a root would automatically unroot itself when dropped. But in the general case that requires holding a reference to the store's root set, and that root set needs to be held simultaneously by all GC roots, and they each need to mutate the set to unroot themselves. That implies `Rc<RefCell<...>>` or `Arc<Mutex<...>>`! The former makes the store and GC root types not `Send` and not `Sync`. The latter imposes synchronization and locking overhead. So we instead make GC roots indirect and require passing in a store context explicitly to unroot in the general case. This trades worse ergonomics for better performance and support for moving GC and async Rust.
Okay, with that out of the way, this module provides two flavors of rooting API. One for the common, scoped lifetime case, and another for the rare case where we really need a GC root with an arbitrary, non-LIFO/non-scoped lifetime:
1. `RootScope` and `Rooted<T>`: These are used for temporarily rooting GC objects for the duration of a scope. Upon exiting the scope, they are automatically unrooted. The internal implementation takes advantage of the LIFO property inherent in scopes, making creating and dropping `Rooted<T>`s and `RootScope`s super fast and roughly equivalent to bump allocation.
This type is vaguely similar to V8's [`HandleScope`].
[`HandleScope`]: https://v8.github.io/api/head/classv8_1_1HandleScope.html
Note that `Rooted<T>` can't be statically tied to its context scope via a lifetime parameter, unfortunately, as that would allow the creation and use of only one `Rooted<T>` at a time, since the `Rooted<T>` would take a borrow of the whole context.
This supports the common use case for rooting and provides good ergonomics.
2. `ManuallyRooted<T>`: This is the fully general rooting API used for holding onto non-LIFO GC roots with arbitrary lifetimes. However, users must manually unroot them. Failure to manually unroot a `ManuallyRooted<T>` before it is dropped will result in the GC object (and everything it transitively references) leaking for the duration of the `Store`'s lifetime.
This type is roughly similar to SpiderMonkey's [`PersistentRooted<T>`], although they avoid the manual-unrooting with internal mutation and shared references. (Our constraints mean we can't do those things, as mentioned explained above.)
[`PersistentRooted<T>`]: http://devdoc.net/web/developer.mozilla.org/en-US/docs/Mozilla/Projects/SpiderMonkey/JSAPI_reference/JS::PersistentRooted.html
At the end of the day, both `Rooted<T>` and `ManuallyRooted<T>` are just tagged indices into the store's `RootSet`. This indirection allows working with Rust's borrowing discipline (we use `&mut Store` to represent mutable access to the GC heap) while still allowing rooted references to be moved around without tying up the whole store in borrows. Additionally, and crucially, this indirection allows us to update the *actual* GC pointers in the `RootSet` and support moving GCs (again, as mentioned above).
* Reorganize GC-related submodules in `wasmtime-runtime`
* Reorganize GC-related submodules in `wasmtime`
* Use `Into<StoreContext[Mut]<'a, T>` for `Externref::data[_mut]` methods
* Run rooting tests under MIRI
* Make `into_abi` take an `AutoAssertNoGc`
* Don't use atomics to update externref ref counts anymore
* Try to make lifetimes/safety more-obviously correct
Remove some transmute methods, assert that `VMExternRef`s are the only valid `VMGcRef`, etc.
* Update extenref constructor examples
* Make `GcRefImpl::transmute_ref` a non-default trait method
* Make inline fast paths for GC LIFO scopes
* Make `RootSet::unroot_gc_ref` an `unsafe` function
* Move Hash and Eq for Rooted, move to impl methods
* Remove type parameter from `AutoAssertNoGc`
Just wrap a `&mut StoreOpaque` directly.
* Make a bunch of internal `ExternRef` methods that deal with raw `VMGcRef`s take `AutoAssertNoGc` instead of `StoreOpaque`
* Fix compile after rebase
* rustfmt
* revert unrelated egraph changes
* Fix non-gc build
* Mark `AutoAssertNoGc` methods inline
* review feedback
* Temporarily remove externref support from the C API
Until we can add proper GC rooting.
* Remove doxygen reference to temp deleted function
* Remove need to `allow(private_interfaces)`
* Fix call benchmark compilation
show more ...
|
|
Revision tags: v18.0.2, v17.0.2 |
|
| #
9ce3ffe1 |
| 22-Feb-2024 |
Alex Crichton <[email protected]> |
Update some CI dependencies (#7983)
* Update some CI dependencies
* Update to the latest nightly toolchain * Update mdbook * Update QEMU for cross-compiled testing * Update `cargo nextest` for usag
Update some CI dependencies (#7983)
* Update some CI dependencies
* Update to the latest nightly toolchain * Update mdbook * Update QEMU for cross-compiled testing * Update `cargo nextest` for usage with MIRI
prtest:full
* Remove lots of unnecessary imports
* Downgrade qemu as 8.2.1 seems to segfault
* Remove more imports
* Remove unused winch trait method
* Fix warnings about unused trait methods
* More unused imports
* More unused imports
show more ...
|
|
Revision tags: v18.0.1 |
|
| #
ff93bce0 |
| 20-Feb-2024 |
Nick Fitzgerald <[email protected]> |
Wasmtime: Finish support for the typed function references proposal (#7943)
* Wasmtime: Finish support for the typed function references proposal
While we supported the function references proposal
Wasmtime: Finish support for the typed function references proposal (#7943)
* Wasmtime: Finish support for the typed function references proposal
While we supported the function references proposal inside Wasm, we didn't support it on the "outside" in the Wasmtime embedder APIs. So much of the work here is exposing typed function references, and their type system updates, in the embedder API. These changes include:
* `ValType::FuncRef` and `ValType::ExternRef` are gone, replaced with the introduction of the `RefType` and `HeapType` types and a `ValType::Ref(RefType)` variant.
* `ValType` and `FuncType` no longer implement `Eq` and `PartialEq`. Instead there are `ValType::matches` and `FuncType::matches` methods which check directional subtyping. I also added `ValType::eq` and `FuncType::eq` static methods for the rare case where someone needs to check precise equality, but that is almost never actually the case, 99.99% of the time you want to check subtyping.
* There are also public `Val::matches_ty` predicates for checking if a value is an instance of a type, as well as internal helpers like `Val::ensure_matches_ty` that return a formatted error if the value does not match the given type. These helpers are used throughout Wasmtime internals now.
* There is now a dedicated `wasmtime::Ref` type that represents reference values. Table operations have been updated to take and return `Ref`s rather than `Val`s.
Furthermore, this commit also includes type registry changes to correctly manage lifetimes of types that reference other types. This wasn't previously an issue because the only thing that could reference types that reference other types was a Wasm module that added all the types that could reference each other at the same time and removed them all at the same time. But now that the previously discussed work to expose these things in the embedder API is done, type lifetime management in the registry becomes a little trickier because the embedder might grab a reference to a type that references another type, and then unload the Wasm module that originally defined that type, but then the user should still be able use that type and the other types it transtively references. Before, we were refcounting individual registry entries. Now, we still are refcounting individual entries, but now we are also accounting for type-to-type references and adding a new type to the registry will increment the refcounts of each of the types that it references, and removing a type from the registry will decrement the refcounts of each of the types it references, and then recursively (logically, not literally) remove any types whose refcount has now reached zero.
Additionally, this PR adds support for subtyping to `Func::typed`- and `Func::wrap`-style APIs. For result types, you can always use a supertype of the WebAssembly function's actual declared return type in `Func::typed`. And for param types, you can always use a subtype of the Wasm function's actual declared param type. Doing these things essentially erases information but is always correct. But additionally, for functions which take a reference to a concrete type as a parameter, you can also use the concrete type's supertype. Consider a WebAssembly function that takes a reference to a function with a concrete type: `(ref null <func type index>)`. In this scenario, there is no static `wasmtime::Foo` Rust type that corresponds to that particular Wasm-defined concrete reference type because Wasm modules are loaded dynamically at runtime. You *could* do `f.typed::<Option<NoFunc>, ()>()`, and while that is correctly typed and valid, it is often overly restrictive. The only value you could call the resulting typed function with is the null function reference, but we'd like to call it with non-null function references that happen to be of the correct type. Therefore, `f.typed<Option<Func>, ()>()` is also allowed in this case, even though `Option<Func>` represents `(ref null func)` which is the supertype, not subtype, of `(ref null <func type index>)`. This does imply some minimal dynamic type checks in this case, but it is supported for better ergonomics, to enable passing non-null references into the function.
We can investigate whether it is possible to use generic type parameters and combinators to define Rust types that precisely match concrete reference types in future, follow-up pull requests. But for now, we've made things usable, at least.
Finally, this also takes the first baby step towards adding support for the Wasm GC proposal. Right now the only thing that is supported is `nofunc` references, and this was mainly to make testing function reference subtyping easier. But that does mean that supporting `nofunc` references entailed also adding a `wasmtime::NoFunc` type as well as the `Config::wasm_gc(enabled)` knob. So we officially have an in-progress implementation of Wasm GC in Wasmtime after this PR lands!
Fixes https://github.com/bytecodealliance/wasmtime/issues/6455
* Fix WAT in test to be valid
* Check that dependent features are enabled for function-references and GC
* Remove unnecessary engine parameters from a few methods
Ever since `FuncType`'s internal `RegisteredType` holds onto its own `Engine`, we don't need these anymore.
Still useful to keep the `Engine` parameter around for the `ensure_matches` methods because that can be used to check correct store/engine usage for embedders.
* Add missing dependent feature enabling for some tests
* Remove copy-paste bit from test
* match self to show it is uninhabited
* Add a missing `is_v128` method
* Short circuit a few func type comparisons
* Turn comment into part of doc comment
* Add test for `Global::new` and subtyping
* Add tests for embedder API, tables, and subtyping
* Add an embedder API test for setting globals and subtyping
* Construct realloc's type from its index, rather than from scratch
* Help LLVM better optimize our dynamic type checks in `TypedFunc::call_raw`
* Fix call benchmark compilation
* Change `WasmParams::into_abi` to take the whole func type instead of iter of params
* Fix doc links
prtest:full
* Fix size assertion on s390x
show more ...
|
|
Revision tags: v18.0.0 |
|
| #
2aaeddbd |
| 15-Feb-2024 |
Andrew Brown <[email protected]> |
mpk: restore PKRU state when a fiber resumes execution (#7789)
* mpk: restore PKRU state when a fiber resumes execution
Previously, when a fiber was suspended, other computation could change the PK
mpk: restore PKRU state when a fiber resumes execution (#7789)
* mpk: restore PKRU state when a fiber resumes execution
Previously, when a fiber was suspended, other computation could change the PKRU state on the current CPU. This means that the fiber could be resumed with a different PKRU state. This could be bad, resulting in situations in which the fiber can access more memory slots than it should or cannot even access its own memory slots.
This change saves the PKRU state prior to a fiber being suspended. When the fiber resumes execution, that PKRU state is restored.
* mpk: check correct PKRU switching on async suspension
This adds a test that alternately polls two Wasm instances in a loop. Since the instances are async, we can set up epochs to suspend each fiber as we iterate over a loop. Because we alternate between the two instances, it checks that `AsyncCx::block_on` has correctly restored the PKRU bits; otherwise we should see test failures. In the process of writing this test I discovered #7942, which can be solved separately (it has to do with the interaction between memory images, _not_ used here, and MPK).
prtest:full
* fix: condition the PKRU context switches
Not all stores have protection keys and MPK is not always enabled. This change checks for these conditions before context-switching the PKRU bits.
show more ...
|
| #
8652011f |
| 09-Feb-2024 |
Nick Fitzgerald <[email protected]> |
Refactor `wasmtime::FuncType` to hold a handle to its registered type (#7892)
* Refactor `wasmtime::FuncType` to hold a handle to its registered type
Rather than holding a copy of the type directly
Refactor `wasmtime::FuncType` to hold a handle to its registered type (#7892)
* Refactor `wasmtime::FuncType` to hold a handle to its registered type
Rather than holding a copy of the type directly, it now holds a `RegisteredType` which internally is
* A `VMSharedTypeIndex` pointing into the engine's types registry. * An `Arc` handle to the engine's type registry. * An `Arc` handle to the actual type.
The last exists only to keep it so that accessing a `wasmtime::FuncType`'s parameters and results fast, avoiding any new locking on call hot paths.
This is helping set the stage for further types and `TypeRegistry` refactors needed for Wasm GC.
* Update the C API for the function types refactor
prtest:full
* rustfmt
* Fix benches build
show more ...
|
|
Revision tags: v17.0.1, v17.0.0, v16.0.0, v15.0.1, v15.0.0, v14.0.4, v14.0.3, v14.0.2, v13.0.1 |
|
| #
85c0a2df |
| 23-Oct-2023 |
Tyler Rockwood <[email protected]> |
Switch to simpler fuel APIs (#7298)
In an effort to simplify the many fuel related APIs, simplify the interface here to a single counter with get and set methods. Additionally the async yield is red
Switch to simpler fuel APIs (#7298)
In an effort to simplify the many fuel related APIs, simplify the interface here to a single counter with get and set methods. Additionally the async yield is reduced to an interval of the total fuel instead of injecting fuel, so it's easy to still reason about how much fuel is left even with yielding turned on.
Internally this works by keeping two counters - one the VM uses to increment towards 0 for fuel, the other to track how much is in "reserve". Then when we're out of gas, we pull from the reserve to refuel and continue. We use the reserve in two cases: one for overflow of the fuel (which is an i64 and the API expresses fuel as u64) and the other for async yieling, which then the yield interval acts as a cap to how much we can refuel with.
This also means that `get_fuel` can return the full range of `u64` before this change it could only return up to `i64::MAX`. This is important because this PR is removing the functionality to track fuel consumption, and this makes the API less error prone for embedders to track consumption themselves.
Careful to note that the VM counter that is stored as `i64` can be positive if an instruction "costs" multiple units of fuel when the fuel ran out.
prtest:full
Signed-off-by: Tyler Rockwood <[email protected]>
show more ...
|
|
Revision tags: v14.0.1, v14.0.0, minimum-viable-wasi-proxy-serve, v13.0.0, v12.0.2, v11.0.2, v10.0.2, v12.0.1, v12.0.0 |
|
| #
a34427a3 |
| 18-Aug-2023 |
Nick Fitzgerald <[email protected]> |
Wasmtime: refactor the pooling allocator for components (#6835)
* Wasmtime: Rename `IndexAllocator` to `ModuleAffinityIndexAllocator`
We will have multiple kinds of index allocators soon, so clarif
Wasmtime: refactor the pooling allocator for components (#6835)
* Wasmtime: Rename `IndexAllocator` to `ModuleAffinityIndexAllocator`
We will have multiple kinds of index allocators soon, so clarify which one this is.
* Wasmtime: Introduce a simple index allocator
This will be used in future commits refactoring the pooling allocator.
* Wasmtime: refactor the pooling allocator for components
We used to have one index allocator, an index per instance, and give out N tables and M memories to every instance regardless how many tables and memories they need.
Now we have an index allocator for memories and another for tables. An instance isn't associated with a single instance, each of its memories and tables have an index. We allocate exactly as many tables and memories as the instance actually needs.
Ultimately, this gives us better component support, where a component instance might have varying numbers of internal tables and memories.
Additionally, you can now limit the number of tables, memories, and core instances a single component can allocate from the pooling allocator, even if there is the capacity for that many available. This is to give embedders tools to limit individual component instances and prevent them from hogging too much of the pooling allocator's resources.
* Remove unused file
Messed up from rebasing, this code is actually just inline in the index allocator module.
* Address review feedback
* Fix benchmarks build
* Fix ignoring test under miri
The `async_functions` module is not even compiled-but-ignored with miri, it is completely `cfg`ed off. Therefore we ahve to do the same with this test that imports stuff from that module.
* Fix doc links
* Allow testing utilities to be unused
The exact `cfg`s that unlock the tests that use these are platform and feature dependent and ends up being like 5 things and super long. Simpler to just allow unused for when we are testing on other platforms or don't have the compile time features enabled.
* Debug assert that the pool is empty on drop, per Alex's suggestion
Also fix a couple scenarios where we could leak indices if allocating an index for a memory/table succeeded but then creating the memory/table itself failed.
* Fix windows compile errors
show more ...
|
|
Revision tags: v11.0.1, v11.0.0, v10.0.1, v10.0.0, v9.0.4 |
|
| #
550a16f5 |
| 02-Jun-2023 |
Alex Crichton <[email protected]> |
Fix a soundness issue with the component model and async (#6509)
* Force `execute_across_threads` to use multiple threads
Currently this uses tokio's `spawn_blocking` but that will reuse threads in
Fix a soundness issue with the component model and async (#6509)
* Force `execute_across_threads` to use multiple threads
Currently this uses tokio's `spawn_blocking` but that will reuse threads in its thread pool. Instead spawn a thread and perform a single poll on that thread to force lots of fresh threads to be used and ideally stress TLS management further.
* Add a guard against using stale stacks
This commit adds a guard to Wasmtime's async support to double-check that when a call to `poll` is finished that the currently active TLS activation pointer does not point to the stack that is being switched off of. This is attempting to be a bit of a defense-in-depth measure to prevent stale pointers from sticking around in TLS. This is currently happening and causing #6493 which can result in unsoundness but currently is manifesting as a crash.
* Fix a soundness issue with the component model and async
This commit addresses #6493 by fixing a soundness issue with the async implementation of the component model. This issue has been presence since the inception of the addition of async support to the component model and doesn't represent a recent regression. The underlying problem is that one of the base assumptions of the trap handling code is that there's only one single activation in TLS that needs to be pushed/popped when a stack is switched (e.g. a fiber is switched to or from). In the case of the component model there might be two activations: one for an invocation of a component function and then a second for an invocation of a `realloc` function to return results back to wasm (e.g. in the case an imported function returns a list).
This problem is fixed by changing how TLS is managed in the presence of fibers. Previously when a fiber was suspended it would pop a single activation from the top of the stack and save that to get pushed when the fiber was resumed. This has the benefit of maintaining an entire linked list of activations for the current thread but has the problem above where it doesn't handle a fiber with multiple activations on it. Instead now TLS management is done when a fiber is resumed instead of suspended. Instead of pushing/popping a single activation the entire linked list of activations is tracked for a particular fiber and stored within the fiber itself. In this manner resuming a fiber will push all activations onto the current thread and suspending a fiber will pop all activations for the fiber (and store them as a new linked list in the fiber's state itself).
This end result is that all activations on a fiber should now be managed correctly, regardless of how many there are. The main downside of this commit is that fiber suspension and resumption is more complicated, but the hope there is that fiber suspension typically corresponds with I/O not being ready or similar so the order of magnitude of TLS operations isn't too significant compared to the I/O overhead.
Closes #6493
* Review comments
* Fix restoration during panic
show more ...
|
| #
eb472401 |
| 01-Jun-2023 |
Alex Crichton <[email protected]> |
Fix `execute_across_threads` in tests (#6494)
This commit fixes the helper function `execute_across_threads` in tests to actually execute across threads. This function was refactored in #3975 and ac
Fix `execute_across_threads` in tests (#6494)
This commit fixes the helper function `execute_across_threads` in tests to actually execute across threads. This function was refactored in #3975 and accidentally introduced a bug where the future provided was polled once and then dropped, cancelling it instead of executing it to completion.
show more ...
|
|
Revision tags: v9.0.3, v9.0.2, v9.0.1, v9.0.0 |
|
| #
7f0228c9 |
| 16-May-2023 |
Alex Crichton <[email protected]> |
Fix some warnings on nightly Rust (#6388)
Upstream rust has decided that ignoring a value is not spelled `drop(foo)` but instead it's spelled `let _ = foo`
|