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.

85 lines
2.9 KiB

//! An example of how to interact with wasm memory.
//!
//! Here a small wasm module is used to show how memory is initialized, how to
//! read and write memory through the `Memory` object, and how wasm functions
//! can trap when dealing with out-of-bounds addresses.
// You can execute this example with `cargo run --example example`
use anyhow::Result;
use wasmtime::*;
fn main() -> Result<()> {
// Create our `Store` context and then compile a module and create an
// instance from the compiled module all in one go.
let wasmtime_store = Store::default();
let module = Module::from_file(wasmtime_store.engine(), "examples/memory.wat")?;
let instance = Instance::new(&wasmtime_store, &module, &[])?;
// Load up our exports from the instance
let memory = instance
Refactor (#1524) * Compute instance exports on demand. Instead having instances eagerly compute a Vec of Externs, and bumping the refcount for each Extern, compute Externs on demand. This also enables `Instance::get_export` to avoid doing a linear search. This also means that the closure returned by `get0` and friends now holds an `InstanceHandle` to dynamically hold the instance live rather than being scoped to a lifetime. * Compute module imports and exports on demand too. And compute Extern::ty on demand too. * Add a utility function for computing an ExternType. * Add a utility function for looking up a function&#39;s signature. * Add a utility function for computing the ValType of a Global. * Rename wasmtime_environ::Export to EntityIndex. This helps differentiate it from other Export types in the tree, and describes what it is. * Fix a typo in a comment. * Simplify module imports and exports. * Make `Instance::exports` return the export names. This significantly simplifies the public API, as it&#39;s relatively common to need the names, and this avoids the need to do a zip with `Module::exports`. This also changes `ImportType` and `ExportType` to have public members instead of private members and accessors, as I find that simplifies the usage particularly in cases where there are temporary instances. * Remove `Instance::module`. This doesn&#39;t quite remove `Instance`&#39;s `module` member, it gets a step closer. * Use a InstanceHandle utility function. * Don&#39;t consume self in the `Func::get*` methods. Instead, just create a closure containing the instance handle and the export for them to call. * Use `ExactSizeIterator` to avoid needing separate `num_*` methods. * Rename `Extern::func()` etc. to `into_func()` etc. * Revise examples to avoid using `nth`. * Add convenience methods to instance for getting specific extern types. * Use the convenience functions in more tests and examples. * Avoid cloning strings for `ImportType` and `ExportType`. * Remove more obviated clone() calls. * Simplify `Func`&#39;s closure state. * Make wasmtime::Export&#39;s fields private. This makes them more consistent with ExportType. * Fix compilation error. * Make a lifetime parameter explicit, and use better lifetime names. Instead of &#39;me, use &#39;instance and &#39;module to make it clear what the lifetime is. * More lifetime cleanups.
5 years ago
.get_memory("memory")
.ok_or(anyhow::format_err!("failed to find `memory` export"))?;
Redo the statically typed `Func` API (#2719) * Redo the statically typed `Func` API This commit reimplements the `Func` API with respect to statically typed dispatch. Previously `Func` had a `getN` and `getN_async` family of methods which were implemented for 0 to 16 parameters. The return value of these functions was an `impl Fn(..)` closure with the appropriate parameters and return values. There are a number of downsides with this approach that have become apparent over time: * The addition of `*_async` doubled the API surface area (which is quite large here due to one-method-per-number-of-parameters). * The [documentation of `Func`][old-docs] are quite verbose and feel &#34;polluted&#34; with all these getters, making it harder to understand the other methods that can be used to interact with a `Func`. * These methods unconditionally pay the cost of returning an owned `impl Fn` with a `&#39;static` lifetime. While cheap, this is still paying the cost for cloning the `Store` effectively and moving data into the closed-over environment. * Storage of the return value into a struct, for example, always requires `Box`-ing the returned closure since it otherwise cannot be named. * Recently I had the desire to implement an &#34;unchecked&#34; path for invoking wasm where you unsafely assert the type signature of a wasm function. Doing this with today&#39;s scheme would require doubling (again) the API surface area for both async and synchronous calls, further polluting the documentation. The main benefit of the previous scheme is that by returning a `impl Fn` it was quite easy and ergonomic to actually invoke the function. In practice, though, examples would often have something akin to `.get0::&lt;()&gt;()?()?` which is a lot of things to interpret all at once. Note that `get0` means &#34;0 parameters&#34; yet a type parameter is passed. There&#39;s also a double function invocation which looks like a lot of characters all lined up in a row. Overall, I think that the previous design is starting to show too many cracks and deserves a rewrite. This commit is that rewrite. The new design in this commit is to delete the `getN{,_async}` family of functions and instead have a new API: impl Func { fn typed&lt;P, R&gt;(&amp;self) -&gt; Result&lt;&amp;Typed&lt;P, R&gt;&gt;; } impl Typed&lt;P, R&gt; { fn call(&amp;self, params: P) -&gt; Result&lt;R, Trap&gt;; async fn call_async(&amp;self, params: P) -&gt; Result&lt;R, Trap&gt;; } This should entirely replace the current scheme, albeit by slightly losing ergonomics use cases. The idea behind the API is that the existence of `Typed&lt;P, R&gt;` is a &#34;proof&#34; that the underlying function takes `P` and returns `R`. The `Func::typed` method peforms a runtime type-check to ensure that types all match up, and if successful you get a `Typed` value. Otherwise an error is returned. Once you have a `Typed` then, like `Func`, you can either `call` or `call_async`. The difference with a `Typed`, however, is that the params/results are statically known and hence these calls can be much more efficient. This is a much smaller API surface area from before and should greatly simplify the `Func` documentation. There&#39;s still a problem where `Func::wrapN_async` produces a lot of functions to document, but that&#39;s now the sole offender. It&#39;s a nice benefit that the statically-typed-async verisons are now expressed with an `async` function rather than a function-returning-a-future which makes it both more efficient and easier to understand. The type `P` and `R` are intended to either be bare types (e.g. `i32`) or tuples of any length (including 0). At this time `R` is only allowed to be `()` or a bare `i32`-style type because multi-value is not supported with a native ABI (yet). The `P`, however, can be any size of tuples of parameters. This is also where some ergonomics are lost because instead of `f(1, 2)` you now have to write `f.call((1, 2))` (note the double-parens). Similarly `f()` becomes `f.call(())`. Overall I feel that this is a better tradeoff than before. While not universally better due to the loss in ergonomics I feel that this design is much more flexible in terms of what you can do with the return value and also understanding the API surface area (just less to take in). [old-docs]: https://docs.rs/wasmtime/0.24.0/wasmtime/struct.Func.html#method.get0 * Rename Typed to TypedFunc * Implement multi-value returns through `Func::typed` * Fix examples in docs * Fix some more errors * More test fixes * Rebasing and adding `get_typed_func` * Updating tests * Fix typo * More doc tweaks * Tweak visibility on `Func::invoke` * Fix tests again
4 years ago
let size = instance.get_typed_func::<(), i32>("size")?;
let load = instance.get_typed_func::<i32, i32>("load")?;
let store = instance.get_typed_func::<(i32, i32), ()>("store")?;
// Note that these memory reads are *unsafe* due to unknown knowledge about
// aliasing with wasm memory. For more information about the safety
// guarantees here and how to use `Memory` safely, see the API
// documentation.
println!("Checking memory...");
assert_eq!(memory.size(), 2);
assert_eq!(memory.data_size(), 0x20000);
unsafe {
assert_eq!(memory.data_unchecked_mut()[0], 0);
assert_eq!(memory.data_unchecked_mut()[0x1000], 1);
assert_eq!(memory.data_unchecked_mut()[0x1003], 4);
}
Redo the statically typed `Func` API (#2719) * Redo the statically typed `Func` API This commit reimplements the `Func` API with respect to statically typed dispatch. Previously `Func` had a `getN` and `getN_async` family of methods which were implemented for 0 to 16 parameters. The return value of these functions was an `impl Fn(..)` closure with the appropriate parameters and return values. There are a number of downsides with this approach that have become apparent over time: * The addition of `*_async` doubled the API surface area (which is quite large here due to one-method-per-number-of-parameters). * The [documentation of `Func`][old-docs] are quite verbose and feel &#34;polluted&#34; with all these getters, making it harder to understand the other methods that can be used to interact with a `Func`. * These methods unconditionally pay the cost of returning an owned `impl Fn` with a `&#39;static` lifetime. While cheap, this is still paying the cost for cloning the `Store` effectively and moving data into the closed-over environment. * Storage of the return value into a struct, for example, always requires `Box`-ing the returned closure since it otherwise cannot be named. * Recently I had the desire to implement an &#34;unchecked&#34; path for invoking wasm where you unsafely assert the type signature of a wasm function. Doing this with today&#39;s scheme would require doubling (again) the API surface area for both async and synchronous calls, further polluting the documentation. The main benefit of the previous scheme is that by returning a `impl Fn` it was quite easy and ergonomic to actually invoke the function. In practice, though, examples would often have something akin to `.get0::&lt;()&gt;()?()?` which is a lot of things to interpret all at once. Note that `get0` means &#34;0 parameters&#34; yet a type parameter is passed. There&#39;s also a double function invocation which looks like a lot of characters all lined up in a row. Overall, I think that the previous design is starting to show too many cracks and deserves a rewrite. This commit is that rewrite. The new design in this commit is to delete the `getN{,_async}` family of functions and instead have a new API: impl Func { fn typed&lt;P, R&gt;(&amp;self) -&gt; Result&lt;&amp;Typed&lt;P, R&gt;&gt;; } impl Typed&lt;P, R&gt; { fn call(&amp;self, params: P) -&gt; Result&lt;R, Trap&gt;; async fn call_async(&amp;self, params: P) -&gt; Result&lt;R, Trap&gt;; } This should entirely replace the current scheme, albeit by slightly losing ergonomics use cases. The idea behind the API is that the existence of `Typed&lt;P, R&gt;` is a &#34;proof&#34; that the underlying function takes `P` and returns `R`. The `Func::typed` method peforms a runtime type-check to ensure that types all match up, and if successful you get a `Typed` value. Otherwise an error is returned. Once you have a `Typed` then, like `Func`, you can either `call` or `call_async`. The difference with a `Typed`, however, is that the params/results are statically known and hence these calls can be much more efficient. This is a much smaller API surface area from before and should greatly simplify the `Func` documentation. There&#39;s still a problem where `Func::wrapN_async` produces a lot of functions to document, but that&#39;s now the sole offender. It&#39;s a nice benefit that the statically-typed-async verisons are now expressed with an `async` function rather than a function-returning-a-future which makes it both more efficient and easier to understand. The type `P` and `R` are intended to either be bare types (e.g. `i32`) or tuples of any length (including 0). At this time `R` is only allowed to be `()` or a bare `i32`-style type because multi-value is not supported with a native ABI (yet). The `P`, however, can be any size of tuples of parameters. This is also where some ergonomics are lost because instead of `f(1, 2)` you now have to write `f.call((1, 2))` (note the double-parens). Similarly `f()` becomes `f.call(())`. Overall I feel that this is a better tradeoff than before. While not universally better due to the loss in ergonomics I feel that this design is much more flexible in terms of what you can do with the return value and also understanding the API surface area (just less to take in). [old-docs]: https://docs.rs/wasmtime/0.24.0/wasmtime/struct.Func.html#method.get0 * Rename Typed to TypedFunc * Implement multi-value returns through `Func::typed` * Fix examples in docs * Fix some more errors * More test fixes * Rebasing and adding `get_typed_func` * Updating tests * Fix typo * More doc tweaks * Tweak visibility on `Func::invoke` * Fix tests again
4 years ago
assert_eq!(size.call(())?, 2);
assert_eq!(load.call(0)?, 0);
assert_eq!(load.call(0x1000)?, 1);
assert_eq!(load.call(0x1003)?, 4);
assert_eq!(load.call(0x1ffff)?, 0);
assert!(load.call(0x20000).is_err()); // out of bounds trap
println!("Mutating memory...");
unsafe {
memory.data_unchecked_mut()[0x1003] = 5;
}
Redo the statically typed `Func` API (#2719) * Redo the statically typed `Func` API This commit reimplements the `Func` API with respect to statically typed dispatch. Previously `Func` had a `getN` and `getN_async` family of methods which were implemented for 0 to 16 parameters. The return value of these functions was an `impl Fn(..)` closure with the appropriate parameters and return values. There are a number of downsides with this approach that have become apparent over time: * The addition of `*_async` doubled the API surface area (which is quite large here due to one-method-per-number-of-parameters). * The [documentation of `Func`][old-docs] are quite verbose and feel &#34;polluted&#34; with all these getters, making it harder to understand the other methods that can be used to interact with a `Func`. * These methods unconditionally pay the cost of returning an owned `impl Fn` with a `&#39;static` lifetime. While cheap, this is still paying the cost for cloning the `Store` effectively and moving data into the closed-over environment. * Storage of the return value into a struct, for example, always requires `Box`-ing the returned closure since it otherwise cannot be named. * Recently I had the desire to implement an &#34;unchecked&#34; path for invoking wasm where you unsafely assert the type signature of a wasm function. Doing this with today&#39;s scheme would require doubling (again) the API surface area for both async and synchronous calls, further polluting the documentation. The main benefit of the previous scheme is that by returning a `impl Fn` it was quite easy and ergonomic to actually invoke the function. In practice, though, examples would often have something akin to `.get0::&lt;()&gt;()?()?` which is a lot of things to interpret all at once. Note that `get0` means &#34;0 parameters&#34; yet a type parameter is passed. There&#39;s also a double function invocation which looks like a lot of characters all lined up in a row. Overall, I think that the previous design is starting to show too many cracks and deserves a rewrite. This commit is that rewrite. The new design in this commit is to delete the `getN{,_async}` family of functions and instead have a new API: impl Func { fn typed&lt;P, R&gt;(&amp;self) -&gt; Result&lt;&amp;Typed&lt;P, R&gt;&gt;; } impl Typed&lt;P, R&gt; { fn call(&amp;self, params: P) -&gt; Result&lt;R, Trap&gt;; async fn call_async(&amp;self, params: P) -&gt; Result&lt;R, Trap&gt;; } This should entirely replace the current scheme, albeit by slightly losing ergonomics use cases. The idea behind the API is that the existence of `Typed&lt;P, R&gt;` is a &#34;proof&#34; that the underlying function takes `P` and returns `R`. The `Func::typed` method peforms a runtime type-check to ensure that types all match up, and if successful you get a `Typed` value. Otherwise an error is returned. Once you have a `Typed` then, like `Func`, you can either `call` or `call_async`. The difference with a `Typed`, however, is that the params/results are statically known and hence these calls can be much more efficient. This is a much smaller API surface area from before and should greatly simplify the `Func` documentation. There&#39;s still a problem where `Func::wrapN_async` produces a lot of functions to document, but that&#39;s now the sole offender. It&#39;s a nice benefit that the statically-typed-async verisons are now expressed with an `async` function rather than a function-returning-a-future which makes it both more efficient and easier to understand. The type `P` and `R` are intended to either be bare types (e.g. `i32`) or tuples of any length (including 0). At this time `R` is only allowed to be `()` or a bare `i32`-style type because multi-value is not supported with a native ABI (yet). The `P`, however, can be any size of tuples of parameters. This is also where some ergonomics are lost because instead of `f(1, 2)` you now have to write `f.call((1, 2))` (note the double-parens). Similarly `f()` becomes `f.call(())`. Overall I feel that this is a better tradeoff than before. While not universally better due to the loss in ergonomics I feel that this design is much more flexible in terms of what you can do with the return value and also understanding the API surface area (just less to take in). [old-docs]: https://docs.rs/wasmtime/0.24.0/wasmtime/struct.Func.html#method.get0 * Rename Typed to TypedFunc * Implement multi-value returns through `Func::typed` * Fix examples in docs * Fix some more errors * More test fixes * Rebasing and adding `get_typed_func` * Updating tests * Fix typo * More doc tweaks * Tweak visibility on `Func::invoke` * Fix tests again
4 years ago
store.call((0x1002, 6))?;
assert!(store.call((0x20000, 0)).is_err()); // out of bounds trap
unsafe {
assert_eq!(memory.data_unchecked_mut()[0x1002], 6);
assert_eq!(memory.data_unchecked_mut()[0x1003], 5);
}
Redo the statically typed `Func` API (#2719) * Redo the statically typed `Func` API This commit reimplements the `Func` API with respect to statically typed dispatch. Previously `Func` had a `getN` and `getN_async` family of methods which were implemented for 0 to 16 parameters. The return value of these functions was an `impl Fn(..)` closure with the appropriate parameters and return values. There are a number of downsides with this approach that have become apparent over time: * The addition of `*_async` doubled the API surface area (which is quite large here due to one-method-per-number-of-parameters). * The [documentation of `Func`][old-docs] are quite verbose and feel &#34;polluted&#34; with all these getters, making it harder to understand the other methods that can be used to interact with a `Func`. * These methods unconditionally pay the cost of returning an owned `impl Fn` with a `&#39;static` lifetime. While cheap, this is still paying the cost for cloning the `Store` effectively and moving data into the closed-over environment. * Storage of the return value into a struct, for example, always requires `Box`-ing the returned closure since it otherwise cannot be named. * Recently I had the desire to implement an &#34;unchecked&#34; path for invoking wasm where you unsafely assert the type signature of a wasm function. Doing this with today&#39;s scheme would require doubling (again) the API surface area for both async and synchronous calls, further polluting the documentation. The main benefit of the previous scheme is that by returning a `impl Fn` it was quite easy and ergonomic to actually invoke the function. In practice, though, examples would often have something akin to `.get0::&lt;()&gt;()?()?` which is a lot of things to interpret all at once. Note that `get0` means &#34;0 parameters&#34; yet a type parameter is passed. There&#39;s also a double function invocation which looks like a lot of characters all lined up in a row. Overall, I think that the previous design is starting to show too many cracks and deserves a rewrite. This commit is that rewrite. The new design in this commit is to delete the `getN{,_async}` family of functions and instead have a new API: impl Func { fn typed&lt;P, R&gt;(&amp;self) -&gt; Result&lt;&amp;Typed&lt;P, R&gt;&gt;; } impl Typed&lt;P, R&gt; { fn call(&amp;self, params: P) -&gt; Result&lt;R, Trap&gt;; async fn call_async(&amp;self, params: P) -&gt; Result&lt;R, Trap&gt;; } This should entirely replace the current scheme, albeit by slightly losing ergonomics use cases. The idea behind the API is that the existence of `Typed&lt;P, R&gt;` is a &#34;proof&#34; that the underlying function takes `P` and returns `R`. The `Func::typed` method peforms a runtime type-check to ensure that types all match up, and if successful you get a `Typed` value. Otherwise an error is returned. Once you have a `Typed` then, like `Func`, you can either `call` or `call_async`. The difference with a `Typed`, however, is that the params/results are statically known and hence these calls can be much more efficient. This is a much smaller API surface area from before and should greatly simplify the `Func` documentation. There&#39;s still a problem where `Func::wrapN_async` produces a lot of functions to document, but that&#39;s now the sole offender. It&#39;s a nice benefit that the statically-typed-async verisons are now expressed with an `async` function rather than a function-returning-a-future which makes it both more efficient and easier to understand. The type `P` and `R` are intended to either be bare types (e.g. `i32`) or tuples of any length (including 0). At this time `R` is only allowed to be `()` or a bare `i32`-style type because multi-value is not supported with a native ABI (yet). The `P`, however, can be any size of tuples of parameters. This is also where some ergonomics are lost because instead of `f(1, 2)` you now have to write `f.call((1, 2))` (note the double-parens). Similarly `f()` becomes `f.call(())`. Overall I feel that this is a better tradeoff than before. While not universally better due to the loss in ergonomics I feel that this design is much more flexible in terms of what you can do with the return value and also understanding the API surface area (just less to take in). [old-docs]: https://docs.rs/wasmtime/0.24.0/wasmtime/struct.Func.html#method.get0 * Rename Typed to TypedFunc * Implement multi-value returns through `Func::typed` * Fix examples in docs * Fix some more errors * More test fixes * Rebasing and adding `get_typed_func` * Updating tests * Fix typo * More doc tweaks * Tweak visibility on `Func::invoke` * Fix tests again
4 years ago
assert_eq!(load.call(0x1002)?, 6);
assert_eq!(load.call(0x1003)?, 5);
// Grow memory.
println!("Growing memory...");
memory.grow(1)?;
assert_eq!(memory.size(), 3);
assert_eq!(memory.data_size(), 0x30000);
Redo the statically typed `Func` API (#2719) * Redo the statically typed `Func` API This commit reimplements the `Func` API with respect to statically typed dispatch. Previously `Func` had a `getN` and `getN_async` family of methods which were implemented for 0 to 16 parameters. The return value of these functions was an `impl Fn(..)` closure with the appropriate parameters and return values. There are a number of downsides with this approach that have become apparent over time: * The addition of `*_async` doubled the API surface area (which is quite large here due to one-method-per-number-of-parameters). * The [documentation of `Func`][old-docs] are quite verbose and feel &#34;polluted&#34; with all these getters, making it harder to understand the other methods that can be used to interact with a `Func`. * These methods unconditionally pay the cost of returning an owned `impl Fn` with a `&#39;static` lifetime. While cheap, this is still paying the cost for cloning the `Store` effectively and moving data into the closed-over environment. * Storage of the return value into a struct, for example, always requires `Box`-ing the returned closure since it otherwise cannot be named. * Recently I had the desire to implement an &#34;unchecked&#34; path for invoking wasm where you unsafely assert the type signature of a wasm function. Doing this with today&#39;s scheme would require doubling (again) the API surface area for both async and synchronous calls, further polluting the documentation. The main benefit of the previous scheme is that by returning a `impl Fn` it was quite easy and ergonomic to actually invoke the function. In practice, though, examples would often have something akin to `.get0::&lt;()&gt;()?()?` which is a lot of things to interpret all at once. Note that `get0` means &#34;0 parameters&#34; yet a type parameter is passed. There&#39;s also a double function invocation which looks like a lot of characters all lined up in a row. Overall, I think that the previous design is starting to show too many cracks and deserves a rewrite. This commit is that rewrite. The new design in this commit is to delete the `getN{,_async}` family of functions and instead have a new API: impl Func { fn typed&lt;P, R&gt;(&amp;self) -&gt; Result&lt;&amp;Typed&lt;P, R&gt;&gt;; } impl Typed&lt;P, R&gt; { fn call(&amp;self, params: P) -&gt; Result&lt;R, Trap&gt;; async fn call_async(&amp;self, params: P) -&gt; Result&lt;R, Trap&gt;; } This should entirely replace the current scheme, albeit by slightly losing ergonomics use cases. The idea behind the API is that the existence of `Typed&lt;P, R&gt;` is a &#34;proof&#34; that the underlying function takes `P` and returns `R`. The `Func::typed` method peforms a runtime type-check to ensure that types all match up, and if successful you get a `Typed` value. Otherwise an error is returned. Once you have a `Typed` then, like `Func`, you can either `call` or `call_async`. The difference with a `Typed`, however, is that the params/results are statically known and hence these calls can be much more efficient. This is a much smaller API surface area from before and should greatly simplify the `Func` documentation. There&#39;s still a problem where `Func::wrapN_async` produces a lot of functions to document, but that&#39;s now the sole offender. It&#39;s a nice benefit that the statically-typed-async verisons are now expressed with an `async` function rather than a function-returning-a-future which makes it both more efficient and easier to understand. The type `P` and `R` are intended to either be bare types (e.g. `i32`) or tuples of any length (including 0). At this time `R` is only allowed to be `()` or a bare `i32`-style type because multi-value is not supported with a native ABI (yet). The `P`, however, can be any size of tuples of parameters. This is also where some ergonomics are lost because instead of `f(1, 2)` you now have to write `f.call((1, 2))` (note the double-parens). Similarly `f()` becomes `f.call(())`. Overall I feel that this is a better tradeoff than before. While not universally better due to the loss in ergonomics I feel that this design is much more flexible in terms of what you can do with the return value and also understanding the API surface area (just less to take in). [old-docs]: https://docs.rs/wasmtime/0.24.0/wasmtime/struct.Func.html#method.get0 * Rename Typed to TypedFunc * Implement multi-value returns through `Func::typed` * Fix examples in docs * Fix some more errors * More test fixes * Rebasing and adding `get_typed_func` * Updating tests * Fix typo * More doc tweaks * Tweak visibility on `Func::invoke` * Fix tests again
4 years ago
assert_eq!(load.call(0x20000)?, 0);
store.call((0x20000, 0))?;
assert!(load.call(0x30000).is_err());
assert!(store.call((0x30000, 0)).is_err());
assert!(memory.grow(1).is_err());
assert!(memory.grow(0).is_ok());
println!("Creating stand-alone memory...");
let memorytype = MemoryType::new(Limits::new(5, Some(5)));
Add resource limiting to the Wasmtime API. (#2736) * Add resource limiting to the Wasmtime API. This commit adds a `ResourceLimiter` trait to the Wasmtime API. When used in conjunction with `Store::new_with_limiter`, this can be used to monitor and prevent WebAssembly code from growing linear memories and tables. This is particularly useful when hosts need to take into account host resource usage to determine if WebAssembly code can consume more resources. A simple `StaticResourceLimiter` is also included with these changes that will simply limit the size of linear memories or tables for all instances created in the store based on static values. * Code review feedback. * Implemented `StoreLimits` and `StoreLimitsBuilder`. * Moved `max_instances`, `max_memories`, `max_tables` out of `Config` and into `StoreLimits`. * Moved storage of the limiter in the runtime into `Memory` and `Table`. * Made `InstanceAllocationRequest` use a reference to the limiter. * Updated docs. * Made `ResourceLimiterProxy` generic to remove a level of indirection. * Fixed the limiter not being used for `wasmtime::Memory` and `wasmtime::Table`. * Code review feedback and bug fix. * `Memory::new` now returns `Result&lt;Self&gt;` so that an error can be returned if the initial requested memory exceeds any limits placed on the store. * Changed an `Arc` to `Rc` as the `Arc` wasn&#39;t necessary. * Removed `Store` from the `ResourceLimiter` callbacks. Custom resource limiter implementations are free to capture any context they want, so no need to unnecessarily store a weak reference to `Store` from the proxy type. * Fixed a bug in the pooling instance allocator where an instance would be leaked from the pool. Previously, this would only have happened if the OS was unable to make the necessary linear memory available for the instance. With these changes, however, the instance might not be created due to limits placed on the store. We now properly deallocate the instance on error. * Added more tests, including one that covers the fix mentioned above. * Code review feedback. * Add another memory to `test_pooling_allocator_initial_limits_exceeded` to ensure a partially created instance is successfully deallocated. * Update some doc comments for better documentation of `Store` and `ResourceLimiter`.
4 years ago
let memory2 = Memory::new(&wasmtime_store, memorytype)?;
assert_eq!(memory2.size(), 5);
assert!(memory2.grow(1).is_err());
assert!(memory2.grow(0).is_ok());
Ok(())
}