Disconnects Store state fields from Compiler (#1761)
* Moves CodeMemory, VMInterrupts and SignatureRegistry from Compiler * CompiledModule holds CodeMemory and GdbJitImageRegistration * Store keeps track of its JIT code * Makes "jit_int.rs" stuff Send+Sync * Adds the threads example.
This commit is contained in:
@@ -659,13 +659,14 @@ impl Memory {
|
||||
/// ```
|
||||
/// # use wasmtime::*;
|
||||
/// # fn main() -> anyhow::Result<()> {
|
||||
/// let store = Store::default();
|
||||
/// let engine = Engine::default();
|
||||
/// let store = Store::new(&engine);
|
||||
///
|
||||
/// let memory_ty = MemoryType::new(Limits::new(1, None));
|
||||
/// let memory = Memory::new(&store, memory_ty);
|
||||
///
|
||||
/// let module = Module::new(&store, "(module (memory (import \"\" \"\") 1))")?;
|
||||
/// let instance = Instance::new(&module, &[memory.into()])?;
|
||||
/// let module = Module::new(&engine, "(module (memory (import \"\" \"\") 1))")?;
|
||||
/// let instance = Instance::new(&store, &module, &[memory.into()])?;
|
||||
/// // ...
|
||||
/// # Ok(())
|
||||
/// # }
|
||||
@@ -686,9 +687,10 @@ impl Memory {
|
||||
/// ```
|
||||
/// # use wasmtime::*;
|
||||
/// # fn main() -> anyhow::Result<()> {
|
||||
/// let store = Store::default();
|
||||
/// let module = Module::new(&store, "(module (memory (export \"mem\") 1))")?;
|
||||
/// let instance = Instance::new(&module, &[])?;
|
||||
/// let engine = Engine::default();
|
||||
/// let store = Store::new(&engine);
|
||||
/// let module = Module::new(&engine, "(module (memory (export \"mem\") 1))")?;
|
||||
/// let instance = Instance::new(&store, &module, &[])?;
|
||||
/// let memory = instance.get_memory("mem").unwrap();
|
||||
/// let ty = memory.ty();
|
||||
/// assert_eq!(ty.limits().min(), 1);
|
||||
@@ -798,9 +800,10 @@ impl Memory {
|
||||
/// ```
|
||||
/// # use wasmtime::*;
|
||||
/// # fn main() -> anyhow::Result<()> {
|
||||
/// let store = Store::default();
|
||||
/// let module = Module::new(&store, "(module (memory (export \"mem\") 1 2))")?;
|
||||
/// let instance = Instance::new(&module, &[])?;
|
||||
/// let engine = Engine::default();
|
||||
/// let store = Store::new(&engine);
|
||||
/// let module = Module::new(&engine, "(module (memory (export \"mem\") 1 2))")?;
|
||||
/// let instance = Instance::new(&store, &module, &[])?;
|
||||
/// let memory = instance.get_memory("mem").unwrap();
|
||||
///
|
||||
/// assert_eq!(memory.size(), 1);
|
||||
|
||||
@@ -42,6 +42,8 @@ struct ModuleFrameInfo {
|
||||
start: usize,
|
||||
functions: BTreeMap<usize, FunctionInfo>,
|
||||
module: Arc<Module>,
|
||||
#[allow(dead_code)]
|
||||
module_code: Arc<dyn std::any::Any + Send + Sync>,
|
||||
}
|
||||
|
||||
struct FunctionInfo {
|
||||
@@ -192,6 +194,7 @@ pub fn register(module: &CompiledModule) -> Option<GlobalFrameInfoRegistration>
|
||||
start: min,
|
||||
functions,
|
||||
module: module.module().clone(),
|
||||
module_code: module.code().clone(),
|
||||
},
|
||||
);
|
||||
assert!(prev.is_none());
|
||||
|
||||
@@ -38,9 +38,10 @@ use wasmtime_runtime::{Export, InstanceHandle, VMContext, VMFunctionBody};
|
||||
/// ```
|
||||
/// # use wasmtime::*;
|
||||
/// # fn main() -> anyhow::Result<()> {
|
||||
/// let store = Store::default();
|
||||
/// let module = Module::new(&store, r#"(module (func (export "foo")))"#)?;
|
||||
/// let instance = Instance::new(&module, &[])?;
|
||||
/// let engine = Engine::default();
|
||||
/// let store = Store::new(&engine);
|
||||
/// let module = Module::new(&engine, r#"(module (func (export "foo")))"#)?;
|
||||
/// let instance = Instance::new(&store, &module, &[])?;
|
||||
/// let foo = instance.get_func("foo").expect("export wasn't a function");
|
||||
///
|
||||
/// // Work with `foo` as a `Func` at this point, such as calling it
|
||||
@@ -76,7 +77,7 @@ use wasmtime_runtime::{Export, InstanceHandle, VMContext, VMFunctionBody};
|
||||
///
|
||||
/// // Next we can hook that up to a wasm module which uses it.
|
||||
/// let module = Module::new(
|
||||
/// &store,
|
||||
/// store.engine(),
|
||||
/// r#"
|
||||
/// (module
|
||||
/// (import "" "" (func $add (param i32 i32) (result i32)))
|
||||
@@ -90,7 +91,7 @@ use wasmtime_runtime::{Export, InstanceHandle, VMContext, VMFunctionBody};
|
||||
/// i32.add))
|
||||
/// "#,
|
||||
/// )?;
|
||||
/// let instance = Instance::new(&module, &[add.into()])?;
|
||||
/// let instance = Instance::new(&store, &module, &[add.into()])?;
|
||||
/// let call_add_twice = instance.get_func("call_add_twice").expect("export wasn't a function");
|
||||
/// let call_add_twice = call_add_twice.get0::<i32>()?;
|
||||
///
|
||||
@@ -120,7 +121,7 @@ use wasmtime_runtime::{Export, InstanceHandle, VMContext, VMFunctionBody};
|
||||
/// });
|
||||
///
|
||||
/// let module = Module::new(
|
||||
/// &store,
|
||||
/// store.engine(),
|
||||
/// r#"
|
||||
/// (module
|
||||
/// (import "" "" (func $double (param i32) (result i32)))
|
||||
@@ -131,7 +132,7 @@ use wasmtime_runtime::{Export, InstanceHandle, VMContext, VMFunctionBody};
|
||||
/// (start $start))
|
||||
/// "#,
|
||||
/// )?;
|
||||
/// let instance = Instance::new(&module, &[double.into()])?;
|
||||
/// let instance = Instance::new(&store, &module, &[double.into()])?;
|
||||
/// // .. work with `instance` if necessary
|
||||
/// # Ok(())
|
||||
/// # }
|
||||
@@ -335,7 +336,7 @@ impl Func {
|
||||
/// # let store = Store::default();
|
||||
/// let add = Func::wrap(&store, |a: i32, b: i32| a + b);
|
||||
/// let module = Module::new(
|
||||
/// &store,
|
||||
/// store.engine(),
|
||||
/// r#"
|
||||
/// (module
|
||||
/// (import "" "" (func $add (param i32 i32) (result i32)))
|
||||
@@ -345,7 +346,7 @@ impl Func {
|
||||
/// call $add))
|
||||
/// "#,
|
||||
/// )?;
|
||||
/// let instance = Instance::new(&module, &[add.into()])?;
|
||||
/// let instance = Instance::new(&store, &module, &[add.into()])?;
|
||||
/// let foo = instance.get_func("foo").unwrap().get2::<i32, i32, i32>()?;
|
||||
/// assert_eq!(foo(1, 2)?, 3);
|
||||
/// # Ok(())
|
||||
@@ -366,7 +367,7 @@ impl Func {
|
||||
/// }
|
||||
/// });
|
||||
/// let module = Module::new(
|
||||
/// &store,
|
||||
/// store.engine(),
|
||||
/// r#"
|
||||
/// (module
|
||||
/// (import "" "" (func $add (param i32 i32) (result i32)))
|
||||
@@ -376,7 +377,7 @@ impl Func {
|
||||
/// call $add))
|
||||
/// "#,
|
||||
/// )?;
|
||||
/// let instance = Instance::new(&module, &[add.into()])?;
|
||||
/// let instance = Instance::new(&store, &module, &[add.into()])?;
|
||||
/// let foo = instance.get_func("foo").unwrap().get2::<i32, i32, i32>()?;
|
||||
/// assert_eq!(foo(1, 2)?, 3);
|
||||
/// assert!(foo(i32::max_value(), 1).is_err());
|
||||
@@ -397,7 +398,7 @@ impl Func {
|
||||
/// println!("d={}", d);
|
||||
/// });
|
||||
/// let module = Module::new(
|
||||
/// &store,
|
||||
/// store.engine(),
|
||||
/// r#"
|
||||
/// (module
|
||||
/// (import "" "" (func $debug (param i32 f32 i64 f64)))
|
||||
@@ -409,7 +410,7 @@ impl Func {
|
||||
/// call $debug))
|
||||
/// "#,
|
||||
/// )?;
|
||||
/// let instance = Instance::new(&module, &[debug.into()])?;
|
||||
/// let instance = Instance::new(&store, &module, &[debug.into()])?;
|
||||
/// let foo = instance.get_func("foo").unwrap().get0::<()>()?;
|
||||
/// foo()?;
|
||||
/// # Ok(())
|
||||
@@ -453,7 +454,7 @@ impl Func {
|
||||
/// Ok(())
|
||||
/// });
|
||||
/// let module = Module::new(
|
||||
/// &store,
|
||||
/// store.engine(),
|
||||
/// r#"
|
||||
/// (module
|
||||
/// (import "" "" (func $log_str (param i32 i32)))
|
||||
@@ -465,7 +466,7 @@ impl Func {
|
||||
/// (data (i32.const 4) "Hello, world!"))
|
||||
/// "#,
|
||||
/// )?;
|
||||
/// let instance = Instance::new(&module, &[log_str.into()])?;
|
||||
/// let instance = Instance::new(&store, &module, &[log_str.into()])?;
|
||||
/// let foo = instance.get_func("foo").unwrap().get0::<()>()?;
|
||||
/// foo()?;
|
||||
/// # Ok(())
|
||||
@@ -479,13 +480,7 @@ impl Func {
|
||||
pub fn ty(&self) -> FuncType {
|
||||
// Signatures should always be registered in the store's registry of
|
||||
// shared signatures, so we should be able to unwrap safely here.
|
||||
let sig = self
|
||||
.instance
|
||||
.store
|
||||
.compiler()
|
||||
.signatures()
|
||||
.lookup_wasm(self.export.signature)
|
||||
.expect("failed to lookup signature");
|
||||
let sig = self.instance.store.lookup_signature(self.export.signature);
|
||||
|
||||
// This is only called with `Export::Function`, and since it's coming
|
||||
// from wasmtime_runtime itself we should support all the types coming
|
||||
@@ -495,25 +490,13 @@ impl Func {
|
||||
|
||||
/// Returns the number of parameters that this function takes.
|
||||
pub fn param_arity(&self) -> usize {
|
||||
self.instance
|
||||
.store
|
||||
.compiler()
|
||||
.signatures()
|
||||
.lookup_wasm(self.export.signature)
|
||||
.expect("failed to lookup signature")
|
||||
.params
|
||||
.len()
|
||||
let sig = self.instance.store.lookup_signature(self.export.signature);
|
||||
sig.params.len()
|
||||
}
|
||||
|
||||
/// Returns the number of results this function produces.
|
||||
pub fn result_arity(&self) -> usize {
|
||||
let sig = self
|
||||
.instance
|
||||
.store
|
||||
.compiler()
|
||||
.signatures()
|
||||
.lookup_wasm(self.export.signature)
|
||||
.expect("failed to lookup signature");
|
||||
let sig = self.instance.store.lookup_signature(self.export.signature);
|
||||
sig.returns.len()
|
||||
}
|
||||
|
||||
@@ -749,7 +732,7 @@ pub(crate) fn catch_traps(
|
||||
wasmtime_runtime::catch_traps(
|
||||
vmctx,
|
||||
store.engine().config().max_wasm_stack,
|
||||
|addr| store.compiler().is_in_jit_code(addr),
|
||||
|addr| store.is_in_jit_code(addr),
|
||||
signalhandler.as_deref(),
|
||||
closure,
|
||||
)
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
use crate::trampoline::StoreInstanceHandle;
|
||||
use crate::{Export, Extern, Func, Global, Memory, Module, Store, Table, Trap};
|
||||
use crate::{Engine, Export, Extern, Func, Global, Memory, Module, Store, Table, Trap};
|
||||
use anyhow::{bail, Error, Result};
|
||||
use std::any::Any;
|
||||
use std::mem;
|
||||
use wasmtime_environ::EntityIndex;
|
||||
use wasmtime_jit::{CompiledModule, Resolver};
|
||||
use wasmtime_runtime::{InstantiationError, SignatureRegistry, VMContext, VMFunctionBody};
|
||||
use wasmtime_runtime::{InstantiationError, VMContext, VMFunctionBody};
|
||||
|
||||
struct SimpleResolver<'a> {
|
||||
imports: &'a [Extern],
|
||||
@@ -23,7 +23,6 @@ fn instantiate(
|
||||
store: &Store,
|
||||
compiled_module: &CompiledModule,
|
||||
imports: &[Extern],
|
||||
sig_registry: &SignatureRegistry,
|
||||
host: Box<dyn Any>,
|
||||
) -> Result<StoreInstanceHandle, Error> {
|
||||
// For now we have a restriction that the `Store` that we're working
|
||||
@@ -47,8 +46,9 @@ fn instantiate(
|
||||
let instance = unsafe {
|
||||
let instance = compiled_module.instantiate(
|
||||
&mut resolver,
|
||||
sig_registry,
|
||||
&mut store.signatures_mut(),
|
||||
config.memory_creator.as_ref().map(|a| a as _),
|
||||
store.interrupts().clone(),
|
||||
host,
|
||||
)?;
|
||||
|
||||
@@ -120,6 +120,7 @@ fn instantiate(
|
||||
#[derive(Clone)]
|
||||
pub struct Instance {
|
||||
pub(crate) handle: StoreInstanceHandle,
|
||||
store: Store,
|
||||
module: Module,
|
||||
}
|
||||
|
||||
@@ -177,19 +178,19 @@ impl Instance {
|
||||
/// [inst]: https://webassembly.github.io/spec/core/exec/modules.html#exec-instantiation
|
||||
/// [issue]: https://github.com/bytecodealliance/wasmtime/issues/727
|
||||
/// [`ExternType`]: crate::ExternType
|
||||
pub fn new(module: &Module, imports: &[Extern]) -> Result<Instance, Error> {
|
||||
let store = module.store();
|
||||
pub fn new(store: &Store, module: &Module, imports: &[Extern]) -> Result<Instance, Error> {
|
||||
if !Engine::same(store.engine(), module.engine()) {
|
||||
bail!("cross-`Engine` instantiation is not currently supported");
|
||||
}
|
||||
|
||||
let info = module.register_frame_info();
|
||||
let handle = instantiate(
|
||||
store,
|
||||
module.compiled_module(),
|
||||
imports,
|
||||
store.compiler().signatures(),
|
||||
Box::new(info),
|
||||
)?;
|
||||
store.register_jit_code(module.compiled_module().jit_code_ranges());
|
||||
|
||||
let handle = instantiate(store, module.compiled_module(), imports, Box::new(info))?;
|
||||
|
||||
Ok(Instance {
|
||||
handle,
|
||||
store: store.clone(),
|
||||
module: module.clone(),
|
||||
})
|
||||
}
|
||||
@@ -199,7 +200,7 @@ impl Instance {
|
||||
/// This is the [`Store`] that generally serves as a sort of global cache
|
||||
/// for various instance-related things.
|
||||
pub fn store(&self) -> &Store {
|
||||
self.module.store()
|
||||
&self.store
|
||||
}
|
||||
|
||||
/// Returns the list of exported items from this [`Instance`].
|
||||
|
||||
@@ -150,7 +150,7 @@ impl Linker {
|
||||
/// (data (global.get 0) "foo")
|
||||
/// )
|
||||
/// "#;
|
||||
/// let module = Module::new(&store, wat)?;
|
||||
/// let module = Module::new(store.engine(), wat)?;
|
||||
/// linker.instantiate(&module)?;
|
||||
/// # Ok(())
|
||||
/// # }
|
||||
@@ -203,7 +203,7 @@ impl Linker {
|
||||
/// (import "host" "log_str" (func (param i32 i32)))
|
||||
/// )
|
||||
/// "#;
|
||||
/// let module = Module::new(&store, wat)?;
|
||||
/// let module = Module::new(store.engine(), wat)?;
|
||||
/// linker.instantiate(&module)?;
|
||||
/// # Ok(())
|
||||
/// # }
|
||||
@@ -241,7 +241,7 @@ impl Linker {
|
||||
///
|
||||
/// // Instantiate a small instance...
|
||||
/// let wat = r#"(module (func (export "run") ))"#;
|
||||
/// let module = Module::new(&store, wat)?;
|
||||
/// let module = Module::new(store.engine(), wat)?;
|
||||
/// let instance = linker.instantiate(&module)?;
|
||||
///
|
||||
/// // ... and inform the linker that the name of this instance is
|
||||
@@ -257,7 +257,7 @@ impl Linker {
|
||||
/// )
|
||||
/// )
|
||||
/// "#;
|
||||
/// let module = Module::new(&store, wat)?;
|
||||
/// let module = Module::new(store.engine(), wat)?;
|
||||
/// let instance = linker.instantiate(&module)?;
|
||||
/// # Ok(())
|
||||
/// # }
|
||||
@@ -312,7 +312,7 @@ impl Linker {
|
||||
/// // this instance is `instance1`. This defines the `instance1::run` name
|
||||
/// // for our next module to use.
|
||||
/// let wat = r#"(module (func (export "run") ))"#;
|
||||
/// let module = Module::new(&store, wat)?;
|
||||
/// let module = Module::new(store.engine(), wat)?;
|
||||
/// linker.module("instance1", &module)?;
|
||||
///
|
||||
/// let wat = r#"
|
||||
@@ -323,7 +323,7 @@ impl Linker {
|
||||
/// )
|
||||
/// )
|
||||
/// "#;
|
||||
/// let module = Module::new(&store, wat)?;
|
||||
/// let module = Module::new(store.engine(), wat)?;
|
||||
/// let instance = linker.instantiate(&module)?;
|
||||
/// # Ok(())
|
||||
/// # }
|
||||
@@ -350,7 +350,7 @@ impl Linker {
|
||||
/// )
|
||||
/// )
|
||||
/// "#;
|
||||
/// let module = Module::new(&store, wat)?;
|
||||
/// let module = Module::new(store.engine(), wat)?;
|
||||
/// linker.module("commander", &module)?;
|
||||
/// let run = linker.get_default("")?.get0::<()>()?;
|
||||
/// run()?;
|
||||
@@ -369,7 +369,7 @@ impl Linker {
|
||||
/// )
|
||||
/// )
|
||||
/// "#;
|
||||
/// let module = Module::new(&store, wat)?;
|
||||
/// let module = Module::new(store.engine(), wat)?;
|
||||
/// linker.module("", &module)?;
|
||||
/// let count = linker.get_one_by_name("", "run")?.into_func().unwrap().get0::<i32>()?()?;
|
||||
/// assert_eq!(count, 0, "a Command should get a fresh instance on each invocation");
|
||||
@@ -400,11 +400,12 @@ impl Linker {
|
||||
for export in module.exports() {
|
||||
if let Some(func_ty) = export.ty().func() {
|
||||
let imports = self.compute_imports(module)?;
|
||||
let store = self.store.clone();
|
||||
let module = module.clone();
|
||||
let export_name = export.name().to_owned();
|
||||
let func = Func::new(&self.store, func_ty.clone(), move |_, params, results| {
|
||||
// Create a new instance for this command execution.
|
||||
let instance = Instance::new(&module, &imports)?;
|
||||
let instance = Instance::new(&store, &module, &imports)?;
|
||||
|
||||
// `unwrap()` everything here because we know the instance contains a
|
||||
// function export with the given name and signature because we're
|
||||
@@ -560,7 +561,7 @@ impl Linker {
|
||||
/// (import "host" "double" (func (param i32) (result i32)))
|
||||
/// )
|
||||
/// "#;
|
||||
/// let module = Module::new(&store, wat)?;
|
||||
/// let module = Module::new(store.engine(), wat)?;
|
||||
/// linker.instantiate(&module)?;
|
||||
/// # Ok(())
|
||||
/// # }
|
||||
@@ -568,7 +569,7 @@ impl Linker {
|
||||
pub fn instantiate(&self, module: &Module) -> Result<Instance> {
|
||||
let imports = self.compute_imports(module)?;
|
||||
|
||||
Instance::new(module, &imports)
|
||||
Instance::new(&self.store, module, &imports)
|
||||
}
|
||||
|
||||
fn compute_imports(&self, module: &Module) -> Result<Vec<Extern>> {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
use crate::frame_info::GlobalFrameInfoRegistration;
|
||||
use crate::runtime::Store;
|
||||
use crate::runtime::Engine;
|
||||
use crate::types::{EntityType, ExportType, ExternType, ImportType};
|
||||
use anyhow::{Error, Result};
|
||||
use std::path::Path;
|
||||
@@ -23,6 +23,8 @@ use wasmtime_jit::CompiledModule;
|
||||
/// compiling the original wasm module only once with a single [`Module`]
|
||||
/// instance.
|
||||
///
|
||||
/// The `Module` is threadsafe and safe to share accross threads.
|
||||
///
|
||||
/// ## Modules and `Clone`
|
||||
///
|
||||
/// Using `clone` on a `Module` is a cheap operation. It will not create an
|
||||
@@ -38,8 +40,8 @@ use wasmtime_jit::CompiledModule;
|
||||
/// ```no_run
|
||||
/// # use wasmtime::*;
|
||||
/// # fn main() -> anyhow::Result<()> {
|
||||
/// let store = Store::default();
|
||||
/// let module = Module::from_file(&store, "path/to/foo.wasm")?;
|
||||
/// let engine = Engine::default();
|
||||
/// let module = Module::from_file(&engine, "path/to/foo.wasm")?;
|
||||
/// # Ok(())
|
||||
/// # }
|
||||
/// ```
|
||||
@@ -49,9 +51,9 @@ use wasmtime_jit::CompiledModule;
|
||||
/// ```no_run
|
||||
/// # use wasmtime::*;
|
||||
/// # fn main() -> anyhow::Result<()> {
|
||||
/// let store = Store::default();
|
||||
/// let engine = Engine::default();
|
||||
/// // Now we're using the WebAssembly text extension: `.wat`!
|
||||
/// let module = Module::from_file(&store, "path/to/foo.wat")?;
|
||||
/// let module = Module::from_file(&engine, "path/to/foo.wat")?;
|
||||
/// # Ok(())
|
||||
/// # }
|
||||
/// ```
|
||||
@@ -62,12 +64,12 @@ use wasmtime_jit::CompiledModule;
|
||||
/// ```no_run
|
||||
/// # use wasmtime::*;
|
||||
/// # fn main() -> anyhow::Result<()> {
|
||||
/// let store = Store::default();
|
||||
/// let engine = Engine::default();
|
||||
/// # let wasm_bytes: Vec<u8> = Vec::new();
|
||||
/// let module = Module::new(&store, &wasm_bytes)?;
|
||||
/// let module = Module::new(&engine, &wasm_bytes)?;
|
||||
///
|
||||
/// // It also works with the text format!
|
||||
/// let module = Module::new(&store, "(module (func))")?;
|
||||
/// let module = Module::new(&engine, "(module (func))")?;
|
||||
/// # Ok(())
|
||||
/// # }
|
||||
/// ```
|
||||
@@ -75,13 +77,9 @@ use wasmtime_jit::CompiledModule;
|
||||
/// [`Config`]: crate::Config
|
||||
#[derive(Clone)]
|
||||
pub struct Module {
|
||||
inner: Arc<ModuleInner>,
|
||||
}
|
||||
|
||||
struct ModuleInner {
|
||||
store: Store,
|
||||
compiled: CompiledModule,
|
||||
frame_info_registration: Mutex<Option<Option<Arc<GlobalFrameInfoRegistration>>>>,
|
||||
engine: Engine,
|
||||
compiled: Arc<CompiledModule>,
|
||||
frame_info_registration: Arc<Mutex<Option<Option<Arc<GlobalFrameInfoRegistration>>>>>,
|
||||
}
|
||||
|
||||
impl Module {
|
||||
@@ -103,12 +101,7 @@ impl Module {
|
||||
/// compilation of a module.
|
||||
///
|
||||
/// The WebAssembly binary will be decoded and validated. It will also be
|
||||
/// compiled according to the configuration of the provided `store` and
|
||||
/// cached in this type.
|
||||
///
|
||||
/// The provided `store` is a global cache for compiled resources as well as
|
||||
/// configuration for what wasm features are enabled. It's recommended to
|
||||
/// share a `store` among modules if possible.
|
||||
/// compiled according to the configuration of the provided `engine`.
|
||||
///
|
||||
/// # Errors
|
||||
///
|
||||
@@ -121,7 +114,7 @@ impl Module {
|
||||
/// * Implementation-specific limits were exceeded with a valid binary (for
|
||||
/// example too many locals)
|
||||
/// * The wasm binary may use features that are not enabled in the
|
||||
/// configuration of `store`
|
||||
/// configuration of `enging`
|
||||
/// * If the `wat` feature is enabled and the input is text, then it may be
|
||||
/// rejected if it fails to parse.
|
||||
///
|
||||
@@ -138,9 +131,9 @@ impl Module {
|
||||
/// ```no_run
|
||||
/// # use wasmtime::*;
|
||||
/// # fn main() -> anyhow::Result<()> {
|
||||
/// # let store = Store::default();
|
||||
/// # let engine = Engine::default();
|
||||
/// # let wasm_bytes: Vec<u8> = Vec::new();
|
||||
/// let module = Module::new(&store, &wasm_bytes)?;
|
||||
/// let module = Module::new(&engine, &wasm_bytes)?;
|
||||
/// # Ok(())
|
||||
/// # }
|
||||
/// ```
|
||||
@@ -151,25 +144,28 @@ impl Module {
|
||||
/// ```
|
||||
/// # use wasmtime::*;
|
||||
/// # fn main() -> anyhow::Result<()> {
|
||||
/// # let store = Store::default();
|
||||
/// let module = Module::new(&store, "(module (func))")?;
|
||||
/// # let engine = Engine::default();
|
||||
/// let module = Module::new(&engine, "(module (func))")?;
|
||||
/// # Ok(())
|
||||
/// # }
|
||||
/// ```
|
||||
pub fn new(store: &Store, bytes: impl AsRef<[u8]>) -> Result<Module> {
|
||||
pub fn new(engine: &Engine, bytes: impl AsRef<[u8]>) -> Result<Module> {
|
||||
#[cfg(feature = "wat")]
|
||||
let bytes = wat::parse_bytes(bytes.as_ref())?;
|
||||
Module::from_binary(store, bytes.as_ref())
|
||||
Module::from_binary(engine, bytes.as_ref())
|
||||
}
|
||||
|
||||
/// Creates a new WebAssembly `Module` from the given in-memory `binary`
|
||||
/// data. The provided `name` will be used in traps/backtrace details.
|
||||
///
|
||||
/// See [`Module::new`] for other details.
|
||||
pub fn new_with_name(store: &Store, bytes: impl AsRef<[u8]>, name: &str) -> Result<Module> {
|
||||
let mut module = Module::new(store, bytes.as_ref())?;
|
||||
let inner = Arc::get_mut(&mut module.inner).unwrap();
|
||||
Arc::get_mut(inner.compiled.module_mut()).unwrap().name = Some(name.to_string());
|
||||
pub fn new_with_name(engine: &Engine, bytes: impl AsRef<[u8]>, name: &str) -> Result<Module> {
|
||||
let mut module = Module::new(engine, bytes.as_ref())?;
|
||||
Arc::get_mut(&mut module.compiled)
|
||||
.unwrap()
|
||||
.module_mut()
|
||||
.expect("mutable module")
|
||||
.name = Some(name.to_string());
|
||||
Ok(module)
|
||||
}
|
||||
|
||||
@@ -185,8 +181,8 @@ impl Module {
|
||||
/// ```no_run
|
||||
/// # use wasmtime::*;
|
||||
/// # fn main() -> anyhow::Result<()> {
|
||||
/// let store = Store::default();
|
||||
/// let module = Module::from_file(&store, "./path/to/foo.wasm")?;
|
||||
/// let engine = Engine::default();
|
||||
/// let module = Module::from_file(&engine, "./path/to/foo.wasm")?;
|
||||
/// # Ok(())
|
||||
/// # }
|
||||
/// ```
|
||||
@@ -196,17 +192,17 @@ impl Module {
|
||||
/// ```no_run
|
||||
/// # use wasmtime::*;
|
||||
/// # fn main() -> anyhow::Result<()> {
|
||||
/// # let store = Store::default();
|
||||
/// let module = Module::from_file(&store, "./path/to/foo.wat")?;
|
||||
/// # let engine = Engine::default();
|
||||
/// let module = Module::from_file(&engine, "./path/to/foo.wat")?;
|
||||
/// # Ok(())
|
||||
/// # }
|
||||
/// ```
|
||||
pub fn from_file(store: &Store, file: impl AsRef<Path>) -> Result<Module> {
|
||||
pub fn from_file(engine: &Engine, file: impl AsRef<Path>) -> Result<Module> {
|
||||
#[cfg(feature = "wat")]
|
||||
let wasm = wat::parse_file(file)?;
|
||||
#[cfg(not(feature = "wat"))]
|
||||
let wasm = std::fs::read(file)?;
|
||||
Module::new(store, &wasm)
|
||||
Module::new(engine, &wasm)
|
||||
}
|
||||
|
||||
/// Creates a new WebAssembly `Module` from the given in-memory `binary`
|
||||
@@ -223,9 +219,9 @@ impl Module {
|
||||
/// ```
|
||||
/// # use wasmtime::*;
|
||||
/// # fn main() -> anyhow::Result<()> {
|
||||
/// # let store = Store::default();
|
||||
/// # let engine = Engine::default();
|
||||
/// let wasm = b"\0asm\x01\0\0\0";
|
||||
/// let module = Module::from_binary(&store, wasm)?;
|
||||
/// let module = Module::from_binary(&engine, wasm)?;
|
||||
/// # Ok(())
|
||||
/// # }
|
||||
/// ```
|
||||
@@ -235,17 +231,17 @@ impl Module {
|
||||
/// ```
|
||||
/// # use wasmtime::*;
|
||||
/// # fn main() -> anyhow::Result<()> {
|
||||
/// # let store = Store::default();
|
||||
/// assert!(Module::from_binary(&store, b"(module)").is_err());
|
||||
/// # let engine = Engine::default();
|
||||
/// assert!(Module::from_binary(&engine, b"(module)").is_err());
|
||||
/// # Ok(())
|
||||
/// # }
|
||||
/// ```
|
||||
pub fn from_binary(store: &Store, binary: &[u8]) -> Result<Module> {
|
||||
Module::validate(store, binary)?;
|
||||
pub fn from_binary(engine: &Engine, binary: &[u8]) -> Result<Module> {
|
||||
Module::validate(engine, binary)?;
|
||||
// Note that the call to `from_binary_unchecked` here should be ok
|
||||
// because we previously validated the binary, meaning we're guaranteed
|
||||
// to pass a valid binary for `store`.
|
||||
unsafe { Module::from_binary_unchecked(store, binary) }
|
||||
// to pass a valid binary for `engine`.
|
||||
unsafe { Module::from_binary_unchecked(engine, binary) }
|
||||
}
|
||||
|
||||
/// Creates a new WebAssembly `Module` from the given in-memory `binary`
|
||||
@@ -257,7 +253,7 @@ impl Module {
|
||||
/// WebAssembly. The WebAssembly binary is not validated for
|
||||
/// correctness and it is simply assumed as valid.
|
||||
///
|
||||
/// For more information about creation of a module and the `store` argument
|
||||
/// For more information about creation of a module and the `engine` argument
|
||||
/// see the documentation of [`Module::new`].
|
||||
///
|
||||
/// # Unsafety
|
||||
@@ -275,17 +271,17 @@ impl Module {
|
||||
/// While this assumes that the binary is valid it still needs to actually
|
||||
/// be somewhat valid for decoding purposes, and the basics of decoding can
|
||||
/// still fail.
|
||||
pub unsafe fn from_binary_unchecked(store: &Store, binary: &[u8]) -> Result<Module> {
|
||||
Module::compile(store, binary)
|
||||
pub unsafe fn from_binary_unchecked(engine: &Engine, binary: &[u8]) -> Result<Module> {
|
||||
Module::compile(engine, binary)
|
||||
}
|
||||
|
||||
/// Validates `binary` input data as a WebAssembly binary given the
|
||||
/// configuration in `store`.
|
||||
/// configuration in `engine`.
|
||||
///
|
||||
/// This function will perform a speedy validation of the `binary` input
|
||||
/// WebAssembly module (which is in [binary form][binary], the text format
|
||||
/// is not accepted by this function) and return either `Ok` or `Err`
|
||||
/// depending on the results of validation. The `store` argument indicates
|
||||
/// depending on the results of validation. The `engine` argument indicates
|
||||
/// configuration for WebAssembly features, for example, which are used to
|
||||
/// indicate what should be valid and what shouldn't be.
|
||||
///
|
||||
@@ -299,29 +295,23 @@ impl Module {
|
||||
/// validation issue will be returned.
|
||||
///
|
||||
/// [binary]: https://webassembly.github.io/spec/core/binary/index.html
|
||||
pub fn validate(store: &Store, binary: &[u8]) -> Result<()> {
|
||||
let config = store.engine().config().validating_config.clone();
|
||||
pub fn validate(engine: &Engine, binary: &[u8]) -> Result<()> {
|
||||
let config = engine.config().validating_config.clone();
|
||||
validate(binary, Some(config)).map_err(Error::new)
|
||||
}
|
||||
|
||||
unsafe fn compile(store: &Store, binary: &[u8]) -> Result<Self> {
|
||||
let compiled = CompiledModule::new(
|
||||
&mut store.compiler_mut(),
|
||||
binary,
|
||||
&*store.engine().config().profiler,
|
||||
)?;
|
||||
unsafe fn compile(engine: &Engine, binary: &[u8]) -> Result<Self> {
|
||||
let compiled = CompiledModule::new(engine.compiler(), binary, &*engine.config().profiler)?;
|
||||
|
||||
Ok(Module {
|
||||
inner: Arc::new(ModuleInner {
|
||||
store: store.clone(),
|
||||
compiled,
|
||||
frame_info_registration: Mutex::new(None),
|
||||
}),
|
||||
engine: engine.clone(),
|
||||
compiled: Arc::new(compiled),
|
||||
frame_info_registration: Arc::new(Mutex::new(None)),
|
||||
})
|
||||
}
|
||||
|
||||
pub(crate) fn compiled_module(&self) -> &CompiledModule {
|
||||
&self.inner.compiled
|
||||
&self.compiled
|
||||
}
|
||||
|
||||
/// Returns identifier/name that this [`Module`] has. This name
|
||||
@@ -336,20 +326,20 @@ impl Module {
|
||||
/// ```
|
||||
/// # use wasmtime::*;
|
||||
/// # fn main() -> anyhow::Result<()> {
|
||||
/// # let store = Store::default();
|
||||
/// let module = Module::new(&store, "(module $foo)")?;
|
||||
/// # let engine = Engine::default();
|
||||
/// let module = Module::new(&engine, "(module $foo)")?;
|
||||
/// assert_eq!(module.name(), Some("foo"));
|
||||
///
|
||||
/// let module = Module::new(&store, "(module)")?;
|
||||
/// let module = Module::new(&engine, "(module)")?;
|
||||
/// assert_eq!(module.name(), None);
|
||||
///
|
||||
/// let module = Module::new_with_name(&store, "(module)", "bar")?;
|
||||
/// let module = Module::new_with_name(&engine, "(module)", "bar")?;
|
||||
/// assert_eq!(module.name(), Some("bar"));
|
||||
/// # Ok(())
|
||||
/// # }
|
||||
/// ```
|
||||
pub fn name(&self) -> Option<&str> {
|
||||
self.inner.compiled.module().name.as_deref()
|
||||
self.compiled.module().name.as_deref()
|
||||
}
|
||||
|
||||
/// Returns the list of imports that this [`Module`] has and must be
|
||||
@@ -371,8 +361,8 @@ impl Module {
|
||||
/// ```
|
||||
/// # use wasmtime::*;
|
||||
/// # fn main() -> anyhow::Result<()> {
|
||||
/// # let store = Store::default();
|
||||
/// let module = Module::new(&store, "(module)")?;
|
||||
/// # let engine = Engine::default();
|
||||
/// let module = Module::new(&engine, "(module)")?;
|
||||
/// assert_eq!(module.imports().len(), 0);
|
||||
/// # Ok(())
|
||||
/// # }
|
||||
@@ -383,13 +373,13 @@ impl Module {
|
||||
/// ```
|
||||
/// # use wasmtime::*;
|
||||
/// # fn main() -> anyhow::Result<()> {
|
||||
/// # let store = Store::default();
|
||||
/// # let engine = Engine::default();
|
||||
/// let wat = r#"
|
||||
/// (module
|
||||
/// (import "host" "foo" (func))
|
||||
/// )
|
||||
/// "#;
|
||||
/// let module = Module::new(&store, wat)?;
|
||||
/// let module = Module::new(&engine, wat)?;
|
||||
/// assert_eq!(module.imports().len(), 1);
|
||||
/// let import = module.imports().next().unwrap();
|
||||
/// assert_eq!(import.module(), "host");
|
||||
@@ -404,7 +394,7 @@ impl Module {
|
||||
pub fn imports<'module>(
|
||||
&'module self,
|
||||
) -> impl ExactSizeIterator<Item = ImportType<'module>> + 'module {
|
||||
let module = self.inner.compiled.module_ref();
|
||||
let module = self.compiled.module();
|
||||
module
|
||||
.imports
|
||||
.iter()
|
||||
@@ -429,8 +419,8 @@ impl Module {
|
||||
/// ```
|
||||
/// # use wasmtime::*;
|
||||
/// # fn main() -> anyhow::Result<()> {
|
||||
/// # let store = Store::default();
|
||||
/// let module = Module::new(&store, "(module)")?;
|
||||
/// # let engine = Engine::default();
|
||||
/// let module = Module::new(&engine, "(module)")?;
|
||||
/// assert!(module.exports().next().is_none());
|
||||
/// # Ok(())
|
||||
/// # }
|
||||
@@ -441,14 +431,14 @@ impl Module {
|
||||
/// ```
|
||||
/// # use wasmtime::*;
|
||||
/// # fn main() -> anyhow::Result<()> {
|
||||
/// # let store = Store::default();
|
||||
/// # let engine = Engine::default();
|
||||
/// let wat = r#"
|
||||
/// (module
|
||||
/// (func (export "foo"))
|
||||
/// (memory (export "memory") 1)
|
||||
/// )
|
||||
/// "#;
|
||||
/// let module = Module::new(&store, wat)?;
|
||||
/// let module = Module::new(&engine, wat)?;
|
||||
/// assert_eq!(module.exports().len(), 2);
|
||||
///
|
||||
/// let mut exports = module.exports();
|
||||
@@ -471,7 +461,7 @@ impl Module {
|
||||
pub fn exports<'module>(
|
||||
&'module self,
|
||||
) -> impl ExactSizeIterator<Item = ExportType<'module>> + 'module {
|
||||
let module = self.inner.compiled.module_ref();
|
||||
let module = self.compiled.module();
|
||||
module.exports.iter().map(move |(name, entity_index)| {
|
||||
let r#type = EntityType::new(entity_index, module);
|
||||
ExportType::new(name, r#type)
|
||||
@@ -489,8 +479,8 @@ impl Module {
|
||||
/// ```
|
||||
/// # use wasmtime::*;
|
||||
/// # fn main() -> anyhow::Result<()> {
|
||||
/// # let store = Store::default();
|
||||
/// let module = Module::new(&store, "(module)")?;
|
||||
/// # let engine = Engine::default();
|
||||
/// let module = Module::new(&engine, "(module)")?;
|
||||
/// assert!(module.get_export("foo").is_none());
|
||||
/// # Ok(())
|
||||
/// # }
|
||||
@@ -501,14 +491,14 @@ impl Module {
|
||||
/// ```
|
||||
/// # use wasmtime::*;
|
||||
/// # fn main() -> anyhow::Result<()> {
|
||||
/// # let store = Store::default();
|
||||
/// # let engine = Engine::default();
|
||||
/// let wat = r#"
|
||||
/// (module
|
||||
/// (func (export "foo"))
|
||||
/// (memory (export "memory") 1)
|
||||
/// )
|
||||
/// "#;
|
||||
/// let module = Module::new(&store, wat)?;
|
||||
/// let module = Module::new(&engine, wat)?;
|
||||
/// let foo = module.get_export("foo");
|
||||
/// assert!(foo.is_some());
|
||||
///
|
||||
@@ -522,26 +512,31 @@ impl Module {
|
||||
/// # }
|
||||
/// ```
|
||||
pub fn get_export<'module>(&'module self, name: &'module str) -> Option<ExternType> {
|
||||
let module = self.inner.compiled.module_ref();
|
||||
let module = self.compiled.module();
|
||||
let entity_index = module.exports.get(name)?;
|
||||
Some(EntityType::new(entity_index, module).extern_type())
|
||||
}
|
||||
|
||||
/// Returns the [`Store`] that this [`Module`] was compiled into.
|
||||
pub fn store(&self) -> &Store {
|
||||
&self.inner.store
|
||||
/// Returns the [`Engine`] that this [`Module`] was compiled by.
|
||||
pub fn engine(&self) -> &Engine {
|
||||
&self.engine
|
||||
}
|
||||
|
||||
/// Register this module's stack frame information into the global scope.
|
||||
///
|
||||
/// This is required to ensure that any traps can be properly symbolicated.
|
||||
pub(crate) fn register_frame_info(&self) -> Option<Arc<GlobalFrameInfoRegistration>> {
|
||||
let mut info = self.inner.frame_info_registration.lock().unwrap();
|
||||
let mut info = self.frame_info_registration.lock().unwrap();
|
||||
if let Some(info) = &*info {
|
||||
return info.clone();
|
||||
}
|
||||
let ret = super::frame_info::register(&self.inner.compiled).map(Arc::new);
|
||||
let ret = super::frame_info::register(&self.compiled).map(Arc::new);
|
||||
*info = Some(ret.clone());
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
fn _assert_send_sync() {
|
||||
fn _assert<T: Send + Sync>() {}
|
||||
_assert::<Module>();
|
||||
}
|
||||
|
||||
@@ -14,11 +14,12 @@ use std::rc::{Rc, Weak};
|
||||
use std::sync::Arc;
|
||||
use wasmparser::{OperatorValidatorConfig, ValidatingParserConfig};
|
||||
use wasmtime_environ::settings::{self, Configurable};
|
||||
use wasmtime_environ::{CacheConfig, Tunables};
|
||||
use wasmtime_environ::{ir, wasm, CacheConfig, Tunables};
|
||||
use wasmtime_jit::{native, CompilationStrategy, Compiler};
|
||||
use wasmtime_profiling::{JitDumpAgent, NullProfilerAgent, ProfilingAgent, VTuneAgent};
|
||||
use wasmtime_runtime::{
|
||||
debug_builtins, InstanceHandle, RuntimeMemoryCreator, SignalHandler, VMExternRef, VMInterrupts,
|
||||
debug_builtins, InstanceHandle, RuntimeMemoryCreator, SignalHandler, SignatureRegistry,
|
||||
VMExternRef, VMInterrupts, VMSharedSignatureIndex,
|
||||
};
|
||||
|
||||
// Runtime Environment
|
||||
@@ -571,6 +572,16 @@ impl Config {
|
||||
cmp::max(guard_size, self.tunables.static_memory_offset_guard_size);
|
||||
self
|
||||
}
|
||||
|
||||
fn build_compiler(&self) -> Compiler {
|
||||
let isa = native::builder().finish(settings::Flags::new(self.flags.clone()));
|
||||
Compiler::new(
|
||||
isa,
|
||||
self.strategy,
|
||||
self.cache_config.clone(),
|
||||
self.tunables.clone(),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fn round_up_to_pages(val: u64) -> u64 {
|
||||
@@ -687,9 +698,14 @@ pub enum ProfilingStrategy {
|
||||
/// You can create an engine with default configuration settings using
|
||||
/// `Engine::default()`. Be sure to consult the documentation of [`Config`] for
|
||||
/// default settings.
|
||||
#[derive(Default, Clone)]
|
||||
#[derive(Clone)]
|
||||
pub struct Engine {
|
||||
config: Arc<Config>,
|
||||
inner: Arc<EngineInner>,
|
||||
}
|
||||
|
||||
struct EngineInner {
|
||||
config: Config,
|
||||
compiler: Compiler,
|
||||
}
|
||||
|
||||
impl Engine {
|
||||
@@ -698,13 +714,31 @@ impl Engine {
|
||||
pub fn new(config: &Config) -> Engine {
|
||||
debug_builtins::ensure_exported();
|
||||
Engine {
|
||||
config: Arc::new(config.clone()),
|
||||
inner: Arc::new(EngineInner {
|
||||
config: config.clone(),
|
||||
compiler: config.build_compiler(),
|
||||
}),
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the configuration settings that this engine is using.
|
||||
pub fn config(&self) -> &Config {
|
||||
&self.config
|
||||
&self.inner.config
|
||||
}
|
||||
|
||||
pub(crate) fn compiler(&self) -> &Compiler {
|
||||
&self.inner.compiler
|
||||
}
|
||||
|
||||
/// Returns whether the engine `a` and `b` refer to the same configuration.
|
||||
pub fn same(a: &Engine, b: &Engine) -> bool {
|
||||
Arc::ptr_eq(&a.inner, &b.inner)
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for Engine {
|
||||
fn default() -> Engine {
|
||||
Engine::new(&Config::default())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -734,9 +768,11 @@ pub struct Store {
|
||||
|
||||
pub(crate) struct StoreInner {
|
||||
engine: Engine,
|
||||
compiler: RefCell<Compiler>,
|
||||
interrupts: Arc<VMInterrupts>,
|
||||
signatures: RefCell<SignatureRegistry>,
|
||||
instances: RefCell<Vec<InstanceHandle>>,
|
||||
signal_handler: RefCell<Option<Box<SignalHandler<'static>>>>,
|
||||
jit_code_ranges: RefCell<Vec<(usize, usize)>>,
|
||||
host_info: RefCell<HashMap<HostInfoKey, Rc<RefCell<dyn Any>>>>,
|
||||
}
|
||||
|
||||
@@ -769,19 +805,14 @@ impl Store {
|
||||
// each one that's not relevant just won't do anything.
|
||||
wasmtime_runtime::init_traps();
|
||||
|
||||
let isa = native::builder().finish(settings::Flags::new(engine.config.flags.clone()));
|
||||
let compiler = Compiler::new(
|
||||
isa,
|
||||
engine.config.strategy,
|
||||
engine.config.cache_config.clone(),
|
||||
engine.config.tunables.clone(),
|
||||
);
|
||||
Store {
|
||||
inner: Rc::new(StoreInner {
|
||||
engine: engine.clone(),
|
||||
compiler: RefCell::new(compiler),
|
||||
interrupts: Arc::new(Default::default()),
|
||||
signatures: RefCell::new(Default::default()),
|
||||
instances: RefCell::new(Vec::new()),
|
||||
signal_handler: RefCell::new(None),
|
||||
jit_code_ranges: RefCell::new(Vec::new()),
|
||||
host_info: RefCell::new(HashMap::new()),
|
||||
}),
|
||||
}
|
||||
@@ -798,15 +829,61 @@ impl Store {
|
||||
|
||||
/// Returns an optional reference to a ['RuntimeMemoryCreator']
|
||||
pub(crate) fn memory_creator(&self) -> Option<&dyn RuntimeMemoryCreator> {
|
||||
self.engine().config.memory_creator.as_ref().map(|x| x as _)
|
||||
self.engine()
|
||||
.config()
|
||||
.memory_creator
|
||||
.as_ref()
|
||||
.map(|x| x as _)
|
||||
}
|
||||
|
||||
pub(crate) fn compiler(&self) -> std::cell::Ref<'_, Compiler> {
|
||||
self.inner.compiler.borrow()
|
||||
pub(crate) fn lookup_signature(&self, sig_index: VMSharedSignatureIndex) -> wasm::WasmFuncType {
|
||||
self.inner
|
||||
.signatures
|
||||
.borrow()
|
||||
.lookup_wasm(sig_index)
|
||||
.expect("failed to lookup signature")
|
||||
}
|
||||
|
||||
pub(crate) fn compiler_mut(&self) -> std::cell::RefMut<'_, Compiler> {
|
||||
self.inner.compiler.borrow_mut()
|
||||
pub(crate) fn register_signature(
|
||||
&self,
|
||||
wasm_sig: wasm::WasmFuncType,
|
||||
native: ir::Signature,
|
||||
) -> VMSharedSignatureIndex {
|
||||
self.inner
|
||||
.signatures
|
||||
.borrow_mut()
|
||||
.register(wasm_sig, native)
|
||||
}
|
||||
|
||||
pub(crate) fn signatures_mut(&self) -> std::cell::RefMut<'_, SignatureRegistry> {
|
||||
self.inner.signatures.borrow_mut()
|
||||
}
|
||||
|
||||
/// Returns whether or not the given address falls within the JIT code
|
||||
/// managed by the compiler
|
||||
pub(crate) fn is_in_jit_code(&self, addr: usize) -> bool {
|
||||
self.inner
|
||||
.jit_code_ranges
|
||||
.borrow()
|
||||
.iter()
|
||||
.any(|(start, end)| *start <= addr && addr < *end)
|
||||
}
|
||||
|
||||
pub(crate) fn register_jit_code(&self, mut ranges: impl Iterator<Item = (usize, usize)>) {
|
||||
// Checking of we already registered JIT code ranges by searching
|
||||
// first range start.
|
||||
match ranges.next() {
|
||||
None => (),
|
||||
Some(first) => {
|
||||
if !self.is_in_jit_code(first.0) {
|
||||
// The range is not registered -- add all ranges (including
|
||||
// first one) to the jit_code_ranges.
|
||||
let mut jit_code_ranges = self.inner.jit_code_ranges.borrow_mut();
|
||||
jit_code_ranges.push(first);
|
||||
jit_code_ranges.extend(ranges);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) unsafe fn add_instance(&self, handle: InstanceHandle) -> StoreInstanceHandle {
|
||||
@@ -875,6 +952,10 @@ impl Store {
|
||||
self.inner.signal_handler.borrow_mut()
|
||||
}
|
||||
|
||||
pub(crate) fn interrupts(&self) -> &Arc<VMInterrupts> {
|
||||
&self.inner.interrupts
|
||||
}
|
||||
|
||||
/// Returns whether the stores `a` and `b` refer to the same underlying
|
||||
/// `Store`.
|
||||
///
|
||||
@@ -946,10 +1027,10 @@ impl Store {
|
||||
/// let interrupt_handle = store.interrupt_handle()?;
|
||||
///
|
||||
/// // Compile and instantiate a small example with an infinite loop.
|
||||
/// let module = Module::new(&store, r#"
|
||||
/// let module = Module::new(&engine, r#"
|
||||
/// (func (export "run") (loop br 0))
|
||||
/// "#)?;
|
||||
/// let instance = Instance::new(&module, &[])?;
|
||||
/// let instance = Instance::new(&store, &module, &[])?;
|
||||
/// let run = instance
|
||||
/// .get_func("run")
|
||||
/// .ok_or(anyhow::format_err!("failed to find `run` function export"))?
|
||||
@@ -967,9 +1048,9 @@ impl Store {
|
||||
/// # }
|
||||
/// ```
|
||||
pub fn interrupt_handle(&self) -> Result<InterruptHandle> {
|
||||
if self.engine().config.tunables.interruptable {
|
||||
if self.engine().config().tunables.interruptable {
|
||||
Ok(InterruptHandle {
|
||||
interrupts: self.compiler().interrupts().clone(),
|
||||
interrupts: self.interrupts().clone(),
|
||||
})
|
||||
} else {
|
||||
bail!("interrupts aren't enabled for this `Store`")
|
||||
@@ -1052,47 +1133,47 @@ mod tests {
|
||||
let mut cfg = Config::new();
|
||||
cfg.cranelift_opt_level(OptLevel::None)
|
||||
.cache_config_load(&config_path)?;
|
||||
let store = Store::new(&Engine::new(&cfg));
|
||||
Module::new(&store, "(module (func))")?;
|
||||
assert_eq!(store.engine().config.cache_config.cache_hits(), 0);
|
||||
assert_eq!(store.engine().config.cache_config.cache_misses(), 1);
|
||||
Module::new(&store, "(module (func))")?;
|
||||
assert_eq!(store.engine().config.cache_config.cache_hits(), 1);
|
||||
assert_eq!(store.engine().config.cache_config.cache_misses(), 1);
|
||||
let engine = Engine::new(&cfg);
|
||||
Module::new(&engine, "(module (func))")?;
|
||||
assert_eq!(engine.config().cache_config.cache_hits(), 0);
|
||||
assert_eq!(engine.config().cache_config.cache_misses(), 1);
|
||||
Module::new(&engine, "(module (func))")?;
|
||||
assert_eq!(engine.config().cache_config.cache_hits(), 1);
|
||||
assert_eq!(engine.config().cache_config.cache_misses(), 1);
|
||||
|
||||
let mut cfg = Config::new();
|
||||
cfg.cranelift_opt_level(OptLevel::Speed)
|
||||
.cache_config_load(&config_path)?;
|
||||
let store = Store::new(&Engine::new(&cfg));
|
||||
Module::new(&store, "(module (func))")?;
|
||||
assert_eq!(store.engine().config.cache_config.cache_hits(), 0);
|
||||
assert_eq!(store.engine().config.cache_config.cache_misses(), 1);
|
||||
Module::new(&store, "(module (func))")?;
|
||||
assert_eq!(store.engine().config.cache_config.cache_hits(), 1);
|
||||
assert_eq!(store.engine().config.cache_config.cache_misses(), 1);
|
||||
let engine = Engine::new(&cfg);
|
||||
Module::new(&engine, "(module (func))")?;
|
||||
assert_eq!(engine.config().cache_config.cache_hits(), 0);
|
||||
assert_eq!(engine.config().cache_config.cache_misses(), 1);
|
||||
Module::new(&engine, "(module (func))")?;
|
||||
assert_eq!(engine.config().cache_config.cache_hits(), 1);
|
||||
assert_eq!(engine.config().cache_config.cache_misses(), 1);
|
||||
|
||||
let mut cfg = Config::new();
|
||||
cfg.cranelift_opt_level(OptLevel::SpeedAndSize)
|
||||
.cache_config_load(&config_path)?;
|
||||
let store = Store::new(&Engine::new(&cfg));
|
||||
Module::new(&store, "(module (func))")?;
|
||||
assert_eq!(store.engine().config.cache_config.cache_hits(), 0);
|
||||
assert_eq!(store.engine().config.cache_config.cache_misses(), 1);
|
||||
Module::new(&store, "(module (func))")?;
|
||||
assert_eq!(store.engine().config.cache_config.cache_hits(), 1);
|
||||
assert_eq!(store.engine().config.cache_config.cache_misses(), 1);
|
||||
let engine = Engine::new(&cfg);
|
||||
Module::new(&engine, "(module (func))")?;
|
||||
assert_eq!(engine.config().cache_config.cache_hits(), 0);
|
||||
assert_eq!(engine.config().cache_config.cache_misses(), 1);
|
||||
Module::new(&engine, "(module (func))")?;
|
||||
assert_eq!(engine.config().cache_config.cache_hits(), 1);
|
||||
assert_eq!(engine.config().cache_config.cache_misses(), 1);
|
||||
|
||||
// FIXME(#1523) need debuginfo on aarch64 before we run this test there
|
||||
if !cfg!(target_arch = "aarch64") {
|
||||
let mut cfg = Config::new();
|
||||
cfg.debug_info(true).cache_config_load(&config_path)?;
|
||||
let store = Store::new(&Engine::new(&cfg));
|
||||
Module::new(&store, "(module (func))")?;
|
||||
assert_eq!(store.engine().config.cache_config.cache_hits(), 0);
|
||||
assert_eq!(store.engine().config.cache_config.cache_misses(), 1);
|
||||
Module::new(&store, "(module (func))")?;
|
||||
assert_eq!(store.engine().config.cache_config.cache_hits(), 1);
|
||||
assert_eq!(store.engine().config.cache_config.cache_misses(), 1);
|
||||
let engine = Engine::new(&cfg);
|
||||
Module::new(&engine, "(module (func))")?;
|
||||
assert_eq!(engine.config().cache_config.cache_hits(), 0);
|
||||
assert_eq!(engine.config().cache_config.cache_misses(), 1);
|
||||
Module::new(&engine, "(module (func))")?;
|
||||
assert_eq!(engine.config().cache_config.cache_hits(), 1);
|
||||
assert_eq!(engine.config().cache_config.cache_misses(), 1);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
|
||||
@@ -32,25 +32,20 @@ pub(crate) fn create_handle(
|
||||
.local
|
||||
.signatures
|
||||
.values()
|
||||
.map(|(wasm, native)| {
|
||||
store
|
||||
.compiler()
|
||||
.signatures()
|
||||
.register(wasm.clone(), native.clone())
|
||||
})
|
||||
.map(|(wasm, native)| store.register_signature(wasm.clone(), native.clone()))
|
||||
.collect::<PrimaryMap<_, _>>();
|
||||
|
||||
unsafe {
|
||||
let handle = InstanceHandle::new(
|
||||
Arc::new(module),
|
||||
Arc::new(()),
|
||||
finished_functions.into_boxed_slice(),
|
||||
trampolines,
|
||||
imports,
|
||||
store.memory_creator(),
|
||||
signatures.into_boxed_slice(),
|
||||
None,
|
||||
state,
|
||||
store.compiler().interrupts().clone(),
|
||||
store.interrupts().clone(),
|
||||
)?;
|
||||
Ok(store.add_instance(handle))
|
||||
}
|
||||
|
||||
@@ -247,10 +247,7 @@ pub fn create_handle_with_function(
|
||||
mem::size_of::<u128>(),
|
||||
)?;
|
||||
assert!(relocations.is_empty());
|
||||
let sig_id = store
|
||||
.compiler()
|
||||
.signatures()
|
||||
.register(ft.to_wasm_func_type(), sig);
|
||||
let sig_id = store.register_signature(ft.to_wasm_func_type(), sig);
|
||||
trampolines.insert(sig_id, trampoline);
|
||||
|
||||
// Next up we wrap everything up into an `InstanceHandle` by publishing our
|
||||
@@ -300,10 +297,7 @@ pub unsafe fn create_handle_with_raw_function(
|
||||
.exports
|
||||
.insert("trampoline".to_string(), EntityIndex::Function(func_id));
|
||||
finished_functions.push(func);
|
||||
let sig_id = store
|
||||
.compiler()
|
||||
.signatures()
|
||||
.register(ft.to_wasm_func_type(), sig);
|
||||
let sig_id = store.register_signature(ft.to_wasm_func_type(), sig);
|
||||
trampolines.insert(sig_id, trampoline);
|
||||
|
||||
create_handle(module, store, finished_functions, trampolines, state)
|
||||
|
||||
Reference in New Issue
Block a user