make ResourceLimiter operate on Store data; add hooks for entering and exiting native code (#2952)

* wasmtime_runtime: move ResourceLimiter defaults into this crate

In preparation of changing wasmtime::ResourceLimiter to be a re-export
of this definition, because translating between two traits was causing
problems elsewhere.

* wasmtime: make ResourceLimiter a re-export of wasmtime_runtime::ResourceLimiter

* refactor Store internals to support ResourceLimiter as part of store's data

* add hooks for entering and exiting native code to Store

* wasmtime-wast, fuzz: changes to adapt ResourceLimiter API

* fix tests

* wrap calls into wasm with entering/exiting exit hooks as well

* the most trivial test found a bug, lets write some more

* store: mark some methods as #[inline] on Store, StoreInner, StoreInnerMost

Co-authored-By: Alex Crichton <alex@alexcrichton.com>

* improve tests for the entering/exiting native hooks

Co-authored-by: Alex Crichton <alex@alexcrichton.com>
This commit is contained in:
Pat Hickey
2021-06-08 07:37:00 -07:00
committed by GitHub
parent ffb92d9109
commit 8b4bdf92e2
17 changed files with 550 additions and 283 deletions

View File

@@ -42,9 +42,9 @@ fn log_wasm(wasm: &[u8]) {
}
}
fn create_store(engine: &Engine) -> Store<()> {
let mut store = Store::new(&engine, ());
store.limiter(
fn create_store(engine: &Engine) -> Store<StoreLimits> {
let mut store = Store::new(
&engine,
StoreLimitsBuilder::new()
// The limits here are chosen based on the default "maximum type size"
// configured in wasm-smith, which is 1000. This means that instances
@@ -55,6 +55,7 @@ fn create_store(engine: &Engine) -> Store<()> {
.memories(1100)
.build(),
);
store.limiter(|s| s as &mut dyn ResourceLimiter);
store
}
@@ -268,7 +269,7 @@ pub fn differential_execution(
}
}
fn init_hang_limit(store: &mut Store<()>, instance: Instance) {
fn init_hang_limit<T>(store: &mut Store<T>, instance: Instance) {
match instance.get_export(&mut *store, "hangLimitInitializer") {
None => return,
Some(Extern::Func(f)) => {
@@ -337,7 +338,7 @@ pub fn make_api_calls(api: crate::generators::api::ApiCalls) {
let mut config: Option<Config> = None;
let mut engine: Option<Engine> = None;
let mut store: Option<Store<()>> = None;
let mut store: Option<Store<StoreLimits>> = None;
let mut modules: HashMap<usize, Module> = Default::default();
let mut instances: HashMap<usize, Instance> = Default::default();
@@ -501,7 +502,7 @@ pub fn table_ops(
const MAX_GCS: usize = 5;
let num_gcs = AtomicUsize::new(0);
let gc = Func::wrap(&mut store, move |mut caller: Caller<'_, ()>| {
let gc = Func::wrap(&mut store, move |mut caller: Caller<'_, StoreLimits>| {
if num_gcs.fetch_add(1, SeqCst) < MAX_GCS {
caller.gc();
}

View File

@@ -4,7 +4,7 @@ use std::fmt::Write;
use wasmtime::*;
/// Create a set of dummy functions/globals/etc for the given imports.
pub fn dummy_linker<'module>(store: &mut Store<()>, module: &Module) -> Linker<()> {
pub fn dummy_linker<'module, T>(store: &mut Store<T>, module: &Module) -> Linker<T> {
let mut linker = Linker::new(store.engine());
linker.allow_shadowing(true);
for import in module.imports() {
@@ -34,7 +34,7 @@ pub fn dummy_linker<'module>(store: &mut Store<()>, module: &Module) -> Linker<(
}
/// Construct a dummy `Extern` from its type signature
pub fn dummy_extern(store: &mut Store<()>, ty: ExternType) -> Extern {
pub fn dummy_extern<T>(store: &mut Store<T>, ty: ExternType) -> Extern {
match ty {
ExternType::Func(func_ty) => Extern::Func(dummy_func(store, func_ty)),
ExternType::Global(global_ty) => Extern::Global(dummy_global(store, global_ty)),
@@ -46,7 +46,7 @@ pub fn dummy_extern(store: &mut Store<()>, ty: ExternType) -> Extern {
}
/// Construct a dummy function for the given function type
pub fn dummy_func(store: &mut Store<()>, ty: FuncType) -> Func {
pub fn dummy_func<T>(store: &mut Store<T>, ty: FuncType) -> Func {
Func::new(store, ty.clone(), move |_, _, results| {
for (ret_ty, result) in ty.results().zip(results) {
*result = dummy_value(ret_ty);
@@ -74,19 +74,19 @@ pub fn dummy_values(val_tys: impl IntoIterator<Item = ValType>) -> Vec<Val> {
}
/// Construct a dummy global for the given global type.
pub fn dummy_global(store: &mut Store<()>, ty: GlobalType) -> Global {
pub fn dummy_global<T>(store: &mut Store<T>, ty: GlobalType) -> Global {
let val = dummy_value(ty.content().clone());
Global::new(store, ty, val).unwrap()
}
/// Construct a dummy table for the given table type.
pub fn dummy_table(store: &mut Store<()>, ty: TableType) -> Table {
pub fn dummy_table<T>(store: &mut Store<T>, ty: TableType) -> Table {
let init_val = dummy_value(ty.element().clone());
Table::new(store, ty, init_val).unwrap()
}
/// Construct a dummy memory for the given memory type.
pub fn dummy_memory(store: &mut Store<()>, ty: MemoryType) -> Memory {
pub fn dummy_memory<T>(store: &mut Store<T>, ty: MemoryType) -> Memory {
Memory::new(store, ty).unwrap()
}
@@ -94,7 +94,7 @@ pub fn dummy_memory(store: &mut Store<()>, ty: MemoryType) -> Memory {
///
/// This is done by using the expected type to generate a module on-the-fly
/// which we the instantiate.
pub fn dummy_instance(store: &mut Store<()>, ty: InstanceType) -> Instance {
pub fn dummy_instance<T>(store: &mut Store<T>, ty: InstanceType) -> Instance {
let mut wat = WatGenerator::new();
for ty in ty.exports() {
wat.export(&ty);