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:
1
Cargo.lock
generated
1
Cargo.lock
generated
@@ -2381,6 +2381,7 @@ dependencies = [
|
|||||||
"cc",
|
"cc",
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
"indexmap",
|
"indexmap",
|
||||||
|
"lazy_static",
|
||||||
"libc",
|
"libc",
|
||||||
"memoffset",
|
"memoffset",
|
||||||
"more-asserts",
|
"more-asserts",
|
||||||
|
|||||||
@@ -43,6 +43,10 @@ is now enabled by default.
|
|||||||
|
|
||||||
[#1667](https://github.com/bytecodealliance/wasmtime/pull/1667)
|
[#1667](https://github.com/bytecodealliance/wasmtime/pull/1667)
|
||||||
|
|
||||||
|
The Rust API does not require a store provided during `Module::new` operation. The `Module` can be send accross threads and instantiate for a specific store. The `Instance::new` now requires the store.
|
||||||
|
|
||||||
|
[#1761](https://github.com/bytecodealliance/wasmtime/pull/1761)
|
||||||
|
|
||||||
--------------------------------------------------------------------------------
|
--------------------------------------------------------------------------------
|
||||||
|
|
||||||
## 0.16.0
|
## 0.16.0
|
||||||
|
|||||||
@@ -244,6 +244,7 @@ WASM_API_EXTERN own wasmtime_error_t *wasmtime_global_set(
|
|||||||
// instance is returned), or an instance can be returned (meaning no error or
|
// instance is returned), or an instance can be returned (meaning no error or
|
||||||
// trap is returned).
|
// trap is returned).
|
||||||
WASM_API_EXTERN own wasmtime_error_t *wasmtime_instance_new(
|
WASM_API_EXTERN own wasmtime_error_t *wasmtime_instance_new(
|
||||||
|
wasm_store_t *store,
|
||||||
const wasm_module_t *module,
|
const wasm_module_t *module,
|
||||||
const wasm_extern_t* const imports[],
|
const wasm_extern_t* const imports[],
|
||||||
size_t num_imports,
|
size_t num_imports,
|
||||||
|
|||||||
@@ -36,19 +36,10 @@ pub unsafe extern "C" fn wasm_instance_new(
|
|||||||
imports: *const Box<wasm_extern_t>,
|
imports: *const Box<wasm_extern_t>,
|
||||||
result: Option<&mut *mut wasm_trap_t>,
|
result: Option<&mut *mut wasm_trap_t>,
|
||||||
) -> Option<Box<wasm_instance_t>> {
|
) -> Option<Box<wasm_instance_t>> {
|
||||||
let store = &store.store;
|
|
||||||
let module = &wasm_module.module.borrow();
|
|
||||||
if !Store::same(&store, module.store()) {
|
|
||||||
if let Some(result) = result {
|
|
||||||
let trap = Trap::new("wasm_store_t must match store in wasm_module_t");
|
|
||||||
let trap = Box::new(wasm_trap_t::new(store, trap));
|
|
||||||
*result = Box::into_raw(trap);
|
|
||||||
}
|
|
||||||
return None;
|
|
||||||
}
|
|
||||||
let mut instance = ptr::null_mut();
|
let mut instance = ptr::null_mut();
|
||||||
let mut trap = ptr::null_mut();
|
let mut trap = ptr::null_mut();
|
||||||
let err = wasmtime_instance_new(
|
let err = wasmtime_instance_new(
|
||||||
|
store,
|
||||||
wasm_module,
|
wasm_module,
|
||||||
imports,
|
imports,
|
||||||
wasm_module.imports.len(),
|
wasm_module.imports.len(),
|
||||||
@@ -60,7 +51,7 @@ pub unsafe extern "C" fn wasm_instance_new(
|
|||||||
assert!(trap.is_null());
|
assert!(trap.is_null());
|
||||||
assert!(instance.is_null());
|
assert!(instance.is_null());
|
||||||
if let Some(result) = result {
|
if let Some(result) = result {
|
||||||
*result = Box::into_raw(err.to_trap(store));
|
*result = Box::into_raw(err.to_trap(&store.store));
|
||||||
}
|
}
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
@@ -83,6 +74,7 @@ pub unsafe extern "C" fn wasm_instance_new(
|
|||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub unsafe extern "C" fn wasmtime_instance_new(
|
pub unsafe extern "C" fn wasmtime_instance_new(
|
||||||
|
store: &wasm_store_t,
|
||||||
module: &wasm_module_t,
|
module: &wasm_module_t,
|
||||||
imports: *const Box<wasm_extern_t>,
|
imports: *const Box<wasm_extern_t>,
|
||||||
num_imports: usize,
|
num_imports: usize,
|
||||||
@@ -90,6 +82,7 @@ pub unsafe extern "C" fn wasmtime_instance_new(
|
|||||||
trap_ptr: &mut *mut wasm_trap_t,
|
trap_ptr: &mut *mut wasm_trap_t,
|
||||||
) -> Option<Box<wasmtime_error_t>> {
|
) -> Option<Box<wasmtime_error_t>> {
|
||||||
_wasmtime_instance_new(
|
_wasmtime_instance_new(
|
||||||
|
store,
|
||||||
module,
|
module,
|
||||||
std::slice::from_raw_parts(imports, num_imports),
|
std::slice::from_raw_parts(imports, num_imports),
|
||||||
instance_ptr,
|
instance_ptr,
|
||||||
@@ -98,11 +91,13 @@ pub unsafe extern "C" fn wasmtime_instance_new(
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn _wasmtime_instance_new(
|
fn _wasmtime_instance_new(
|
||||||
|
store: &wasm_store_t,
|
||||||
module: &wasm_module_t,
|
module: &wasm_module_t,
|
||||||
imports: &[Box<wasm_extern_t>],
|
imports: &[Box<wasm_extern_t>],
|
||||||
instance_ptr: &mut *mut wasm_instance_t,
|
instance_ptr: &mut *mut wasm_instance_t,
|
||||||
trap_ptr: &mut *mut wasm_trap_t,
|
trap_ptr: &mut *mut wasm_trap_t,
|
||||||
) -> Option<Box<wasmtime_error_t>> {
|
) -> Option<Box<wasmtime_error_t>> {
|
||||||
|
let store = &store.store;
|
||||||
let imports = imports
|
let imports = imports
|
||||||
.iter()
|
.iter()
|
||||||
.map(|import| match &import.which {
|
.map(|import| match &import.which {
|
||||||
@@ -114,8 +109,8 @@ fn _wasmtime_instance_new(
|
|||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
let module = &module.module.borrow();
|
let module = &module.module.borrow();
|
||||||
handle_instantiate(
|
handle_instantiate(
|
||||||
module.store(),
|
store,
|
||||||
Instance::new(module, &imports),
|
Instance::new(store, module, &imports),
|
||||||
instance_ptr,
|
instance_ptr,
|
||||||
trap_ptr,
|
trap_ptr,
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,9 +1,10 @@
|
|||||||
use crate::host_ref::HostRef;
|
use crate::host_ref::HostRef;
|
||||||
use crate::{handle_result, wasmtime_error_t};
|
use crate::{
|
||||||
use crate::{wasm_byte_vec_t, wasm_exporttype_vec_t, wasm_importtype_vec_t};
|
handle_result, wasm_byte_vec_t, wasm_exporttype_t, wasm_exporttype_vec_t, wasm_importtype_t,
|
||||||
use crate::{wasm_exporttype_t, wasm_importtype_t, wasm_store_t};
|
wasm_importtype_vec_t, wasm_store_t, wasmtime_error_t,
|
||||||
|
};
|
||||||
use std::ptr;
|
use std::ptr;
|
||||||
use wasmtime::Module;
|
use wasmtime::{Engine, Module};
|
||||||
|
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
@@ -21,6 +22,14 @@ impl wasm_module_t {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[repr(C)]
|
||||||
|
#[derive(Clone)]
|
||||||
|
pub struct wasm_shared_module_t {
|
||||||
|
module: Module,
|
||||||
|
}
|
||||||
|
|
||||||
|
wasmtime_c_api_macros::declare_own!(wasm_shared_module_t);
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
pub extern "C" fn wasm_module_new(
|
pub extern "C" fn wasm_module_new(
|
||||||
store: &wasm_store_t,
|
store: &wasm_store_t,
|
||||||
@@ -44,7 +53,7 @@ pub extern "C" fn wasmtime_module_new(
|
|||||||
) -> Option<Box<wasmtime_error_t>> {
|
) -> Option<Box<wasmtime_error_t>> {
|
||||||
let binary = binary.as_slice();
|
let binary = binary.as_slice();
|
||||||
let store = &store.store;
|
let store = &store.store;
|
||||||
handle_result(Module::from_binary(store, binary), |module| {
|
handle_result(Module::from_binary(store.engine(), binary), |module| {
|
||||||
let imports = module
|
let imports = module
|
||||||
.imports()
|
.imports()
|
||||||
.map(|i| wasm_importtype_t::new(i.module().to_owned(), i.name().to_owned(), i.ty()))
|
.map(|i| wasm_importtype_t::new(i.module().to_owned(), i.name().to_owned(), i.ty()))
|
||||||
@@ -73,8 +82,7 @@ pub extern "C" fn wasmtime_module_validate(
|
|||||||
binary: &wasm_byte_vec_t,
|
binary: &wasm_byte_vec_t,
|
||||||
) -> Option<Box<wasmtime_error_t>> {
|
) -> Option<Box<wasmtime_error_t>> {
|
||||||
let binary = binary.as_slice();
|
let binary = binary.as_slice();
|
||||||
let store = &store.store;
|
handle_result(Module::validate(store.store.engine(), binary), |()| {})
|
||||||
handle_result(Module::validate(store, binary), |()| {})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
@@ -96,3 +104,34 @@ pub extern "C" fn wasm_module_imports(module: &wasm_module_t, out: &mut wasm_imp
|
|||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
out.set_buffer(buffer);
|
out.set_buffer(buffer);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
pub extern "C" fn wasm_module_share(module: &wasm_module_t) -> Box<wasm_shared_module_t> {
|
||||||
|
Box::new(wasm_shared_module_t {
|
||||||
|
module: module.module.borrow().clone(),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
pub extern "C" fn wasm_module_obtain(
|
||||||
|
store: &wasm_store_t,
|
||||||
|
shared_module: &wasm_shared_module_t,
|
||||||
|
) -> Option<Box<wasm_module_t>> {
|
||||||
|
let module = shared_module.module.clone();
|
||||||
|
if !Engine::same(store.store.engine(), module.engine()) {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
let imports = module
|
||||||
|
.imports()
|
||||||
|
.map(|i| wasm_importtype_t::new(i.module().to_owned(), i.name().to_owned(), i.ty()))
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
let exports = module
|
||||||
|
.exports()
|
||||||
|
.map(|e| wasm_exporttype_t::new(e.name().to_owned(), e.ty()))
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
Some(Box::new(wasm_module_t {
|
||||||
|
module: HostRef::new(&store.store, module),
|
||||||
|
imports,
|
||||||
|
exports,
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
|||||||
@@ -56,7 +56,7 @@ pub fn instantiate_with_config(wasm: &[u8], config: Config) {
|
|||||||
let store = Store::new(&engine);
|
let store = Store::new(&engine);
|
||||||
|
|
||||||
log_wasm(wasm);
|
log_wasm(wasm);
|
||||||
let module = match Module::new(&store, wasm) {
|
let module = match Module::new(&engine, wasm) {
|
||||||
Ok(module) => module,
|
Ok(module) => module,
|
||||||
Err(_) => return,
|
Err(_) => return,
|
||||||
};
|
};
|
||||||
@@ -75,7 +75,7 @@ pub fn instantiate_with_config(wasm: &[u8], config: Config) {
|
|||||||
// aren't caught during validation or compilation. For example, an imported
|
// aren't caught during validation or compilation. For example, an imported
|
||||||
// table might not have room for an element segment that we want to
|
// table might not have room for an element segment that we want to
|
||||||
// initialize into it.
|
// initialize into it.
|
||||||
let _result = Instance::new(&module, &imports);
|
let _result = Instance::new(&store, &module, &imports);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Compile the Wasm buffer, and implicitly fail if we have an unexpected
|
/// Compile the Wasm buffer, and implicitly fail if we have an unexpected
|
||||||
@@ -88,9 +88,8 @@ pub fn compile(wasm: &[u8], strategy: Strategy) {
|
|||||||
crate::init_fuzzing();
|
crate::init_fuzzing();
|
||||||
|
|
||||||
let engine = Engine::new(&crate::fuzz_default_config(strategy).unwrap());
|
let engine = Engine::new(&crate::fuzz_default_config(strategy).unwrap());
|
||||||
let store = Store::new(&engine);
|
|
||||||
log_wasm(wasm);
|
log_wasm(wasm);
|
||||||
let _ = Module::new(&store, wasm);
|
let _ = Module::new(&engine, wasm);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Instantiate the given Wasm module with each `Config` and call all of its
|
/// Instantiate the given Wasm module with each `Config` and call all of its
|
||||||
@@ -128,7 +127,7 @@ pub fn differential_execution(
|
|||||||
let engine = Engine::new(config);
|
let engine = Engine::new(config);
|
||||||
let store = Store::new(&engine);
|
let store = Store::new(&engine);
|
||||||
|
|
||||||
let module = match Module::new(&store, &ttf.wasm) {
|
let module = match Module::new(&engine, &ttf.wasm) {
|
||||||
Ok(module) => module,
|
Ok(module) => module,
|
||||||
// The module might rely on some feature that our config didn't
|
// The module might rely on some feature that our config didn't
|
||||||
// enable or something like that.
|
// enable or something like that.
|
||||||
@@ -158,7 +157,7 @@ pub fn differential_execution(
|
|||||||
// aren't caught during validation or compilation. For example, an imported
|
// aren't caught during validation or compilation. For example, an imported
|
||||||
// table might not have room for an element segment that we want to
|
// table might not have room for an element segment that we want to
|
||||||
// initialize into it.
|
// initialize into it.
|
||||||
let instance = match Instance::new(&module, &imports) {
|
let instance = match Instance::new(&store, &module, &imports) {
|
||||||
Ok(instance) => instance,
|
Ok(instance) => instance,
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
eprintln!(
|
eprintln!(
|
||||||
@@ -304,7 +303,7 @@ pub fn make_api_calls(api: crate::generators::api::ApiCalls) {
|
|||||||
ApiCall::ModuleNew { id, wasm } => {
|
ApiCall::ModuleNew { id, wasm } => {
|
||||||
log::debug!("creating module: {}", id);
|
log::debug!("creating module: {}", id);
|
||||||
log_wasm(&wasm.wasm);
|
log_wasm(&wasm.wasm);
|
||||||
let module = match Module::new(store.as_ref().unwrap(), &wasm.wasm) {
|
let module = match Module::new(engine.as_ref().unwrap(), &wasm.wasm) {
|
||||||
Ok(m) => m,
|
Ok(m) => m,
|
||||||
Err(_) => continue,
|
Err(_) => continue,
|
||||||
};
|
};
|
||||||
@@ -324,7 +323,9 @@ pub fn make_api_calls(api: crate::generators::api::ApiCalls) {
|
|||||||
None => continue,
|
None => continue,
|
||||||
};
|
};
|
||||||
|
|
||||||
let imports = match dummy_imports(store.as_ref().unwrap(), module.imports()) {
|
let store = store.as_ref().unwrap();
|
||||||
|
|
||||||
|
let imports = match dummy_imports(store, module.imports()) {
|
||||||
Ok(imps) => imps,
|
Ok(imps) => imps,
|
||||||
Err(_) => {
|
Err(_) => {
|
||||||
// There are some value types that we can't synthesize a
|
// There are some value types that we can't synthesize a
|
||||||
@@ -338,7 +339,7 @@ pub fn make_api_calls(api: crate::generators::api::ApiCalls) {
|
|||||||
// aren't caught during validation or compilation. For example, an imported
|
// aren't caught during validation or compilation. For example, an imported
|
||||||
// table might not have room for an element segment that we want to
|
// table might not have room for an element segment that we want to
|
||||||
// initialize into it.
|
// initialize into it.
|
||||||
if let Ok(instance) = Instance::new(&module, &imports) {
|
if let Ok(instance) = Instance::new(store, &module, &imports) {
|
||||||
instances.insert(id, instance);
|
instances.insert(id, instance);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,10 +22,10 @@ impl CodeMemoryEntry {
|
|||||||
Ok(Self { mmap, registry })
|
Ok(Self { mmap, registry })
|
||||||
}
|
}
|
||||||
|
|
||||||
fn contains(&self, addr: usize) -> bool {
|
fn range(&self) -> (usize, usize) {
|
||||||
let start = self.mmap.as_ptr() as usize;
|
let start = self.mmap.as_ptr() as usize;
|
||||||
let end = start + self.mmap.len();
|
let end = start + self.mmap.len();
|
||||||
start <= addr && addr < end
|
(start, end)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -243,11 +243,10 @@ impl CodeMemory {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns whether any published segment of this code memory contains
|
/// Returns all published segment ranges.
|
||||||
/// `addr`.
|
pub fn published_ranges<'a>(&'a self) -> impl Iterator<Item = (usize, usize)> + 'a {
|
||||||
pub fn published_contains(&self, addr: usize) -> bool {
|
|
||||||
self.entries[..self.published]
|
self.entries[..self.published]
|
||||||
.iter()
|
.iter()
|
||||||
.any(|entry| entry.contains(addr))
|
.map(|entry| entry.range())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,20 +9,16 @@ use cranelift_codegen::Context;
|
|||||||
use cranelift_codegen::{binemit, ir};
|
use cranelift_codegen::{binemit, ir};
|
||||||
use cranelift_frontend::{FunctionBuilder, FunctionBuilderContext};
|
use cranelift_frontend::{FunctionBuilder, FunctionBuilderContext};
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::sync::Arc;
|
|
||||||
use wasmtime_debug::{emit_debugsections_image, DebugInfoData};
|
use wasmtime_debug::{emit_debugsections_image, DebugInfoData};
|
||||||
use wasmtime_environ::entity::{EntityRef, PrimaryMap};
|
use wasmtime_environ::entity::{EntityRef, PrimaryMap};
|
||||||
use wasmtime_environ::isa::{TargetFrontendConfig, TargetIsa};
|
use wasmtime_environ::isa::{TargetFrontendConfig, TargetIsa};
|
||||||
use wasmtime_environ::wasm::{DefinedFuncIndex, DefinedMemoryIndex, MemoryIndex};
|
use wasmtime_environ::wasm::{DefinedFuncIndex, DefinedMemoryIndex, MemoryIndex, SignatureIndex};
|
||||||
use wasmtime_environ::{
|
use wasmtime_environ::{
|
||||||
CacheConfig, CompileError, CompiledFunction, Compiler as _C, ModuleAddressMap,
|
CacheConfig, CompileError, CompiledFunction, Compiler as _C, ModuleAddressMap,
|
||||||
ModuleMemoryOffset, ModuleTranslation, ModuleVmctxInfo, Relocation, RelocationTarget,
|
ModuleMemoryOffset, ModuleTranslation, ModuleVmctxInfo, Relocation, RelocationTarget,
|
||||||
Relocations, Traps, Tunables, VMOffsets,
|
Relocations, Traps, Tunables, VMOffsets,
|
||||||
};
|
};
|
||||||
use wasmtime_runtime::{
|
use wasmtime_runtime::{InstantiationError, VMFunctionBody, VMTrampoline};
|
||||||
InstantiationError, SignatureRegistry, VMFunctionBody, VMInterrupts, VMSharedSignatureIndex,
|
|
||||||
VMTrampoline,
|
|
||||||
};
|
|
||||||
|
|
||||||
/// Select which kind of compilation to use.
|
/// Select which kind of compilation to use.
|
||||||
#[derive(Copy, Clone, Debug)]
|
#[derive(Copy, Clone, Debug)]
|
||||||
@@ -48,12 +44,9 @@ pub enum CompilationStrategy {
|
|||||||
/// TODO: Consider using cranelift-module.
|
/// TODO: Consider using cranelift-module.
|
||||||
pub struct Compiler {
|
pub struct Compiler {
|
||||||
isa: Box<dyn TargetIsa>,
|
isa: Box<dyn TargetIsa>,
|
||||||
code_memory: CodeMemory,
|
|
||||||
signatures: SignatureRegistry,
|
|
||||||
strategy: CompilationStrategy,
|
strategy: CompilationStrategy,
|
||||||
cache_config: CacheConfig,
|
cache_config: CacheConfig,
|
||||||
tunables: Tunables,
|
tunables: Tunables,
|
||||||
interrupts: Arc<VMInterrupts>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Compiler {
|
impl Compiler {
|
||||||
@@ -66,22 +59,25 @@ impl Compiler {
|
|||||||
) -> Self {
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
isa,
|
isa,
|
||||||
code_memory: CodeMemory::new(),
|
|
||||||
signatures: SignatureRegistry::new(),
|
|
||||||
strategy,
|
strategy,
|
||||||
cache_config,
|
cache_config,
|
||||||
tunables,
|
tunables,
|
||||||
interrupts: Arc::new(VMInterrupts::default()),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn _assert_compiler_send_sync() {
|
||||||
|
fn _assert<T: Send + Sync>() {}
|
||||||
|
_assert::<Compiler>();
|
||||||
|
}
|
||||||
|
|
||||||
#[allow(missing_docs)]
|
#[allow(missing_docs)]
|
||||||
pub struct Compilation {
|
pub struct Compilation {
|
||||||
|
pub code_memory: CodeMemory,
|
||||||
pub finished_functions: PrimaryMap<DefinedFuncIndex, *mut [VMFunctionBody]>,
|
pub finished_functions: PrimaryMap<DefinedFuncIndex, *mut [VMFunctionBody]>,
|
||||||
pub relocations: Relocations,
|
pub relocations: Relocations,
|
||||||
pub trampolines: HashMap<VMSharedSignatureIndex, VMTrampoline>,
|
pub trampolines: PrimaryMap<SignatureIndex, VMTrampoline>,
|
||||||
pub trampoline_relocations: HashMap<VMSharedSignatureIndex, Vec<Relocation>>,
|
pub trampoline_relocations: HashMap<SignatureIndex, Vec<Relocation>>,
|
||||||
pub jt_offsets: PrimaryMap<DefinedFuncIndex, ir::JumpTableOffsets>,
|
pub jt_offsets: PrimaryMap<DefinedFuncIndex, ir::JumpTableOffsets>,
|
||||||
pub dbg_image: Option<Vec<u8>>,
|
pub dbg_image: Option<Vec<u8>>,
|
||||||
pub traps: Traps,
|
pub traps: Traps,
|
||||||
@@ -89,6 +85,11 @@ pub struct Compilation {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Compiler {
|
impl Compiler {
|
||||||
|
/// Return the isa.
|
||||||
|
pub fn isa(&self) -> &dyn TargetIsa {
|
||||||
|
self.isa.as_ref()
|
||||||
|
}
|
||||||
|
|
||||||
/// Return the target's frontend configuration settings.
|
/// Return the target's frontend configuration settings.
|
||||||
pub fn frontend_config(&self) -> TargetFrontendConfig {
|
pub fn frontend_config(&self) -> TargetFrontendConfig {
|
||||||
self.isa.frontend_config()
|
self.isa.frontend_config()
|
||||||
@@ -99,17 +100,14 @@ impl Compiler {
|
|||||||
&self.tunables
|
&self.tunables
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return the handle by which to interrupt instances
|
|
||||||
pub fn interrupts(&self) -> &Arc<VMInterrupts> {
|
|
||||||
&self.interrupts
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Compile the given function bodies.
|
/// Compile the given function bodies.
|
||||||
pub(crate) fn compile<'data>(
|
pub(crate) fn compile<'data>(
|
||||||
&mut self,
|
&self,
|
||||||
translation: &ModuleTranslation,
|
translation: &ModuleTranslation,
|
||||||
debug_data: Option<DebugInfoData>,
|
debug_data: Option<DebugInfoData>,
|
||||||
) -> Result<Compilation, SetupError> {
|
) -> Result<Compilation, SetupError> {
|
||||||
|
let mut code_memory = CodeMemory::new();
|
||||||
|
|
||||||
let (compilation, relocations, address_transform, value_ranges, stack_slots, traps) =
|
let (compilation, relocations, address_transform, value_ranges, stack_slots, traps) =
|
||||||
match self.strategy {
|
match self.strategy {
|
||||||
// For now, interpret `Auto` as `Cranelift` since that's the most stable
|
// For now, interpret `Auto` as `Cranelift` since that's the most stable
|
||||||
@@ -135,7 +133,7 @@ impl Compiler {
|
|||||||
// Allocate all of the compiled functions into executable memory,
|
// Allocate all of the compiled functions into executable memory,
|
||||||
// copying over their contents.
|
// copying over their contents.
|
||||||
let finished_functions =
|
let finished_functions =
|
||||||
allocate_functions(&mut self.code_memory, &compilation).map_err(|message| {
|
allocate_functions(&mut code_memory, &compilation).map_err(|message| {
|
||||||
SetupError::Instantiate(InstantiationError::Resource(format!(
|
SetupError::Instantiate(InstantiationError::Resource(format!(
|
||||||
"failed to allocate memory for functions: {}",
|
"failed to allocate memory for functions: {}",
|
||||||
message
|
message
|
||||||
@@ -147,23 +145,17 @@ impl Compiler {
|
|||||||
// guarantees that all functions (including indirect ones through
|
// guarantees that all functions (including indirect ones through
|
||||||
// tables) have a trampoline when invoked through the wasmtime API.
|
// tables) have a trampoline when invoked through the wasmtime API.
|
||||||
let mut cx = FunctionBuilderContext::new();
|
let mut cx = FunctionBuilderContext::new();
|
||||||
let mut trampolines = HashMap::new();
|
let mut trampolines = PrimaryMap::new();
|
||||||
let mut trampoline_relocations = HashMap::new();
|
let mut trampoline_relocations = HashMap::new();
|
||||||
for (wasm_func_ty, native_sig) in translation.module.local.signatures.values() {
|
for (index, (_, native_sig)) in translation.module.local.signatures.iter() {
|
||||||
let index = self
|
|
||||||
.signatures
|
|
||||||
.register(wasm_func_ty.clone(), native_sig.clone());
|
|
||||||
if trampolines.contains_key(&index) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
let (trampoline, relocations) = make_trampoline(
|
let (trampoline, relocations) = make_trampoline(
|
||||||
&*self.isa,
|
&*self.isa,
|
||||||
&mut self.code_memory,
|
&mut code_memory,
|
||||||
&mut cx,
|
&mut cx,
|
||||||
native_sig,
|
native_sig,
|
||||||
std::mem::size_of::<u128>(),
|
std::mem::size_of::<u128>(),
|
||||||
)?;
|
)?;
|
||||||
trampolines.insert(index, trampoline);
|
trampolines.push(trampoline);
|
||||||
|
|
||||||
// Typically trampolines do not have relocations, so if one does
|
// Typically trampolines do not have relocations, so if one does
|
||||||
// show up be sure to log it in case anyone's listening and there's
|
// show up be sure to log it in case anyone's listening and there's
|
||||||
@@ -217,6 +209,7 @@ impl Compiler {
|
|||||||
let jt_offsets = compilation.get_jt_offsets();
|
let jt_offsets = compilation.get_jt_offsets();
|
||||||
|
|
||||||
Ok(Compilation {
|
Ok(Compilation {
|
||||||
|
code_memory,
|
||||||
finished_functions,
|
finished_functions,
|
||||||
relocations,
|
relocations,
|
||||||
trampolines,
|
trampolines,
|
||||||
@@ -227,22 +220,6 @@ impl Compiler {
|
|||||||
address_transform,
|
address_transform,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Make memory containing compiled code executable.
|
|
||||||
pub(crate) fn publish_compiled_code(&mut self) {
|
|
||||||
self.code_memory.publish(self.isa.as_ref());
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Shared signature registry.
|
|
||||||
pub fn signatures(&self) -> &SignatureRegistry {
|
|
||||||
&self.signatures
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns whether or not the given address falls within the JIT code
|
|
||||||
/// managed by the compiler
|
|
||||||
pub fn is_in_jit_code(&self, addr: usize) -> bool {
|
|
||||||
self.code_memory.published_contains(addr)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create a trampoline for invoking a function.
|
/// Create a trampoline for invoking a function.
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
//! `CompiledModule` to allow compiling and instantiating to be done as separate
|
//! `CompiledModule` to allow compiling and instantiating to be done as separate
|
||||||
//! steps.
|
//! steps.
|
||||||
|
|
||||||
|
use crate::code_memory::CodeMemory;
|
||||||
use crate::compiler::Compiler;
|
use crate::compiler::Compiler;
|
||||||
use crate::imports::resolve_imports;
|
use crate::imports::resolve_imports;
|
||||||
use crate::link::link_module;
|
use crate::link::link_module;
|
||||||
@@ -10,7 +11,6 @@ use crate::resolver::Resolver;
|
|||||||
use std::any::Any;
|
use std::any::Any;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::io::Write;
|
use std::io::Write;
|
||||||
use std::rc::Rc;
|
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
use wasmtime_debug::read_debuginfo;
|
use wasmtime_debug::read_debuginfo;
|
||||||
@@ -24,7 +24,7 @@ use wasmtime_profiling::ProfilingAgent;
|
|||||||
use wasmtime_runtime::VMInterrupts;
|
use wasmtime_runtime::VMInterrupts;
|
||||||
use wasmtime_runtime::{
|
use wasmtime_runtime::{
|
||||||
GdbJitImageRegistration, InstanceHandle, InstantiationError, RuntimeMemoryCreator,
|
GdbJitImageRegistration, InstanceHandle, InstantiationError, RuntimeMemoryCreator,
|
||||||
SignatureRegistry, VMFunctionBody, VMSharedSignatureIndex, VMTrampoline,
|
SignatureRegistry, VMFunctionBody, VMTrampoline,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// An error condition while setting up a wasm instance, be it validation,
|
/// An error condition while setting up a wasm instance, be it validation,
|
||||||
@@ -49,23 +49,33 @@ pub enum SetupError {
|
|||||||
DebugInfo(#[from] anyhow::Error),
|
DebugInfo(#[from] anyhow::Error),
|
||||||
}
|
}
|
||||||
|
|
||||||
/// This is similar to `CompiledModule`, but references the data initializers
|
struct FinishedFunctions(BoxedSlice<DefinedFuncIndex, *mut [VMFunctionBody]>);
|
||||||
/// from the wasm buffer rather than holding its own copy.
|
|
||||||
struct RawCompiledModule<'data> {
|
unsafe impl Send for FinishedFunctions {}
|
||||||
module: Module,
|
unsafe impl Sync for FinishedFunctions {}
|
||||||
finished_functions: BoxedSlice<DefinedFuncIndex, *mut [VMFunctionBody]>,
|
|
||||||
trampolines: HashMap<VMSharedSignatureIndex, VMTrampoline>,
|
/// Container for data needed for an Instance function to exist.
|
||||||
data_initializers: Box<[DataInitializer<'data>]>,
|
pub struct ModuleCode {
|
||||||
signatures: BoxedSlice<SignatureIndex, VMSharedSignatureIndex>,
|
code_memory: CodeMemory,
|
||||||
|
#[allow(dead_code)]
|
||||||
dbg_jit_registration: Option<GdbJitImageRegistration>,
|
dbg_jit_registration: Option<GdbJitImageRegistration>,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// A compiled wasm module, ready to be instantiated.
|
||||||
|
pub struct CompiledModule {
|
||||||
|
module: Arc<Module>,
|
||||||
|
code: Arc<ModuleCode>,
|
||||||
|
finished_functions: FinishedFunctions,
|
||||||
|
trampolines: PrimaryMap<SignatureIndex, VMTrampoline>,
|
||||||
|
data_initializers: Box<[OwnedDataInitializer]>,
|
||||||
traps: Traps,
|
traps: Traps,
|
||||||
address_transform: ModuleAddressMap,
|
address_transform: ModuleAddressMap,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'data> RawCompiledModule<'data> {
|
impl CompiledModule {
|
||||||
/// Create a new `RawCompiledModule` by compiling the wasm module in `data` and instatiating it.
|
/// Compile a data buffer into a `CompiledModule`, which may then be instantiated.
|
||||||
fn new(
|
pub fn new<'data>(
|
||||||
compiler: &mut Compiler,
|
compiler: &Compiler,
|
||||||
data: &'data [u8],
|
data: &'data [u8],
|
||||||
profiler: &dyn ProfilingAgent,
|
profiler: &dyn ProfilingAgent,
|
||||||
) -> Result<Self, SetupError> {
|
) -> Result<Self, SetupError> {
|
||||||
@@ -83,26 +93,24 @@ impl<'data> RawCompiledModule<'data> {
|
|||||||
|
|
||||||
let compilation = compiler.compile(&translation, debug_data)?;
|
let compilation = compiler.compile(&translation, debug_data)?;
|
||||||
|
|
||||||
link_module(&translation.module, &compilation);
|
let module = translation.module;
|
||||||
|
|
||||||
// Compute indices into the shared signature table.
|
link_module(&module, &compilation);
|
||||||
let signatures = {
|
|
||||||
let signature_registry = compiler.signatures();
|
|
||||||
translation
|
|
||||||
.module
|
|
||||||
.local
|
|
||||||
.signatures
|
|
||||||
.values()
|
|
||||||
.map(|(wasm, native)| signature_registry.register(wasm.clone(), native.clone()))
|
|
||||||
.collect::<PrimaryMap<_, _>>()
|
|
||||||
};
|
|
||||||
|
|
||||||
// Make all code compiled thus far executable.
|
// Make all code compiled thus far executable.
|
||||||
compiler.publish_compiled_code();
|
let mut code_memory = compilation.code_memory;
|
||||||
|
code_memory.publish(compiler.isa());
|
||||||
|
|
||||||
|
let data_initializers = translation
|
||||||
|
.data_initializers
|
||||||
|
.into_iter()
|
||||||
|
.map(OwnedDataInitializer::new)
|
||||||
|
.collect::<Vec<_>>()
|
||||||
|
.into_boxed_slice();
|
||||||
|
|
||||||
// Initialize profiler and load the wasm module
|
// Initialize profiler and load the wasm module
|
||||||
profiler.module_load(
|
profiler.module_load(
|
||||||
&translation.module,
|
&module,
|
||||||
&compilation.finished_functions,
|
&compilation.finished_functions,
|
||||||
compilation.dbg_image.as_deref(),
|
compilation.dbg_image.as_deref(),
|
||||||
);
|
);
|
||||||
@@ -116,82 +124,22 @@ impl<'data> RawCompiledModule<'data> {
|
|||||||
None
|
None
|
||||||
};
|
};
|
||||||
|
|
||||||
|
let finished_functions =
|
||||||
|
FinishedFunctions(compilation.finished_functions.into_boxed_slice());
|
||||||
|
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
module: translation.module,
|
module: Arc::new(module),
|
||||||
finished_functions: compilation.finished_functions.into_boxed_slice(),
|
code: Arc::new(ModuleCode {
|
||||||
trampolines: compilation.trampolines,
|
code_memory,
|
||||||
data_initializers: translation.data_initializers.into_boxed_slice(),
|
|
||||||
signatures: signatures.into_boxed_slice(),
|
|
||||||
dbg_jit_registration,
|
dbg_jit_registration,
|
||||||
|
}),
|
||||||
|
finished_functions,
|
||||||
|
trampolines: compilation.trampolines,
|
||||||
|
data_initializers,
|
||||||
traps: compilation.traps,
|
traps: compilation.traps,
|
||||||
address_transform: compilation.address_transform,
|
address_transform: compilation.address_transform,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/// A compiled wasm module, ready to be instantiated.
|
|
||||||
pub struct CompiledModule {
|
|
||||||
module: Arc<Module>,
|
|
||||||
finished_functions: BoxedSlice<DefinedFuncIndex, *mut [VMFunctionBody]>,
|
|
||||||
trampolines: HashMap<VMSharedSignatureIndex, VMTrampoline>,
|
|
||||||
data_initializers: Box<[OwnedDataInitializer]>,
|
|
||||||
signatures: BoxedSlice<SignatureIndex, VMSharedSignatureIndex>,
|
|
||||||
dbg_jit_registration: Option<Rc<GdbJitImageRegistration>>,
|
|
||||||
traps: Traps,
|
|
||||||
address_transform: ModuleAddressMap,
|
|
||||||
interrupts: Arc<VMInterrupts>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl CompiledModule {
|
|
||||||
/// Compile a data buffer into a `CompiledModule`, which may then be instantiated.
|
|
||||||
pub fn new<'data>(
|
|
||||||
compiler: &mut Compiler,
|
|
||||||
data: &'data [u8],
|
|
||||||
profiler: &dyn ProfilingAgent,
|
|
||||||
) -> Result<Self, SetupError> {
|
|
||||||
let raw = RawCompiledModule::<'data>::new(compiler, data, profiler)?;
|
|
||||||
|
|
||||||
Ok(Self::from_parts(
|
|
||||||
raw.module,
|
|
||||||
raw.finished_functions,
|
|
||||||
raw.trampolines,
|
|
||||||
raw.data_initializers
|
|
||||||
.iter()
|
|
||||||
.map(OwnedDataInitializer::new)
|
|
||||||
.collect::<Vec<_>>()
|
|
||||||
.into_boxed_slice(),
|
|
||||||
raw.signatures.clone(),
|
|
||||||
raw.dbg_jit_registration,
|
|
||||||
raw.traps,
|
|
||||||
raw.address_transform,
|
|
||||||
compiler.interrupts().clone(),
|
|
||||||
))
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Construct a `CompiledModule` from component parts.
|
|
||||||
pub fn from_parts(
|
|
||||||
module: Module,
|
|
||||||
finished_functions: BoxedSlice<DefinedFuncIndex, *mut [VMFunctionBody]>,
|
|
||||||
trampolines: HashMap<VMSharedSignatureIndex, VMTrampoline>,
|
|
||||||
data_initializers: Box<[OwnedDataInitializer]>,
|
|
||||||
signatures: BoxedSlice<SignatureIndex, VMSharedSignatureIndex>,
|
|
||||||
dbg_jit_registration: Option<GdbJitImageRegistration>,
|
|
||||||
traps: Traps,
|
|
||||||
address_transform: ModuleAddressMap,
|
|
||||||
interrupts: Arc<VMInterrupts>,
|
|
||||||
) -> Self {
|
|
||||||
Self {
|
|
||||||
module: Arc::new(module),
|
|
||||||
finished_functions,
|
|
||||||
trampolines,
|
|
||||||
data_initializers,
|
|
||||||
signatures,
|
|
||||||
dbg_jit_registration: dbg_jit_registration.map(Rc::new),
|
|
||||||
traps,
|
|
||||||
address_transform,
|
|
||||||
interrupts,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Crate an `Instance` from this `CompiledModule`.
|
/// Crate an `Instance` from this `CompiledModule`.
|
||||||
///
|
///
|
||||||
@@ -205,21 +153,41 @@ impl CompiledModule {
|
|||||||
pub unsafe fn instantiate(
|
pub unsafe fn instantiate(
|
||||||
&self,
|
&self,
|
||||||
resolver: &mut dyn Resolver,
|
resolver: &mut dyn Resolver,
|
||||||
sig_registry: &SignatureRegistry,
|
signature_registry: &mut SignatureRegistry,
|
||||||
mem_creator: Option<&dyn RuntimeMemoryCreator>,
|
mem_creator: Option<&dyn RuntimeMemoryCreator>,
|
||||||
|
interrupts: Arc<VMInterrupts>,
|
||||||
host_state: Box<dyn Any>,
|
host_state: Box<dyn Any>,
|
||||||
) -> Result<InstanceHandle, InstantiationError> {
|
) -> Result<InstanceHandle, InstantiationError> {
|
||||||
let imports = resolve_imports(&self.module, &sig_registry, resolver)?;
|
// Compute indices into the shared signature table.
|
||||||
|
let signatures = {
|
||||||
|
self.module
|
||||||
|
.local
|
||||||
|
.signatures
|
||||||
|
.values()
|
||||||
|
.map(|(wasm_sig, native)| {
|
||||||
|
signature_registry.register(wasm_sig.clone(), native.clone())
|
||||||
|
})
|
||||||
|
.collect::<PrimaryMap<_, _>>()
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut trampolines = HashMap::new();
|
||||||
|
for (i, trampoline) in self.trampolines.iter() {
|
||||||
|
trampolines.insert(signatures[i], trampoline.clone());
|
||||||
|
}
|
||||||
|
|
||||||
|
let finished_functions = self.finished_functions.0.clone();
|
||||||
|
|
||||||
|
let imports = resolve_imports(&self.module, signature_registry, resolver)?;
|
||||||
InstanceHandle::new(
|
InstanceHandle::new(
|
||||||
Arc::clone(&self.module),
|
self.module.clone(),
|
||||||
self.finished_functions.clone(),
|
self.code.clone(),
|
||||||
self.trampolines.clone(),
|
finished_functions,
|
||||||
|
trampolines,
|
||||||
imports,
|
imports,
|
||||||
mem_creator,
|
mem_creator,
|
||||||
self.signatures.clone(),
|
signatures.into_boxed_slice(),
|
||||||
self.dbg_jit_registration.as_ref().map(|r| Rc::clone(&r)),
|
|
||||||
host_state,
|
host_state,
|
||||||
self.interrupts.clone(),
|
interrupts,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -239,19 +207,14 @@ impl CompiledModule {
|
|||||||
&self.module
|
&self.module
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return a reference-counting pointer to a module.
|
/// Return a reference to a mutable module (if possible).
|
||||||
pub fn module_mut(&mut self) -> &mut Arc<Module> {
|
pub fn module_mut(&mut self) -> Option<&mut Module> {
|
||||||
&mut self.module
|
Arc::get_mut(&mut self.module)
|
||||||
}
|
|
||||||
|
|
||||||
/// Return a reference to a module.
|
|
||||||
pub fn module_ref(&self) -> &Module {
|
|
||||||
&self.module
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the map of all finished JIT functions compiled for this module
|
/// Returns the map of all finished JIT functions compiled for this module
|
||||||
pub fn finished_functions(&self) -> &BoxedSlice<DefinedFuncIndex, *mut [VMFunctionBody]> {
|
pub fn finished_functions(&self) -> &BoxedSlice<DefinedFuncIndex, *mut [VMFunctionBody]> {
|
||||||
&self.finished_functions
|
&self.finished_functions.0
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the a map for all traps in this module.
|
/// Returns the a map for all traps in this module.
|
||||||
@@ -263,6 +226,16 @@ impl CompiledModule {
|
|||||||
pub fn address_transform(&self) -> &ModuleAddressMap {
|
pub fn address_transform(&self) -> &ModuleAddressMap {
|
||||||
&self.address_transform
|
&self.address_transform
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns all ranges convered by JIT code.
|
||||||
|
pub fn jit_code_ranges<'a>(&'a self) -> impl Iterator<Item = (usize, usize)> + 'a {
|
||||||
|
self.code.code_memory.published_ranges()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns module's JIT code.
|
||||||
|
pub fn code(&self) -> &Arc<ModuleCode> {
|
||||||
|
&self.code
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Similar to `DataInitializer`, but owns its own copy of the data rather
|
/// Similar to `DataInitializer`, but owns its own copy of the data rather
|
||||||
@@ -276,7 +249,7 @@ pub struct OwnedDataInitializer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl OwnedDataInitializer {
|
impl OwnedDataInitializer {
|
||||||
fn new(borrowed: &DataInitializer<'_>) -> Self {
|
fn new(borrowed: DataInitializer<'_>) -> Self {
|
||||||
Self {
|
Self {
|
||||||
location: borrowed.location.clone(),
|
location: borrowed.location.clone(),
|
||||||
data: borrowed.data.to_vec().into_boxed_slice(),
|
data: borrowed.data.to_vec().into_boxed_slice(),
|
||||||
|
|||||||
@@ -22,7 +22,7 @@ pub fn link_module(module: &Module, compilation: &Compilation) {
|
|||||||
for (i, function_relocs) in compilation.trampoline_relocations.iter() {
|
for (i, function_relocs) in compilation.trampoline_relocations.iter() {
|
||||||
for r in function_relocs.iter() {
|
for r in function_relocs.iter() {
|
||||||
println!("tramopline relocation");
|
println!("tramopline relocation");
|
||||||
let body = compilation.trampolines[&i] as *const VMFunctionBody;
|
let body = compilation.trampolines[*i] as *const VMFunctionBody;
|
||||||
apply_reloc(module, compilation, body, r);
|
apply_reloc(module, compilation, body, r);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -57,7 +57,7 @@ fn generate_load(item: &syn::ItemTrait) -> syn::Result<TokenStream> {
|
|||||||
|
|
||||||
let data = #root::wasmtime_interface_types::ModuleData::new(bytes.as_ref())?;
|
let data = #root::wasmtime_interface_types::ModuleData::new(bytes.as_ref())?;
|
||||||
|
|
||||||
let module = Module::new(&store, bytes.as_ref())?;
|
let module = Module::new(&engine, bytes.as_ref())?;
|
||||||
|
|
||||||
let mut imports: Vec<Extern> = Vec::new();
|
let mut imports: Vec<Extern> = Vec::new();
|
||||||
if let Some(module_name) = data.find_wasi_module_name() {
|
if let Some(module_name) = data.find_wasi_module_name() {
|
||||||
@@ -75,7 +75,7 @@ fn generate_load(item: &syn::ItemTrait) -> syn::Result<TokenStream> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
let instance =
|
let instance =
|
||||||
Instance::new(&module, &imports).map_err(|t| format_err!("instantiation trap: {:?}", t))?;
|
Instance::new(&store, &module, &imports).map_err(|t| format_err!("instantiation trap: {:?}", t))?;
|
||||||
|
|
||||||
Ok(#name { instance, data })
|
Ok(#name { instance, data })
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ thiserror = "1.0.4"
|
|||||||
more-asserts = "0.2.1"
|
more-asserts = "0.2.1"
|
||||||
cfg-if = "0.1.9"
|
cfg-if = "0.1.9"
|
||||||
backtrace = "0.3.42"
|
backtrace = "0.3.42"
|
||||||
|
lazy_static = "1.3.0"
|
||||||
|
|
||||||
[target.'cfg(target_os = "windows")'.dependencies]
|
[target.'cfg(target_os = "windows")'.dependencies]
|
||||||
winapi = { version = "0.3.7", features = ["winbase", "memoryapi", "errhandlingapi"] }
|
winapi = { version = "0.3.7", features = ["winbase", "memoryapi", "errhandlingapi"] }
|
||||||
|
|||||||
@@ -4,7 +4,6 @@
|
|||||||
|
|
||||||
use crate::export::Export;
|
use crate::export::Export;
|
||||||
use crate::imports::Imports;
|
use crate::imports::Imports;
|
||||||
use crate::jit_int::GdbJitImageRegistration;
|
|
||||||
use crate::memory::{DefaultMemoryCreator, RuntimeLinearMemory, RuntimeMemoryCreator};
|
use crate::memory::{DefaultMemoryCreator, RuntimeLinearMemory, RuntimeMemoryCreator};
|
||||||
use crate::table::Table;
|
use crate::table::Table;
|
||||||
use crate::traphandlers::Trap;
|
use crate::traphandlers::Trap;
|
||||||
@@ -21,7 +20,6 @@ use std::any::Any;
|
|||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::convert::TryFrom;
|
use std::convert::TryFrom;
|
||||||
use std::rc::Rc;
|
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use std::{mem, ptr, slice};
|
use std::{mem, ptr, slice};
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
@@ -40,6 +38,9 @@ pub(crate) struct Instance {
|
|||||||
/// The `Module` this `Instance` was instantiated from.
|
/// The `Module` this `Instance` was instantiated from.
|
||||||
module: Arc<Module>,
|
module: Arc<Module>,
|
||||||
|
|
||||||
|
/// The module's JIT code (if exists).
|
||||||
|
code: Arc<dyn Any>,
|
||||||
|
|
||||||
/// Offsets in the `vmctx` region.
|
/// Offsets in the `vmctx` region.
|
||||||
offsets: VMOffsets,
|
offsets: VMOffsets,
|
||||||
|
|
||||||
@@ -67,9 +68,6 @@ pub(crate) struct Instance {
|
|||||||
/// Hosts can store arbitrary per-instance information here.
|
/// Hosts can store arbitrary per-instance information here.
|
||||||
host_state: Box<dyn Any>,
|
host_state: Box<dyn Any>,
|
||||||
|
|
||||||
/// Optional image of JIT'ed code for debugger registration.
|
|
||||||
dbg_jit_registration: Option<Rc<GdbJitImageRegistration>>,
|
|
||||||
|
|
||||||
/// Externally allocated data indicating how this instance will be
|
/// Externally allocated data indicating how this instance will be
|
||||||
/// interrupted.
|
/// interrupted.
|
||||||
pub(crate) interrupts: Arc<VMInterrupts>,
|
pub(crate) interrupts: Arc<VMInterrupts>,
|
||||||
@@ -96,14 +94,10 @@ impl Instance {
|
|||||||
unsafe { *self.signature_ids_ptr().add(index) }
|
unsafe { *self.signature_ids_ptr().add(index) }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn module(&self) -> &Arc<Module> {
|
pub(crate) fn module(&self) -> &Module {
|
||||||
&self.module
|
&self.module
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn module_ref(&self) -> &Module {
|
|
||||||
&*self.module
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Return a pointer to the `VMSharedSignatureIndex`s.
|
/// Return a pointer to the `VMSharedSignatureIndex`s.
|
||||||
fn signature_ids_ptr(&self) -> *mut VMSharedSignatureIndex {
|
fn signature_ids_ptr(&self) -> *mut VMSharedSignatureIndex {
|
||||||
unsafe { self.vmctx_plus_offset(self.offsets.vmctx_signature_ids_begin()) }
|
unsafe { self.vmctx_plus_offset(self.offsets.vmctx_signature_ids_begin()) }
|
||||||
@@ -782,12 +776,12 @@ impl InstanceHandle {
|
|||||||
/// safety.
|
/// safety.
|
||||||
pub unsafe fn new(
|
pub unsafe fn new(
|
||||||
module: Arc<Module>,
|
module: Arc<Module>,
|
||||||
|
code: Arc<dyn Any>,
|
||||||
finished_functions: BoxedSlice<DefinedFuncIndex, *mut [VMFunctionBody]>,
|
finished_functions: BoxedSlice<DefinedFuncIndex, *mut [VMFunctionBody]>,
|
||||||
trampolines: HashMap<VMSharedSignatureIndex, VMTrampoline>,
|
trampolines: HashMap<VMSharedSignatureIndex, VMTrampoline>,
|
||||||
imports: Imports,
|
imports: Imports,
|
||||||
mem_creator: Option<&dyn RuntimeMemoryCreator>,
|
mem_creator: Option<&dyn RuntimeMemoryCreator>,
|
||||||
vmshared_signatures: BoxedSlice<SignatureIndex, VMSharedSignatureIndex>,
|
vmshared_signatures: BoxedSlice<SignatureIndex, VMSharedSignatureIndex>,
|
||||||
dbg_jit_registration: Option<Rc<GdbJitImageRegistration>>,
|
|
||||||
host_state: Box<dyn Any>,
|
host_state: Box<dyn Any>,
|
||||||
interrupts: Arc<VMInterrupts>,
|
interrupts: Arc<VMInterrupts>,
|
||||||
) -> Result<Self, InstantiationError> {
|
) -> Result<Self, InstantiationError> {
|
||||||
@@ -815,6 +809,7 @@ impl InstanceHandle {
|
|||||||
let handle = {
|
let handle = {
|
||||||
let instance = Instance {
|
let instance = Instance {
|
||||||
module,
|
module,
|
||||||
|
code,
|
||||||
offsets,
|
offsets,
|
||||||
memories,
|
memories,
|
||||||
tables,
|
tables,
|
||||||
@@ -822,7 +817,6 @@ impl InstanceHandle {
|
|||||||
passive_data,
|
passive_data,
|
||||||
finished_functions,
|
finished_functions,
|
||||||
trampolines,
|
trampolines,
|
||||||
dbg_jit_registration,
|
|
||||||
host_state,
|
host_state,
|
||||||
interrupts,
|
interrupts,
|
||||||
vmctx: VMContext {},
|
vmctx: VMContext {},
|
||||||
@@ -941,14 +935,9 @@ impl InstanceHandle {
|
|||||||
self.instance().vmctx_ptr()
|
self.instance().vmctx_ptr()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return a reference-counting pointer to a module.
|
|
||||||
pub fn module(&self) -> &Arc<Module> {
|
|
||||||
self.instance().module()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Return a reference to a module.
|
/// Return a reference to a module.
|
||||||
pub fn module_ref(&self) -> &Module {
|
pub fn module(&self) -> &Module {
|
||||||
self.instance().module_ref()
|
self.instance().module()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Lookup an export with the given name.
|
/// Lookup an export with the given name.
|
||||||
@@ -1065,8 +1054,7 @@ impl InstanceHandle {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn check_table_init_bounds(instance: &Instance) -> Result<(), InstantiationError> {
|
fn check_table_init_bounds(instance: &Instance) -> Result<(), InstantiationError> {
|
||||||
let module = Arc::clone(&instance.module);
|
for init in &instance.module().table_elements {
|
||||||
for init in &module.table_elements {
|
|
||||||
let start = get_table_init_start(init, instance);
|
let start = get_table_init_start(init, instance);
|
||||||
let table = instance.get_table(init.table_index);
|
let table = instance.get_table(init.table_index);
|
||||||
|
|
||||||
@@ -1170,8 +1158,7 @@ fn get_table_init_start(init: &TableElements, instance: &Instance) -> usize {
|
|||||||
|
|
||||||
/// Initialize the table memory from the provided initializers.
|
/// Initialize the table memory from the provided initializers.
|
||||||
fn initialize_tables(instance: &Instance) -> Result<(), InstantiationError> {
|
fn initialize_tables(instance: &Instance) -> Result<(), InstantiationError> {
|
||||||
let module = Arc::clone(&instance.module);
|
for init in &instance.module().table_elements {
|
||||||
for init in &module.table_elements {
|
|
||||||
let start = get_table_init_start(init, instance);
|
let start = get_table_init_start(init, instance);
|
||||||
let table = instance.get_table(init.table_index);
|
let table = instance.get_table(init.table_index);
|
||||||
|
|
||||||
@@ -1284,7 +1271,7 @@ fn create_globals(module: &Module) -> BoxedSlice<DefinedGlobalIndex, VMGlobalDef
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn initialize_globals(instance: &Instance) {
|
fn initialize_globals(instance: &Instance) {
|
||||||
let module = Arc::clone(&instance.module);
|
let module = instance.module();
|
||||||
let num_imports = module.local.num_imported_globals;
|
let num_imports = module.local.num_imported_globals;
|
||||||
for (index, global) in module.local.globals.iter().skip(num_imports) {
|
for (index, global) in module.local.globals.iter().skip(num_imports) {
|
||||||
let def_index = module.local.defined_global_index(index).unwrap();
|
let def_index = module.local.defined_global_index(index).unwrap();
|
||||||
|
|||||||
@@ -2,7 +2,10 @@
|
|||||||
//! the __jit_debug_register_code() and __jit_debug_descriptor to register
|
//! the __jit_debug_register_code() and __jit_debug_descriptor to register
|
||||||
//! or unregister generated object images with debuggers.
|
//! or unregister generated object images with debuggers.
|
||||||
|
|
||||||
|
use lazy_static::lazy_static;
|
||||||
|
use std::pin::Pin;
|
||||||
use std::ptr;
|
use std::ptr;
|
||||||
|
use std::sync::Mutex;
|
||||||
|
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
struct JITCodeEntry {
|
struct JITCodeEntry {
|
||||||
@@ -43,19 +46,41 @@ extern "C" fn __jit_debug_register_code() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
lazy_static! {
|
||||||
|
// The process controls access to the __jit_debug_descriptor by itself --
|
||||||
|
// the GDB/LLDB accesses this structure and its data at the process startup
|
||||||
|
// and when paused in __jit_debug_register_code.
|
||||||
|
//
|
||||||
|
// The GDB_REGISTRATION lock is needed for GdbJitImageRegistration to protect
|
||||||
|
// access to the __jit_debug_descriptor within this process.
|
||||||
|
pub static ref GDB_REGISTRATION: Mutex<()> = Mutex::new(Default::default());
|
||||||
|
}
|
||||||
|
|
||||||
/// Registeration for JIT image
|
/// Registeration for JIT image
|
||||||
pub struct GdbJitImageRegistration {
|
pub struct GdbJitImageRegistration {
|
||||||
entry: *mut JITCodeEntry,
|
entry: Pin<Box<JITCodeEntry>>,
|
||||||
file: Vec<u8>,
|
file: Pin<Box<[u8]>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl GdbJitImageRegistration {
|
impl GdbJitImageRegistration {
|
||||||
/// Registers JIT image using __jit_debug_register_code
|
/// Registers JIT image using __jit_debug_register_code
|
||||||
pub fn register(file: Vec<u8>) -> Self {
|
pub fn register(file: Vec<u8>) -> Self {
|
||||||
Self {
|
let file = Pin::new(file.into_boxed_slice());
|
||||||
entry: unsafe { register_gdb_jit_image(&file) },
|
|
||||||
file,
|
// Create a code entry for the file, which gives the start and size
|
||||||
|
// of the symbol file.
|
||||||
|
let mut entry = Pin::new(Box::new(JITCodeEntry {
|
||||||
|
next_entry: ptr::null_mut(),
|
||||||
|
prev_entry: ptr::null_mut(),
|
||||||
|
symfile_addr: file.as_ptr(),
|
||||||
|
symfile_size: file.len() as u64,
|
||||||
|
}));
|
||||||
|
|
||||||
|
unsafe {
|
||||||
|
register_gdb_jit_image(&mut *entry);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Self { entry, file }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// JIT image used in registration
|
/// JIT image used in registration
|
||||||
@@ -67,20 +92,19 @@ impl GdbJitImageRegistration {
|
|||||||
impl Drop for GdbJitImageRegistration {
|
impl Drop for GdbJitImageRegistration {
|
||||||
fn drop(&mut self) {
|
fn drop(&mut self) {
|
||||||
unsafe {
|
unsafe {
|
||||||
unregister_gdb_jit_image(self.entry);
|
unregister_gdb_jit_image(&mut *self.entry);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe fn register_gdb_jit_image(file: &[u8]) -> *mut JITCodeEntry {
|
unsafe impl Send for GdbJitImageRegistration {}
|
||||||
// Create a code entry for the file, which gives the start and size of the symbol file.
|
unsafe impl Sync for GdbJitImageRegistration {}
|
||||||
let entry = Box::into_raw(Box::new(JITCodeEntry {
|
|
||||||
next_entry: __jit_debug_descriptor.first_entry,
|
unsafe fn register_gdb_jit_image(entry: *mut JITCodeEntry) {
|
||||||
prev_entry: ptr::null_mut(),
|
let _lock = GDB_REGISTRATION.lock().unwrap();
|
||||||
symfile_addr: file.as_ptr(),
|
|
||||||
symfile_size: file.len() as u64,
|
|
||||||
}));
|
|
||||||
// Add it to the linked list in the JIT descriptor.
|
// Add it to the linked list in the JIT descriptor.
|
||||||
|
(*entry).next_entry = __jit_debug_descriptor.first_entry;
|
||||||
if !__jit_debug_descriptor.first_entry.is_null() {
|
if !__jit_debug_descriptor.first_entry.is_null() {
|
||||||
(*__jit_debug_descriptor.first_entry).prev_entry = entry;
|
(*__jit_debug_descriptor.first_entry).prev_entry = entry;
|
||||||
}
|
}
|
||||||
@@ -93,10 +117,11 @@ unsafe fn register_gdb_jit_image(file: &[u8]) -> *mut JITCodeEntry {
|
|||||||
|
|
||||||
__jit_debug_descriptor.action_flag = JIT_NOACTION;
|
__jit_debug_descriptor.action_flag = JIT_NOACTION;
|
||||||
__jit_debug_descriptor.relevant_entry = ptr::null_mut();
|
__jit_debug_descriptor.relevant_entry = ptr::null_mut();
|
||||||
entry
|
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe fn unregister_gdb_jit_image(entry: *mut JITCodeEntry) {
|
unsafe fn unregister_gdb_jit_image(entry: *mut JITCodeEntry) {
|
||||||
|
let _lock = GDB_REGISTRATION.lock().unwrap();
|
||||||
|
|
||||||
// Remove the code entry corresponding to the code from the linked list.
|
// Remove the code entry corresponding to the code from the linked list.
|
||||||
if !(*entry).prev_entry.is_null() {
|
if !(*entry).prev_entry.is_null() {
|
||||||
(*(*entry).prev_entry).next_entry = (*entry).next_entry;
|
(*(*entry).prev_entry).next_entry = (*entry).next_entry;
|
||||||
@@ -114,5 +139,4 @@ unsafe fn unregister_gdb_jit_image(entry: *mut JITCodeEntry) {
|
|||||||
|
|
||||||
__jit_debug_descriptor.action_flag = JIT_NOACTION;
|
__jit_debug_descriptor.action_flag = JIT_NOACTION;
|
||||||
__jit_debug_descriptor.relevant_entry = ptr::null_mut();
|
__jit_debug_descriptor.relevant_entry = ptr::null_mut();
|
||||||
let _box = Box::from_raw(entry);
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,27 +3,16 @@
|
|||||||
|
|
||||||
use crate::vmcontext::VMSharedSignatureIndex;
|
use crate::vmcontext::VMSharedSignatureIndex;
|
||||||
use more_asserts::assert_lt;
|
use more_asserts::assert_lt;
|
||||||
use std::collections::HashMap;
|
use std::collections::{hash_map, HashMap};
|
||||||
use std::convert::TryFrom;
|
use std::convert::TryFrom;
|
||||||
use std::sync::RwLock;
|
|
||||||
use wasmtime_environ::{ir, wasm::WasmFuncType};
|
use wasmtime_environ::{ir, wasm::WasmFuncType};
|
||||||
|
|
||||||
/// WebAssembly requires that the caller and callee signatures in an indirect
|
/// WebAssembly requires that the caller and callee signatures in an indirect
|
||||||
/// call must match. To implement this efficiently, keep a registry of all
|
/// call must match. To implement this efficiently, keep a registry of all
|
||||||
/// signatures, shared by all instances, so that call sites can just do an
|
/// signatures, shared by all instances, so that call sites can just do an
|
||||||
/// index comparison.
|
/// index comparison.
|
||||||
#[derive(Debug)]
|
|
||||||
pub struct SignatureRegistry {
|
|
||||||
// This structure is stored in a `Compiler` and is intended to be shared
|
|
||||||
// across many instances. Ideally instances can themselves be sent across
|
|
||||||
// threads, and ideally we can compile across many threads. As a result we
|
|
||||||
// use interior mutability here with a lock to avoid having callers to
|
|
||||||
// externally synchronize calls to compilation.
|
|
||||||
inner: RwLock<Inner>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug, Default)]
|
#[derive(Debug, Default)]
|
||||||
struct Inner {
|
pub struct SignatureRegistry {
|
||||||
wasm2index: HashMap<WasmFuncType, VMSharedSignatureIndex>,
|
wasm2index: HashMap<WasmFuncType, VMSharedSignatureIndex>,
|
||||||
|
|
||||||
// Maps the index to the original Wasm signature.
|
// Maps the index to the original Wasm signature.
|
||||||
@@ -34,23 +23,17 @@ struct Inner {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl SignatureRegistry {
|
impl SignatureRegistry {
|
||||||
/// Create a new `SignatureRegistry`.
|
|
||||||
pub fn new() -> Self {
|
|
||||||
Self {
|
|
||||||
inner: Default::default(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Register a signature and return its unique index.
|
/// Register a signature and return its unique index.
|
||||||
pub fn register(&self, wasm: WasmFuncType, native: ir::Signature) -> VMSharedSignatureIndex {
|
pub fn register(
|
||||||
let Inner {
|
&mut self,
|
||||||
wasm2index,
|
wasm: WasmFuncType,
|
||||||
index2wasm,
|
native: ir::Signature,
|
||||||
index2native,
|
) -> VMSharedSignatureIndex {
|
||||||
} = &mut *self.inner.write().unwrap();
|
let len = self.wasm2index.len();
|
||||||
let len = wasm2index.len();
|
|
||||||
|
|
||||||
*wasm2index.entry(wasm.clone()).or_insert_with(|| {
|
match self.wasm2index.entry(wasm.clone()) {
|
||||||
|
hash_map::Entry::Occupied(entry) => *entry.get(),
|
||||||
|
hash_map::Entry::Vacant(entry) => {
|
||||||
// Keep `signature_hash` len under 2**32 -- VMSharedSignatureIndex::new(std::u32::MAX)
|
// Keep `signature_hash` len under 2**32 -- VMSharedSignatureIndex::new(std::u32::MAX)
|
||||||
// is reserved for VMSharedSignatureIndex::default().
|
// is reserved for VMSharedSignatureIndex::default().
|
||||||
assert_lt!(
|
assert_lt!(
|
||||||
@@ -59,10 +42,12 @@ impl SignatureRegistry {
|
|||||||
"Invariant check: signature_hash.len() < std::u32::MAX"
|
"Invariant check: signature_hash.len() < std::u32::MAX"
|
||||||
);
|
);
|
||||||
let index = VMSharedSignatureIndex::new(u32::try_from(len).unwrap());
|
let index = VMSharedSignatureIndex::new(u32::try_from(len).unwrap());
|
||||||
index2wasm.insert(index, wasm);
|
entry.insert(index);
|
||||||
index2native.insert(index, native);
|
self.index2wasm.insert(index, wasm);
|
||||||
|
self.index2native.insert(index, native);
|
||||||
index
|
index
|
||||||
})
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Looks up a shared native signature within this registry.
|
/// Looks up a shared native signature within this registry.
|
||||||
@@ -70,7 +55,7 @@ impl SignatureRegistry {
|
|||||||
/// Note that for this operation to be semantically correct the `idx` must
|
/// Note that for this operation to be semantically correct the `idx` must
|
||||||
/// have previously come from a call to `register` of this same object.
|
/// have previously come from a call to `register` of this same object.
|
||||||
pub fn lookup_native(&self, idx: VMSharedSignatureIndex) -> Option<ir::Signature> {
|
pub fn lookup_native(&self, idx: VMSharedSignatureIndex) -> Option<ir::Signature> {
|
||||||
self.inner.read().unwrap().index2native.get(&idx).cloned()
|
self.index2native.get(&idx).cloned()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Looks up a shared Wasm signature within this registry.
|
/// Looks up a shared Wasm signature within this registry.
|
||||||
@@ -78,6 +63,6 @@ impl SignatureRegistry {
|
|||||||
/// Note that for this operation to be semantically correct the `idx` must
|
/// Note that for this operation to be semantically correct the `idx` must
|
||||||
/// have previously come from a call to `register` of this same object.
|
/// have previously come from a call to `register` of this same object.
|
||||||
pub fn lookup_wasm(&self, idx: VMSharedSignatureIndex) -> Option<WasmFuncType> {
|
pub fn lookup_wasm(&self, idx: VMSharedSignatureIndex) -> Option<WasmFuncType> {
|
||||||
self.inner.read().unwrap().index2wasm.get(&idx).cloned()
|
self.index2wasm.get(&idx).cloned()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -53,7 +53,7 @@ pub fn instantiate(
|
|||||||
|
|
||||||
snapshot1.add_to_linker(&mut linker)?;
|
snapshot1.add_to_linker(&mut linker)?;
|
||||||
|
|
||||||
let module = Module::new(&store, &data).context("failed to create wasm module")?;
|
let module = Module::new(store.engine(), &data).context("failed to create wasm module")?;
|
||||||
|
|
||||||
linker
|
linker
|
||||||
.module("", &module)
|
.module("", &module)
|
||||||
|
|||||||
@@ -659,13 +659,14 @@ impl Memory {
|
|||||||
/// ```
|
/// ```
|
||||||
/// # use wasmtime::*;
|
/// # use wasmtime::*;
|
||||||
/// # fn main() -> anyhow::Result<()> {
|
/// # 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_ty = MemoryType::new(Limits::new(1, None));
|
||||||
/// let memory = Memory::new(&store, memory_ty);
|
/// let memory = Memory::new(&store, memory_ty);
|
||||||
///
|
///
|
||||||
/// let module = Module::new(&store, "(module (memory (import \"\" \"\") 1))")?;
|
/// let module = Module::new(&engine, "(module (memory (import \"\" \"\") 1))")?;
|
||||||
/// let instance = Instance::new(&module, &[memory.into()])?;
|
/// let instance = Instance::new(&store, &module, &[memory.into()])?;
|
||||||
/// // ...
|
/// // ...
|
||||||
/// # Ok(())
|
/// # Ok(())
|
||||||
/// # }
|
/// # }
|
||||||
@@ -686,9 +687,10 @@ impl Memory {
|
|||||||
/// ```
|
/// ```
|
||||||
/// # use wasmtime::*;
|
/// # use wasmtime::*;
|
||||||
/// # fn main() -> anyhow::Result<()> {
|
/// # fn main() -> anyhow::Result<()> {
|
||||||
/// let store = Store::default();
|
/// let engine = Engine::default();
|
||||||
/// let module = Module::new(&store, "(module (memory (export \"mem\") 1))")?;
|
/// let store = Store::new(&engine);
|
||||||
/// let instance = Instance::new(&module, &[])?;
|
/// let module = Module::new(&engine, "(module (memory (export \"mem\") 1))")?;
|
||||||
|
/// let instance = Instance::new(&store, &module, &[])?;
|
||||||
/// let memory = instance.get_memory("mem").unwrap();
|
/// let memory = instance.get_memory("mem").unwrap();
|
||||||
/// let ty = memory.ty();
|
/// let ty = memory.ty();
|
||||||
/// assert_eq!(ty.limits().min(), 1);
|
/// assert_eq!(ty.limits().min(), 1);
|
||||||
@@ -798,9 +800,10 @@ impl Memory {
|
|||||||
/// ```
|
/// ```
|
||||||
/// # use wasmtime::*;
|
/// # use wasmtime::*;
|
||||||
/// # fn main() -> anyhow::Result<()> {
|
/// # fn main() -> anyhow::Result<()> {
|
||||||
/// let store = Store::default();
|
/// let engine = Engine::default();
|
||||||
/// let module = Module::new(&store, "(module (memory (export \"mem\") 1 2))")?;
|
/// let store = Store::new(&engine);
|
||||||
/// let instance = Instance::new(&module, &[])?;
|
/// let module = Module::new(&engine, "(module (memory (export \"mem\") 1 2))")?;
|
||||||
|
/// let instance = Instance::new(&store, &module, &[])?;
|
||||||
/// let memory = instance.get_memory("mem").unwrap();
|
/// let memory = instance.get_memory("mem").unwrap();
|
||||||
///
|
///
|
||||||
/// assert_eq!(memory.size(), 1);
|
/// assert_eq!(memory.size(), 1);
|
||||||
|
|||||||
@@ -42,6 +42,8 @@ struct ModuleFrameInfo {
|
|||||||
start: usize,
|
start: usize,
|
||||||
functions: BTreeMap<usize, FunctionInfo>,
|
functions: BTreeMap<usize, FunctionInfo>,
|
||||||
module: Arc<Module>,
|
module: Arc<Module>,
|
||||||
|
#[allow(dead_code)]
|
||||||
|
module_code: Arc<dyn std::any::Any + Send + Sync>,
|
||||||
}
|
}
|
||||||
|
|
||||||
struct FunctionInfo {
|
struct FunctionInfo {
|
||||||
@@ -192,6 +194,7 @@ pub fn register(module: &CompiledModule) -> Option<GlobalFrameInfoRegistration>
|
|||||||
start: min,
|
start: min,
|
||||||
functions,
|
functions,
|
||||||
module: module.module().clone(),
|
module: module.module().clone(),
|
||||||
|
module_code: module.code().clone(),
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
assert!(prev.is_none());
|
assert!(prev.is_none());
|
||||||
|
|||||||
@@ -38,9 +38,10 @@ use wasmtime_runtime::{Export, InstanceHandle, VMContext, VMFunctionBody};
|
|||||||
/// ```
|
/// ```
|
||||||
/// # use wasmtime::*;
|
/// # use wasmtime::*;
|
||||||
/// # fn main() -> anyhow::Result<()> {
|
/// # fn main() -> anyhow::Result<()> {
|
||||||
/// let store = Store::default();
|
/// let engine = Engine::default();
|
||||||
/// let module = Module::new(&store, r#"(module (func (export "foo")))"#)?;
|
/// let store = Store::new(&engine);
|
||||||
/// let instance = Instance::new(&module, &[])?;
|
/// 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");
|
/// 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
|
/// // 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.
|
/// // Next we can hook that up to a wasm module which uses it.
|
||||||
/// let module = Module::new(
|
/// let module = Module::new(
|
||||||
/// &store,
|
/// store.engine(),
|
||||||
/// r#"
|
/// r#"
|
||||||
/// (module
|
/// (module
|
||||||
/// (import "" "" (func $add (param i32 i32) (result i32)))
|
/// (import "" "" (func $add (param i32 i32) (result i32)))
|
||||||
@@ -90,7 +91,7 @@ use wasmtime_runtime::{Export, InstanceHandle, VMContext, VMFunctionBody};
|
|||||||
/// i32.add))
|
/// 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 = instance.get_func("call_add_twice").expect("export wasn't a function");
|
||||||
/// let call_add_twice = call_add_twice.get0::<i32>()?;
|
/// let call_add_twice = call_add_twice.get0::<i32>()?;
|
||||||
///
|
///
|
||||||
@@ -120,7 +121,7 @@ use wasmtime_runtime::{Export, InstanceHandle, VMContext, VMFunctionBody};
|
|||||||
/// });
|
/// });
|
||||||
///
|
///
|
||||||
/// let module = Module::new(
|
/// let module = Module::new(
|
||||||
/// &store,
|
/// store.engine(),
|
||||||
/// r#"
|
/// r#"
|
||||||
/// (module
|
/// (module
|
||||||
/// (import "" "" (func $double (param i32) (result i32)))
|
/// (import "" "" (func $double (param i32) (result i32)))
|
||||||
@@ -131,7 +132,7 @@ use wasmtime_runtime::{Export, InstanceHandle, VMContext, VMFunctionBody};
|
|||||||
/// (start $start))
|
/// (start $start))
|
||||||
/// "#,
|
/// "#,
|
||||||
/// )?;
|
/// )?;
|
||||||
/// let instance = Instance::new(&module, &[double.into()])?;
|
/// let instance = Instance::new(&store, &module, &[double.into()])?;
|
||||||
/// // .. work with `instance` if necessary
|
/// // .. work with `instance` if necessary
|
||||||
/// # Ok(())
|
/// # Ok(())
|
||||||
/// # }
|
/// # }
|
||||||
@@ -335,7 +336,7 @@ impl Func {
|
|||||||
/// # let store = Store::default();
|
/// # let store = Store::default();
|
||||||
/// let add = Func::wrap(&store, |a: i32, b: i32| a + b);
|
/// let add = Func::wrap(&store, |a: i32, b: i32| a + b);
|
||||||
/// let module = Module::new(
|
/// let module = Module::new(
|
||||||
/// &store,
|
/// store.engine(),
|
||||||
/// r#"
|
/// r#"
|
||||||
/// (module
|
/// (module
|
||||||
/// (import "" "" (func $add (param i32 i32) (result i32)))
|
/// (import "" "" (func $add (param i32 i32) (result i32)))
|
||||||
@@ -345,7 +346,7 @@ impl Func {
|
|||||||
/// call $add))
|
/// 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>()?;
|
/// let foo = instance.get_func("foo").unwrap().get2::<i32, i32, i32>()?;
|
||||||
/// assert_eq!(foo(1, 2)?, 3);
|
/// assert_eq!(foo(1, 2)?, 3);
|
||||||
/// # Ok(())
|
/// # Ok(())
|
||||||
@@ -366,7 +367,7 @@ impl Func {
|
|||||||
/// }
|
/// }
|
||||||
/// });
|
/// });
|
||||||
/// let module = Module::new(
|
/// let module = Module::new(
|
||||||
/// &store,
|
/// store.engine(),
|
||||||
/// r#"
|
/// r#"
|
||||||
/// (module
|
/// (module
|
||||||
/// (import "" "" (func $add (param i32 i32) (result i32)))
|
/// (import "" "" (func $add (param i32 i32) (result i32)))
|
||||||
@@ -376,7 +377,7 @@ impl Func {
|
|||||||
/// call $add))
|
/// 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>()?;
|
/// let foo = instance.get_func("foo").unwrap().get2::<i32, i32, i32>()?;
|
||||||
/// assert_eq!(foo(1, 2)?, 3);
|
/// assert_eq!(foo(1, 2)?, 3);
|
||||||
/// assert!(foo(i32::max_value(), 1).is_err());
|
/// assert!(foo(i32::max_value(), 1).is_err());
|
||||||
@@ -397,7 +398,7 @@ impl Func {
|
|||||||
/// println!("d={}", d);
|
/// println!("d={}", d);
|
||||||
/// });
|
/// });
|
||||||
/// let module = Module::new(
|
/// let module = Module::new(
|
||||||
/// &store,
|
/// store.engine(),
|
||||||
/// r#"
|
/// r#"
|
||||||
/// (module
|
/// (module
|
||||||
/// (import "" "" (func $debug (param i32 f32 i64 f64)))
|
/// (import "" "" (func $debug (param i32 f32 i64 f64)))
|
||||||
@@ -409,7 +410,7 @@ impl Func {
|
|||||||
/// call $debug))
|
/// 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::<()>()?;
|
/// let foo = instance.get_func("foo").unwrap().get0::<()>()?;
|
||||||
/// foo()?;
|
/// foo()?;
|
||||||
/// # Ok(())
|
/// # Ok(())
|
||||||
@@ -453,7 +454,7 @@ impl Func {
|
|||||||
/// Ok(())
|
/// Ok(())
|
||||||
/// });
|
/// });
|
||||||
/// let module = Module::new(
|
/// let module = Module::new(
|
||||||
/// &store,
|
/// store.engine(),
|
||||||
/// r#"
|
/// r#"
|
||||||
/// (module
|
/// (module
|
||||||
/// (import "" "" (func $log_str (param i32 i32)))
|
/// (import "" "" (func $log_str (param i32 i32)))
|
||||||
@@ -465,7 +466,7 @@ impl Func {
|
|||||||
/// (data (i32.const 4) "Hello, world!"))
|
/// (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::<()>()?;
|
/// let foo = instance.get_func("foo").unwrap().get0::<()>()?;
|
||||||
/// foo()?;
|
/// foo()?;
|
||||||
/// # Ok(())
|
/// # Ok(())
|
||||||
@@ -479,13 +480,7 @@ impl Func {
|
|||||||
pub fn ty(&self) -> FuncType {
|
pub fn ty(&self) -> FuncType {
|
||||||
// Signatures should always be registered in the store's registry of
|
// Signatures should always be registered in the store's registry of
|
||||||
// shared signatures, so we should be able to unwrap safely here.
|
// shared signatures, so we should be able to unwrap safely here.
|
||||||
let sig = self
|
let sig = self.instance.store.lookup_signature(self.export.signature);
|
||||||
.instance
|
|
||||||
.store
|
|
||||||
.compiler()
|
|
||||||
.signatures()
|
|
||||||
.lookup_wasm(self.export.signature)
|
|
||||||
.expect("failed to lookup signature");
|
|
||||||
|
|
||||||
// This is only called with `Export::Function`, and since it's coming
|
// This is only called with `Export::Function`, and since it's coming
|
||||||
// from wasmtime_runtime itself we should support all the types 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.
|
/// Returns the number of parameters that this function takes.
|
||||||
pub fn param_arity(&self) -> usize {
|
pub fn param_arity(&self) -> usize {
|
||||||
self.instance
|
let sig = self.instance.store.lookup_signature(self.export.signature);
|
||||||
.store
|
sig.params.len()
|
||||||
.compiler()
|
|
||||||
.signatures()
|
|
||||||
.lookup_wasm(self.export.signature)
|
|
||||||
.expect("failed to lookup signature")
|
|
||||||
.params
|
|
||||||
.len()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the number of results this function produces.
|
/// Returns the number of results this function produces.
|
||||||
pub fn result_arity(&self) -> usize {
|
pub fn result_arity(&self) -> usize {
|
||||||
let sig = self
|
let sig = self.instance.store.lookup_signature(self.export.signature);
|
||||||
.instance
|
|
||||||
.store
|
|
||||||
.compiler()
|
|
||||||
.signatures()
|
|
||||||
.lookup_wasm(self.export.signature)
|
|
||||||
.expect("failed to lookup signature");
|
|
||||||
sig.returns.len()
|
sig.returns.len()
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -749,7 +732,7 @@ pub(crate) fn catch_traps(
|
|||||||
wasmtime_runtime::catch_traps(
|
wasmtime_runtime::catch_traps(
|
||||||
vmctx,
|
vmctx,
|
||||||
store.engine().config().max_wasm_stack,
|
store.engine().config().max_wasm_stack,
|
||||||
|addr| store.compiler().is_in_jit_code(addr),
|
|addr| store.is_in_jit_code(addr),
|
||||||
signalhandler.as_deref(),
|
signalhandler.as_deref(),
|
||||||
closure,
|
closure,
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
use crate::trampoline::StoreInstanceHandle;
|
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 anyhow::{bail, Error, Result};
|
||||||
use std::any::Any;
|
use std::any::Any;
|
||||||
use std::mem;
|
use std::mem;
|
||||||
use wasmtime_environ::EntityIndex;
|
use wasmtime_environ::EntityIndex;
|
||||||
use wasmtime_jit::{CompiledModule, Resolver};
|
use wasmtime_jit::{CompiledModule, Resolver};
|
||||||
use wasmtime_runtime::{InstantiationError, SignatureRegistry, VMContext, VMFunctionBody};
|
use wasmtime_runtime::{InstantiationError, VMContext, VMFunctionBody};
|
||||||
|
|
||||||
struct SimpleResolver<'a> {
|
struct SimpleResolver<'a> {
|
||||||
imports: &'a [Extern],
|
imports: &'a [Extern],
|
||||||
@@ -23,7 +23,6 @@ fn instantiate(
|
|||||||
store: &Store,
|
store: &Store,
|
||||||
compiled_module: &CompiledModule,
|
compiled_module: &CompiledModule,
|
||||||
imports: &[Extern],
|
imports: &[Extern],
|
||||||
sig_registry: &SignatureRegistry,
|
|
||||||
host: Box<dyn Any>,
|
host: Box<dyn Any>,
|
||||||
) -> Result<StoreInstanceHandle, Error> {
|
) -> Result<StoreInstanceHandle, Error> {
|
||||||
// For now we have a restriction that the `Store` that we're working
|
// For now we have a restriction that the `Store` that we're working
|
||||||
@@ -47,8 +46,9 @@ fn instantiate(
|
|||||||
let instance = unsafe {
|
let instance = unsafe {
|
||||||
let instance = compiled_module.instantiate(
|
let instance = compiled_module.instantiate(
|
||||||
&mut resolver,
|
&mut resolver,
|
||||||
sig_registry,
|
&mut store.signatures_mut(),
|
||||||
config.memory_creator.as_ref().map(|a| a as _),
|
config.memory_creator.as_ref().map(|a| a as _),
|
||||||
|
store.interrupts().clone(),
|
||||||
host,
|
host,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
@@ -120,6 +120,7 @@ fn instantiate(
|
|||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct Instance {
|
pub struct Instance {
|
||||||
pub(crate) handle: StoreInstanceHandle,
|
pub(crate) handle: StoreInstanceHandle,
|
||||||
|
store: Store,
|
||||||
module: Module,
|
module: Module,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -177,19 +178,19 @@ impl Instance {
|
|||||||
/// [inst]: https://webassembly.github.io/spec/core/exec/modules.html#exec-instantiation
|
/// [inst]: https://webassembly.github.io/spec/core/exec/modules.html#exec-instantiation
|
||||||
/// [issue]: https://github.com/bytecodealliance/wasmtime/issues/727
|
/// [issue]: https://github.com/bytecodealliance/wasmtime/issues/727
|
||||||
/// [`ExternType`]: crate::ExternType
|
/// [`ExternType`]: crate::ExternType
|
||||||
pub fn new(module: &Module, imports: &[Extern]) -> Result<Instance, Error> {
|
pub fn new(store: &Store, module: &Module, imports: &[Extern]) -> Result<Instance, Error> {
|
||||||
let store = module.store();
|
if !Engine::same(store.engine(), module.engine()) {
|
||||||
|
bail!("cross-`Engine` instantiation is not currently supported");
|
||||||
|
}
|
||||||
|
|
||||||
let info = module.register_frame_info();
|
let info = module.register_frame_info();
|
||||||
let handle = instantiate(
|
store.register_jit_code(module.compiled_module().jit_code_ranges());
|
||||||
store,
|
|
||||||
module.compiled_module(),
|
let handle = instantiate(store, module.compiled_module(), imports, Box::new(info))?;
|
||||||
imports,
|
|
||||||
store.compiler().signatures(),
|
|
||||||
Box::new(info),
|
|
||||||
)?;
|
|
||||||
|
|
||||||
Ok(Instance {
|
Ok(Instance {
|
||||||
handle,
|
handle,
|
||||||
|
store: store.clone(),
|
||||||
module: module.clone(),
|
module: module.clone(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@@ -199,7 +200,7 @@ impl Instance {
|
|||||||
/// This is the [`Store`] that generally serves as a sort of global cache
|
/// This is the [`Store`] that generally serves as a sort of global cache
|
||||||
/// for various instance-related things.
|
/// for various instance-related things.
|
||||||
pub fn store(&self) -> &Store {
|
pub fn store(&self) -> &Store {
|
||||||
self.module.store()
|
&self.store
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the list of exported items from this [`Instance`].
|
/// Returns the list of exported items from this [`Instance`].
|
||||||
|
|||||||
@@ -150,7 +150,7 @@ impl Linker {
|
|||||||
/// (data (global.get 0) "foo")
|
/// (data (global.get 0) "foo")
|
||||||
/// )
|
/// )
|
||||||
/// "#;
|
/// "#;
|
||||||
/// let module = Module::new(&store, wat)?;
|
/// let module = Module::new(store.engine(), wat)?;
|
||||||
/// linker.instantiate(&module)?;
|
/// linker.instantiate(&module)?;
|
||||||
/// # Ok(())
|
/// # Ok(())
|
||||||
/// # }
|
/// # }
|
||||||
@@ -203,7 +203,7 @@ impl Linker {
|
|||||||
/// (import "host" "log_str" (func (param i32 i32)))
|
/// (import "host" "log_str" (func (param i32 i32)))
|
||||||
/// )
|
/// )
|
||||||
/// "#;
|
/// "#;
|
||||||
/// let module = Module::new(&store, wat)?;
|
/// let module = Module::new(store.engine(), wat)?;
|
||||||
/// linker.instantiate(&module)?;
|
/// linker.instantiate(&module)?;
|
||||||
/// # Ok(())
|
/// # Ok(())
|
||||||
/// # }
|
/// # }
|
||||||
@@ -241,7 +241,7 @@ impl Linker {
|
|||||||
///
|
///
|
||||||
/// // Instantiate a small instance...
|
/// // Instantiate a small instance...
|
||||||
/// let wat = r#"(module (func (export "run") ))"#;
|
/// 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)?;
|
/// let instance = linker.instantiate(&module)?;
|
||||||
///
|
///
|
||||||
/// // ... and inform the linker that the name of this instance is
|
/// // ... 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)?;
|
/// let instance = linker.instantiate(&module)?;
|
||||||
/// # Ok(())
|
/// # Ok(())
|
||||||
/// # }
|
/// # }
|
||||||
@@ -312,7 +312,7 @@ impl Linker {
|
|||||||
/// // this instance is `instance1`. This defines the `instance1::run` name
|
/// // this instance is `instance1`. This defines the `instance1::run` name
|
||||||
/// // for our next module to use.
|
/// // for our next module to use.
|
||||||
/// let wat = r#"(module (func (export "run") ))"#;
|
/// let wat = r#"(module (func (export "run") ))"#;
|
||||||
/// let module = Module::new(&store, wat)?;
|
/// let module = Module::new(store.engine(), wat)?;
|
||||||
/// linker.module("instance1", &module)?;
|
/// linker.module("instance1", &module)?;
|
||||||
///
|
///
|
||||||
/// let wat = r#"
|
/// 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)?;
|
/// let instance = linker.instantiate(&module)?;
|
||||||
/// # Ok(())
|
/// # Ok(())
|
||||||
/// # }
|
/// # }
|
||||||
@@ -350,7 +350,7 @@ impl Linker {
|
|||||||
/// )
|
/// )
|
||||||
/// )
|
/// )
|
||||||
/// "#;
|
/// "#;
|
||||||
/// let module = Module::new(&store, wat)?;
|
/// let module = Module::new(store.engine(), wat)?;
|
||||||
/// linker.module("commander", &module)?;
|
/// linker.module("commander", &module)?;
|
||||||
/// let run = linker.get_default("")?.get0::<()>()?;
|
/// let run = linker.get_default("")?.get0::<()>()?;
|
||||||
/// run()?;
|
/// run()?;
|
||||||
@@ -369,7 +369,7 @@ impl Linker {
|
|||||||
/// )
|
/// )
|
||||||
/// )
|
/// )
|
||||||
/// "#;
|
/// "#;
|
||||||
/// let module = Module::new(&store, wat)?;
|
/// let module = Module::new(store.engine(), wat)?;
|
||||||
/// linker.module("", &module)?;
|
/// linker.module("", &module)?;
|
||||||
/// let count = linker.get_one_by_name("", "run")?.into_func().unwrap().get0::<i32>()?()?;
|
/// 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");
|
/// 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() {
|
for export in module.exports() {
|
||||||
if let Some(func_ty) = export.ty().func() {
|
if let Some(func_ty) = export.ty().func() {
|
||||||
let imports = self.compute_imports(module)?;
|
let imports = self.compute_imports(module)?;
|
||||||
|
let store = self.store.clone();
|
||||||
let module = module.clone();
|
let module = module.clone();
|
||||||
let export_name = export.name().to_owned();
|
let export_name = export.name().to_owned();
|
||||||
let func = Func::new(&self.store, func_ty.clone(), move |_, params, results| {
|
let func = Func::new(&self.store, func_ty.clone(), move |_, params, results| {
|
||||||
// Create a new instance for this command execution.
|
// 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
|
// `unwrap()` everything here because we know the instance contains a
|
||||||
// function export with the given name and signature because we're
|
// 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)))
|
/// (import "host" "double" (func (param i32) (result i32)))
|
||||||
/// )
|
/// )
|
||||||
/// "#;
|
/// "#;
|
||||||
/// let module = Module::new(&store, wat)?;
|
/// let module = Module::new(store.engine(), wat)?;
|
||||||
/// linker.instantiate(&module)?;
|
/// linker.instantiate(&module)?;
|
||||||
/// # Ok(())
|
/// # Ok(())
|
||||||
/// # }
|
/// # }
|
||||||
@@ -568,7 +569,7 @@ impl Linker {
|
|||||||
pub fn instantiate(&self, module: &Module) -> Result<Instance> {
|
pub fn instantiate(&self, module: &Module) -> Result<Instance> {
|
||||||
let imports = self.compute_imports(module)?;
|
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>> {
|
fn compute_imports(&self, module: &Module) -> Result<Vec<Extern>> {
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
use crate::frame_info::GlobalFrameInfoRegistration;
|
use crate::frame_info::GlobalFrameInfoRegistration;
|
||||||
use crate::runtime::Store;
|
use crate::runtime::Engine;
|
||||||
use crate::types::{EntityType, ExportType, ExternType, ImportType};
|
use crate::types::{EntityType, ExportType, ExternType, ImportType};
|
||||||
use anyhow::{Error, Result};
|
use anyhow::{Error, Result};
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
@@ -23,6 +23,8 @@ use wasmtime_jit::CompiledModule;
|
|||||||
/// compiling the original wasm module only once with a single [`Module`]
|
/// compiling the original wasm module only once with a single [`Module`]
|
||||||
/// instance.
|
/// instance.
|
||||||
///
|
///
|
||||||
|
/// The `Module` is threadsafe and safe to share accross threads.
|
||||||
|
///
|
||||||
/// ## Modules and `Clone`
|
/// ## Modules and `Clone`
|
||||||
///
|
///
|
||||||
/// Using `clone` on a `Module` is a cheap operation. It will not create an
|
/// Using `clone` on a `Module` is a cheap operation. It will not create an
|
||||||
@@ -38,8 +40,8 @@ use wasmtime_jit::CompiledModule;
|
|||||||
/// ```no_run
|
/// ```no_run
|
||||||
/// # use wasmtime::*;
|
/// # use wasmtime::*;
|
||||||
/// # fn main() -> anyhow::Result<()> {
|
/// # fn main() -> anyhow::Result<()> {
|
||||||
/// let store = Store::default();
|
/// let engine = Engine::default();
|
||||||
/// let module = Module::from_file(&store, "path/to/foo.wasm")?;
|
/// let module = Module::from_file(&engine, "path/to/foo.wasm")?;
|
||||||
/// # Ok(())
|
/// # Ok(())
|
||||||
/// # }
|
/// # }
|
||||||
/// ```
|
/// ```
|
||||||
@@ -49,9 +51,9 @@ use wasmtime_jit::CompiledModule;
|
|||||||
/// ```no_run
|
/// ```no_run
|
||||||
/// # use wasmtime::*;
|
/// # use wasmtime::*;
|
||||||
/// # fn main() -> anyhow::Result<()> {
|
/// # fn main() -> anyhow::Result<()> {
|
||||||
/// let store = Store::default();
|
/// let engine = Engine::default();
|
||||||
/// // Now we're using the WebAssembly text extension: `.wat`!
|
/// // 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(())
|
/// # Ok(())
|
||||||
/// # }
|
/// # }
|
||||||
/// ```
|
/// ```
|
||||||
@@ -62,12 +64,12 @@ use wasmtime_jit::CompiledModule;
|
|||||||
/// ```no_run
|
/// ```no_run
|
||||||
/// # use wasmtime::*;
|
/// # use wasmtime::*;
|
||||||
/// # fn main() -> anyhow::Result<()> {
|
/// # fn main() -> anyhow::Result<()> {
|
||||||
/// let store = Store::default();
|
/// let engine = Engine::default();
|
||||||
/// # let wasm_bytes: Vec<u8> = Vec::new();
|
/// # 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!
|
/// // It also works with the text format!
|
||||||
/// let module = Module::new(&store, "(module (func))")?;
|
/// let module = Module::new(&engine, "(module (func))")?;
|
||||||
/// # Ok(())
|
/// # Ok(())
|
||||||
/// # }
|
/// # }
|
||||||
/// ```
|
/// ```
|
||||||
@@ -75,13 +77,9 @@ use wasmtime_jit::CompiledModule;
|
|||||||
/// [`Config`]: crate::Config
|
/// [`Config`]: crate::Config
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct Module {
|
pub struct Module {
|
||||||
inner: Arc<ModuleInner>,
|
engine: Engine,
|
||||||
}
|
compiled: Arc<CompiledModule>,
|
||||||
|
frame_info_registration: Arc<Mutex<Option<Option<Arc<GlobalFrameInfoRegistration>>>>>,
|
||||||
struct ModuleInner {
|
|
||||||
store: Store,
|
|
||||||
compiled: CompiledModule,
|
|
||||||
frame_info_registration: Mutex<Option<Option<Arc<GlobalFrameInfoRegistration>>>>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Module {
|
impl Module {
|
||||||
@@ -103,12 +101,7 @@ impl Module {
|
|||||||
/// compilation of a module.
|
/// compilation of a module.
|
||||||
///
|
///
|
||||||
/// The WebAssembly binary will be decoded and validated. It will also be
|
/// The WebAssembly binary will be decoded and validated. It will also be
|
||||||
/// compiled according to the configuration of the provided `store` and
|
/// compiled according to the configuration of the provided `engine`.
|
||||||
/// 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.
|
|
||||||
///
|
///
|
||||||
/// # Errors
|
/// # Errors
|
||||||
///
|
///
|
||||||
@@ -121,7 +114,7 @@ impl Module {
|
|||||||
/// * Implementation-specific limits were exceeded with a valid binary (for
|
/// * Implementation-specific limits were exceeded with a valid binary (for
|
||||||
/// example too many locals)
|
/// example too many locals)
|
||||||
/// * The wasm binary may use features that are not enabled in the
|
/// * 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
|
/// * If the `wat` feature is enabled and the input is text, then it may be
|
||||||
/// rejected if it fails to parse.
|
/// rejected if it fails to parse.
|
||||||
///
|
///
|
||||||
@@ -138,9 +131,9 @@ impl Module {
|
|||||||
/// ```no_run
|
/// ```no_run
|
||||||
/// # use wasmtime::*;
|
/// # use wasmtime::*;
|
||||||
/// # fn main() -> anyhow::Result<()> {
|
/// # fn main() -> anyhow::Result<()> {
|
||||||
/// # let store = Store::default();
|
/// # let engine = Engine::default();
|
||||||
/// # let wasm_bytes: Vec<u8> = Vec::new();
|
/// # let wasm_bytes: Vec<u8> = Vec::new();
|
||||||
/// let module = Module::new(&store, &wasm_bytes)?;
|
/// let module = Module::new(&engine, &wasm_bytes)?;
|
||||||
/// # Ok(())
|
/// # Ok(())
|
||||||
/// # }
|
/// # }
|
||||||
/// ```
|
/// ```
|
||||||
@@ -151,25 +144,28 @@ impl Module {
|
|||||||
/// ```
|
/// ```
|
||||||
/// # use wasmtime::*;
|
/// # use wasmtime::*;
|
||||||
/// # fn main() -> anyhow::Result<()> {
|
/// # fn main() -> anyhow::Result<()> {
|
||||||
/// # let store = Store::default();
|
/// # let engine = Engine::default();
|
||||||
/// let module = Module::new(&store, "(module (func))")?;
|
/// let module = Module::new(&engine, "(module (func))")?;
|
||||||
/// # Ok(())
|
/// # 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")]
|
#[cfg(feature = "wat")]
|
||||||
let bytes = wat::parse_bytes(bytes.as_ref())?;
|
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`
|
/// Creates a new WebAssembly `Module` from the given in-memory `binary`
|
||||||
/// data. The provided `name` will be used in traps/backtrace details.
|
/// data. The provided `name` will be used in traps/backtrace details.
|
||||||
///
|
///
|
||||||
/// See [`Module::new`] for other details.
|
/// See [`Module::new`] for other details.
|
||||||
pub fn new_with_name(store: &Store, bytes: impl AsRef<[u8]>, name: &str) -> Result<Module> {
|
pub fn new_with_name(engine: &Engine, bytes: impl AsRef<[u8]>, name: &str) -> Result<Module> {
|
||||||
let mut module = Module::new(store, bytes.as_ref())?;
|
let mut module = Module::new(engine, bytes.as_ref())?;
|
||||||
let inner = Arc::get_mut(&mut module.inner).unwrap();
|
Arc::get_mut(&mut module.compiled)
|
||||||
Arc::get_mut(inner.compiled.module_mut()).unwrap().name = Some(name.to_string());
|
.unwrap()
|
||||||
|
.module_mut()
|
||||||
|
.expect("mutable module")
|
||||||
|
.name = Some(name.to_string());
|
||||||
Ok(module)
|
Ok(module)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -185,8 +181,8 @@ impl Module {
|
|||||||
/// ```no_run
|
/// ```no_run
|
||||||
/// # use wasmtime::*;
|
/// # use wasmtime::*;
|
||||||
/// # fn main() -> anyhow::Result<()> {
|
/// # fn main() -> anyhow::Result<()> {
|
||||||
/// let store = Store::default();
|
/// let engine = Engine::default();
|
||||||
/// let module = Module::from_file(&store, "./path/to/foo.wasm")?;
|
/// let module = Module::from_file(&engine, "./path/to/foo.wasm")?;
|
||||||
/// # Ok(())
|
/// # Ok(())
|
||||||
/// # }
|
/// # }
|
||||||
/// ```
|
/// ```
|
||||||
@@ -196,17 +192,17 @@ impl Module {
|
|||||||
/// ```no_run
|
/// ```no_run
|
||||||
/// # use wasmtime::*;
|
/// # use wasmtime::*;
|
||||||
/// # fn main() -> anyhow::Result<()> {
|
/// # fn main() -> anyhow::Result<()> {
|
||||||
/// # let store = Store::default();
|
/// # let engine = Engine::default();
|
||||||
/// let module = Module::from_file(&store, "./path/to/foo.wat")?;
|
/// let module = Module::from_file(&engine, "./path/to/foo.wat")?;
|
||||||
/// # Ok(())
|
/// # 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")]
|
#[cfg(feature = "wat")]
|
||||||
let wasm = wat::parse_file(file)?;
|
let wasm = wat::parse_file(file)?;
|
||||||
#[cfg(not(feature = "wat"))]
|
#[cfg(not(feature = "wat"))]
|
||||||
let wasm = std::fs::read(file)?;
|
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`
|
/// Creates a new WebAssembly `Module` from the given in-memory `binary`
|
||||||
@@ -223,9 +219,9 @@ impl Module {
|
|||||||
/// ```
|
/// ```
|
||||||
/// # use wasmtime::*;
|
/// # use wasmtime::*;
|
||||||
/// # fn main() -> anyhow::Result<()> {
|
/// # fn main() -> anyhow::Result<()> {
|
||||||
/// # let store = Store::default();
|
/// # let engine = Engine::default();
|
||||||
/// let wasm = b"\0asm\x01\0\0\0";
|
/// let wasm = b"\0asm\x01\0\0\0";
|
||||||
/// let module = Module::from_binary(&store, wasm)?;
|
/// let module = Module::from_binary(&engine, wasm)?;
|
||||||
/// # Ok(())
|
/// # Ok(())
|
||||||
/// # }
|
/// # }
|
||||||
/// ```
|
/// ```
|
||||||
@@ -235,17 +231,17 @@ impl Module {
|
|||||||
/// ```
|
/// ```
|
||||||
/// # use wasmtime::*;
|
/// # use wasmtime::*;
|
||||||
/// # fn main() -> anyhow::Result<()> {
|
/// # fn main() -> anyhow::Result<()> {
|
||||||
/// # let store = Store::default();
|
/// # let engine = Engine::default();
|
||||||
/// assert!(Module::from_binary(&store, b"(module)").is_err());
|
/// assert!(Module::from_binary(&engine, b"(module)").is_err());
|
||||||
/// # Ok(())
|
/// # Ok(())
|
||||||
/// # }
|
/// # }
|
||||||
/// ```
|
/// ```
|
||||||
pub fn from_binary(store: &Store, binary: &[u8]) -> Result<Module> {
|
pub fn from_binary(engine: &Engine, binary: &[u8]) -> Result<Module> {
|
||||||
Module::validate(store, binary)?;
|
Module::validate(engine, binary)?;
|
||||||
// Note that the call to `from_binary_unchecked` here should be ok
|
// Note that the call to `from_binary_unchecked` here should be ok
|
||||||
// because we previously validated the binary, meaning we're guaranteed
|
// because we previously validated the binary, meaning we're guaranteed
|
||||||
// to pass a valid binary for `store`.
|
// to pass a valid binary for `engine`.
|
||||||
unsafe { Module::from_binary_unchecked(store, binary) }
|
unsafe { Module::from_binary_unchecked(engine, binary) }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates a new WebAssembly `Module` from the given in-memory `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
|
/// WebAssembly. The WebAssembly binary is not validated for
|
||||||
/// correctness and it is simply assumed as valid.
|
/// 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`].
|
/// see the documentation of [`Module::new`].
|
||||||
///
|
///
|
||||||
/// # Unsafety
|
/// # Unsafety
|
||||||
@@ -275,17 +271,17 @@ impl Module {
|
|||||||
/// While this assumes that the binary is valid it still needs to actually
|
/// 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
|
/// be somewhat valid for decoding purposes, and the basics of decoding can
|
||||||
/// still fail.
|
/// still fail.
|
||||||
pub unsafe fn from_binary_unchecked(store: &Store, binary: &[u8]) -> Result<Module> {
|
pub unsafe fn from_binary_unchecked(engine: &Engine, binary: &[u8]) -> Result<Module> {
|
||||||
Module::compile(store, binary)
|
Module::compile(engine, binary)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Validates `binary` input data as a WebAssembly binary given the
|
/// 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
|
/// This function will perform a speedy validation of the `binary` input
|
||||||
/// WebAssembly module (which is in [binary form][binary], the text format
|
/// WebAssembly module (which is in [binary form][binary], the text format
|
||||||
/// is not accepted by this function) and return either `Ok` or `Err`
|
/// 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
|
/// configuration for WebAssembly features, for example, which are used to
|
||||||
/// indicate what should be valid and what shouldn't be.
|
/// indicate what should be valid and what shouldn't be.
|
||||||
///
|
///
|
||||||
@@ -299,29 +295,23 @@ impl Module {
|
|||||||
/// validation issue will be returned.
|
/// validation issue will be returned.
|
||||||
///
|
///
|
||||||
/// [binary]: https://webassembly.github.io/spec/core/binary/index.html
|
/// [binary]: https://webassembly.github.io/spec/core/binary/index.html
|
||||||
pub fn validate(store: &Store, binary: &[u8]) -> Result<()> {
|
pub fn validate(engine: &Engine, binary: &[u8]) -> Result<()> {
|
||||||
let config = store.engine().config().validating_config.clone();
|
let config = engine.config().validating_config.clone();
|
||||||
validate(binary, Some(config)).map_err(Error::new)
|
validate(binary, Some(config)).map_err(Error::new)
|
||||||
}
|
}
|
||||||
|
|
||||||
unsafe fn compile(store: &Store, binary: &[u8]) -> Result<Self> {
|
unsafe fn compile(engine: &Engine, binary: &[u8]) -> Result<Self> {
|
||||||
let compiled = CompiledModule::new(
|
let compiled = CompiledModule::new(engine.compiler(), binary, &*engine.config().profiler)?;
|
||||||
&mut store.compiler_mut(),
|
|
||||||
binary,
|
|
||||||
&*store.engine().config().profiler,
|
|
||||||
)?;
|
|
||||||
|
|
||||||
Ok(Module {
|
Ok(Module {
|
||||||
inner: Arc::new(ModuleInner {
|
engine: engine.clone(),
|
||||||
store: store.clone(),
|
compiled: Arc::new(compiled),
|
||||||
compiled,
|
frame_info_registration: Arc::new(Mutex::new(None)),
|
||||||
frame_info_registration: Mutex::new(None),
|
|
||||||
}),
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn compiled_module(&self) -> &CompiledModule {
|
pub(crate) fn compiled_module(&self) -> &CompiledModule {
|
||||||
&self.inner.compiled
|
&self.compiled
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns identifier/name that this [`Module`] has. This name
|
/// Returns identifier/name that this [`Module`] has. This name
|
||||||
@@ -336,20 +326,20 @@ impl Module {
|
|||||||
/// ```
|
/// ```
|
||||||
/// # use wasmtime::*;
|
/// # use wasmtime::*;
|
||||||
/// # fn main() -> anyhow::Result<()> {
|
/// # fn main() -> anyhow::Result<()> {
|
||||||
/// # let store = Store::default();
|
/// # let engine = Engine::default();
|
||||||
/// let module = Module::new(&store, "(module $foo)")?;
|
/// let module = Module::new(&engine, "(module $foo)")?;
|
||||||
/// assert_eq!(module.name(), Some("foo"));
|
/// assert_eq!(module.name(), Some("foo"));
|
||||||
///
|
///
|
||||||
/// let module = Module::new(&store, "(module)")?;
|
/// let module = Module::new(&engine, "(module)")?;
|
||||||
/// assert_eq!(module.name(), None);
|
/// 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"));
|
/// assert_eq!(module.name(), Some("bar"));
|
||||||
/// # Ok(())
|
/// # Ok(())
|
||||||
/// # }
|
/// # }
|
||||||
/// ```
|
/// ```
|
||||||
pub fn name(&self) -> Option<&str> {
|
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
|
/// Returns the list of imports that this [`Module`] has and must be
|
||||||
@@ -371,8 +361,8 @@ impl Module {
|
|||||||
/// ```
|
/// ```
|
||||||
/// # use wasmtime::*;
|
/// # use wasmtime::*;
|
||||||
/// # fn main() -> anyhow::Result<()> {
|
/// # fn main() -> anyhow::Result<()> {
|
||||||
/// # let store = Store::default();
|
/// # let engine = Engine::default();
|
||||||
/// let module = Module::new(&store, "(module)")?;
|
/// let module = Module::new(&engine, "(module)")?;
|
||||||
/// assert_eq!(module.imports().len(), 0);
|
/// assert_eq!(module.imports().len(), 0);
|
||||||
/// # Ok(())
|
/// # Ok(())
|
||||||
/// # }
|
/// # }
|
||||||
@@ -383,13 +373,13 @@ impl Module {
|
|||||||
/// ```
|
/// ```
|
||||||
/// # use wasmtime::*;
|
/// # use wasmtime::*;
|
||||||
/// # fn main() -> anyhow::Result<()> {
|
/// # fn main() -> anyhow::Result<()> {
|
||||||
/// # let store = Store::default();
|
/// # let engine = Engine::default();
|
||||||
/// let wat = r#"
|
/// let wat = r#"
|
||||||
/// (module
|
/// (module
|
||||||
/// (import "host" "foo" (func))
|
/// (import "host" "foo" (func))
|
||||||
/// )
|
/// )
|
||||||
/// "#;
|
/// "#;
|
||||||
/// let module = Module::new(&store, wat)?;
|
/// let module = Module::new(&engine, wat)?;
|
||||||
/// assert_eq!(module.imports().len(), 1);
|
/// assert_eq!(module.imports().len(), 1);
|
||||||
/// let import = module.imports().next().unwrap();
|
/// let import = module.imports().next().unwrap();
|
||||||
/// assert_eq!(import.module(), "host");
|
/// assert_eq!(import.module(), "host");
|
||||||
@@ -404,7 +394,7 @@ impl Module {
|
|||||||
pub fn imports<'module>(
|
pub fn imports<'module>(
|
||||||
&'module self,
|
&'module self,
|
||||||
) -> impl ExactSizeIterator<Item = ImportType<'module>> + 'module {
|
) -> impl ExactSizeIterator<Item = ImportType<'module>> + 'module {
|
||||||
let module = self.inner.compiled.module_ref();
|
let module = self.compiled.module();
|
||||||
module
|
module
|
||||||
.imports
|
.imports
|
||||||
.iter()
|
.iter()
|
||||||
@@ -429,8 +419,8 @@ impl Module {
|
|||||||
/// ```
|
/// ```
|
||||||
/// # use wasmtime::*;
|
/// # use wasmtime::*;
|
||||||
/// # fn main() -> anyhow::Result<()> {
|
/// # fn main() -> anyhow::Result<()> {
|
||||||
/// # let store = Store::default();
|
/// # let engine = Engine::default();
|
||||||
/// let module = Module::new(&store, "(module)")?;
|
/// let module = Module::new(&engine, "(module)")?;
|
||||||
/// assert!(module.exports().next().is_none());
|
/// assert!(module.exports().next().is_none());
|
||||||
/// # Ok(())
|
/// # Ok(())
|
||||||
/// # }
|
/// # }
|
||||||
@@ -441,14 +431,14 @@ impl Module {
|
|||||||
/// ```
|
/// ```
|
||||||
/// # use wasmtime::*;
|
/// # use wasmtime::*;
|
||||||
/// # fn main() -> anyhow::Result<()> {
|
/// # fn main() -> anyhow::Result<()> {
|
||||||
/// # let store = Store::default();
|
/// # let engine = Engine::default();
|
||||||
/// let wat = r#"
|
/// let wat = r#"
|
||||||
/// (module
|
/// (module
|
||||||
/// (func (export "foo"))
|
/// (func (export "foo"))
|
||||||
/// (memory (export "memory") 1)
|
/// (memory (export "memory") 1)
|
||||||
/// )
|
/// )
|
||||||
/// "#;
|
/// "#;
|
||||||
/// let module = Module::new(&store, wat)?;
|
/// let module = Module::new(&engine, wat)?;
|
||||||
/// assert_eq!(module.exports().len(), 2);
|
/// assert_eq!(module.exports().len(), 2);
|
||||||
///
|
///
|
||||||
/// let mut exports = module.exports();
|
/// let mut exports = module.exports();
|
||||||
@@ -471,7 +461,7 @@ impl Module {
|
|||||||
pub fn exports<'module>(
|
pub fn exports<'module>(
|
||||||
&'module self,
|
&'module self,
|
||||||
) -> impl ExactSizeIterator<Item = ExportType<'module>> + 'module {
|
) -> 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)| {
|
module.exports.iter().map(move |(name, entity_index)| {
|
||||||
let r#type = EntityType::new(entity_index, module);
|
let r#type = EntityType::new(entity_index, module);
|
||||||
ExportType::new(name, r#type)
|
ExportType::new(name, r#type)
|
||||||
@@ -489,8 +479,8 @@ impl Module {
|
|||||||
/// ```
|
/// ```
|
||||||
/// # use wasmtime::*;
|
/// # use wasmtime::*;
|
||||||
/// # fn main() -> anyhow::Result<()> {
|
/// # fn main() -> anyhow::Result<()> {
|
||||||
/// # let store = Store::default();
|
/// # let engine = Engine::default();
|
||||||
/// let module = Module::new(&store, "(module)")?;
|
/// let module = Module::new(&engine, "(module)")?;
|
||||||
/// assert!(module.get_export("foo").is_none());
|
/// assert!(module.get_export("foo").is_none());
|
||||||
/// # Ok(())
|
/// # Ok(())
|
||||||
/// # }
|
/// # }
|
||||||
@@ -501,14 +491,14 @@ impl Module {
|
|||||||
/// ```
|
/// ```
|
||||||
/// # use wasmtime::*;
|
/// # use wasmtime::*;
|
||||||
/// # fn main() -> anyhow::Result<()> {
|
/// # fn main() -> anyhow::Result<()> {
|
||||||
/// # let store = Store::default();
|
/// # let engine = Engine::default();
|
||||||
/// let wat = r#"
|
/// let wat = r#"
|
||||||
/// (module
|
/// (module
|
||||||
/// (func (export "foo"))
|
/// (func (export "foo"))
|
||||||
/// (memory (export "memory") 1)
|
/// (memory (export "memory") 1)
|
||||||
/// )
|
/// )
|
||||||
/// "#;
|
/// "#;
|
||||||
/// let module = Module::new(&store, wat)?;
|
/// let module = Module::new(&engine, wat)?;
|
||||||
/// let foo = module.get_export("foo");
|
/// let foo = module.get_export("foo");
|
||||||
/// assert!(foo.is_some());
|
/// assert!(foo.is_some());
|
||||||
///
|
///
|
||||||
@@ -522,26 +512,31 @@ impl Module {
|
|||||||
/// # }
|
/// # }
|
||||||
/// ```
|
/// ```
|
||||||
pub fn get_export<'module>(&'module self, name: &'module str) -> Option<ExternType> {
|
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)?;
|
let entity_index = module.exports.get(name)?;
|
||||||
Some(EntityType::new(entity_index, module).extern_type())
|
Some(EntityType::new(entity_index, module).extern_type())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the [`Store`] that this [`Module`] was compiled into.
|
/// Returns the [`Engine`] that this [`Module`] was compiled by.
|
||||||
pub fn store(&self) -> &Store {
|
pub fn engine(&self) -> &Engine {
|
||||||
&self.inner.store
|
&self.engine
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Register this module's stack frame information into the global scope.
|
/// Register this module's stack frame information into the global scope.
|
||||||
///
|
///
|
||||||
/// This is required to ensure that any traps can be properly symbolicated.
|
/// This is required to ensure that any traps can be properly symbolicated.
|
||||||
pub(crate) fn register_frame_info(&self) -> Option<Arc<GlobalFrameInfoRegistration>> {
|
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 {
|
if let Some(info) = &*info {
|
||||||
return info.clone();
|
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());
|
*info = Some(ret.clone());
|
||||||
return ret;
|
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 std::sync::Arc;
|
||||||
use wasmparser::{OperatorValidatorConfig, ValidatingParserConfig};
|
use wasmparser::{OperatorValidatorConfig, ValidatingParserConfig};
|
||||||
use wasmtime_environ::settings::{self, Configurable};
|
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_jit::{native, CompilationStrategy, Compiler};
|
||||||
use wasmtime_profiling::{JitDumpAgent, NullProfilerAgent, ProfilingAgent, VTuneAgent};
|
use wasmtime_profiling::{JitDumpAgent, NullProfilerAgent, ProfilingAgent, VTuneAgent};
|
||||||
use wasmtime_runtime::{
|
use wasmtime_runtime::{
|
||||||
debug_builtins, InstanceHandle, RuntimeMemoryCreator, SignalHandler, VMExternRef, VMInterrupts,
|
debug_builtins, InstanceHandle, RuntimeMemoryCreator, SignalHandler, SignatureRegistry,
|
||||||
|
VMExternRef, VMInterrupts, VMSharedSignatureIndex,
|
||||||
};
|
};
|
||||||
|
|
||||||
// Runtime Environment
|
// Runtime Environment
|
||||||
@@ -571,6 +572,16 @@ impl Config {
|
|||||||
cmp::max(guard_size, self.tunables.static_memory_offset_guard_size);
|
cmp::max(guard_size, self.tunables.static_memory_offset_guard_size);
|
||||||
self
|
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 {
|
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
|
/// You can create an engine with default configuration settings using
|
||||||
/// `Engine::default()`. Be sure to consult the documentation of [`Config`] for
|
/// `Engine::default()`. Be sure to consult the documentation of [`Config`] for
|
||||||
/// default settings.
|
/// default settings.
|
||||||
#[derive(Default, Clone)]
|
#[derive(Clone)]
|
||||||
pub struct Engine {
|
pub struct Engine {
|
||||||
config: Arc<Config>,
|
inner: Arc<EngineInner>,
|
||||||
|
}
|
||||||
|
|
||||||
|
struct EngineInner {
|
||||||
|
config: Config,
|
||||||
|
compiler: Compiler,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Engine {
|
impl Engine {
|
||||||
@@ -698,13 +714,31 @@ impl Engine {
|
|||||||
pub fn new(config: &Config) -> Engine {
|
pub fn new(config: &Config) -> Engine {
|
||||||
debug_builtins::ensure_exported();
|
debug_builtins::ensure_exported();
|
||||||
Engine {
|
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.
|
/// Returns the configuration settings that this engine is using.
|
||||||
pub fn config(&self) -> &Config {
|
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 {
|
pub(crate) struct StoreInner {
|
||||||
engine: Engine,
|
engine: Engine,
|
||||||
compiler: RefCell<Compiler>,
|
interrupts: Arc<VMInterrupts>,
|
||||||
|
signatures: RefCell<SignatureRegistry>,
|
||||||
instances: RefCell<Vec<InstanceHandle>>,
|
instances: RefCell<Vec<InstanceHandle>>,
|
||||||
signal_handler: RefCell<Option<Box<SignalHandler<'static>>>>,
|
signal_handler: RefCell<Option<Box<SignalHandler<'static>>>>,
|
||||||
|
jit_code_ranges: RefCell<Vec<(usize, usize)>>,
|
||||||
host_info: RefCell<HashMap<HostInfoKey, Rc<RefCell<dyn Any>>>>,
|
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.
|
// each one that's not relevant just won't do anything.
|
||||||
wasmtime_runtime::init_traps();
|
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 {
|
Store {
|
||||||
inner: Rc::new(StoreInner {
|
inner: Rc::new(StoreInner {
|
||||||
engine: engine.clone(),
|
engine: engine.clone(),
|
||||||
compiler: RefCell::new(compiler),
|
interrupts: Arc::new(Default::default()),
|
||||||
|
signatures: RefCell::new(Default::default()),
|
||||||
instances: RefCell::new(Vec::new()),
|
instances: RefCell::new(Vec::new()),
|
||||||
signal_handler: RefCell::new(None),
|
signal_handler: RefCell::new(None),
|
||||||
|
jit_code_ranges: RefCell::new(Vec::new()),
|
||||||
host_info: RefCell::new(HashMap::new()),
|
host_info: RefCell::new(HashMap::new()),
|
||||||
}),
|
}),
|
||||||
}
|
}
|
||||||
@@ -798,15 +829,61 @@ impl Store {
|
|||||||
|
|
||||||
/// Returns an optional reference to a ['RuntimeMemoryCreator']
|
/// Returns an optional reference to a ['RuntimeMemoryCreator']
|
||||||
pub(crate) fn memory_creator(&self) -> Option<&dyn 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> {
|
pub(crate) fn lookup_signature(&self, sig_index: VMSharedSignatureIndex) -> wasm::WasmFuncType {
|
||||||
self.inner.compiler.borrow()
|
self.inner
|
||||||
|
.signatures
|
||||||
|
.borrow()
|
||||||
|
.lookup_wasm(sig_index)
|
||||||
|
.expect("failed to lookup signature")
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn compiler_mut(&self) -> std::cell::RefMut<'_, Compiler> {
|
pub(crate) fn register_signature(
|
||||||
self.inner.compiler.borrow_mut()
|
&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 {
|
pub(crate) unsafe fn add_instance(&self, handle: InstanceHandle) -> StoreInstanceHandle {
|
||||||
@@ -875,6 +952,10 @@ impl Store {
|
|||||||
self.inner.signal_handler.borrow_mut()
|
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
|
/// Returns whether the stores `a` and `b` refer to the same underlying
|
||||||
/// `Store`.
|
/// `Store`.
|
||||||
///
|
///
|
||||||
@@ -946,10 +1027,10 @@ impl Store {
|
|||||||
/// let interrupt_handle = store.interrupt_handle()?;
|
/// let interrupt_handle = store.interrupt_handle()?;
|
||||||
///
|
///
|
||||||
/// // Compile and instantiate a small example with an infinite loop.
|
/// // 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))
|
/// (func (export "run") (loop br 0))
|
||||||
/// "#)?;
|
/// "#)?;
|
||||||
/// let instance = Instance::new(&module, &[])?;
|
/// let instance = Instance::new(&store, &module, &[])?;
|
||||||
/// let run = instance
|
/// let run = instance
|
||||||
/// .get_func("run")
|
/// .get_func("run")
|
||||||
/// .ok_or(anyhow::format_err!("failed to find `run` function export"))?
|
/// .ok_or(anyhow::format_err!("failed to find `run` function export"))?
|
||||||
@@ -967,9 +1048,9 @@ impl Store {
|
|||||||
/// # }
|
/// # }
|
||||||
/// ```
|
/// ```
|
||||||
pub fn interrupt_handle(&self) -> Result<InterruptHandle> {
|
pub fn interrupt_handle(&self) -> Result<InterruptHandle> {
|
||||||
if self.engine().config.tunables.interruptable {
|
if self.engine().config().tunables.interruptable {
|
||||||
Ok(InterruptHandle {
|
Ok(InterruptHandle {
|
||||||
interrupts: self.compiler().interrupts().clone(),
|
interrupts: self.interrupts().clone(),
|
||||||
})
|
})
|
||||||
} else {
|
} else {
|
||||||
bail!("interrupts aren't enabled for this `Store`")
|
bail!("interrupts aren't enabled for this `Store`")
|
||||||
@@ -1052,47 +1133,47 @@ mod tests {
|
|||||||
let mut cfg = Config::new();
|
let mut cfg = Config::new();
|
||||||
cfg.cranelift_opt_level(OptLevel::None)
|
cfg.cranelift_opt_level(OptLevel::None)
|
||||||
.cache_config_load(&config_path)?;
|
.cache_config_load(&config_path)?;
|
||||||
let store = Store::new(&Engine::new(&cfg));
|
let engine = Engine::new(&cfg);
|
||||||
Module::new(&store, "(module (func))")?;
|
Module::new(&engine, "(module (func))")?;
|
||||||
assert_eq!(store.engine().config.cache_config.cache_hits(), 0);
|
assert_eq!(engine.config().cache_config.cache_hits(), 0);
|
||||||
assert_eq!(store.engine().config.cache_config.cache_misses(), 1);
|
assert_eq!(engine.config().cache_config.cache_misses(), 1);
|
||||||
Module::new(&store, "(module (func))")?;
|
Module::new(&engine, "(module (func))")?;
|
||||||
assert_eq!(store.engine().config.cache_config.cache_hits(), 1);
|
assert_eq!(engine.config().cache_config.cache_hits(), 1);
|
||||||
assert_eq!(store.engine().config.cache_config.cache_misses(), 1);
|
assert_eq!(engine.config().cache_config.cache_misses(), 1);
|
||||||
|
|
||||||
let mut cfg = Config::new();
|
let mut cfg = Config::new();
|
||||||
cfg.cranelift_opt_level(OptLevel::Speed)
|
cfg.cranelift_opt_level(OptLevel::Speed)
|
||||||
.cache_config_load(&config_path)?;
|
.cache_config_load(&config_path)?;
|
||||||
let store = Store::new(&Engine::new(&cfg));
|
let engine = Engine::new(&cfg);
|
||||||
Module::new(&store, "(module (func))")?;
|
Module::new(&engine, "(module (func))")?;
|
||||||
assert_eq!(store.engine().config.cache_config.cache_hits(), 0);
|
assert_eq!(engine.config().cache_config.cache_hits(), 0);
|
||||||
assert_eq!(store.engine().config.cache_config.cache_misses(), 1);
|
assert_eq!(engine.config().cache_config.cache_misses(), 1);
|
||||||
Module::new(&store, "(module (func))")?;
|
Module::new(&engine, "(module (func))")?;
|
||||||
assert_eq!(store.engine().config.cache_config.cache_hits(), 1);
|
assert_eq!(engine.config().cache_config.cache_hits(), 1);
|
||||||
assert_eq!(store.engine().config.cache_config.cache_misses(), 1);
|
assert_eq!(engine.config().cache_config.cache_misses(), 1);
|
||||||
|
|
||||||
let mut cfg = Config::new();
|
let mut cfg = Config::new();
|
||||||
cfg.cranelift_opt_level(OptLevel::SpeedAndSize)
|
cfg.cranelift_opt_level(OptLevel::SpeedAndSize)
|
||||||
.cache_config_load(&config_path)?;
|
.cache_config_load(&config_path)?;
|
||||||
let store = Store::new(&Engine::new(&cfg));
|
let engine = Engine::new(&cfg);
|
||||||
Module::new(&store, "(module (func))")?;
|
Module::new(&engine, "(module (func))")?;
|
||||||
assert_eq!(store.engine().config.cache_config.cache_hits(), 0);
|
assert_eq!(engine.config().cache_config.cache_hits(), 0);
|
||||||
assert_eq!(store.engine().config.cache_config.cache_misses(), 1);
|
assert_eq!(engine.config().cache_config.cache_misses(), 1);
|
||||||
Module::new(&store, "(module (func))")?;
|
Module::new(&engine, "(module (func))")?;
|
||||||
assert_eq!(store.engine().config.cache_config.cache_hits(), 1);
|
assert_eq!(engine.config().cache_config.cache_hits(), 1);
|
||||||
assert_eq!(store.engine().config.cache_config.cache_misses(), 1);
|
assert_eq!(engine.config().cache_config.cache_misses(), 1);
|
||||||
|
|
||||||
// FIXME(#1523) need debuginfo on aarch64 before we run this test there
|
// FIXME(#1523) need debuginfo on aarch64 before we run this test there
|
||||||
if !cfg!(target_arch = "aarch64") {
|
if !cfg!(target_arch = "aarch64") {
|
||||||
let mut cfg = Config::new();
|
let mut cfg = Config::new();
|
||||||
cfg.debug_info(true).cache_config_load(&config_path)?;
|
cfg.debug_info(true).cache_config_load(&config_path)?;
|
||||||
let store = Store::new(&Engine::new(&cfg));
|
let engine = Engine::new(&cfg);
|
||||||
Module::new(&store, "(module (func))")?;
|
Module::new(&engine, "(module (func))")?;
|
||||||
assert_eq!(store.engine().config.cache_config.cache_hits(), 0);
|
assert_eq!(engine.config().cache_config.cache_hits(), 0);
|
||||||
assert_eq!(store.engine().config.cache_config.cache_misses(), 1);
|
assert_eq!(engine.config().cache_config.cache_misses(), 1);
|
||||||
Module::new(&store, "(module (func))")?;
|
Module::new(&engine, "(module (func))")?;
|
||||||
assert_eq!(store.engine().config.cache_config.cache_hits(), 1);
|
assert_eq!(engine.config().cache_config.cache_hits(), 1);
|
||||||
assert_eq!(store.engine().config.cache_config.cache_misses(), 1);
|
assert_eq!(engine.config().cache_config.cache_misses(), 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|||||||
@@ -32,25 +32,20 @@ pub(crate) fn create_handle(
|
|||||||
.local
|
.local
|
||||||
.signatures
|
.signatures
|
||||||
.values()
|
.values()
|
||||||
.map(|(wasm, native)| {
|
.map(|(wasm, native)| store.register_signature(wasm.clone(), native.clone()))
|
||||||
store
|
|
||||||
.compiler()
|
|
||||||
.signatures()
|
|
||||||
.register(wasm.clone(), native.clone())
|
|
||||||
})
|
|
||||||
.collect::<PrimaryMap<_, _>>();
|
.collect::<PrimaryMap<_, _>>();
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
let handle = InstanceHandle::new(
|
let handle = InstanceHandle::new(
|
||||||
Arc::new(module),
|
Arc::new(module),
|
||||||
|
Arc::new(()),
|
||||||
finished_functions.into_boxed_slice(),
|
finished_functions.into_boxed_slice(),
|
||||||
trampolines,
|
trampolines,
|
||||||
imports,
|
imports,
|
||||||
store.memory_creator(),
|
store.memory_creator(),
|
||||||
signatures.into_boxed_slice(),
|
signatures.into_boxed_slice(),
|
||||||
None,
|
|
||||||
state,
|
state,
|
||||||
store.compiler().interrupts().clone(),
|
store.interrupts().clone(),
|
||||||
)?;
|
)?;
|
||||||
Ok(store.add_instance(handle))
|
Ok(store.add_instance(handle))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -247,10 +247,7 @@ pub fn create_handle_with_function(
|
|||||||
mem::size_of::<u128>(),
|
mem::size_of::<u128>(),
|
||||||
)?;
|
)?;
|
||||||
assert!(relocations.is_empty());
|
assert!(relocations.is_empty());
|
||||||
let sig_id = store
|
let sig_id = store.register_signature(ft.to_wasm_func_type(), sig);
|
||||||
.compiler()
|
|
||||||
.signatures()
|
|
||||||
.register(ft.to_wasm_func_type(), sig);
|
|
||||||
trampolines.insert(sig_id, trampoline);
|
trampolines.insert(sig_id, trampoline);
|
||||||
|
|
||||||
// Next up we wrap everything up into an `InstanceHandle` by publishing our
|
// 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
|
.exports
|
||||||
.insert("trampoline".to_string(), EntityIndex::Function(func_id));
|
.insert("trampoline".to_string(), EntityIndex::Function(func_id));
|
||||||
finished_functions.push(func);
|
finished_functions.push(func);
|
||||||
let sig_id = store
|
let sig_id = store.register_signature(ft.to_wasm_func_type(), sig);
|
||||||
.compiler()
|
|
||||||
.signatures()
|
|
||||||
.register(ft.to_wasm_func_type(), sig);
|
|
||||||
trampolines.insert(sig_id, trampoline);
|
trampolines.insert(sig_id, trampoline);
|
||||||
|
|
||||||
create_handle(module, store, finished_functions, trampolines, state)
|
create_handle(module, store, finished_functions, trampolines, state)
|
||||||
|
|||||||
@@ -84,7 +84,7 @@ impl WastContext {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn instantiate(&mut self, module: &[u8]) -> Result<Outcome<Instance>> {
|
fn instantiate(&mut self, module: &[u8]) -> Result<Outcome<Instance>> {
|
||||||
let module = Module::new(&self.store, module)?;
|
let module = Module::new(self.store.engine(), module)?;
|
||||||
self.modules.push(module.clone());
|
self.modules.push(module.clone());
|
||||||
let instance = match self.linker.instantiate(&module) {
|
let instance = match self.linker.instantiate(&module) {
|
||||||
Ok(i) => i,
|
Ok(i) => i,
|
||||||
|
|||||||
@@ -55,21 +55,22 @@ use std::error::Error;
|
|||||||
use wasmtime::*;
|
use wasmtime::*;
|
||||||
|
|
||||||
fn main() -> Result<(), Box<dyn Error>> {
|
fn main() -> Result<(), Box<dyn Error>> {
|
||||||
|
let engine = Engine::default();
|
||||||
// A `Store` is a sort of "global object" in a sense, but for now it suffices
|
// A `Store` is a sort of "global object" in a sense, but for now it suffices
|
||||||
// to say that it's generally passed to most constructors.
|
// to say that it's generally passed to most constructors.
|
||||||
let store = Store::default();
|
let store = Store::new(&engine);
|
||||||
|
|
||||||
# if false {
|
# if false {
|
||||||
// We start off by creating a `Module` which represents a compiled form
|
// We start off by creating a `Module` which represents a compiled form
|
||||||
// of our input wasm module. In this case it'll be JIT-compiled after
|
// of our input wasm module. In this case it'll be JIT-compiled after
|
||||||
// we parse the text format.
|
// we parse the text format.
|
||||||
let module = Module::from_file(&store, "hello.wat")?;
|
let module = Module::from_file(&engine, "hello.wat")?;
|
||||||
# }
|
# }
|
||||||
# let module = Module::new(&store, r#"(module (func (export "answer") (result i32) i32.const 42))"#)?;
|
# let module = Module::new(&engine, r#"(module (func (export "answer") (result i32) i32.const 42))"#)?;
|
||||||
|
|
||||||
// After we have a compiled `Module` we can then instantiate it, creating
|
// After we have a compiled `Module` we can then instantiate it, creating
|
||||||
// an `Instance` which we can actually poke at functions on.
|
// an `Instance` which we can actually poke at functions on.
|
||||||
let instance = Instance::new(&module, &[])?;
|
let instance = Instance::new(&store, &module, &[])?;
|
||||||
|
|
||||||
// The `Instance` gives us access to various exported functions and items,
|
// The `Instance` gives us access to various exported functions and items,
|
||||||
// which we access here to pull out our `answer` exported function and
|
// which we access here to pull out our `answer` exported function and
|
||||||
@@ -142,11 +143,12 @@ use std::error::Error;
|
|||||||
use wasmtime::*;
|
use wasmtime::*;
|
||||||
|
|
||||||
fn main() -> Result<(), Box<dyn Error>> {
|
fn main() -> Result<(), Box<dyn Error>> {
|
||||||
let store = Store::default();
|
let engine = Engine::default();
|
||||||
|
let store = Store::new(&engine);
|
||||||
# if false {
|
# if false {
|
||||||
let module = Module::from_file(&store, "hello.wat")?;
|
let module = Module::from_file(&engine, "hello.wat")?;
|
||||||
# }
|
# }
|
||||||
# let module = Module::new(&store, r#"(module (import "" "log" (func $log (param i32))) (import "" "double" (func $double (param i32) (result i32))) (func (export "run") i32.const 0 call $log i32.const 1 call $log i32.const 2 call $double call $log))"#)?;
|
# let module = Module::new(&engine, r#"(module (import "" "log" (func $log (param i32))) (import "" "double" (func $double (param i32) (result i32))) (func (export "run") i32.const 0 call $log i32.const 1 call $log i32.const 2 call $double call $log))"#)?;
|
||||||
|
|
||||||
// First we can create our `log` function, which will simply print out the
|
// First we can create our `log` function, which will simply print out the
|
||||||
// parameter it receives.
|
// parameter it receives.
|
||||||
@@ -160,7 +162,7 @@ fn main() -> Result<(), Box<dyn Error>> {
|
|||||||
// When instantiating the module we now need to provide the imports to the
|
// When instantiating the module we now need to provide the imports to the
|
||||||
// instantiation process. This is the second slice argument, where each
|
// instantiation process. This is the second slice argument, where each
|
||||||
// entry in the slice must line up with the imports in the module.
|
// entry in the slice must line up with the imports in the module.
|
||||||
let instance = Instance::new(&module, &[log.into(), double.into()])?;
|
let instance = Instance::new(&store, &module, &[log.into(), double.into()])?;
|
||||||
|
|
||||||
let run = instance
|
let run = instance
|
||||||
.get_func("run")
|
.get_func("run")
|
||||||
|
|||||||
@@ -37,7 +37,8 @@ You can also see how this works in the Rust API like so:
|
|||||||
use wasmtime::*;
|
use wasmtime::*;
|
||||||
|
|
||||||
# fn main() -> anyhow::Result<()> {
|
# fn main() -> anyhow::Result<()> {
|
||||||
let store = Store::default();
|
let engine = Engine::default();
|
||||||
|
let store = Store::new(&engine);
|
||||||
let wat = r#"
|
let wat = r#"
|
||||||
(module
|
(module
|
||||||
(func (export "add") (param i32 i32) (result i32)
|
(func (export "add") (param i32 i32) (result i32)
|
||||||
@@ -45,8 +46,8 @@ let wat = r#"
|
|||||||
local.get 1
|
local.get 1
|
||||||
i32.add))
|
i32.add))
|
||||||
"#;
|
"#;
|
||||||
let module = Module::new(&store, wat)?;
|
let module = Module::new(&engine, wat)?;
|
||||||
let instance = Instance::new(&module, &[])?;
|
let instance = Instance::new(&store, &module, &[])?;
|
||||||
let add = instance.get_func("add").unwrap();
|
let add = instance.get_func("add").unwrap();
|
||||||
let add = add.get2::<i32, i32, i32>()?;
|
let add = add.get2::<i32, i32, i32>()?;
|
||||||
println!("1 + 2 = {}", add(1, 2)?);
|
println!("1 + 2 = {}", add(1, 2)?);
|
||||||
|
|||||||
@@ -71,7 +71,7 @@ int main(int argc, const char* argv[]) {
|
|||||||
printf("Instantiating module...\n");
|
printf("Instantiating module...\n");
|
||||||
wasm_instance_t* instance = NULL;
|
wasm_instance_t* instance = NULL;
|
||||||
wasm_trap_t *trap = NULL;
|
wasm_trap_t *trap = NULL;
|
||||||
error = wasmtime_instance_new(module, NULL, 0, &instance, &trap);
|
error = wasmtime_instance_new(store, module, NULL, 0, &instance, &trap);
|
||||||
if (error != NULL || trap != NULL)
|
if (error != NULL || trap != NULL)
|
||||||
exit_with_error("failed to instantiate", error, trap);
|
exit_with_error("failed to instantiate", error, trap);
|
||||||
wasm_module_delete(module);
|
wasm_module_delete(module);
|
||||||
|
|||||||
@@ -17,8 +17,8 @@ fn main() -> Result<()> {
|
|||||||
// debugged in GDB.
|
// debugged in GDB.
|
||||||
let engine = Engine::new(Config::new().debug_info(true));
|
let engine = Engine::new(Config::new().debug_info(true));
|
||||||
let store = Store::new(&engine);
|
let store = Store::new(&engine);
|
||||||
let module = Module::from_file(&store, "target/wasm32-unknown-unknown/debug/fib.wasm")?;
|
let module = Module::from_file(&engine, "target/wasm32-unknown-unknown/debug/fib.wasm")?;
|
||||||
let instance = Instance::new(&module, &[])?;
|
let instance = Instance::new(&store, &module, &[])?;
|
||||||
|
|
||||||
// Invoke `fib` export
|
// Invoke `fib` export
|
||||||
let fib = instance
|
let fib = instance
|
||||||
|
|||||||
@@ -65,7 +65,7 @@ int main() {
|
|||||||
wasm_byte_vec_delete(&wasm);
|
wasm_byte_vec_delete(&wasm);
|
||||||
wasm_trap_t *trap = NULL;
|
wasm_trap_t *trap = NULL;
|
||||||
wasm_instance_t *instance = NULL;
|
wasm_instance_t *instance = NULL;
|
||||||
error = wasmtime_instance_new(module, NULL, 0, &instance, &trap);
|
error = wasmtime_instance_new(store, module, NULL, 0, &instance, &trap);
|
||||||
if (instance == NULL)
|
if (instance == NULL)
|
||||||
exit_with_error("failed to instantiate", error, trap);
|
exit_with_error("failed to instantiate", error, trap);
|
||||||
|
|
||||||
|
|||||||
@@ -11,8 +11,8 @@ fn main() -> Result<()> {
|
|||||||
// `Module` which is attached to a `Store` cache. After we've got that we
|
// `Module` which is attached to a `Store` cache. After we've got that we
|
||||||
// can instantiate it.
|
// can instantiate it.
|
||||||
let store = Store::default();
|
let store = Store::default();
|
||||||
let module = Module::from_file(&store, "examples/gcd.wat")?;
|
let module = Module::from_file(store.engine(), "examples/gcd.wat")?;
|
||||||
let instance = Instance::new(&module, &[])?;
|
let instance = Instance::new(&store, &module, &[])?;
|
||||||
|
|
||||||
// Invoke `gcd` export
|
// Invoke `gcd` export
|
||||||
let gcd = instance
|
let gcd = instance
|
||||||
|
|||||||
@@ -87,7 +87,7 @@ int main() {
|
|||||||
wasm_trap_t *trap = NULL;
|
wasm_trap_t *trap = NULL;
|
||||||
wasm_instance_t *instance = NULL;
|
wasm_instance_t *instance = NULL;
|
||||||
const wasm_extern_t *imports[] = { wasm_func_as_extern(hello) };
|
const wasm_extern_t *imports[] = { wasm_func_as_extern(hello) };
|
||||||
error = wasmtime_instance_new(module, imports, 1, &instance, &trap);
|
error = wasmtime_instance_new(store, module, imports, 1, &instance, &trap);
|
||||||
if (instance == NULL)
|
if (instance == NULL)
|
||||||
exit_with_error("failed to instantiate", error, trap);
|
exit_with_error("failed to instantiate", error, trap);
|
||||||
|
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ fn main() -> Result<()> {
|
|||||||
|
|
||||||
// Compile the wasm binary into an in-memory instance of a `Module`.
|
// Compile the wasm binary into an in-memory instance of a `Module`.
|
||||||
println!("Compiling module...");
|
println!("Compiling module...");
|
||||||
let module = Module::from_file(&store, "examples/hello.wat")?;
|
let module = Module::from_file(store.engine(), "examples/hello.wat")?;
|
||||||
|
|
||||||
// Here we handle the imports of the module, which in this case is our
|
// Here we handle the imports of the module, which in this case is our
|
||||||
// `HelloCallback` type and its associated implementation of `Callback.
|
// `HelloCallback` type and its associated implementation of `Callback.
|
||||||
@@ -30,7 +30,7 @@ fn main() -> Result<()> {
|
|||||||
// Note that this is where the wasm `start` function, if any, would run.
|
// Note that this is where the wasm `start` function, if any, would run.
|
||||||
println!("Instantiating module...");
|
println!("Instantiating module...");
|
||||||
let imports = [hello_func.into()];
|
let imports = [hello_func.into()];
|
||||||
let instance = Instance::new(&module, &imports)?;
|
let instance = Instance::new(&store, &module, &imports)?;
|
||||||
|
|
||||||
// Next we poke around a bit to extract the `run` function from the module.
|
// Next we poke around a bit to extract the `run` function from the module.
|
||||||
println!("Extracting export...");
|
println!("Extracting export...");
|
||||||
|
|||||||
@@ -93,7 +93,7 @@ int main() {
|
|||||||
wasm_byte_vec_delete(&wasm);
|
wasm_byte_vec_delete(&wasm);
|
||||||
if (error != NULL)
|
if (error != NULL)
|
||||||
exit_with_error("failed to compile module", error, NULL);
|
exit_with_error("failed to compile module", error, NULL);
|
||||||
error = wasmtime_instance_new(module, NULL, 0, &instance, &trap);
|
error = wasmtime_instance_new(store, module, NULL, 0, &instance, &trap);
|
||||||
if (instance == NULL)
|
if (instance == NULL)
|
||||||
exit_with_error("failed to instantiate", error, trap);
|
exit_with_error("failed to instantiate", error, trap);
|
||||||
|
|
||||||
|
|||||||
@@ -14,8 +14,8 @@ fn main() -> Result<()> {
|
|||||||
let interrupt_handle = store.interrupt_handle()?;
|
let interrupt_handle = store.interrupt_handle()?;
|
||||||
|
|
||||||
// Compile and instantiate a small example with an infinite loop.
|
// Compile and instantiate a small example with an infinite loop.
|
||||||
let module = Module::from_file(&store, "examples/interrupt.wat")?;
|
let module = Module::from_file(&engine, "examples/interrupt.wat")?;
|
||||||
let instance = Instance::new(&module, &[])?;
|
let instance = Instance::new(&store, &module, &[])?;
|
||||||
let run = instance
|
let run = instance
|
||||||
.get_func("run")
|
.get_func("run")
|
||||||
.ok_or(anyhow::format_err!("failed to find `run` function export"))?
|
.ok_or(anyhow::format_err!("failed to find `run` function export"))?
|
||||||
|
|||||||
@@ -7,7 +7,8 @@ use wasmtime::*;
|
|||||||
use wasmtime_wasi::{Wasi, WasiCtx};
|
use wasmtime_wasi::{Wasi, WasiCtx};
|
||||||
|
|
||||||
fn main() -> Result<()> {
|
fn main() -> Result<()> {
|
||||||
let store = Store::default();
|
let engine = Engine::default();
|
||||||
|
let store = Store::new(&engine);
|
||||||
|
|
||||||
// First set up our linker which is going to be linking modules together. We
|
// First set up our linker which is going to be linking modules together. We
|
||||||
// want our linker to have wasi available, so we set that up here as well.
|
// want our linker to have wasi available, so we set that up here as well.
|
||||||
@@ -16,8 +17,8 @@ fn main() -> Result<()> {
|
|||||||
wasi.add_to_linker(&mut linker)?;
|
wasi.add_to_linker(&mut linker)?;
|
||||||
|
|
||||||
// Load and compile our two modules
|
// Load and compile our two modules
|
||||||
let linking1 = Module::from_file(&store, "examples/linking1.wat")?;
|
let linking1 = Module::from_file(&engine, "examples/linking1.wat")?;
|
||||||
let linking2 = Module::from_file(&store, "examples/linking2.wat")?;
|
let linking2 = Module::from_file(&engine, "examples/linking2.wat")?;
|
||||||
|
|
||||||
// Instantiate our first module which only uses WASI, then register that
|
// Instantiate our first module which only uses WASI, then register that
|
||||||
// instance with the linker since the next linking will use it.
|
// instance with the linker since the next linking will use it.
|
||||||
|
|||||||
@@ -167,7 +167,7 @@ int main(int argc, const char* argv[]) {
|
|||||||
printf("Instantiating module...\n");
|
printf("Instantiating module...\n");
|
||||||
wasm_instance_t* instance = NULL;
|
wasm_instance_t* instance = NULL;
|
||||||
wasm_trap_t *trap = NULL;
|
wasm_trap_t *trap = NULL;
|
||||||
error = wasmtime_instance_new(module, NULL, 0, &instance, &trap);
|
error = wasmtime_instance_new(store, module, NULL, 0, &instance, &trap);
|
||||||
if (!instance)
|
if (!instance)
|
||||||
exit_with_error("failed to instantiate", error, trap);
|
exit_with_error("failed to instantiate", error, trap);
|
||||||
|
|
||||||
|
|||||||
@@ -13,8 +13,8 @@ fn main() -> Result<()> {
|
|||||||
// Create our `Store` context and then compile a module and create an
|
// Create our `Store` context and then compile a module and create an
|
||||||
// instance from the compiled module all in one go.
|
// instance from the compiled module all in one go.
|
||||||
let wasmtime_store = Store::default();
|
let wasmtime_store = Store::default();
|
||||||
let module = Module::from_file(&wasmtime_store, "examples/memory.wat")?;
|
let module = Module::from_file(wasmtime_store.engine(), "examples/memory.wat")?;
|
||||||
let instance = Instance::new(&module, &[])?;
|
let instance = Instance::new(&wasmtime_store, &module, &[])?;
|
||||||
|
|
||||||
// Load up our exports from the instance
|
// Load up our exports from the instance
|
||||||
let memory = instance
|
let memory = instance
|
||||||
|
|||||||
@@ -115,7 +115,7 @@ int main(int argc, const char* argv[]) {
|
|||||||
const wasm_extern_t* imports[] = {wasm_func_as_extern(callback_func)};
|
const wasm_extern_t* imports[] = {wasm_func_as_extern(callback_func)};
|
||||||
wasm_instance_t* instance = NULL;
|
wasm_instance_t* instance = NULL;
|
||||||
wasm_trap_t* trap = NULL;
|
wasm_trap_t* trap = NULL;
|
||||||
error = wasmtime_instance_new(module, imports, 1, &instance, &trap);
|
error = wasmtime_instance_new(store, module, imports, 1, &instance, &trap);
|
||||||
if (!instance)
|
if (!instance)
|
||||||
exit_with_error("failed to instantiate", error, trap);
|
exit_with_error("failed to instantiate", error, trap);
|
||||||
|
|
||||||
|
|||||||
@@ -12,11 +12,12 @@ use wasmtime::*;
|
|||||||
|
|
||||||
fn main() -> Result<()> {
|
fn main() -> Result<()> {
|
||||||
println!("Initializing...");
|
println!("Initializing...");
|
||||||
let store = Store::default();
|
let engine = Engine::default();
|
||||||
|
let store = Store::new(&engine);
|
||||||
|
|
||||||
// Compile.
|
// Compile.
|
||||||
println!("Compiling module...");
|
println!("Compiling module...");
|
||||||
let module = Module::from_file(&store, "examples/multi.wat")?;
|
let module = Module::from_file(&engine, "examples/multi.wat")?;
|
||||||
|
|
||||||
// Create external print functions.
|
// Create external print functions.
|
||||||
println!("Creating callback...");
|
println!("Creating callback...");
|
||||||
@@ -35,7 +36,7 @@ fn main() -> Result<()> {
|
|||||||
|
|
||||||
// Instantiate.
|
// Instantiate.
|
||||||
println!("Instantiating module...");
|
println!("Instantiating module...");
|
||||||
let instance = Instance::new(&module, &[callback_func.into()])?;
|
let instance = Instance::new(&store, &module, &[callback_func.into()])?;
|
||||||
|
|
||||||
// Extract exports.
|
// Extract exports.
|
||||||
println!("Extracting export...");
|
println!("Extracting export...");
|
||||||
|
|||||||
184
examples/threads.c
Normal file
184
examples/threads.c
Normal file
@@ -0,0 +1,184 @@
|
|||||||
|
#ifndef _WIN32
|
||||||
|
|
||||||
|
#include <inttypes.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <pthread.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <wasm.h>
|
||||||
|
#include <wasmtime.h>
|
||||||
|
|
||||||
|
#define own
|
||||||
|
|
||||||
|
static void exit_with_error(const char *message, wasmtime_error_t *error, wasm_trap_t *trap);
|
||||||
|
|
||||||
|
const int N_THREADS = 10;
|
||||||
|
const int N_REPS = 3;
|
||||||
|
|
||||||
|
// A function to be called from Wasm code.
|
||||||
|
own wasm_trap_t* callback(const wasm_val_t args[], wasm_val_t results[]) {
|
||||||
|
assert(args[0].kind == WASM_I32);
|
||||||
|
printf("> Thread %d running\n", args[0].of.i32);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
wasm_engine_t* engine;
|
||||||
|
wasm_shared_module_t* module;
|
||||||
|
int id;
|
||||||
|
} thread_args;
|
||||||
|
|
||||||
|
void* run(void* args_abs) {
|
||||||
|
thread_args* args = (thread_args*)args_abs;
|
||||||
|
|
||||||
|
// Rereate store and module.
|
||||||
|
own wasm_store_t* store = wasm_store_new(args->engine);
|
||||||
|
own wasm_module_t* module = wasm_module_obtain(store, args->module);
|
||||||
|
|
||||||
|
// Run the example N times.
|
||||||
|
for (int i = 0; i < N_REPS; ++i) {
|
||||||
|
usleep(100000);
|
||||||
|
|
||||||
|
// Create imports.
|
||||||
|
own wasm_functype_t* func_type = wasm_functype_new_1_0(wasm_valtype_new_i32());
|
||||||
|
own wasm_func_t* func = wasm_func_new(store, func_type, callback);
|
||||||
|
wasm_functype_delete(func_type);
|
||||||
|
|
||||||
|
wasm_val_t val = {.kind = WASM_I32, .of = {.i32 = (int32_t)args->id}};
|
||||||
|
own wasm_globaltype_t* global_type =
|
||||||
|
wasm_globaltype_new(wasm_valtype_new_i32(), WASM_CONST);
|
||||||
|
own wasm_global_t* global = wasm_global_new(store, global_type, &val);
|
||||||
|
wasm_globaltype_delete(global_type);
|
||||||
|
|
||||||
|
// Instantiate.
|
||||||
|
const wasm_extern_t* imports[] = {
|
||||||
|
wasm_func_as_extern(func), wasm_global_as_extern(global),
|
||||||
|
};
|
||||||
|
own wasm_instance_t* instance =
|
||||||
|
wasm_instance_new(store, module, imports, NULL);
|
||||||
|
if (!instance) {
|
||||||
|
printf("> Error instantiating module!\n");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
wasm_func_delete(func);
|
||||||
|
wasm_global_delete(global);
|
||||||
|
|
||||||
|
// Extract export.
|
||||||
|
own wasm_extern_vec_t exports;
|
||||||
|
wasm_instance_exports(instance, &exports);
|
||||||
|
if (exports.size == 0) {
|
||||||
|
printf("> Error accessing exports!\n");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
const wasm_func_t *run_func = wasm_extern_as_func(exports.data[0]);
|
||||||
|
if (run_func == NULL) {
|
||||||
|
printf("> Error accessing export!\n");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
wasm_instance_delete(instance);
|
||||||
|
|
||||||
|
// Call.
|
||||||
|
if (wasm_func_call(run_func, NULL, NULL)) {
|
||||||
|
printf("> Error calling function!\n");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
wasm_extern_vec_delete(&exports);
|
||||||
|
}
|
||||||
|
|
||||||
|
wasm_module_delete(module);
|
||||||
|
wasm_store_delete(store);
|
||||||
|
|
||||||
|
free(args_abs);
|
||||||
|
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, const char *argv[]) {
|
||||||
|
// Initialize.
|
||||||
|
wasm_engine_t* engine = wasm_engine_new();
|
||||||
|
|
||||||
|
// Load our input file to parse it next
|
||||||
|
FILE* file = fopen("examples/threads.wat", "r");
|
||||||
|
if (!file) {
|
||||||
|
printf("> Error loading file!\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
fseek(file, 0L, SEEK_END);
|
||||||
|
size_t file_size = ftell(file);
|
||||||
|
fseek(file, 0L, SEEK_SET);
|
||||||
|
wasm_byte_vec_t wat;
|
||||||
|
wasm_byte_vec_new_uninitialized(&wat, file_size);
|
||||||
|
if (fread(wat.data, file_size, 1, file) != 1) {
|
||||||
|
printf("> Error loading module!\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
fclose(file);
|
||||||
|
|
||||||
|
// Parse the wat into the binary wasm format
|
||||||
|
wasm_byte_vec_t binary;
|
||||||
|
wasmtime_error_t *error = wasmtime_wat2wasm(&wat, &binary);
|
||||||
|
if (error != NULL)
|
||||||
|
exit_with_error("failed to parse wat", error, NULL);
|
||||||
|
wasm_byte_vec_delete(&wat);
|
||||||
|
|
||||||
|
// Compile and share.
|
||||||
|
own wasm_store_t* store = wasm_store_new(engine);
|
||||||
|
own wasm_module_t* module = wasm_module_new(store, &binary);
|
||||||
|
if (!module) {
|
||||||
|
printf("> Error compiling module!\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
wasm_byte_vec_delete(&binary);
|
||||||
|
|
||||||
|
own wasm_shared_module_t* shared = wasm_module_share(module);
|
||||||
|
|
||||||
|
wasm_module_delete(module);
|
||||||
|
wasm_store_delete(store);
|
||||||
|
|
||||||
|
// Spawn threads.
|
||||||
|
pthread_t threads[N_THREADS];
|
||||||
|
for (int i = 0; i < N_THREADS; i++) {
|
||||||
|
thread_args* args = malloc(sizeof(thread_args));
|
||||||
|
args->id = i;
|
||||||
|
args->engine = engine;
|
||||||
|
args->module = shared;
|
||||||
|
printf("Initializing thread %d...\n", i);
|
||||||
|
pthread_create(&threads[i], NULL, &run, args);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < N_THREADS; i++) {
|
||||||
|
printf("Waiting for thread: %d\n", i);
|
||||||
|
pthread_join(threads[i], NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
wasm_shared_module_delete(shared);
|
||||||
|
wasm_engine_delete(engine);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void exit_with_error(const char *message, wasmtime_error_t *error, wasm_trap_t *trap) {
|
||||||
|
fprintf(stderr, "error: %s\n", message);
|
||||||
|
wasm_byte_vec_t error_message;
|
||||||
|
if (error != NULL) {
|
||||||
|
wasmtime_error_message(error, &error_message);
|
||||||
|
} else {
|
||||||
|
wasm_trap_message(trap, &error_message);
|
||||||
|
}
|
||||||
|
fprintf(stderr, "%.*s\n", (int) error_message.size, error_message.data);
|
||||||
|
wasm_byte_vec_delete(&error_message);
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
// TODO implement example for Windows
|
||||||
|
int main(int argc, const char *argv[]) {
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
#endif // _WIN32
|
||||||
70
examples/threads.rs
Normal file
70
examples/threads.rs
Normal file
@@ -0,0 +1,70 @@
|
|||||||
|
// You can execute this example with `cargo run --example threads`
|
||||||
|
|
||||||
|
use anyhow::{format_err, Result};
|
||||||
|
use std::thread;
|
||||||
|
use std::time;
|
||||||
|
use wasmtime::*;
|
||||||
|
|
||||||
|
const N_THREADS: i32 = 10;
|
||||||
|
const N_REPS: i32 = 3;
|
||||||
|
|
||||||
|
fn print_message(_: Caller<'_>, args: &[Val], _: &mut [Val]) -> Result<(), Trap> {
|
||||||
|
println!("> Thread {} is running", args[0].unwrap_i32());
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn run(engine: &Engine, module: Module, id: i32) -> Result<()> {
|
||||||
|
let store = Store::new(&engine);
|
||||||
|
|
||||||
|
// Create external print functions.
|
||||||
|
println!("Creating callback...");
|
||||||
|
let callback_type = FuncType::new(Box::new([ValType::I32]), Box::new([]));
|
||||||
|
let callback_func = Func::new(&store, callback_type, print_message);
|
||||||
|
|
||||||
|
let id_type = GlobalType::new(ValType::I32, Mutability::Const);
|
||||||
|
let id_global = Global::new(&store, id_type, Val::I32(id))?;
|
||||||
|
|
||||||
|
// Instantiate.
|
||||||
|
println!("Instantiating module...");
|
||||||
|
let instance = Instance::new(&store, &module, &[callback_func.into(), id_global.into()])?;
|
||||||
|
|
||||||
|
// Extract exports.
|
||||||
|
println!("Extracting export...");
|
||||||
|
let g = instance
|
||||||
|
.get_func("run")
|
||||||
|
.ok_or(format_err!("failed to find export `eun`"))?;
|
||||||
|
|
||||||
|
for _ in 0..N_REPS {
|
||||||
|
thread::sleep(time::Duration::from_millis(100));
|
||||||
|
// Call `$run`.
|
||||||
|
drop(g.call(&[])?);
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() -> Result<()> {
|
||||||
|
println!("Initializing...");
|
||||||
|
let engine = Engine::default();
|
||||||
|
|
||||||
|
// Compile.
|
||||||
|
println!("Compiling module...");
|
||||||
|
let module = Module::from_file(&engine, "examples/threads.wat")?;
|
||||||
|
|
||||||
|
let mut children = Vec::new();
|
||||||
|
for id in 0..N_THREADS {
|
||||||
|
let engine = engine.clone();
|
||||||
|
let module = module.clone();
|
||||||
|
children.push(thread::spawn(move || {
|
||||||
|
run(&engine, module, id).expect("Success");
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i, child) in children.into_iter().enumerate() {
|
||||||
|
if let Err(_) = child.join() {
|
||||||
|
println!("Thread #{} errors", i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
5
examples/threads.wat
Normal file
5
examples/threads.wat
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
(module
|
||||||
|
(func $message (import "" "hello") (param i32))
|
||||||
|
(global $id (import "" "id") i32)
|
||||||
|
(func (export "run") (call $message (global.get $id)))
|
||||||
|
)
|
||||||
@@ -18,7 +18,7 @@ fn main() -> Result<()> {
|
|||||||
wasi.add_to_linker(&mut linker)?;
|
wasi.add_to_linker(&mut linker)?;
|
||||||
|
|
||||||
// Instantiate our module with the imports we've created, and run it.
|
// Instantiate our module with the imports we've created, and run it.
|
||||||
let module = Module::from_file(&store, "target/wasm32-wasi/debug/wasi.wasm")?;
|
let module = Module::from_file(store.engine(), "target/wasm32-wasi/debug/wasi.wasm")?;
|
||||||
linker.module("", &module)?;
|
linker.module("", &module)?;
|
||||||
linker.get_default("")?.get0::<()>()?()?;
|
linker.get_default("")?.get0::<()>()?()?;
|
||||||
|
|
||||||
|
|||||||
@@ -141,7 +141,7 @@ impl RunCommand {
|
|||||||
// Load the preload wasm modules.
|
// Load the preload wasm modules.
|
||||||
for (name, path) in self.preloads.iter() {
|
for (name, path) in self.preloads.iter() {
|
||||||
// Read the wasm module binary either as `*.wat` or a raw binary
|
// Read the wasm module binary either as `*.wat` or a raw binary
|
||||||
let module = Module::from_file(linker.store(), path)?;
|
let module = Module::from_file(&engine, path)?;
|
||||||
|
|
||||||
// Add the module's functions to the linker.
|
// Add the module's functions to the linker.
|
||||||
linker.module(name, &module).context(format!(
|
linker.module(name, &module).context(format!(
|
||||||
@@ -247,7 +247,7 @@ impl RunCommand {
|
|||||||
|
|
||||||
// Read the wasm module binary either as `*.wat` or a raw binary.
|
// Read the wasm module binary either as `*.wat` or a raw binary.
|
||||||
// Use "" as a default module name.
|
// Use "" as a default module name.
|
||||||
let module = Module::from_file(linker.store(), &self.module)?;
|
let module = Module::from_file(linker.store().engine(), &self.module)?;
|
||||||
linker
|
linker
|
||||||
.module("", &module)
|
.module("", &module)
|
||||||
.context(format!("failed to instantiate {:?}", self.module))?;
|
.context(format!("failed to instantiate {:?}", self.module))?;
|
||||||
|
|||||||
@@ -90,8 +90,8 @@ mod tests {
|
|||||||
fn test_custom_signal_handler_single_instance() -> Result<()> {
|
fn test_custom_signal_handler_single_instance() -> Result<()> {
|
||||||
let engine = Engine::new(&Config::default());
|
let engine = Engine::new(&Config::default());
|
||||||
let store = Store::new(&engine);
|
let store = Store::new(&engine);
|
||||||
let module = Module::new(&store, WAT1)?;
|
let module = Module::new(&engine, WAT1)?;
|
||||||
let instance = Instance::new(&module, &[])?;
|
let instance = Instance::new(&store, &module, &[])?;
|
||||||
|
|
||||||
let (base, length) = set_up_memory(&instance);
|
let (base, length) = set_up_memory(&instance);
|
||||||
unsafe {
|
unsafe {
|
||||||
@@ -150,11 +150,11 @@ mod tests {
|
|||||||
fn test_custom_signal_handler_multiple_instances() -> Result<()> {
|
fn test_custom_signal_handler_multiple_instances() -> Result<()> {
|
||||||
let engine = Engine::new(&Config::default());
|
let engine = Engine::new(&Config::default());
|
||||||
let store = Store::new(&engine);
|
let store = Store::new(&engine);
|
||||||
let module = Module::new(&store, WAT1)?;
|
let module = Module::new(&engine, WAT1)?;
|
||||||
|
|
||||||
// Set up multiple instances
|
// Set up multiple instances
|
||||||
|
|
||||||
let instance1 = Instance::new(&module, &[])?;
|
let instance1 = Instance::new(&store, &module, &[])?;
|
||||||
let instance1_handler_triggered = Rc::new(AtomicBool::new(false));
|
let instance1_handler_triggered = Rc::new(AtomicBool::new(false));
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
@@ -196,7 +196,7 @@ mod tests {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
let instance2 = Instance::new(&module, &[]).expect("failed to instantiate module");
|
let instance2 = Instance::new(&store, &module, &[]).expect("failed to instantiate module");
|
||||||
let instance2_handler_triggered = Rc::new(AtomicBool::new(false));
|
let instance2_handler_triggered = Rc::new(AtomicBool::new(false));
|
||||||
|
|
||||||
unsafe {
|
unsafe {
|
||||||
@@ -244,8 +244,8 @@ mod tests {
|
|||||||
let store = Store::new(&engine);
|
let store = Store::new(&engine);
|
||||||
|
|
||||||
// instance1 which defines 'read'
|
// instance1 which defines 'read'
|
||||||
let module1 = Module::new(&store, WAT1)?;
|
let module1 = Module::new(&engine, WAT1)?;
|
||||||
let instance1 = Instance::new(&module1, &[])?;
|
let instance1 = Instance::new(&store, &module1, &[])?;
|
||||||
let (base1, length1) = set_up_memory(&instance1);
|
let (base1, length1) = set_up_memory(&instance1);
|
||||||
unsafe {
|
unsafe {
|
||||||
store.set_signal_handler(move |signum, siginfo, _| {
|
store.set_signal_handler(move |signum, siginfo, _| {
|
||||||
@@ -258,8 +258,8 @@ mod tests {
|
|||||||
let instance1_read = instance1_exports.next().unwrap();
|
let instance1_read = instance1_exports.next().unwrap();
|
||||||
|
|
||||||
// instance2 which calls 'instance1.read'
|
// instance2 which calls 'instance1.read'
|
||||||
let module2 = Module::new(&store, WAT2)?;
|
let module2 = Module::new(&engine, WAT2)?;
|
||||||
let instance2 = Instance::new(&module2, &[instance1_read.into_extern()])?;
|
let instance2 = Instance::new(&store, &module2, &[instance1_read.into_extern()])?;
|
||||||
// since 'instance2.run' calls 'instance1.read' we need to set up the signal handler to handle
|
// since 'instance2.run' calls 'instance1.read' we need to set up the signal handler to handle
|
||||||
// SIGSEGV originating from within the memory of instance1
|
// SIGSEGV originating from within the memory of instance1
|
||||||
unsafe {
|
unsafe {
|
||||||
|
|||||||
@@ -57,8 +57,9 @@ fn bad_tables() {
|
|||||||
fn cross_store() -> anyhow::Result<()> {
|
fn cross_store() -> anyhow::Result<()> {
|
||||||
let mut cfg = Config::new();
|
let mut cfg = Config::new();
|
||||||
cfg.wasm_reference_types(true);
|
cfg.wasm_reference_types(true);
|
||||||
let store1 = Store::new(&Engine::new(&cfg));
|
let engine = Engine::new(&cfg);
|
||||||
let store2 = Store::new(&Engine::new(&cfg));
|
let store1 = Store::new(&engine);
|
||||||
|
let store2 = Store::new(&engine);
|
||||||
|
|
||||||
// ============ Cross-store instantiation ==============
|
// ============ Cross-store instantiation ==============
|
||||||
|
|
||||||
@@ -70,17 +71,17 @@ fn cross_store() -> anyhow::Result<()> {
|
|||||||
let ty = TableType::new(ValType::FuncRef, Limits::new(1, None));
|
let ty = TableType::new(ValType::FuncRef, Limits::new(1, None));
|
||||||
let table = Table::new(&store2, ty, Val::ExternRef(None))?;
|
let table = Table::new(&store2, ty, Val::ExternRef(None))?;
|
||||||
|
|
||||||
let need_func = Module::new(&store1, r#"(module (import "" "" (func)))"#)?;
|
let need_func = Module::new(&engine, r#"(module (import "" "" (func)))"#)?;
|
||||||
assert!(Instance::new(&need_func, &[func.into()]).is_err());
|
assert!(Instance::new(&store1, &need_func, &[func.into()]).is_err());
|
||||||
|
|
||||||
let need_global = Module::new(&store1, r#"(module (import "" "" (global i32)))"#)?;
|
let need_global = Module::new(&engine, r#"(module (import "" "" (global i32)))"#)?;
|
||||||
assert!(Instance::new(&need_global, &[global.into()]).is_err());
|
assert!(Instance::new(&store1, &need_global, &[global.into()]).is_err());
|
||||||
|
|
||||||
let need_table = Module::new(&store1, r#"(module (import "" "" (table 1 funcref)))"#)?;
|
let need_table = Module::new(&engine, r#"(module (import "" "" (table 1 funcref)))"#)?;
|
||||||
assert!(Instance::new(&need_table, &[table.into()]).is_err());
|
assert!(Instance::new(&store1, &need_table, &[table.into()]).is_err());
|
||||||
|
|
||||||
let need_memory = Module::new(&store1, r#"(module (import "" "" (memory 1)))"#)?;
|
let need_memory = Module::new(&engine, r#"(module (import "" "" (memory 1)))"#)?;
|
||||||
assert!(Instance::new(&need_memory, &[memory.into()]).is_err());
|
assert!(Instance::new(&store1, &need_memory, &[memory.into()]).is_err());
|
||||||
|
|
||||||
// ============ Cross-store globals ==============
|
// ============ Cross-store globals ==============
|
||||||
|
|
||||||
@@ -106,7 +107,7 @@ fn cross_store() -> anyhow::Result<()> {
|
|||||||
// ============ Cross-store funcs ==============
|
// ============ Cross-store funcs ==============
|
||||||
|
|
||||||
// TODO: need to actually fill this out once we support externref params/locals
|
// TODO: need to actually fill this out once we support externref params/locals
|
||||||
// let module = Module::new(&store1, r#"(module (func (export "a") (param funcref)))"#)?;
|
// let module = Module::new(&engine, r#"(module (func (export "a") (param funcref)))"#)?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -61,8 +61,8 @@ fn dtor_delayed() -> Result<()> {
|
|||||||
|
|
||||||
assert_eq!(HITS.load(SeqCst), 0);
|
assert_eq!(HITS.load(SeqCst), 0);
|
||||||
let wasm = wat::parse_str(r#"(import "" "" (func))"#)?;
|
let wasm = wat::parse_str(r#"(import "" "" (func))"#)?;
|
||||||
let module = Module::new(&store, &wasm)?;
|
let module = Module::new(store.engine(), &wasm)?;
|
||||||
let instance = Instance::new(&module, &[func.into()])?;
|
let instance = Instance::new(&store, &module, &[func.into()])?;
|
||||||
assert_eq!(HITS.load(SeqCst), 0);
|
assert_eq!(HITS.load(SeqCst), 0);
|
||||||
drop((instance, module, store));
|
drop((instance, module, store));
|
||||||
assert_eq!(HITS.load(SeqCst), 1);
|
assert_eq!(HITS.load(SeqCst), 1);
|
||||||
@@ -142,8 +142,9 @@ fn import_works() -> Result<()> {
|
|||||||
"#,
|
"#,
|
||||||
)?;
|
)?;
|
||||||
let store = Store::default();
|
let store = Store::default();
|
||||||
let module = Module::new(&store, &wasm)?;
|
let module = Module::new(store.engine(), &wasm)?;
|
||||||
Instance::new(
|
Instance::new(
|
||||||
|
&store,
|
||||||
&module,
|
&module,
|
||||||
&[
|
&[
|
||||||
Func::wrap(&store, || {
|
Func::wrap(&store, || {
|
||||||
@@ -195,8 +196,9 @@ fn trap_import() -> Result<()> {
|
|||||||
"#,
|
"#,
|
||||||
)?;
|
)?;
|
||||||
let store = Store::default();
|
let store = Store::default();
|
||||||
let module = Module::new(&store, &wasm)?;
|
let module = Module::new(store.engine(), &wasm)?;
|
||||||
let trap = Instance::new(
|
let trap = Instance::new(
|
||||||
|
&store,
|
||||||
&module,
|
&module,
|
||||||
&[Func::wrap(&store, || -> Result<(), Trap> { Err(Trap::new("foo")) }).into()],
|
&[Func::wrap(&store, || -> Result<(), Trap> { Err(Trap::new("foo")) }).into()],
|
||||||
)
|
)
|
||||||
@@ -261,7 +263,7 @@ fn get_from_signature() {
|
|||||||
fn get_from_module() -> anyhow::Result<()> {
|
fn get_from_module() -> anyhow::Result<()> {
|
||||||
let store = Store::default();
|
let store = Store::default();
|
||||||
let module = Module::new(
|
let module = Module::new(
|
||||||
&store,
|
store.engine(),
|
||||||
r#"
|
r#"
|
||||||
(module
|
(module
|
||||||
(func (export "f0"))
|
(func (export "f0"))
|
||||||
@@ -272,7 +274,7 @@ fn get_from_module() -> anyhow::Result<()> {
|
|||||||
|
|
||||||
"#,
|
"#,
|
||||||
)?;
|
)?;
|
||||||
let instance = Instance::new(&module, &[])?;
|
let instance = Instance::new(&store, &module, &[])?;
|
||||||
let f0 = instance.get_func("f0").unwrap();
|
let f0 = instance.get_func("f0").unwrap();
|
||||||
assert!(f0.get0::<()>().is_ok());
|
assert!(f0.get0::<()>().is_ok());
|
||||||
assert!(f0.get0::<i32>().is_err());
|
assert!(f0.get0::<i32>().is_err());
|
||||||
@@ -340,7 +342,7 @@ fn caller_memory() -> anyhow::Result<()> {
|
|||||||
assert!(c.get_export("x").is_none());
|
assert!(c.get_export("x").is_none());
|
||||||
});
|
});
|
||||||
let module = Module::new(
|
let module = Module::new(
|
||||||
&store,
|
store.engine(),
|
||||||
r#"
|
r#"
|
||||||
(module
|
(module
|
||||||
(import "" "" (func $f))
|
(import "" "" (func $f))
|
||||||
@@ -349,13 +351,13 @@ fn caller_memory() -> anyhow::Result<()> {
|
|||||||
|
|
||||||
"#,
|
"#,
|
||||||
)?;
|
)?;
|
||||||
Instance::new(&module, &[f.into()])?;
|
Instance::new(&store, &module, &[f.into()])?;
|
||||||
|
|
||||||
let f = Func::wrap(&store, |c: Caller<'_>| {
|
let f = Func::wrap(&store, |c: Caller<'_>| {
|
||||||
assert!(c.get_export("memory").is_some());
|
assert!(c.get_export("memory").is_some());
|
||||||
});
|
});
|
||||||
let module = Module::new(
|
let module = Module::new(
|
||||||
&store,
|
store.engine(),
|
||||||
r#"
|
r#"
|
||||||
(module
|
(module
|
||||||
(import "" "" (func $f))
|
(import "" "" (func $f))
|
||||||
@@ -365,7 +367,7 @@ fn caller_memory() -> anyhow::Result<()> {
|
|||||||
|
|
||||||
"#,
|
"#,
|
||||||
)?;
|
)?;
|
||||||
Instance::new(&module, &[f.into()])?;
|
Instance::new(&store, &module, &[f.into()])?;
|
||||||
|
|
||||||
let f = Func::wrap(&store, |c: Caller<'_>| {
|
let f = Func::wrap(&store, |c: Caller<'_>| {
|
||||||
assert!(c.get_export("m").is_some());
|
assert!(c.get_export("m").is_some());
|
||||||
@@ -374,7 +376,7 @@ fn caller_memory() -> anyhow::Result<()> {
|
|||||||
assert!(c.get_export("t").is_none());
|
assert!(c.get_export("t").is_none());
|
||||||
});
|
});
|
||||||
let module = Module::new(
|
let module = Module::new(
|
||||||
&store,
|
store.engine(),
|
||||||
r#"
|
r#"
|
||||||
(module
|
(module
|
||||||
(import "" "" (func $f))
|
(import "" "" (func $f))
|
||||||
@@ -387,7 +389,7 @@ fn caller_memory() -> anyhow::Result<()> {
|
|||||||
|
|
||||||
"#,
|
"#,
|
||||||
)?;
|
)?;
|
||||||
Instance::new(&module, &[f.into()])?;
|
Instance::new(&store, &module, &[f.into()])?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -63,19 +63,19 @@ fn mutability() -> anyhow::Result<()> {
|
|||||||
fn use_after_drop() -> anyhow::Result<()> {
|
fn use_after_drop() -> anyhow::Result<()> {
|
||||||
let store = Store::default();
|
let store = Store::default();
|
||||||
let module = Module::new(
|
let module = Module::new(
|
||||||
&store,
|
store.engine(),
|
||||||
r#"
|
r#"
|
||||||
(module
|
(module
|
||||||
(global (export "foo") (mut i32) (i32.const 100)))
|
(global (export "foo") (mut i32) (i32.const 100)))
|
||||||
"#,
|
"#,
|
||||||
)?;
|
)?;
|
||||||
let instance = Instance::new(&module, &[])?;
|
let instance = Instance::new(&store, &module, &[])?;
|
||||||
let g = instance.get_global("foo").unwrap();
|
let g = instance.get_global("foo").unwrap();
|
||||||
assert_eq!(g.get().i32(), Some(100));
|
assert_eq!(g.get().i32(), Some(100));
|
||||||
g.set(101.into())?;
|
g.set(101.into())?;
|
||||||
drop(instance);
|
drop(instance);
|
||||||
assert_eq!(g.get().i32(), Some(101));
|
assert_eq!(g.get().i32(), Some(101));
|
||||||
Instance::new(&module, &[])?;
|
Instance::new(&store, &module, &[])?;
|
||||||
assert_eq!(g.get().i32(), Some(101));
|
assert_eq!(g.get().i32(), Some(101));
|
||||||
drop(module);
|
drop(module);
|
||||||
assert_eq!(g.get().i32(), Some(101));
|
assert_eq!(g.get().i32(), Some(101));
|
||||||
|
|||||||
@@ -19,14 +19,14 @@ fn hugely_recursive_module(store: &Store) -> anyhow::Result<Module> {
|
|||||||
}
|
}
|
||||||
wat.push_str("(func call 0)\n");
|
wat.push_str("(func call 0)\n");
|
||||||
|
|
||||||
Module::new(&store, &wat)
|
Module::new(store.engine(), &wat)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn loops_interruptable() -> anyhow::Result<()> {
|
fn loops_interruptable() -> anyhow::Result<()> {
|
||||||
let store = interruptable_store();
|
let store = interruptable_store();
|
||||||
let module = Module::new(&store, r#"(func (export "loop") (loop br 0))"#)?;
|
let module = Module::new(store.engine(), r#"(func (export "loop") (loop br 0))"#)?;
|
||||||
let instance = Instance::new(&module, &[])?;
|
let instance = Instance::new(&store, &module, &[])?;
|
||||||
let iloop = instance.get_func("loop").unwrap().get0::<()>()?;
|
let iloop = instance.get_func("loop").unwrap().get0::<()>()?;
|
||||||
store.interrupt_handle()?.interrupt();
|
store.interrupt_handle()?.interrupt();
|
||||||
let trap = iloop().unwrap_err();
|
let trap = iloop().unwrap_err();
|
||||||
@@ -39,7 +39,7 @@ fn functions_interruptable() -> anyhow::Result<()> {
|
|||||||
let store = interruptable_store();
|
let store = interruptable_store();
|
||||||
let module = hugely_recursive_module(&store)?;
|
let module = hugely_recursive_module(&store)?;
|
||||||
let func = Func::wrap(&store, || {});
|
let func = Func::wrap(&store, || {});
|
||||||
let instance = Instance::new(&module, &[func.into()])?;
|
let instance = Instance::new(&store, &module, &[func.into()])?;
|
||||||
let iloop = instance.get_func("loop").unwrap().get0::<()>()?;
|
let iloop = instance.get_func("loop").unwrap().get0::<()>()?;
|
||||||
store.interrupt_handle()?.interrupt();
|
store.interrupt_handle()?.interrupt();
|
||||||
let trap = iloop().unwrap_err();
|
let trap = iloop().unwrap_err();
|
||||||
@@ -59,7 +59,7 @@ fn loop_interrupt_from_afar() -> anyhow::Result<()> {
|
|||||||
static HITS: AtomicUsize = AtomicUsize::new(0);
|
static HITS: AtomicUsize = AtomicUsize::new(0);
|
||||||
let store = interruptable_store();
|
let store = interruptable_store();
|
||||||
let module = Module::new(
|
let module = Module::new(
|
||||||
&store,
|
store.engine(),
|
||||||
r#"
|
r#"
|
||||||
(import "" "" (func))
|
(import "" "" (func))
|
||||||
|
|
||||||
@@ -73,7 +73,7 @@ fn loop_interrupt_from_afar() -> anyhow::Result<()> {
|
|||||||
let func = Func::wrap(&store, || {
|
let func = Func::wrap(&store, || {
|
||||||
HITS.fetch_add(1, SeqCst);
|
HITS.fetch_add(1, SeqCst);
|
||||||
});
|
});
|
||||||
let instance = Instance::new(&module, &[func.into()])?;
|
let instance = Instance::new(&store, &module, &[func.into()])?;
|
||||||
|
|
||||||
// Use the instance's interrupt handle to wait for it to enter the loop long
|
// Use the instance's interrupt handle to wait for it to enter the loop long
|
||||||
// enough and then we signal an interrupt happens.
|
// enough and then we signal an interrupt happens.
|
||||||
@@ -109,7 +109,7 @@ fn function_interrupt_from_afar() -> anyhow::Result<()> {
|
|||||||
let func = Func::wrap(&store, || {
|
let func = Func::wrap(&store, || {
|
||||||
HITS.fetch_add(1, SeqCst);
|
HITS.fetch_add(1, SeqCst);
|
||||||
});
|
});
|
||||||
let instance = Instance::new(&module, &[func.into()])?;
|
let instance = Instance::new(&store, &module, &[func.into()])?;
|
||||||
|
|
||||||
// Use the instance's interrupt handle to wait for it to enter the loop long
|
// Use the instance's interrupt handle to wait for it to enter the loop long
|
||||||
// enough and then we signal an interrupt happens.
|
// enough and then we signal an interrupt happens.
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ fn test_import_calling_export() {
|
|||||||
"#;
|
"#;
|
||||||
|
|
||||||
let store = Store::default();
|
let store = Store::default();
|
||||||
let module = Module::new(&store, WAT).expect("failed to create module");
|
let module = Module::new(store.engine(), WAT).expect("failed to create module");
|
||||||
|
|
||||||
let other = Rc::new(RefCell::new(None::<Func>));
|
let other = Rc::new(RefCell::new(None::<Func>));
|
||||||
let other2 = Rc::downgrade(&other);
|
let other2 = Rc::downgrade(&other);
|
||||||
@@ -40,7 +40,7 @@ fn test_import_calling_export() {
|
|||||||
|
|
||||||
let imports = vec![callback_func.into()];
|
let imports = vec![callback_func.into()];
|
||||||
let instance =
|
let instance =
|
||||||
Instance::new(&module, imports.as_slice()).expect("failed to instantiate module");
|
Instance::new(&store, &module, imports.as_slice()).expect("failed to instantiate module");
|
||||||
|
|
||||||
let run_func = instance
|
let run_func = instance
|
||||||
.get_func("run")
|
.get_func("run")
|
||||||
@@ -67,7 +67,7 @@ fn test_returns_incorrect_type() -> Result<()> {
|
|||||||
"#;
|
"#;
|
||||||
|
|
||||||
let store = Store::default();
|
let store = Store::default();
|
||||||
let module = Module::new(&store, WAT)?;
|
let module = Module::new(store.engine(), WAT)?;
|
||||||
|
|
||||||
let callback_func = Func::new(
|
let callback_func = Func::new(
|
||||||
&store,
|
&store,
|
||||||
@@ -80,7 +80,7 @@ fn test_returns_incorrect_type() -> Result<()> {
|
|||||||
);
|
);
|
||||||
|
|
||||||
let imports = vec![callback_func.into()];
|
let imports = vec![callback_func.into()];
|
||||||
let instance = Instance::new(&module, imports.as_slice())?;
|
let instance = Instance::new(&store, &module, imports.as_slice())?;
|
||||||
|
|
||||||
let run_func = instance
|
let run_func = instance
|
||||||
.get_func("run")
|
.get_func("run")
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ fn same_import_names_still_distinct() -> anyhow::Result<()> {
|
|||||||
"#;
|
"#;
|
||||||
|
|
||||||
let store = Store::default();
|
let store = Store::default();
|
||||||
let module = Module::new(&store, WAT)?;
|
let module = Module::new(store.engine(), WAT)?;
|
||||||
|
|
||||||
let imports = [
|
let imports = [
|
||||||
Func::new(
|
Func::new(
|
||||||
@@ -41,7 +41,7 @@ fn same_import_names_still_distinct() -> anyhow::Result<()> {
|
|||||||
)
|
)
|
||||||
.into(),
|
.into(),
|
||||||
];
|
];
|
||||||
let instance = Instance::new(&module, &imports)?;
|
let instance = Instance::new(&store, &module, &imports)?;
|
||||||
|
|
||||||
let func = instance.get_func("foo").unwrap();
|
let func = instance.get_func("foo").unwrap();
|
||||||
let results = func.call(&[])?;
|
let results = func.call(&[])?;
|
||||||
|
|||||||
@@ -4,10 +4,10 @@ use wasmtime::*;
|
|||||||
#[test]
|
#[test]
|
||||||
fn wrong_import_numbers() -> Result<()> {
|
fn wrong_import_numbers() -> Result<()> {
|
||||||
let store = Store::default();
|
let store = Store::default();
|
||||||
let module = Module::new(&store, r#"(module (import "" "" (func)))"#)?;
|
let module = Module::new(store.engine(), r#"(module (import "" "" (func)))"#)?;
|
||||||
|
|
||||||
assert!(Instance::new(&module, &[]).is_err());
|
assert!(Instance::new(&store, &module, &[]).is_err());
|
||||||
let func = Func::wrap(&store, || {});
|
let func = Func::wrap(&store, || {});
|
||||||
assert!(Instance::new(&module, &[func.clone().into(), func.into()]).is_err());
|
assert!(Instance::new(&store, &module, &[func.clone().into(), func.into()]).is_err());
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -13,8 +13,8 @@ fn test_invoke_func_via_table() -> Result<()> {
|
|||||||
(elem (i32.const 0) $f)
|
(elem (i32.const 0) $f)
|
||||||
)
|
)
|
||||||
"#;
|
"#;
|
||||||
let module = Module::new(&store, wat).context("> Error compiling module!")?;
|
let module = Module::new(store.engine(), wat).context("> Error compiling module!")?;
|
||||||
let instance = Instance::new(&module, &[]).context("> Error instantiating module!")?;
|
let instance = Instance::new(&store, &module, &[]).context("> Error instantiating module!")?;
|
||||||
|
|
||||||
let f = instance
|
let f = instance
|
||||||
.get_table("table")
|
.get_table("table")
|
||||||
|
|||||||
@@ -5,13 +5,16 @@ use wasmtime::*;
|
|||||||
fn link_undefined() -> Result<()> {
|
fn link_undefined() -> Result<()> {
|
||||||
let store = Store::default();
|
let store = Store::default();
|
||||||
let linker = Linker::new(&store);
|
let linker = Linker::new(&store);
|
||||||
let module = Module::new(&store, r#"(module (import "" "" (func)))"#)?;
|
let module = Module::new(store.engine(), r#"(module (import "" "" (func)))"#)?;
|
||||||
assert!(linker.instantiate(&module).is_err());
|
assert!(linker.instantiate(&module).is_err());
|
||||||
let module = Module::new(&store, r#"(module (import "" "" (global i32)))"#)?;
|
let module = Module::new(store.engine(), r#"(module (import "" "" (global i32)))"#)?;
|
||||||
assert!(linker.instantiate(&module).is_err());
|
assert!(linker.instantiate(&module).is_err());
|
||||||
let module = Module::new(&store, r#"(module (import "" "" (memory 1)))"#)?;
|
let module = Module::new(store.engine(), r#"(module (import "" "" (memory 1)))"#)?;
|
||||||
assert!(linker.instantiate(&module).is_err());
|
assert!(linker.instantiate(&module).is_err());
|
||||||
let module = Module::new(&store, r#"(module (import "" "" (table 1 funcref)))"#)?;
|
let module = Module::new(
|
||||||
|
store.engine(),
|
||||||
|
r#"(module (import "" "" (table 1 funcref)))"#,
|
||||||
|
)?;
|
||||||
assert!(linker.instantiate(&module).is_err());
|
assert!(linker.instantiate(&module).is_err());
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@@ -71,7 +74,7 @@ fn function_interposition() -> Result<()> {
|
|||||||
let mut linker = Linker::new(&store);
|
let mut linker = Linker::new(&store);
|
||||||
linker.allow_shadowing(true);
|
linker.allow_shadowing(true);
|
||||||
let mut module = Module::new(
|
let mut module = Module::new(
|
||||||
&store,
|
store.engine(),
|
||||||
r#"(module (func (export "green") (result i32) (i32.const 7)))"#,
|
r#"(module (func (export "green") (result i32) (i32.const 7)))"#,
|
||||||
)?;
|
)?;
|
||||||
for _ in 0..4 {
|
for _ in 0..4 {
|
||||||
@@ -82,7 +85,7 @@ fn function_interposition() -> Result<()> {
|
|||||||
instance.get_export("green").unwrap().clone(),
|
instance.get_export("green").unwrap().clone(),
|
||||||
)?;
|
)?;
|
||||||
module = Module::new(
|
module = Module::new(
|
||||||
&store,
|
store.engine(),
|
||||||
r#"(module
|
r#"(module
|
||||||
(import "red" "green" (func (result i32)))
|
(import "red" "green" (func (result i32)))
|
||||||
(func (export "green") (result i32) (i32.mul (call 0) (i32.const 2)))
|
(func (export "green") (result i32) (i32.mul (call 0) (i32.const 2)))
|
||||||
@@ -104,7 +107,7 @@ fn function_interposition_renamed() -> Result<()> {
|
|||||||
let mut linker = Linker::new(&store);
|
let mut linker = Linker::new(&store);
|
||||||
linker.allow_shadowing(true);
|
linker.allow_shadowing(true);
|
||||||
let mut module = Module::new(
|
let mut module = Module::new(
|
||||||
&store,
|
store.engine(),
|
||||||
r#"(module (func (export "export") (result i32) (i32.const 7)))"#,
|
r#"(module (func (export "export") (result i32) (i32.const 7)))"#,
|
||||||
)?;
|
)?;
|
||||||
for _ in 0..4 {
|
for _ in 0..4 {
|
||||||
@@ -115,7 +118,7 @@ fn function_interposition_renamed() -> Result<()> {
|
|||||||
instance.get_export("export").unwrap().clone(),
|
instance.get_export("export").unwrap().clone(),
|
||||||
)?;
|
)?;
|
||||||
module = Module::new(
|
module = Module::new(
|
||||||
&store,
|
store.engine(),
|
||||||
r#"(module
|
r#"(module
|
||||||
(import "red" "green" (func (result i32)))
|
(import "red" "green" (func (result i32)))
|
||||||
(func (export "export") (result i32) (i32.mul (call 0) (i32.const 2)))
|
(func (export "export") (result i32) (i32.mul (call 0) (i32.const 2)))
|
||||||
@@ -137,14 +140,14 @@ fn module_interposition() -> Result<()> {
|
|||||||
let mut linker = Linker::new(&store);
|
let mut linker = Linker::new(&store);
|
||||||
linker.allow_shadowing(true);
|
linker.allow_shadowing(true);
|
||||||
let mut module = Module::new(
|
let mut module = Module::new(
|
||||||
&store,
|
store.engine(),
|
||||||
r#"(module (func (export "export") (result i32) (i32.const 7)))"#,
|
r#"(module (func (export "export") (result i32) (i32.const 7)))"#,
|
||||||
)?;
|
)?;
|
||||||
for _ in 0..4 {
|
for _ in 0..4 {
|
||||||
let instance = linker.instantiate(&module)?;
|
let instance = linker.instantiate(&module)?;
|
||||||
linker.instance("instance", &instance)?;
|
linker.instance("instance", &instance)?;
|
||||||
module = Module::new(
|
module = Module::new(
|
||||||
&store,
|
store.engine(),
|
||||||
r#"(module
|
r#"(module
|
||||||
(import "instance" "export" (func (result i32)))
|
(import "instance" "export" (func (result i32)))
|
||||||
(func (export "export") (result i32) (i32.mul (call 0) (i32.const 2)))
|
(func (export "export") (result i32) (i32.mul (call 0) (i32.const 2)))
|
||||||
|
|||||||
@@ -143,14 +143,14 @@ mod not_for_windows {
|
|||||||
fn host_memory() -> anyhow::Result<()> {
|
fn host_memory() -> anyhow::Result<()> {
|
||||||
let (store, mem_creator) = config();
|
let (store, mem_creator) = config();
|
||||||
let module = Module::new(
|
let module = Module::new(
|
||||||
&store,
|
store.engine(),
|
||||||
r#"
|
r#"
|
||||||
(module
|
(module
|
||||||
(memory (export "memory") 1)
|
(memory (export "memory") 1)
|
||||||
)
|
)
|
||||||
"#,
|
"#,
|
||||||
)?;
|
)?;
|
||||||
Instance::new(&module, &[])?;
|
Instance::new(&store, &module, &[])?;
|
||||||
|
|
||||||
assert_eq!(*mem_creator.num_created_memories.lock().unwrap(), 1);
|
assert_eq!(*mem_creator.num_created_memories.lock().unwrap(), 1);
|
||||||
|
|
||||||
@@ -161,7 +161,7 @@ mod not_for_windows {
|
|||||||
fn host_memory_grow() -> anyhow::Result<()> {
|
fn host_memory_grow() -> anyhow::Result<()> {
|
||||||
let (store, mem_creator) = config();
|
let (store, mem_creator) = config();
|
||||||
let module = Module::new(
|
let module = Module::new(
|
||||||
&store,
|
store.engine(),
|
||||||
r#"
|
r#"
|
||||||
(module
|
(module
|
||||||
(func $f (drop (memory.grow (i32.const 1))))
|
(func $f (drop (memory.grow (i32.const 1))))
|
||||||
@@ -171,8 +171,8 @@ mod not_for_windows {
|
|||||||
"#,
|
"#,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
let instance1 = Instance::new(&module, &[])?;
|
let instance1 = Instance::new(&store, &module, &[])?;
|
||||||
let instance2 = Instance::new(&module, &[])?;
|
let instance2 = Instance::new(&store, &module, &[])?;
|
||||||
|
|
||||||
assert_eq!(*mem_creator.num_created_memories.lock().unwrap(), 2);
|
assert_eq!(*mem_creator.num_created_memories.lock().unwrap(), 2);
|
||||||
|
|
||||||
|
|||||||
@@ -2,14 +2,14 @@ use wasmtime::*;
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_module_no_name() -> anyhow::Result<()> {
|
fn test_module_no_name() -> anyhow::Result<()> {
|
||||||
let store = Store::default();
|
let engine = Engine::default();
|
||||||
let wat = r#"
|
let wat = r#"
|
||||||
(module
|
(module
|
||||||
(func (export "run") (nop))
|
(func (export "run") (nop))
|
||||||
)
|
)
|
||||||
"#;
|
"#;
|
||||||
|
|
||||||
let module = Module::new(&store, wat)?;
|
let module = Module::new(&engine, wat)?;
|
||||||
assert_eq!(module.name(), None);
|
assert_eq!(module.name(), None);
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
@@ -17,17 +17,17 @@ fn test_module_no_name() -> anyhow::Result<()> {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_module_name() -> anyhow::Result<()> {
|
fn test_module_name() -> anyhow::Result<()> {
|
||||||
let store = Store::default();
|
let engine = Engine::default();
|
||||||
let wat = r#"
|
let wat = r#"
|
||||||
(module $from_name_section
|
(module $from_name_section
|
||||||
(func (export "run") (nop))
|
(func (export "run") (nop))
|
||||||
)
|
)
|
||||||
"#;
|
"#;
|
||||||
|
|
||||||
let module = Module::new(&store, wat)?;
|
let module = Module::new(&engine, wat)?;
|
||||||
assert_eq!(module.name(), Some("from_name_section"));
|
assert_eq!(module.name(), Some("from_name_section"));
|
||||||
|
|
||||||
let module = Module::new_with_name(&store, wat, "override")?;
|
let module = Module::new_with_name(&engine, wat, "override")?;
|
||||||
assert_eq!(module.name(), Some("override"));
|
assert_eq!(module.name(), Some("override"));
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ fn host_always_has_some_stack() -> anyhow::Result<()> {
|
|||||||
// Create a module that's infinitely recursive, but calls the host on each
|
// Create a module that's infinitely recursive, but calls the host on each
|
||||||
// level of wasm stack to always test how much host stack we have left.
|
// level of wasm stack to always test how much host stack we have left.
|
||||||
let module = Module::new(
|
let module = Module::new(
|
||||||
&store,
|
store.engine(),
|
||||||
r#"
|
r#"
|
||||||
(module
|
(module
|
||||||
(import "" "" (func $host))
|
(import "" "" (func $host))
|
||||||
@@ -23,7 +23,7 @@ fn host_always_has_some_stack() -> anyhow::Result<()> {
|
|||||||
"#,
|
"#,
|
||||||
)?;
|
)?;
|
||||||
let func = Func::wrap(&store, test_host_stack);
|
let func = Func::wrap(&store, test_host_stack);
|
||||||
let instance = Instance::new(&module, &[func.into()])?;
|
let instance = Instance::new(&store, &module, &[func.into()])?;
|
||||||
let foo = instance.get_func("foo").unwrap().get0::<()>()?;
|
let foo = instance.get_func("foo").unwrap().get0::<()>()?;
|
||||||
|
|
||||||
// Make sure that our function traps and the trap says that the call stack
|
// Make sure that our function traps and the trap says that the call stack
|
||||||
|
|||||||
@@ -12,11 +12,11 @@ fn test_trap_return() -> Result<()> {
|
|||||||
)
|
)
|
||||||
"#;
|
"#;
|
||||||
|
|
||||||
let module = Module::new(&store, wat)?;
|
let module = Module::new(store.engine(), wat)?;
|
||||||
let hello_type = FuncType::new(Box::new([]), Box::new([]));
|
let hello_type = FuncType::new(Box::new([]), Box::new([]));
|
||||||
let hello_func = Func::new(&store, hello_type, |_, _, _| Err(Trap::new("test 123")));
|
let hello_func = Func::new(&store, hello_type, |_, _, _| Err(Trap::new("test 123")));
|
||||||
|
|
||||||
let instance = Instance::new(&module, &[hello_func.into()])?;
|
let instance = Instance::new(&store, &module, &[hello_func.into()])?;
|
||||||
let run_func = instance.get_func("run").expect("expected function export");
|
let run_func = instance.get_func("run").expect("expected function export");
|
||||||
|
|
||||||
let e = run_func
|
let e = run_func
|
||||||
@@ -41,8 +41,8 @@ fn test_trap_trace() -> Result<()> {
|
|||||||
)
|
)
|
||||||
"#;
|
"#;
|
||||||
|
|
||||||
let module = Module::new(&store, wat)?;
|
let module = Module::new(store.engine(), wat)?;
|
||||||
let instance = Instance::new(&module, &[])?;
|
let instance = Instance::new(&store, &module, &[])?;
|
||||||
let run_func = instance.get_func("run").expect("expected function export");
|
let run_func = instance.get_func("run").expect("expected function export");
|
||||||
|
|
||||||
let e = run_func
|
let e = run_func
|
||||||
@@ -87,8 +87,8 @@ fn test_trap_trace_cb() -> Result<()> {
|
|||||||
let fn_type = FuncType::new(Box::new([]), Box::new([]));
|
let fn_type = FuncType::new(Box::new([]), Box::new([]));
|
||||||
let fn_func = Func::new(&store, fn_type, |_, _, _| Err(Trap::new("cb throw")));
|
let fn_func = Func::new(&store, fn_type, |_, _, _| Err(Trap::new("cb throw")));
|
||||||
|
|
||||||
let module = Module::new(&store, wat)?;
|
let module = Module::new(store.engine(), wat)?;
|
||||||
let instance = Instance::new(&module, &[fn_func.into()])?;
|
let instance = Instance::new(&store, &module, &[fn_func.into()])?;
|
||||||
let run_func = instance.get_func("run").expect("expected function export");
|
let run_func = instance.get_func("run").expect("expected function export");
|
||||||
|
|
||||||
let e = run_func
|
let e = run_func
|
||||||
@@ -118,8 +118,8 @@ fn test_trap_stack_overflow() -> Result<()> {
|
|||||||
)
|
)
|
||||||
"#;
|
"#;
|
||||||
|
|
||||||
let module = Module::new(&store, wat)?;
|
let module = Module::new(store.engine(), wat)?;
|
||||||
let instance = Instance::new(&module, &[])?;
|
let instance = Instance::new(&store, &module, &[])?;
|
||||||
let run_func = instance.get_func("run").expect("expected function export");
|
let run_func = instance.get_func("run").expect("expected function export");
|
||||||
|
|
||||||
let e = run_func
|
let e = run_func
|
||||||
@@ -153,8 +153,8 @@ fn trap_display_pretty() -> Result<()> {
|
|||||||
)
|
)
|
||||||
"#;
|
"#;
|
||||||
|
|
||||||
let module = Module::new(&store, wat)?;
|
let module = Module::new(store.engine(), wat)?;
|
||||||
let instance = Instance::new(&module, &[])?;
|
let instance = Instance::new(&store, &module, &[])?;
|
||||||
let run_func = instance.get_func("bar").expect("expected function export");
|
let run_func = instance.get_func("bar").expect("expected function export");
|
||||||
|
|
||||||
let e = run_func.call(&[]).err().expect("error calling function");
|
let e = run_func.call(&[]).err().expect("error calling function");
|
||||||
@@ -185,8 +185,8 @@ fn trap_display_multi_module() -> Result<()> {
|
|||||||
)
|
)
|
||||||
"#;
|
"#;
|
||||||
|
|
||||||
let module = Module::new(&store, wat)?;
|
let module = Module::new(store.engine(), wat)?;
|
||||||
let instance = Instance::new(&module, &[])?;
|
let instance = Instance::new(&store, &module, &[])?;
|
||||||
let bar = instance.get_export("bar").unwrap();
|
let bar = instance.get_export("bar").unwrap();
|
||||||
|
|
||||||
let wat = r#"
|
let wat = r#"
|
||||||
@@ -196,8 +196,8 @@ fn trap_display_multi_module() -> Result<()> {
|
|||||||
(func (export "bar2") call $middle)
|
(func (export "bar2") call $middle)
|
||||||
)
|
)
|
||||||
"#;
|
"#;
|
||||||
let module = Module::new(&store, wat)?;
|
let module = Module::new(store.engine(), wat)?;
|
||||||
let instance = Instance::new(&module, &[bar])?;
|
let instance = Instance::new(&store, &module, &[bar])?;
|
||||||
let bar2 = instance.get_func("bar2").expect("expected function export");
|
let bar2 = instance.get_func("bar2").expect("expected function export");
|
||||||
|
|
||||||
let e = bar2.call(&[]).err().expect("error calling function");
|
let e = bar2.call(&[]).err().expect("error calling function");
|
||||||
@@ -230,10 +230,12 @@ fn trap_start_function_import() -> Result<()> {
|
|||||||
"#,
|
"#,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
let module = Module::new(&store, &binary)?;
|
let module = Module::new(store.engine(), &binary)?;
|
||||||
let sig = FuncType::new(Box::new([]), Box::new([]));
|
let sig = FuncType::new(Box::new([]), Box::new([]));
|
||||||
let func = Func::new(&store, sig, |_, _, _| Err(Trap::new("user trap")));
|
let func = Func::new(&store, sig, |_, _, _| Err(Trap::new("user trap")));
|
||||||
let err = Instance::new(&module, &[func.into()]).err().unwrap();
|
let err = Instance::new(&store, &module, &[func.into()])
|
||||||
|
.err()
|
||||||
|
.unwrap();
|
||||||
assert!(err
|
assert!(err
|
||||||
.downcast_ref::<Trap>()
|
.downcast_ref::<Trap>()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
@@ -257,10 +259,11 @@ fn rust_panic_import() -> Result<()> {
|
|||||||
"#,
|
"#,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
let module = Module::new(&store, &binary)?;
|
let module = Module::new(store.engine(), &binary)?;
|
||||||
let sig = FuncType::new(Box::new([]), Box::new([]));
|
let sig = FuncType::new(Box::new([]), Box::new([]));
|
||||||
let func = Func::new(&store, sig, |_, _, _| panic!("this is a panic"));
|
let func = Func::new(&store, sig, |_, _, _| panic!("this is a panic"));
|
||||||
let instance = Instance::new(
|
let instance = Instance::new(
|
||||||
|
&store,
|
||||||
&module,
|
&module,
|
||||||
&[
|
&[
|
||||||
func.into(),
|
func.into(),
|
||||||
@@ -299,18 +302,18 @@ fn rust_panic_start_function() -> Result<()> {
|
|||||||
"#,
|
"#,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
let module = Module::new(&store, &binary)?;
|
let module = Module::new(store.engine(), &binary)?;
|
||||||
let sig = FuncType::new(Box::new([]), Box::new([]));
|
let sig = FuncType::new(Box::new([]), Box::new([]));
|
||||||
let func = Func::new(&store, sig, |_, _, _| panic!("this is a panic"));
|
let func = Func::new(&store, sig, |_, _, _| panic!("this is a panic"));
|
||||||
let err = panic::catch_unwind(AssertUnwindSafe(|| {
|
let err = panic::catch_unwind(AssertUnwindSafe(|| {
|
||||||
drop(Instance::new(&module, &[func.into()]));
|
drop(Instance::new(&store, &module, &[func.into()]));
|
||||||
}))
|
}))
|
||||||
.unwrap_err();
|
.unwrap_err();
|
||||||
assert_eq!(err.downcast_ref::<&'static str>(), Some(&"this is a panic"));
|
assert_eq!(err.downcast_ref::<&'static str>(), Some(&"this is a panic"));
|
||||||
|
|
||||||
let func = Func::wrap(&store, || panic!("this is another panic"));
|
let func = Func::wrap(&store, || panic!("this is another panic"));
|
||||||
let err = panic::catch_unwind(AssertUnwindSafe(|| {
|
let err = panic::catch_unwind(AssertUnwindSafe(|| {
|
||||||
drop(Instance::new(&module, &[func.into()]));
|
drop(Instance::new(&store, &module, &[func.into()]));
|
||||||
}))
|
}))
|
||||||
.unwrap_err();
|
.unwrap_err();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
@@ -332,8 +335,8 @@ fn mismatched_arguments() -> Result<()> {
|
|||||||
"#,
|
"#,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
let module = Module::new(&store, &binary)?;
|
let module = Module::new(store.engine(), &binary)?;
|
||||||
let instance = Instance::new(&module, &[])?;
|
let instance = Instance::new(&store, &module, &[])?;
|
||||||
let func = instance.get_func("foo").unwrap();
|
let func = instance.get_func("foo").unwrap();
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
func.call(&[]).unwrap_err().to_string(),
|
func.call(&[]).unwrap_err().to_string(),
|
||||||
@@ -371,8 +374,8 @@ fn call_signature_mismatch() -> Result<()> {
|
|||||||
"#,
|
"#,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
let module = Module::new(&store, &binary)?;
|
let module = Module::new(store.engine(), &binary)?;
|
||||||
let err = Instance::new(&module, &[])
|
let err = Instance::new(&store, &module, &[])
|
||||||
.err()
|
.err()
|
||||||
.unwrap()
|
.unwrap()
|
||||||
.downcast::<Trap>()
|
.downcast::<Trap>()
|
||||||
@@ -397,8 +400,8 @@ fn start_trap_pretty() -> Result<()> {
|
|||||||
)
|
)
|
||||||
"#;
|
"#;
|
||||||
|
|
||||||
let module = Module::new(&store, wat)?;
|
let module = Module::new(store.engine(), wat)?;
|
||||||
let e = match Instance::new(&module, &[]) {
|
let e = match Instance::new(&store, &module, &[]) {
|
||||||
Ok(_) => panic!("expected failure"),
|
Ok(_) => panic!("expected failure"),
|
||||||
Err(e) => e.downcast::<Trap>()?,
|
Err(e) => e.downcast::<Trap>()?,
|
||||||
};
|
};
|
||||||
@@ -420,8 +423,8 @@ wasm backtrace:
|
|||||||
#[test]
|
#[test]
|
||||||
fn present_after_module_drop() -> Result<()> {
|
fn present_after_module_drop() -> Result<()> {
|
||||||
let store = Store::default();
|
let store = Store::default();
|
||||||
let module = Module::new(&store, r#"(func (export "foo") unreachable)"#)?;
|
let module = Module::new(store.engine(), r#"(func (export "foo") unreachable)"#)?;
|
||||||
let instance = Instance::new(&module, &[])?;
|
let instance = Instance::new(&store, &module, &[])?;
|
||||||
let func = instance.get_func("foo").unwrap();
|
let func = instance.get_func("foo").unwrap();
|
||||||
|
|
||||||
println!("asserting before we drop modules");
|
println!("asserting before we drop modules");
|
||||||
|
|||||||
@@ -48,22 +48,25 @@ fn main() {
|
|||||||
let tests: &[(&str, fn())] = &[
|
let tests: &[(&str, fn())] = &[
|
||||||
("normal segfault", || segfault()),
|
("normal segfault", || segfault()),
|
||||||
("make instance then segfault", || {
|
("make instance then segfault", || {
|
||||||
let store = Store::default();
|
let engine = Engine::default();
|
||||||
let module = Module::new(&store, "(module)").unwrap();
|
let store = Store::new(&engine);
|
||||||
let _instance = Instance::new(&module, &[]).unwrap();
|
let module = Module::new(&engine, "(module)").unwrap();
|
||||||
|
let _instance = Instance::new(&store, &module, &[]).unwrap();
|
||||||
segfault();
|
segfault();
|
||||||
}),
|
}),
|
||||||
("make instance then overrun the stack", || {
|
("make instance then overrun the stack", || {
|
||||||
let store = Store::default();
|
let engine = Engine::default();
|
||||||
let module = Module::new(&store, "(module)").unwrap();
|
let store = Store::new(&engine);
|
||||||
let _instance = Instance::new(&module, &[]).unwrap();
|
let module = Module::new(&engine, "(module)").unwrap();
|
||||||
|
let _instance = Instance::new(&store, &module, &[]).unwrap();
|
||||||
println!("stack overrun: {}", overrun_the_stack());
|
println!("stack overrun: {}", overrun_the_stack());
|
||||||
}),
|
}),
|
||||||
("segfault in a host function", || {
|
("segfault in a host function", || {
|
||||||
let store = Store::default();
|
let engine = Engine::default();
|
||||||
let module = Module::new(&store, r#"(import "" "" (func)) (start 0)"#).unwrap();
|
let store = Store::new(&engine);
|
||||||
|
let module = Module::new(&engine, r#"(import "" "" (func)) (start 0)"#).unwrap();
|
||||||
let segfault = Func::wrap(&store, || segfault());
|
let segfault = Func::wrap(&store, || segfault());
|
||||||
Instance::new(&module, &[segfault.into()]).unwrap();
|
Instance::new(&store, &module, &[segfault.into()]).unwrap();
|
||||||
}),
|
}),
|
||||||
];
|
];
|
||||||
match env::var(VAR_NAME) {
|
match env::var(VAR_NAME) {
|
||||||
|
|||||||
Reference in New Issue
Block a user