Remove global state for trap registration (#909)
* Remove global state for trap registration There's a number of changes brought about in this commit, motivated by a few things. One motivation was to remove an instance of using `lazy_static!` in an effort to remove global state and encapsulate it wherever possible. A second motivation came when investigating a slowly-compiling wasm module (a bit too slowly) where a good chunk of time was spent in managing trap registrations. The specific change made here is that `TrapRegistry` is now stored inside of a `Compiler` instead of inside a global. Additionally traps are "bulk registered" for a module rather than one-by-one. This form of bulk-registration allows optimizing the locks used here, where a lock is only held for a module at-a-time instead of once-per-function. With these changes the "unregister" logic has also been tweaked a bit here and there to continue to work. As a nice side effect the `Compiler` type now has one fewer field that requires actual mutability and has been updated for multi-threaded compilation, nudging us closer to a world where we can support multi-threaded compilation. Yay! In terms of performance improvements, a local wasm test file that previously took 3 seconds to compile is now 10% faster to compile, taking ~2.7 seconds now. * Perform trap resolution after unwinding This avoids taking locks in signal handlers which feels a bit iffy... * Remove `TrapRegistration::dummy()` Avoid an case where you're trying to lookup trap information from a dummy module for something that happened in a different module. * Tweak some comments
This commit is contained in:
@@ -181,7 +181,7 @@ impl Global {
|
||||
if val.ty() != *ty.content() {
|
||||
bail!("value provided does not match the type of this global");
|
||||
}
|
||||
let (wasmtime_export, wasmtime_state) = generate_global_export(&ty, val)?;
|
||||
let (wasmtime_export, wasmtime_state) = generate_global_export(store, &ty, val)?;
|
||||
Ok(Global {
|
||||
inner: Rc::new(GlobalInner {
|
||||
_store: store.clone(),
|
||||
@@ -321,7 +321,7 @@ impl Table {
|
||||
/// Returns an error if `init` does not match the element type of the table.
|
||||
pub fn new(store: &Store, ty: TableType, init: Val) -> Result<Table> {
|
||||
let item = into_checked_anyfunc(init, store)?;
|
||||
let (mut wasmtime_handle, wasmtime_export) = generate_table_export(&ty)?;
|
||||
let (mut wasmtime_handle, wasmtime_export) = generate_table_export(store, &ty)?;
|
||||
|
||||
// Initialize entries with the init value.
|
||||
match wasmtime_export {
|
||||
@@ -473,7 +473,7 @@ impl Memory {
|
||||
/// type's configuration. All WebAssembly memory is initialized to zero.
|
||||
pub fn new(store: &Store, ty: MemoryType) -> Memory {
|
||||
let (wasmtime_handle, wasmtime_export) =
|
||||
generate_memory_export(&ty).expect("generated memory");
|
||||
generate_memory_export(store, &ty).expect("generated memory");
|
||||
Memory {
|
||||
_store: store.clone(),
|
||||
ty,
|
||||
|
||||
@@ -12,7 +12,7 @@ use wasmtime_runtime::{Imports, InstanceHandle, VMFunctionBody};
|
||||
|
||||
pub(crate) fn create_handle(
|
||||
module: Module,
|
||||
store: Option<&Store>,
|
||||
store: &Store,
|
||||
finished_functions: PrimaryMap<DefinedFuncIndex, *const VMFunctionBody>,
|
||||
state: Box<dyn Any>,
|
||||
) -> Result<InstanceHandle> {
|
||||
@@ -26,19 +26,16 @@ pub(crate) fn create_handle(
|
||||
let data_initializers = Vec::new();
|
||||
|
||||
// Compute indices into the shared signature table.
|
||||
let signatures = store
|
||||
.map(|store| {
|
||||
module
|
||||
.signatures
|
||||
.values()
|
||||
.map(|sig| store.compiler().signatures().register(sig))
|
||||
.collect::<PrimaryMap<_, _>>()
|
||||
})
|
||||
.unwrap_or_else(PrimaryMap::new);
|
||||
let signatures = module
|
||||
.signatures
|
||||
.values()
|
||||
.map(|sig| store.compiler().signatures().register(sig))
|
||||
.collect::<PrimaryMap<_, _>>();
|
||||
|
||||
unsafe {
|
||||
Ok(InstanceHandle::new(
|
||||
Arc::new(module),
|
||||
store.compiler().trap_registry().register_traps(Vec::new()),
|
||||
finished_functions.into_boxed_slice(),
|
||||
imports,
|
||||
&data_initializers,
|
||||
|
||||
@@ -287,7 +287,7 @@ pub fn create_handle_with_function(
|
||||
|
||||
create_handle(
|
||||
module,
|
||||
Some(store),
|
||||
store,
|
||||
finished_functions,
|
||||
Box::new(trampoline_state),
|
||||
)
|
||||
@@ -322,5 +322,5 @@ pub unsafe fn create_handle_with_raw_function(
|
||||
.insert("trampoline".to_string(), Export::Function(func_id));
|
||||
finished_functions.push(func);
|
||||
|
||||
create_handle(module, Some(store), finished_functions, state)
|
||||
create_handle(module, store, finished_functions, state)
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
use super::create_handle::create_handle;
|
||||
use crate::Store;
|
||||
use crate::{GlobalType, Mutability, Val};
|
||||
use anyhow::{bail, Result};
|
||||
use wasmtime_environ::entity::PrimaryMap;
|
||||
@@ -11,7 +12,11 @@ pub struct GlobalState {
|
||||
handle: InstanceHandle,
|
||||
}
|
||||
|
||||
pub fn create_global(gt: &GlobalType, val: Val) -> Result<(wasmtime_runtime::Export, GlobalState)> {
|
||||
pub fn create_global(
|
||||
store: &Store,
|
||||
gt: &GlobalType,
|
||||
val: Val,
|
||||
) -> Result<(wasmtime_runtime::Export, GlobalState)> {
|
||||
let mut definition = Box::new(VMGlobalDefinition::new());
|
||||
unsafe {
|
||||
match val {
|
||||
@@ -35,7 +40,7 @@ pub fn create_global(gt: &GlobalType, val: Val) -> Result<(wasmtime_runtime::Exp
|
||||
initializer: wasm::GlobalInit::Import, // TODO is it right?
|
||||
};
|
||||
let handle =
|
||||
create_handle(Module::new(), None, PrimaryMap::new(), Box::new(())).expect("handle");
|
||||
create_handle(Module::new(), store, PrimaryMap::new(), Box::new(())).expect("handle");
|
||||
Ok((
|
||||
wasmtime_runtime::Export::Global {
|
||||
definition: definition.as_mut(),
|
||||
|
||||
@@ -1,13 +1,12 @@
|
||||
use super::create_handle::create_handle;
|
||||
use crate::MemoryType;
|
||||
use crate::Store;
|
||||
use anyhow::Result;
|
||||
use wasmtime_environ::entity::PrimaryMap;
|
||||
use wasmtime_environ::{wasm, Module};
|
||||
use wasmtime_runtime::InstanceHandle;
|
||||
|
||||
#[allow(dead_code)]
|
||||
|
||||
pub fn create_handle_with_memory(memory: &MemoryType) -> Result<InstanceHandle> {
|
||||
pub fn create_handle_with_memory(store: &Store, memory: &MemoryType) -> Result<InstanceHandle> {
|
||||
let mut module = Module::new();
|
||||
|
||||
let memory = wasm::Memory {
|
||||
@@ -24,5 +23,5 @@ pub fn create_handle_with_memory(memory: &MemoryType) -> Result<InstanceHandle>
|
||||
wasmtime_environ::Export::Memory(memory_id),
|
||||
);
|
||||
|
||||
create_handle(module, None, PrimaryMap::new(), Box::new(()))
|
||||
create_handle(module, store, PrimaryMap::new(), Box::new(()))
|
||||
}
|
||||
|
||||
@@ -43,24 +43,27 @@ pub unsafe fn generate_raw_func_export(
|
||||
}
|
||||
|
||||
pub fn generate_global_export(
|
||||
store: &Store,
|
||||
gt: &GlobalType,
|
||||
val: Val,
|
||||
) -> Result<(wasmtime_runtime::Export, GlobalState)> {
|
||||
create_global(gt, val)
|
||||
create_global(store, gt, val)
|
||||
}
|
||||
|
||||
pub fn generate_memory_export(
|
||||
store: &Store,
|
||||
m: &MemoryType,
|
||||
) -> Result<(wasmtime_runtime::InstanceHandle, wasmtime_runtime::Export)> {
|
||||
let instance = create_handle_with_memory(m)?;
|
||||
let instance = create_handle_with_memory(store, m)?;
|
||||
let export = instance.lookup("memory").expect("memory export");
|
||||
Ok((instance, export))
|
||||
}
|
||||
|
||||
pub fn generate_table_export(
|
||||
store: &Store,
|
||||
t: &TableType,
|
||||
) -> Result<(wasmtime_runtime::InstanceHandle, wasmtime_runtime::Export)> {
|
||||
let instance = create_handle_with_table(t)?;
|
||||
let instance = create_handle_with_table(store, t)?;
|
||||
let export = instance.lookup("table").expect("table export");
|
||||
Ok((instance, export))
|
||||
}
|
||||
|
||||
@@ -1,11 +1,12 @@
|
||||
use super::create_handle::create_handle;
|
||||
use crate::Store;
|
||||
use crate::{TableType, ValType};
|
||||
use anyhow::{bail, Result};
|
||||
use wasmtime_environ::entity::PrimaryMap;
|
||||
use wasmtime_environ::{wasm, Module};
|
||||
use wasmtime_runtime::InstanceHandle;
|
||||
|
||||
pub fn create_handle_with_table(table: &TableType) -> Result<InstanceHandle> {
|
||||
pub fn create_handle_with_table(store: &Store, table: &TableType) -> Result<InstanceHandle> {
|
||||
let mut module = Module::new();
|
||||
|
||||
let table = wasm::Table {
|
||||
@@ -25,5 +26,5 @@ pub fn create_handle_with_table(table: &TableType) -> Result<InstanceHandle> {
|
||||
wasmtime_environ::Export::Table(table_id),
|
||||
);
|
||||
|
||||
create_handle(module, None, PrimaryMap::new(), Box::new(()))
|
||||
create_handle(module, store, PrimaryMap::new(), Box::new(()))
|
||||
}
|
||||
|
||||
@@ -63,7 +63,11 @@ fn test_trap_trace() -> Result<()> {
|
||||
assert_eq!(trace[1].module_name().unwrap(), "hello_mod");
|
||||
assert_eq!(trace[1].func_index(), 0);
|
||||
assert_eq!(trace[1].func_name(), None);
|
||||
assert!(e.message().contains("unreachable"));
|
||||
assert!(
|
||||
e.message().contains("unreachable"),
|
||||
"wrong message: {}",
|
||||
e.message()
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user