You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

62 lines
2.0 KiB

//! Small example of how to use `externref`s.
// You can execute this example with `cargo run --example externref`
use wasmtime::*;
fn main() -> Result<()> {
println!("Initializing...");
let mut config = Config::new();
config.wasm_reference_types(true);
Implement shared host functions. (#2625) * Implement defining host functions at the Config level. This commit introduces defining host functions at the `Config` rather than with `Func` tied to a `Store`. The intention here is to enable a host to define all of the functions once with a `Config` and then use a `Linker` (or directly with `Store::get_host_func`) to use the functions when instantiating a module. This should help improve the performance of use cases where a `Store` is short-lived and redefining the functions at every module instantiation is a noticeable performance hit. This commit adds `add_to_config` to the code generation for Wasmtime&#39;s `Wasi` type. The new method adds the WASI functions to the given config as host functions. This commit adds context functions to `Store`: `get` to get a context of a particular type and `set` to set the context on the store. For safety, `set` cannot replace an existing context value of the same type. `Wasi::set_context` was added to set the WASI context for a `Store` when using `Wasi::add_to_config`. * Add `Config::define_host_func_async`. * Make config &#34;async&#34; rather than store. This commit moves the concept of &#34;async-ness&#34; to `Config` rather than `Store`. Note: this is a breaking API change for anyone that&#39;s already adopted the new async support in Wasmtime. Now `Config::new_async` is used to create an &#34;async&#34; config and any `Store` associated with that config is inherently &#34;async&#34;. This is needed for async shared host functions to have some sanity check during their execution (async host functions, like &#34;async&#34; `Func`, need to be called with the &#34;async&#34; variants). * Update async function tests to smoke async shared host functions. This commit updates the async function tests to also smoke the shared host functions, plus `Func::wrap0_async`. This also changes the &#34;wrap async&#34; method names on `Config` to `wrap$N_host_func_async` to slightly better match what is on `Func`. * Move the instance allocator into `Engine`. This commit moves the instantiated instance allocator from `Config` into `Engine`. This makes certain settings in `Config` no longer order-dependent, which is how `Config` should ideally be. This also removes the confusing concept of the &#34;default&#34; instance allocator, instead opting to construct the on-demand instance allocator when needed. This does alter the semantics of the instance allocator as now each `Engine` gets its own instance allocator rather than sharing a single one between all engines created from a configuration. * Make `Engine::new` return `Result`. This is a breaking API change for anyone using `Engine::new`. As creating the pooling instance allocator may fail (likely cause is not enough memory for the provided limits), instead of panicking when creating an `Engine`, `Engine::new` now returns a `Result`. * Remove `Config::new_async`. This commit removes `Config::new_async` in favor of treating &#34;async support&#34; as any other setting on `Config`. The setting is `Config::async_support`. * Remove order dependency when defining async host functions in `Config`. This commit removes the order dependency where async support must be enabled on the `Config` prior to defining async host functions. The check is now delayed to when an `Engine` is created from the config. * Update WASI example to use shared `Wasi::add_to_config`. This commit updates the WASI example to use `Wasi::add_to_config`. As only a single store and instance are used in the example, it has no semantic difference from the previous example, but the intention is to steer users towards defining WASI on the config and only using `Wasi::add_to_linker` when more explicit scoping of the WASI context is required.
4 years ago
let engine = Engine::new(&config)?;
let mut store = Store::new(&engine, ());
println!("Compiling module...");
let module = Module::from_file(&engine, "examples/externref.wat")?;
println!("Instantiating module...");
let instance = Instance::new(&mut store, &module, &[])?;
println!("Creating new `externref`...");
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 &#34;mistakenly&#34; 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&#39;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&#39;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&#39;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&#39;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&lt;RefCell&lt;...&gt;&gt;` or `Arc&lt;Mutex&lt;...&gt;&gt;`! 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&lt;T&gt;`: 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&lt;T&gt;`s and `RootScope`s super fast and roughly equivalent to bump allocation. This type is vaguely similar to V8&#39;s [`HandleScope`]. [`HandleScope`]: https://v8.github.io/api/head/classv8_1_1HandleScope.html Note that `Rooted&lt;T&gt;` can&#39;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&lt;T&gt;` at a time, since the `Rooted&lt;T&gt;` would take a borrow of the whole context. This supports the common use case for rooting and provides good ergonomics. 2. `ManuallyRooted&lt;T&gt;`: 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&lt;T&gt;` before it is dropped will result in the GC object (and everything it transitively references) leaking for the duration of the `Store`&#39;s lifetime. This type is roughly similar to SpiderMonkey&#39;s [`PersistentRooted&lt;T&gt;`], although they avoid the manual-unrooting with internal mutation and shared references. (Our constraints mean we can&#39;t do those things, as mentioned explained above.) [`PersistentRooted&lt;T&gt;`]: 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&lt;T&gt;` and `ManuallyRooted&lt;T&gt;` are just tagged indices into the store&#39;s `RootSet`. This indirection allows working with Rust&#39;s borrowing discipline (we use `&amp;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&lt;StoreContext[Mut]&lt;&#39;a, T&gt;` for `Externref::data[_mut]` methods * Run rooting tests under MIRI * Make `into_abi` take an `AutoAssertNoGc` * Don&#39;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 `&amp;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
8 months ago
let externref = ExternRef::new(&mut store, "Hello, World!");
assert!(externref.data(&store)?.is::<&'static str>());
assert_eq!(
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 &#34;mistakenly&#34; 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&#39;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&#39;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&#39;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&#39;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&lt;RefCell&lt;...&gt;&gt;` or `Arc&lt;Mutex&lt;...&gt;&gt;`! 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&lt;T&gt;`: 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&lt;T&gt;`s and `RootScope`s super fast and roughly equivalent to bump allocation. This type is vaguely similar to V8&#39;s [`HandleScope`]. [`HandleScope`]: https://v8.github.io/api/head/classv8_1_1HandleScope.html Note that `Rooted&lt;T&gt;` can&#39;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&lt;T&gt;` at a time, since the `Rooted&lt;T&gt;` would take a borrow of the whole context. This supports the common use case for rooting and provides good ergonomics. 2. `ManuallyRooted&lt;T&gt;`: 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&lt;T&gt;` before it is dropped will result in the GC object (and everything it transitively references) leaking for the duration of the `Store`&#39;s lifetime. This type is roughly similar to SpiderMonkey&#39;s [`PersistentRooted&lt;T&gt;`], although they avoid the manual-unrooting with internal mutation and shared references. (Our constraints mean we can&#39;t do those things, as mentioned explained above.) [`PersistentRooted&lt;T&gt;`]: 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&lt;T&gt;` and `ManuallyRooted&lt;T&gt;` are just tagged indices into the store&#39;s `RootSet`. This indirection allows working with Rust&#39;s borrowing discipline (we use `&amp;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&lt;StoreContext[Mut]&lt;&#39;a, T&gt;` for `Externref::data[_mut]` methods * Run rooting tests under MIRI * Make `into_abi` take an `AutoAssertNoGc` * Don&#39;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 `&amp;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
8 months ago
*externref
.data(&store)?
.downcast_ref::<&'static str>()
.unwrap(),
"Hello, World!"
);
println!("Touching `externref` table...");
let table = instance.get_table(&mut store, "table").unwrap();
table.set(&mut store, 3, Some(externref.clone()).into())?;
let elem = table
.get(&mut store, 3)
.unwrap() // assert in bounds
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&#39;t support it on the &#34;outside&#34; 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&#39;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&#39;s actual declared return type in `Func::typed`. And for param types, you can always use a subtype of the Wasm function&#39;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&#39;s supertype. Consider a WebAssembly function that takes a reference to a function with a concrete type: `(ref null &lt;func type index&gt;)`. 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::&lt;Option&lt;NoFunc&gt;, ()&gt;()`, 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&#39;d like to call it with non-null function references that happen to be of the correct type. Therefore, `f.typed&lt;Option&lt;Func&gt;, ()&gt;()` is also allowed in this case, even though `Option&lt;Func&gt;` represents `(ref null func)` which is the supertype, not subtype, of `(ref null &lt;func type index&gt;)`. 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&#39;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`&#39;s internal `RegisteredType` holds onto its own `Engine`, we don&#39;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&#39;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
9 months ago
.unwrap_extern() // assert it's an externref table
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 &#34;mistakenly&#34; 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&#39;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&#39;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&#39;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&#39;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&lt;RefCell&lt;...&gt;&gt;` or `Arc&lt;Mutex&lt;...&gt;&gt;`! 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&lt;T&gt;`: 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&lt;T&gt;`s and `RootScope`s super fast and roughly equivalent to bump allocation. This type is vaguely similar to V8&#39;s [`HandleScope`]. [`HandleScope`]: https://v8.github.io/api/head/classv8_1_1HandleScope.html Note that `Rooted&lt;T&gt;` can&#39;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&lt;T&gt;` at a time, since the `Rooted&lt;T&gt;` would take a borrow of the whole context. This supports the common use case for rooting and provides good ergonomics. 2. `ManuallyRooted&lt;T&gt;`: 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&lt;T&gt;` before it is dropped will result in the GC object (and everything it transitively references) leaking for the duration of the `Store`&#39;s lifetime. This type is roughly similar to SpiderMonkey&#39;s [`PersistentRooted&lt;T&gt;`], although they avoid the manual-unrooting with internal mutation and shared references. (Our constraints mean we can&#39;t do those things, as mentioned explained above.) [`PersistentRooted&lt;T&gt;`]: 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&lt;T&gt;` and `ManuallyRooted&lt;T&gt;` are just tagged indices into the store&#39;s `RootSet`. This indirection allows working with Rust&#39;s borrowing discipline (we use `&amp;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&lt;StoreContext[Mut]&lt;&#39;a, T&gt;` for `Externref::data[_mut]` methods * Run rooting tests under MIRI * Make `into_abi` take an `AutoAssertNoGc` * Don&#39;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 `&amp;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
8 months ago
.copied()
.unwrap(); // assert the externref isn't null
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 &#34;mistakenly&#34; 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&#39;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&#39;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&#39;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&#39;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&lt;RefCell&lt;...&gt;&gt;` or `Arc&lt;Mutex&lt;...&gt;&gt;`! 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&lt;T&gt;`: 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&lt;T&gt;`s and `RootScope`s super fast and roughly equivalent to bump allocation. This type is vaguely similar to V8&#39;s [`HandleScope`]. [`HandleScope`]: https://v8.github.io/api/head/classv8_1_1HandleScope.html Note that `Rooted&lt;T&gt;` can&#39;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&lt;T&gt;` at a time, since the `Rooted&lt;T&gt;` would take a borrow of the whole context. This supports the common use case for rooting and provides good ergonomics. 2. `ManuallyRooted&lt;T&gt;`: 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&lt;T&gt;` before it is dropped will result in the GC object (and everything it transitively references) leaking for the duration of the `Store`&#39;s lifetime. This type is roughly similar to SpiderMonkey&#39;s [`PersistentRooted&lt;T&gt;`], although they avoid the manual-unrooting with internal mutation and shared references. (Our constraints mean we can&#39;t do those things, as mentioned explained above.) [`PersistentRooted&lt;T&gt;`]: 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&lt;T&gt;` and `ManuallyRooted&lt;T&gt;` are just tagged indices into the store&#39;s `RootSet`. This indirection allows working with Rust&#39;s borrowing discipline (we use `&amp;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&lt;StoreContext[Mut]&lt;&#39;a, T&gt;` for `Externref::data[_mut]` methods * Run rooting tests under MIRI * Make `into_abi` take an `AutoAssertNoGc` * Don&#39;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 `&amp;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
8 months ago
assert!(Rooted::ref_eq(&store, &elem, &externref)?);
println!("Touching `externref` global...");
let global = instance.get_global(&mut store, "global").unwrap();
global.set(&mut store, Some(externref.clone()).into())?;
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 &#34;mistakenly&#34; 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&#39;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&#39;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&#39;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&#39;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&lt;RefCell&lt;...&gt;&gt;` or `Arc&lt;Mutex&lt;...&gt;&gt;`! 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&lt;T&gt;`: 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&lt;T&gt;`s and `RootScope`s super fast and roughly equivalent to bump allocation. This type is vaguely similar to V8&#39;s [`HandleScope`]. [`HandleScope`]: https://v8.github.io/api/head/classv8_1_1HandleScope.html Note that `Rooted&lt;T&gt;` can&#39;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&lt;T&gt;` at a time, since the `Rooted&lt;T&gt;` would take a borrow of the whole context. This supports the common use case for rooting and provides good ergonomics. 2. `ManuallyRooted&lt;T&gt;`: 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&lt;T&gt;` before it is dropped will result in the GC object (and everything it transitively references) leaking for the duration of the `Store`&#39;s lifetime. This type is roughly similar to SpiderMonkey&#39;s [`PersistentRooted&lt;T&gt;`], although they avoid the manual-unrooting with internal mutation and shared references. (Our constraints mean we can&#39;t do those things, as mentioned explained above.) [`PersistentRooted&lt;T&gt;`]: 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&lt;T&gt;` and `ManuallyRooted&lt;T&gt;` are just tagged indices into the store&#39;s `RootSet`. This indirection allows working with Rust&#39;s borrowing discipline (we use `&amp;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&lt;StoreContext[Mut]&lt;&#39;a, T&gt;` for `Externref::data[_mut]` methods * Run rooting tests under MIRI * Make `into_abi` take an `AutoAssertNoGc` * Don&#39;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 `&amp;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
8 months ago
let global_val = global.get(&mut store).unwrap_externref().copied().unwrap();
assert!(Rooted::ref_eq(&store, &global_val, &externref)?);
println!("Calling `externref` func...");
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 &#34;mistakenly&#34; 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&#39;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&#39;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&#39;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&#39;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&lt;RefCell&lt;...&gt;&gt;` or `Arc&lt;Mutex&lt;...&gt;&gt;`! 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&lt;T&gt;`: 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&lt;T&gt;`s and `RootScope`s super fast and roughly equivalent to bump allocation. This type is vaguely similar to V8&#39;s [`HandleScope`]. [`HandleScope`]: https://v8.github.io/api/head/classv8_1_1HandleScope.html Note that `Rooted&lt;T&gt;` can&#39;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&lt;T&gt;` at a time, since the `Rooted&lt;T&gt;` would take a borrow of the whole context. This supports the common use case for rooting and provides good ergonomics. 2. `ManuallyRooted&lt;T&gt;`: 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&lt;T&gt;` before it is dropped will result in the GC object (and everything it transitively references) leaking for the duration of the `Store`&#39;s lifetime. This type is roughly similar to SpiderMonkey&#39;s [`PersistentRooted&lt;T&gt;`], although they avoid the manual-unrooting with internal mutation and shared references. (Our constraints mean we can&#39;t do those things, as mentioned explained above.) [`PersistentRooted&lt;T&gt;`]: 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&lt;T&gt;` and `ManuallyRooted&lt;T&gt;` are just tagged indices into the store&#39;s `RootSet`. This indirection allows working with Rust&#39;s borrowing discipline (we use `&amp;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&lt;StoreContext[Mut]&lt;&#39;a, T&gt;` for `Externref::data[_mut]` methods * Run rooting tests under MIRI * Make `into_abi` take an `AutoAssertNoGc` * Don&#39;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 `&amp;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
8 months ago
let func = instance.get_typed_func::<Option<Rooted<ExternRef>>, Option<Rooted<ExternRef>>>(
&mut store, "func",
)?;
let ret = func.call(&mut store, Some(externref))?;
assert!(ret.is_some());
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 &#34;mistakenly&#34; 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&#39;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&#39;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&#39;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&#39;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&lt;RefCell&lt;...&gt;&gt;` or `Arc&lt;Mutex&lt;...&gt;&gt;`! 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&lt;T&gt;`: 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&lt;T&gt;`s and `RootScope`s super fast and roughly equivalent to bump allocation. This type is vaguely similar to V8&#39;s [`HandleScope`]. [`HandleScope`]: https://v8.github.io/api/head/classv8_1_1HandleScope.html Note that `Rooted&lt;T&gt;` can&#39;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&lt;T&gt;` at a time, since the `Rooted&lt;T&gt;` would take a borrow of the whole context. This supports the common use case for rooting and provides good ergonomics. 2. `ManuallyRooted&lt;T&gt;`: 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&lt;T&gt;` before it is dropped will result in the GC object (and everything it transitively references) leaking for the duration of the `Store`&#39;s lifetime. This type is roughly similar to SpiderMonkey&#39;s [`PersistentRooted&lt;T&gt;`], although they avoid the manual-unrooting with internal mutation and shared references. (Our constraints mean we can&#39;t do those things, as mentioned explained above.) [`PersistentRooted&lt;T&gt;`]: 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&lt;T&gt;` and `ManuallyRooted&lt;T&gt;` are just tagged indices into the store&#39;s `RootSet`. This indirection allows working with Rust&#39;s borrowing discipline (we use `&amp;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&lt;StoreContext[Mut]&lt;&#39;a, T&gt;` for `Externref::data[_mut]` methods * Run rooting tests under MIRI * Make `into_abi` take an `AutoAssertNoGc` * Don&#39;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 `&amp;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
8 months ago
assert!(Rooted::ref_eq(&store, &ret.unwrap(), &externref)?);
println!("GCing within the store...");
store.gc();
println!("Done.");
Ok(())
}