Add a concept of "global exports".
This adds a feature which allows one to look up an export by name without knowing what module it's in -- `lookup_global_export` on an `InstanceContents`. The main expected use for this is to support APIs where module A imports a function from module B, and module B needs to access module A's memory. B can't import it from A in the normal way, because that would create a dependency cycle. So for now, allow B to look up A's exported memory dynamically with `lookup_global_export`. In the future, with reference types and possibly host bindings, we'll be able to pass references to memory as arguments, which will obviate the need for this mechanism.
This commit is contained in:
@@ -9,6 +9,9 @@ extern crate wasmtime_environ;
|
|||||||
extern crate wasmtime_jit;
|
extern crate wasmtime_jit;
|
||||||
|
|
||||||
use cranelift_codegen::settings;
|
use cranelift_codegen::settings;
|
||||||
|
use std::cell::RefCell;
|
||||||
|
use std::collections::HashMap;
|
||||||
|
use std::rc::Rc;
|
||||||
use wasmparser::validate;
|
use wasmparser::validate;
|
||||||
use wasmtime_jit::{CompiledModule, Compiler, NullResolver};
|
use wasmtime_jit::{CompiledModule, Compiler, NullResolver};
|
||||||
|
|
||||||
@@ -23,7 +26,8 @@ fuzz_target!(|data: &[u8]| {
|
|||||||
let isa = isa_builder.finish(settings::Flags::new(flag_builder));
|
let isa = isa_builder.finish(settings::Flags::new(flag_builder));
|
||||||
let mut compiler = Compiler::new(isa);
|
let mut compiler = Compiler::new(isa);
|
||||||
let mut resolver = NullResolver {};
|
let mut resolver = NullResolver {};
|
||||||
let _compiled = match CompiledModule::new(&mut compiler, data, &mut resolver) {
|
let mut global_exports = Rc::new(RefCell::new(HashMap::new()));
|
||||||
|
let _compiled = match CompiledModule::new(&mut compiler, data, &mut resolver, global_exports) {
|
||||||
Ok(x) => x,
|
Ok(x) => x,
|
||||||
Err(_) => return,
|
Err(_) => return,
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -18,12 +18,12 @@ cranelift-wasm = "0.26.0"
|
|||||||
cast = { version = "0.2.2", default-features = false }
|
cast = { version = "0.2.2", default-features = false }
|
||||||
failure = { version = "0.1.3", default-features = false }
|
failure = { version = "0.1.3", default-features = false }
|
||||||
failure_derive = { version = "0.1.3", default-features = false }
|
failure_derive = { version = "0.1.3", default-features = false }
|
||||||
hashbrown = { version = "0.1.8", optional = true }
|
indexmap = "1.0.2"
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = ["std"]
|
default = ["std"]
|
||||||
std = ["cranelift-codegen/std", "cranelift-wasm/std"]
|
std = ["cranelift-codegen/std", "cranelift-wasm/std"]
|
||||||
core = ["hashbrown/nightly", "cranelift-codegen/core", "cranelift-wasm/core"]
|
core = ["cranelift-codegen/core", "cranelift-wasm/core"]
|
||||||
|
|
||||||
[badges]
|
[badges]
|
||||||
maintenance = { status = "experimental" }
|
maintenance = { status = "experimental" }
|
||||||
|
|||||||
@@ -34,11 +34,6 @@ extern crate alloc as std;
|
|||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate std;
|
extern crate std;
|
||||||
|
|
||||||
#[cfg(not(feature = "std"))]
|
|
||||||
use hashbrown::HashMap;
|
|
||||||
#[cfg(feature = "std")]
|
|
||||||
use std::collections::HashMap;
|
|
||||||
|
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate failure_derive;
|
extern crate failure_derive;
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
//! Data structures for representing decoded wasm modules.
|
//! Data structures for representing decoded wasm modules.
|
||||||
|
|
||||||
use super::HashMap;
|
|
||||||
use crate::tunables::Tunables;
|
use crate::tunables::Tunables;
|
||||||
use cranelift_codegen::ir;
|
use cranelift_codegen::ir;
|
||||||
use cranelift_entity::{EntityRef, PrimaryMap};
|
use cranelift_entity::{EntityRef, PrimaryMap};
|
||||||
@@ -8,6 +7,7 @@ use cranelift_wasm::{
|
|||||||
DefinedFuncIndex, DefinedGlobalIndex, DefinedMemoryIndex, DefinedTableIndex, FuncIndex, Global,
|
DefinedFuncIndex, DefinedGlobalIndex, DefinedMemoryIndex, DefinedTableIndex, FuncIndex, Global,
|
||||||
GlobalIndex, Memory, MemoryIndex, SignatureIndex, Table, TableIndex,
|
GlobalIndex, Memory, MemoryIndex, SignatureIndex, Table, TableIndex,
|
||||||
};
|
};
|
||||||
|
use indexmap::IndexMap;
|
||||||
use std::string::String;
|
use std::string::String;
|
||||||
use std::vec::Vec;
|
use std::vec::Vec;
|
||||||
|
|
||||||
@@ -162,7 +162,7 @@ pub struct Module {
|
|||||||
pub globals: PrimaryMap<GlobalIndex, Global>,
|
pub globals: PrimaryMap<GlobalIndex, Global>,
|
||||||
|
|
||||||
/// Exported entities.
|
/// Exported entities.
|
||||||
pub exports: HashMap<String, Export>,
|
pub exports: IndexMap<String, Export>,
|
||||||
|
|
||||||
/// The module "start" function, if present.
|
/// The module "start" function, if present.
|
||||||
pub start_func: Option<FuncIndex>,
|
pub start_func: Option<FuncIndex>,
|
||||||
@@ -184,7 +184,7 @@ impl Module {
|
|||||||
table_plans: PrimaryMap::new(),
|
table_plans: PrimaryMap::new(),
|
||||||
memory_plans: PrimaryMap::new(),
|
memory_plans: PrimaryMap::new(),
|
||||||
globals: PrimaryMap::new(),
|
globals: PrimaryMap::new(),
|
||||||
exports: HashMap::new(),
|
exports: IndexMap::new(),
|
||||||
start_func: None,
|
start_func: None,
|
||||||
table_elements: Vec::new(),
|
table_elements: Vec::new(),
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,8 +16,8 @@ cranelift-codegen = "0.26.0"
|
|||||||
cranelift-entity = "0.26.0"
|
cranelift-entity = "0.26.0"
|
||||||
cranelift-wasm = "0.26.0"
|
cranelift-wasm = "0.26.0"
|
||||||
cranelift-frontend = "0.26.0"
|
cranelift-frontend = "0.26.0"
|
||||||
wasmtime-environ = { path = "../environ" }
|
wasmtime-environ = { path = "../environ", default-features = false }
|
||||||
wasmtime-runtime = { path = "../runtime" }
|
wasmtime-runtime = { path = "../runtime", default-features = false }
|
||||||
region = "1.0.0"
|
region = "1.0.0"
|
||||||
failure = { version = "0.1.3", default-features = false }
|
failure = { version = "0.1.3", default-features = false }
|
||||||
failure_derive = { version = "0.1.3", default-features = false }
|
failure_derive = { version = "0.1.3", default-features = false }
|
||||||
|
|||||||
@@ -3,9 +3,11 @@
|
|||||||
//! `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 super::HashMap;
|
||||||
use crate::compiler::Compiler;
|
use crate::compiler::Compiler;
|
||||||
use crate::link::link_module;
|
use crate::link::link_module;
|
||||||
use crate::resolver::Resolver;
|
use crate::resolver::Resolver;
|
||||||
|
use core::cell::RefCell;
|
||||||
use cranelift_entity::{BoxedSlice, PrimaryMap};
|
use cranelift_entity::{BoxedSlice, PrimaryMap};
|
||||||
use cranelift_wasm::{DefinedFuncIndex, SignatureIndex};
|
use cranelift_wasm::{DefinedFuncIndex, SignatureIndex};
|
||||||
use std::boxed::Box;
|
use std::boxed::Box;
|
||||||
@@ -16,7 +18,7 @@ use wasmtime_environ::{
|
|||||||
CompileError, DataInitializer, DataInitializerLocation, Module, ModuleEnvironment,
|
CompileError, DataInitializer, DataInitializerLocation, Module, ModuleEnvironment,
|
||||||
};
|
};
|
||||||
use wasmtime_runtime::{
|
use wasmtime_runtime::{
|
||||||
Imports, Instance, InstantiationError, VMFunctionBody, VMSharedSignatureIndex,
|
Export, Imports, Instance, InstantiationError, VMFunctionBody, VMSharedSignatureIndex,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// An error condition while setting up a wasm instance, be it validation,
|
/// An error condition while setting up a wasm instance, be it validation,
|
||||||
@@ -112,6 +114,7 @@ pub struct CompiledModule {
|
|||||||
imports: Imports,
|
imports: Imports,
|
||||||
data_initializers: Box<[OwnedDataInitializer]>,
|
data_initializers: Box<[OwnedDataInitializer]>,
|
||||||
signatures: BoxedSlice<SignatureIndex, VMSharedSignatureIndex>,
|
signatures: BoxedSlice<SignatureIndex, VMSharedSignatureIndex>,
|
||||||
|
global_exports: Rc<RefCell<HashMap<String, Option<Export>>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl CompiledModule {
|
impl CompiledModule {
|
||||||
@@ -120,26 +123,28 @@ impl CompiledModule {
|
|||||||
compiler: &mut Compiler,
|
compiler: &mut Compiler,
|
||||||
data: &'data [u8],
|
data: &'data [u8],
|
||||||
resolver: &mut dyn Resolver,
|
resolver: &mut dyn Resolver,
|
||||||
|
global_exports: Rc<RefCell<HashMap<String, Option<Export>>>>,
|
||||||
) -> Result<Self, SetupError> {
|
) -> Result<Self, SetupError> {
|
||||||
let raw = RawCompiledModule::<'data>::new(compiler, data, resolver)?;
|
let raw = RawCompiledModule::<'data>::new(compiler, data, resolver)?;
|
||||||
|
|
||||||
Ok(Self {
|
Ok(Self::from_parts(
|
||||||
module: Rc::new(raw.module),
|
raw.module,
|
||||||
finished_functions: raw.finished_functions,
|
global_exports,
|
||||||
imports: raw.imports,
|
raw.finished_functions,
|
||||||
data_initializers: raw
|
raw.imports,
|
||||||
.data_initializers
|
raw.data_initializers
|
||||||
.iter()
|
.iter()
|
||||||
.map(OwnedDataInitializer::new)
|
.map(OwnedDataInitializer::new)
|
||||||
.collect::<Vec<_>>()
|
.collect::<Vec<_>>()
|
||||||
.into_boxed_slice(),
|
.into_boxed_slice(),
|
||||||
signatures: raw.signatures.clone(),
|
raw.signatures.clone(),
|
||||||
})
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Construct a `CompiledModule` from component parts.
|
/// Construct a `CompiledModule` from component parts.
|
||||||
pub fn from_parts(
|
pub fn from_parts(
|
||||||
module: Module,
|
module: Module,
|
||||||
|
global_exports: Rc<RefCell<HashMap<String, Option<Export>>>>,
|
||||||
finished_functions: BoxedSlice<DefinedFuncIndex, *const VMFunctionBody>,
|
finished_functions: BoxedSlice<DefinedFuncIndex, *const VMFunctionBody>,
|
||||||
imports: Imports,
|
imports: Imports,
|
||||||
data_initializers: Box<[OwnedDataInitializer]>,
|
data_initializers: Box<[OwnedDataInitializer]>,
|
||||||
@@ -147,6 +152,7 @@ impl CompiledModule {
|
|||||||
) -> Self {
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
module: Rc::new(module),
|
module: Rc::new(module),
|
||||||
|
global_exports: Rc::clone(&global_exports),
|
||||||
finished_functions,
|
finished_functions,
|
||||||
imports,
|
imports,
|
||||||
data_initializers,
|
data_initializers,
|
||||||
@@ -170,6 +176,7 @@ impl CompiledModule {
|
|||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
Instance::new(
|
Instance::new(
|
||||||
Rc::clone(&self.module),
|
Rc::clone(&self.module),
|
||||||
|
Rc::clone(&self.global_exports),
|
||||||
self.finished_functions.clone(),
|
self.finished_functions.clone(),
|
||||||
self.imports.clone(),
|
self.imports.clone(),
|
||||||
&data_initializers,
|
&data_initializers,
|
||||||
@@ -206,11 +213,13 @@ pub fn instantiate(
|
|||||||
compiler: &mut Compiler,
|
compiler: &mut Compiler,
|
||||||
data: &[u8],
|
data: &[u8],
|
||||||
resolver: &mut dyn Resolver,
|
resolver: &mut dyn Resolver,
|
||||||
|
global_exports: Rc<RefCell<HashMap<String, Option<Export>>>>,
|
||||||
) -> Result<Instance, SetupError> {
|
) -> Result<Instance, SetupError> {
|
||||||
let raw = RawCompiledModule::new(compiler, data, resolver)?;
|
let raw = RawCompiledModule::new(compiler, data, resolver)?;
|
||||||
|
|
||||||
Instance::new(
|
Instance::new(
|
||||||
Rc::new(raw.module),
|
Rc::new(raw.module),
|
||||||
|
global_exports,
|
||||||
raw.finished_functions,
|
raw.finished_functions,
|
||||||
raw.imports,
|
raw.imports,
|
||||||
&*raw.data_initializers,
|
&*raw.data_initializers,
|
||||||
|
|||||||
@@ -32,7 +32,7 @@ extern crate alloc as std;
|
|||||||
extern crate std;
|
extern crate std;
|
||||||
|
|
||||||
#[cfg(not(feature = "std"))]
|
#[cfg(not(feature = "std"))]
|
||||||
use hashbrown::{map as hash_map, HashMap};
|
use hashbrown::{hash_map, HashMap};
|
||||||
#[cfg(feature = "std")]
|
#[cfg(feature = "std")]
|
||||||
use std::collections::{hash_map, HashMap};
|
use std::collections::{hash_map, HashMap};
|
||||||
|
|
||||||
|
|||||||
@@ -15,7 +15,7 @@ edition = "2018"
|
|||||||
cranelift-codegen = "0.26.0"
|
cranelift-codegen = "0.26.0"
|
||||||
cranelift-entity = "0.26.0"
|
cranelift-entity = "0.26.0"
|
||||||
cranelift-wasm = "0.26.0"
|
cranelift-wasm = "0.26.0"
|
||||||
wasmtime-environ = { path = "../environ" }
|
wasmtime-environ = { path = "../environ", default-features = false }
|
||||||
region = "1.0.0"
|
region = "1.0.0"
|
||||||
lazy_static = "1.2.0"
|
lazy_static = "1.2.0"
|
||||||
libc = { version = "0.2.44", default-features = false }
|
libc = { version = "0.2.44", default-features = false }
|
||||||
@@ -24,6 +24,7 @@ memoffset = "0.2.1"
|
|||||||
cast = { version = "0.2.2", default-features = false }
|
cast = { version = "0.2.2", default-features = false }
|
||||||
failure = { version = "0.1.3", default-features = false }
|
failure = { version = "0.1.3", default-features = false }
|
||||||
failure_derive = { version = "0.1.3", default-features = false }
|
failure_derive = { version = "0.1.3", default-features = false }
|
||||||
|
indexmap = "1.0.2"
|
||||||
|
|
||||||
[target.'cfg(target_os = "windows")'.dependencies]
|
[target.'cfg(target_os = "windows")'.dependencies]
|
||||||
winapi = { version = "0.3.6", features = ["winbase", "memoryapi"] }
|
winapi = { version = "0.3.6", features = ["winbase", "memoryapi"] }
|
||||||
@@ -35,8 +36,7 @@ regex = "1.0.6"
|
|||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = ["std"]
|
default = ["std"]
|
||||||
std = ["cranelift-codegen/std", "cranelift-wasm/std"]
|
std = ["cranelift-codegen/std", "cranelift-wasm/std", "wasmtime-environ/std"]
|
||||||
core = ["cranelift-codegen/core", "cranelift-wasm/core", "wasmtime-environ/core"]
|
|
||||||
|
|
||||||
[badges]
|
[badges]
|
||||||
maintenance = { status = "experimental" }
|
maintenance = { status = "experimental" }
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ use cranelift_wasm::Global;
|
|||||||
use wasmtime_environ::{MemoryPlan, TablePlan};
|
use wasmtime_environ::{MemoryPlan, TablePlan};
|
||||||
|
|
||||||
/// The value of an export passed from one instance to another.
|
/// The value of an export passed from one instance to another.
|
||||||
#[derive(Debug)]
|
#[derive(Debug, Clone)]
|
||||||
pub enum Export {
|
pub enum Export {
|
||||||
/// A function export value.
|
/// A function export value.
|
||||||
Function {
|
Function {
|
||||||
|
|||||||
@@ -14,6 +14,8 @@ use crate::vmcontext::{
|
|||||||
VMTableImport,
|
VMTableImport,
|
||||||
};
|
};
|
||||||
use core::any::Any;
|
use core::any::Any;
|
||||||
|
use core::borrow::Borrow;
|
||||||
|
use core::cell::RefCell;
|
||||||
use core::slice;
|
use core::slice;
|
||||||
use core::{mem, ptr};
|
use core::{mem, ptr};
|
||||||
use cranelift_entity::EntityRef;
|
use cranelift_entity::EntityRef;
|
||||||
@@ -22,10 +24,12 @@ use cranelift_wasm::{
|
|||||||
DefinedFuncIndex, DefinedGlobalIndex, DefinedMemoryIndex, DefinedTableIndex, FuncIndex,
|
DefinedFuncIndex, DefinedGlobalIndex, DefinedMemoryIndex, DefinedTableIndex, FuncIndex,
|
||||||
GlobalIndex, GlobalInit, MemoryIndex, SignatureIndex, TableIndex,
|
GlobalIndex, GlobalInit, MemoryIndex, SignatureIndex, TableIndex,
|
||||||
};
|
};
|
||||||
|
use indexmap;
|
||||||
use std::borrow::ToOwned;
|
use std::borrow::ToOwned;
|
||||||
use std::boxed::Box;
|
use std::boxed::Box;
|
||||||
|
use std::collections::{hash_map, HashMap};
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
use std::string::String;
|
use std::string::{String, ToString};
|
||||||
use wasmtime_environ::{DataInitializer, Module, TableElements, VMOffsets};
|
use wasmtime_environ::{DataInitializer, Module, TableElements, VMOffsets};
|
||||||
|
|
||||||
fn signature_id(
|
fn signature_id(
|
||||||
@@ -67,17 +71,127 @@ fn imported_table<'vmctx>(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn imported_memory<'vmctx>(
|
||||||
|
vmctx: &'vmctx VMContext,
|
||||||
|
offsets: &VMOffsets,
|
||||||
|
index: MemoryIndex,
|
||||||
|
) -> &'vmctx VMMemoryImport {
|
||||||
|
#[allow(clippy::cast_ptr_alignment)]
|
||||||
|
unsafe {
|
||||||
|
let ptr = (vmctx as *const VMContext as *const u8)
|
||||||
|
.add(cast::usize(offsets.vmctx_vmmemory_import(index)));
|
||||||
|
&*(ptr as *const VMMemoryImport)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn imported_global<'vmctx>(
|
||||||
|
vmctx: &'vmctx VMContext,
|
||||||
|
offsets: &VMOffsets,
|
||||||
|
index: GlobalIndex,
|
||||||
|
) -> &'vmctx VMGlobalImport {
|
||||||
|
unsafe {
|
||||||
|
let ptr = (vmctx as *const VMContext as *const u8)
|
||||||
|
.add(cast::usize(offsets.vmctx_vmglobal_import(index)));
|
||||||
|
#[allow(clippy::cast_ptr_alignment)]
|
||||||
|
&*(ptr as *const VMGlobalImport)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn table<'vmctx>(
|
||||||
|
vmctx: &'vmctx VMContext,
|
||||||
|
offsets: &VMOffsets,
|
||||||
|
index: DefinedTableIndex,
|
||||||
|
) -> &'vmctx VMTableDefinition {
|
||||||
|
unsafe {
|
||||||
|
let ptr = (vmctx as *const VMContext as *const u8)
|
||||||
|
.add(cast::usize(offsets.vmctx_vmtable_definition(index)));
|
||||||
|
#[allow(clippy::cast_ptr_alignment)]
|
||||||
|
&*(ptr as *const VMTableDefinition)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn table_mut<'vmctx>(
|
||||||
|
vmctx: &'vmctx mut VMContext,
|
||||||
|
offsets: &VMOffsets,
|
||||||
|
index: DefinedTableIndex,
|
||||||
|
) -> &'vmctx mut VMTableDefinition {
|
||||||
|
unsafe {
|
||||||
|
let ptr = (vmctx as *mut VMContext as *mut u8)
|
||||||
|
.add(cast::usize(offsets.vmctx_vmtable_definition(index)));
|
||||||
|
#[allow(clippy::cast_ptr_alignment)]
|
||||||
|
&mut *(ptr as *mut VMTableDefinition)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn memory<'vmctx>(
|
||||||
|
vmctx: &'vmctx VMContext,
|
||||||
|
offsets: &VMOffsets,
|
||||||
|
index: DefinedMemoryIndex,
|
||||||
|
) -> &'vmctx VMMemoryDefinition {
|
||||||
|
unsafe {
|
||||||
|
let ptr = (vmctx as *const VMContext as *const u8)
|
||||||
|
.add(cast::usize(offsets.vmctx_vmmemory_definition(index)));
|
||||||
|
#[allow(clippy::cast_ptr_alignment)]
|
||||||
|
&*(ptr as *const VMMemoryDefinition)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn memory_mut<'vmctx>(
|
||||||
|
vmctx: &'vmctx mut VMContext,
|
||||||
|
offsets: &VMOffsets,
|
||||||
|
index: DefinedMemoryIndex,
|
||||||
|
) -> &'vmctx mut VMMemoryDefinition {
|
||||||
|
unsafe {
|
||||||
|
let ptr = (vmctx as *mut VMContext as *mut u8)
|
||||||
|
.add(cast::usize(offsets.vmctx_vmmemory_definition(index)));
|
||||||
|
#[allow(clippy::cast_ptr_alignment)]
|
||||||
|
&mut *(ptr as *mut VMMemoryDefinition)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn global<'vmctx>(
|
||||||
|
vmctx: &'vmctx VMContext,
|
||||||
|
offsets: &VMOffsets,
|
||||||
|
index: DefinedGlobalIndex,
|
||||||
|
) -> &'vmctx VMGlobalDefinition {
|
||||||
|
unsafe {
|
||||||
|
let ptr = (vmctx as *const VMContext as *const u8)
|
||||||
|
.add(cast::usize(offsets.vmctx_vmglobal_definition(index)));
|
||||||
|
#[allow(clippy::cast_ptr_alignment)]
|
||||||
|
&*(ptr as *const VMGlobalDefinition)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn global_mut<'vmctx>(
|
||||||
|
vmctx: &'vmctx mut VMContext,
|
||||||
|
offsets: &VMOffsets,
|
||||||
|
index: DefinedGlobalIndex,
|
||||||
|
) -> &'vmctx mut VMGlobalDefinition {
|
||||||
|
unsafe {
|
||||||
|
let ptr = (vmctx as *mut VMContext as *mut u8)
|
||||||
|
.add(cast::usize(offsets.vmctx_vmglobal_definition(index)));
|
||||||
|
#[allow(clippy::cast_ptr_alignment)]
|
||||||
|
&mut *(ptr as *mut VMGlobalDefinition)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// The actual contents of an instance.
|
/// The actual contents of an instance.
|
||||||
///
|
///
|
||||||
/// `Instance` is just a handle containing a pointer to an `InstanceContents`,
|
/// `Instance` is just a handle containing a pointer to an `InstanceContents`,
|
||||||
/// which is specially allocated.
|
/// which is specially allocated.
|
||||||
///
|
///
|
||||||
/// This is repr(C) to ensure that the vmctx field is last.
|
/// This is repr(C) to ensure that the vmctx field is last.
|
||||||
|
/// FIXME: Should this be pub(crate)?
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
pub(crate) struct InstanceContents {
|
pub struct InstanceContents {
|
||||||
/// Offsets in the `vmctx` region.
|
/// Offsets in the `vmctx` region.
|
||||||
offsets: VMOffsets,
|
offsets: VMOffsets,
|
||||||
|
|
||||||
|
/// A global namespace of exports. This is a temporary mechanism to avoid
|
||||||
|
/// cyclic dependencies when one module wants to import from another and
|
||||||
|
/// make its memory available too, that will be obviated by host-bindings.
|
||||||
|
global_exports: Rc<RefCell<HashMap<String, Option<Export>>>>,
|
||||||
|
|
||||||
/// WebAssembly linear memory data.
|
/// WebAssembly linear memory data.
|
||||||
memories: BoxedSlice<DefinedMemoryIndex, LinearMemory>,
|
memories: BoxedSlice<DefinedMemoryIndex, LinearMemory>,
|
||||||
|
|
||||||
@@ -128,6 +242,7 @@ impl InstanceContents {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Return the index `VMTableImport`.
|
/// Return the index `VMTableImport`.
|
||||||
|
#[allow(dead_code)]
|
||||||
fn imported_table(&self, index: TableIndex) -> &VMTableImport {
|
fn imported_table(&self, index: TableIndex) -> &VMTableImport {
|
||||||
imported_table(&self.vmctx, &self.offsets, index)
|
imported_table(&self.vmctx, &self.offsets, index)
|
||||||
}
|
}
|
||||||
@@ -143,11 +258,7 @@ impl InstanceContents {
|
|||||||
|
|
||||||
/// Return the indexed `VMMemoryImport`.
|
/// Return the indexed `VMMemoryImport`.
|
||||||
fn imported_memory(&self, index: MemoryIndex) -> &VMMemoryImport {
|
fn imported_memory(&self, index: MemoryIndex) -> &VMMemoryImport {
|
||||||
unsafe {
|
imported_memory(&self.vmctx, &self.offsets, index)
|
||||||
let ptr = (&self.vmctx as *const VMContext as *const u8)
|
|
||||||
.add(cast::usize(self.offsets.vmctx_vmmemory_import(index)));
|
|
||||||
&*(ptr as *const VMMemoryImport)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return a pointer to the `VMMemoryImport`s.
|
/// Return a pointer to the `VMMemoryImport`s.
|
||||||
@@ -161,11 +272,7 @@ impl InstanceContents {
|
|||||||
|
|
||||||
/// Return the indexed `VMGlobalImport`.
|
/// Return the indexed `VMGlobalImport`.
|
||||||
fn imported_global(&self, index: GlobalIndex) -> &VMGlobalImport {
|
fn imported_global(&self, index: GlobalIndex) -> &VMGlobalImport {
|
||||||
unsafe {
|
imported_global(&self.vmctx, &self.offsets, index)
|
||||||
let ptr = (&self.vmctx as *const VMContext as *const u8)
|
|
||||||
.add(cast::usize(self.offsets.vmctx_vmglobal_import(index)));
|
|
||||||
&*(ptr as *const VMGlobalImport)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return a pointer to the `VMGlobalImport`s.
|
/// Return a pointer to the `VMGlobalImport`s.
|
||||||
@@ -180,20 +287,13 @@ impl InstanceContents {
|
|||||||
/// Return the indexed `VMTableDefinition`.
|
/// Return the indexed `VMTableDefinition`.
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
fn table(&self, index: DefinedTableIndex) -> &VMTableDefinition {
|
fn table(&self, index: DefinedTableIndex) -> &VMTableDefinition {
|
||||||
unsafe {
|
table(&self.vmctx, &self.offsets, index)
|
||||||
let ptr = (&self.vmctx as *const VMContext as *const u8)
|
|
||||||
.add(cast::usize(self.offsets.vmctx_vmtable_definition(index)));
|
|
||||||
&*(ptr as *const VMTableDefinition)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return the indexed `VMTableDefinition`.
|
/// Return the indexed `VMTableDefinition`.
|
||||||
|
#[allow(dead_code)]
|
||||||
fn table_mut(&mut self, index: DefinedTableIndex) -> &mut VMTableDefinition {
|
fn table_mut(&mut self, index: DefinedTableIndex) -> &mut VMTableDefinition {
|
||||||
unsafe {
|
table_mut(&mut self.vmctx, &self.offsets, index)
|
||||||
let ptr = (&mut self.vmctx as *mut VMContext as *mut u8)
|
|
||||||
.add(cast::usize(self.offsets.vmctx_vmtable_definition(index)));
|
|
||||||
&mut *(ptr as *mut VMTableDefinition)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return a pointer to the `VMTableDefinition`s.
|
/// Return a pointer to the `VMTableDefinition`s.
|
||||||
@@ -207,20 +307,12 @@ impl InstanceContents {
|
|||||||
|
|
||||||
/// Return the indexed `VMMemoryDefinition`.
|
/// Return the indexed `VMMemoryDefinition`.
|
||||||
fn memory(&self, index: DefinedMemoryIndex) -> &VMMemoryDefinition {
|
fn memory(&self, index: DefinedMemoryIndex) -> &VMMemoryDefinition {
|
||||||
unsafe {
|
memory(&self.vmctx, &self.offsets, index)
|
||||||
let ptr = (&self.vmctx as *const VMContext as *const u8)
|
|
||||||
.add(cast::usize(self.offsets.vmctx_vmmemory_definition(index)));
|
|
||||||
&*(ptr as *const VMMemoryDefinition)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return the indexed `VMMemoryDefinition`.
|
/// Return the indexed `VMMemoryDefinition`.
|
||||||
fn memory_mut(&mut self, index: DefinedMemoryIndex) -> &mut VMMemoryDefinition {
|
fn memory_mut(&mut self, index: DefinedMemoryIndex) -> &mut VMMemoryDefinition {
|
||||||
unsafe {
|
memory_mut(&mut self.vmctx, &self.offsets, index)
|
||||||
let ptr = (&mut self.vmctx as *mut VMContext as *mut u8)
|
|
||||||
.add(cast::usize(self.offsets.vmctx_vmmemory_definition(index)));
|
|
||||||
&mut *(ptr as *mut VMMemoryDefinition)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return a pointer to the `VMMemoryDefinition`s.
|
/// Return a pointer to the `VMMemoryDefinition`s.
|
||||||
@@ -235,20 +327,12 @@ impl InstanceContents {
|
|||||||
/// Return the indexed `VMGlobalDefinition`.
|
/// Return the indexed `VMGlobalDefinition`.
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
fn global(&self, index: DefinedGlobalIndex) -> &VMGlobalDefinition {
|
fn global(&self, index: DefinedGlobalIndex) -> &VMGlobalDefinition {
|
||||||
unsafe {
|
global(&self.vmctx, &self.offsets, index)
|
||||||
let ptr = (&self.vmctx as *const VMContext as *const u8)
|
|
||||||
.add(cast::usize(self.offsets.vmctx_vmglobal_definition(index)));
|
|
||||||
&*(ptr as *const VMGlobalDefinition)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return the indexed `VMGlobalDefinition`.
|
/// Return the indexed `VMGlobalDefinition`.
|
||||||
fn global_mut(&mut self, index: DefinedGlobalIndex) -> &mut VMGlobalDefinition {
|
fn global_mut(&mut self, index: DefinedGlobalIndex) -> &mut VMGlobalDefinition {
|
||||||
unsafe {
|
global_mut(&mut self.vmctx, &self.offsets, index)
|
||||||
let ptr = (&mut self.vmctx as *mut VMContext as *mut u8)
|
|
||||||
.add(cast::usize(self.offsets.vmctx_vmglobal_definition(index)));
|
|
||||||
&mut *(ptr as *mut VMGlobalDefinition)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return a pointer to the `VMGlobalDefinition`s.
|
/// Return a pointer to the `VMGlobalDefinition`s.
|
||||||
@@ -280,30 +364,71 @@ impl InstanceContents {
|
|||||||
self.vmctx_mut()
|
self.vmctx_mut()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn invoke_function(
|
||||||
|
&mut self,
|
||||||
|
module: &Module,
|
||||||
|
index: FuncIndex,
|
||||||
|
) -> Result<(), InstantiationError> {
|
||||||
|
// TODO: Check that the callee's calling convention matches what we expect.
|
||||||
|
|
||||||
|
let (callee_address, callee_vmctx) = match module.defined_func_index(index) {
|
||||||
|
Some(defined_index) => {
|
||||||
|
let body = *self
|
||||||
|
.finished_functions
|
||||||
|
.get(defined_index)
|
||||||
|
.expect("function index is out of bounds");
|
||||||
|
(body, self.vmctx_mut() as *mut VMContext)
|
||||||
|
}
|
||||||
|
None => {
|
||||||
|
assert!(index.index() < module.imported_funcs.len());
|
||||||
|
let import = self.imported_function(index);
|
||||||
|
(import.body, import.vmctx)
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Make the call.
|
||||||
|
unsafe { wasmtime_call(callee_address, callee_vmctx) }
|
||||||
|
.map_err(InstantiationError::StartTrap)
|
||||||
|
}
|
||||||
|
|
||||||
/// Invoke the WebAssembly start function of the instance, if one is present.
|
/// Invoke the WebAssembly start function of the instance, if one is present.
|
||||||
fn invoke_start_function(&mut self, module: &Module) -> Result<(), InstantiationError> {
|
fn invoke_start_function(&mut self, module: &Module) -> Result<(), InstantiationError> {
|
||||||
if let Some(start_index) = module.start_func {
|
if let Some(start_index) = module.start_func {
|
||||||
let (callee_address, callee_vmctx) = match module.defined_func_index(start_index) {
|
self.invoke_function(module, start_index)
|
||||||
Some(defined_start_index) => {
|
} else if let Some(start_export) = module.exports.get("_start") {
|
||||||
let body = *self
|
// As a compatibility measure, if the module doesn't have a start
|
||||||
.finished_functions
|
// function but does have a _start function exported, call that.
|
||||||
.get(defined_start_index)
|
match start_export {
|
||||||
.expect("start function index is out of bounds");
|
wasmtime_environ::Export::Function(func_index) => {
|
||||||
(body, self.vmctx_mut() as *mut VMContext)
|
let sig = &module.signatures[module.functions[*func_index]];
|
||||||
|
// No wasm params or returns; just the vmctx param.
|
||||||
|
if sig.params.len() == 1 && sig.returns.is_empty() {
|
||||||
|
self.invoke_function(module, *func_index)
|
||||||
|
} else {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
None => {
|
_ => Ok(()),
|
||||||
assert!(start_index.index() < module.imported_funcs.len());
|
}
|
||||||
let import = self.imported_function(start_index);
|
} else if let Some(main_export) = module.exports.get("main") {
|
||||||
(import.body, import.vmctx)
|
// As a further compatibility measure, if the module doesn't have a
|
||||||
|
// start function or a _start function exported, but does have a main
|
||||||
|
// function exported, call that.
|
||||||
|
match main_export {
|
||||||
|
wasmtime_environ::Export::Function(func_index) => {
|
||||||
|
let sig = &module.signatures[module.functions[*func_index]];
|
||||||
|
// No wasm params or returns; just the vmctx param.
|
||||||
|
if sig.params.len() == 1 && sig.returns.is_empty() {
|
||||||
|
self.invoke_function(module, *func_index)
|
||||||
|
} else {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
_ => Ok(()),
|
||||||
|
}
|
||||||
// Make the call.
|
} else {
|
||||||
unsafe { wasmtime_call(callee_address, callee_vmctx) }
|
Ok(())
|
||||||
.map_err(InstantiationError::StartTrap)?;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return the offset from the vmctx pointer to its containing Instance.
|
/// Return the offset from the vmctx pointer to its containing Instance.
|
||||||
@@ -328,7 +453,8 @@ impl InstanceContents {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Return the memory index for the given `VMMemoryDefinition`.
|
/// Return the memory index for the given `VMMemoryDefinition`.
|
||||||
pub(crate) fn memory_index(&self, memory: &VMMemoryDefinition) -> DefinedMemoryIndex {
|
/// FIXME: Should this be pub(crate)?
|
||||||
|
pub fn memory_index(&self, memory: &VMMemoryDefinition) -> DefinedMemoryIndex {
|
||||||
let offsets = &self.offsets;
|
let offsets = &self.offsets;
|
||||||
let begin = unsafe {
|
let begin = unsafe {
|
||||||
(&self.vmctx as *const VMContext as *const u8)
|
(&self.vmctx as *const VMContext as *const u8)
|
||||||
@@ -355,11 +481,8 @@ impl InstanceContents {
|
|||||||
///
|
///
|
||||||
/// Returns `None` if memory can't be grown by the specified amount
|
/// Returns `None` if memory can't be grown by the specified amount
|
||||||
/// of pages.
|
/// of pages.
|
||||||
pub(crate) fn memory_grow(
|
/// FIXME: Should this be pub(crate)?
|
||||||
&mut self,
|
pub fn memory_grow(&mut self, memory_index: DefinedMemoryIndex, delta: u32) -> Option<u32> {
|
||||||
memory_index: DefinedMemoryIndex,
|
|
||||||
delta: u32,
|
|
||||||
) -> Option<u32> {
|
|
||||||
let result = self
|
let result = self
|
||||||
.memories
|
.memories
|
||||||
.get_mut(memory_index)
|
.get_mut(memory_index)
|
||||||
@@ -414,6 +537,17 @@ impl InstanceContents {
|
|||||||
pub fn host_state(&mut self) -> &mut Any {
|
pub fn host_state(&mut self) -> &mut Any {
|
||||||
&mut *self.host_state
|
&mut *self.host_state
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn lookup_global_export(&self, field: &str) -> Option<Export> {
|
||||||
|
let cell: &RefCell<HashMap<std::string::String, core::option::Option<Export>>> =
|
||||||
|
self.global_exports.borrow();
|
||||||
|
let map: &mut HashMap<std::string::String, core::option::Option<Export>> =
|
||||||
|
&mut cell.borrow_mut();
|
||||||
|
if let Some(Some(export)) = map.get(field) {
|
||||||
|
return Some(export.clone());
|
||||||
|
}
|
||||||
|
None
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A wrapper around an `Mmap` holding an `InstanceContents`.
|
/// A wrapper around an `Mmap` holding an `InstanceContents`.
|
||||||
@@ -461,6 +595,7 @@ impl Instance {
|
|||||||
/// Create a new `Instance`.
|
/// Create a new `Instance`.
|
||||||
pub fn new(
|
pub fn new(
|
||||||
module: Rc<Module>,
|
module: Rc<Module>,
|
||||||
|
global_exports: Rc<RefCell<HashMap<String, Option<Export>>>>,
|
||||||
finished_functions: BoxedSlice<DefinedFuncIndex, *const VMFunctionBody>,
|
finished_functions: BoxedSlice<DefinedFuncIndex, *const VMFunctionBody>,
|
||||||
imports: Imports,
|
imports: Imports,
|
||||||
data_initializers: &[DataInitializer<'_>],
|
data_initializers: &[DataInitializer<'_>],
|
||||||
@@ -507,6 +642,7 @@ impl Instance {
|
|||||||
#[allow(clippy::cast_ptr_alignment)]
|
#[allow(clippy::cast_ptr_alignment)]
|
||||||
let contents_ptr = contents_mmap.as_mut_ptr() as *mut InstanceContents;
|
let contents_ptr = contents_mmap.as_mut_ptr() as *mut InstanceContents;
|
||||||
let contents = InstanceContents {
|
let contents = InstanceContents {
|
||||||
|
global_exports,
|
||||||
offsets,
|
offsets,
|
||||||
memories,
|
memories,
|
||||||
tables,
|
tables,
|
||||||
@@ -572,6 +708,27 @@ impl Instance {
|
|||||||
initialize_memories(&*module, contents, data_initializers)?;
|
initialize_memories(&*module, contents, data_initializers)?;
|
||||||
initialize_globals(&*module, contents);
|
initialize_globals(&*module, contents);
|
||||||
|
|
||||||
|
// Collect the exports for the global export map.
|
||||||
|
for (field, decl) in &module.exports {
|
||||||
|
use hash_map::Entry::*;
|
||||||
|
let cell: &RefCell<HashMap<std::string::String, core::option::Option<Export>>> =
|
||||||
|
contents.global_exports.borrow();
|
||||||
|
let map: &mut HashMap<std::string::String, core::option::Option<Export>> =
|
||||||
|
&mut cell.borrow_mut();
|
||||||
|
match map.entry(field.to_string()) {
|
||||||
|
Vacant(entry) => {
|
||||||
|
entry.insert(Some(lookup_by_declaration(
|
||||||
|
&module,
|
||||||
|
&mut contents.vmctx,
|
||||||
|
&contents.offsets,
|
||||||
|
&contents.finished_functions,
|
||||||
|
&decl,
|
||||||
|
)));
|
||||||
|
}
|
||||||
|
Occupied(ref mut entry) => *entry.get_mut() = None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Ensure that our signal handlers are ready for action.
|
// Ensure that our signal handlers are ready for action.
|
||||||
// TODO: Move these calls out of `Instance`.
|
// TODO: Move these calls out of `Instance`.
|
||||||
wasmtime_init_eager();
|
wasmtime_init_eager();
|
||||||
@@ -581,7 +738,7 @@ impl Instance {
|
|||||||
// invoked automatically at instantiation time.
|
// invoked automatically at instantiation time.
|
||||||
contents.invoke_start_function(&*module)?;
|
contents.invoke_start_function(&*module)?;
|
||||||
|
|
||||||
Ok(Instance {
|
Ok(Self {
|
||||||
module,
|
module,
|
||||||
mmap_field: MmapField {
|
mmap_field: MmapField {
|
||||||
mmap: contents_mmap,
|
mmap: contents_mmap,
|
||||||
@@ -611,80 +768,21 @@ impl Instance {
|
|||||||
|
|
||||||
/// Lookup an export with the given name.
|
/// Lookup an export with the given name.
|
||||||
pub fn lookup(&mut self, field: &str) -> Option<Export> {
|
pub fn lookup(&mut self, field: &str) -> Option<Export> {
|
||||||
let contents = self.mmap_field.contents_mut();
|
let export = if let Some(export) = self.module.exports.get(field) {
|
||||||
if let Some(export) = self.module.exports.get(field) {
|
export.clone()
|
||||||
Some(match export {
|
} else if let Some(export) = self.mmap_field.contents().lookup_global_export(field) {
|
||||||
wasmtime_environ::Export::Function(index) => {
|
return Some(export.clone());
|
||||||
let signature = self.module.signatures[self.module.functions[*index]].clone();
|
|
||||||
let (address, vmctx) =
|
|
||||||
if let Some(def_index) = self.module.defined_func_index(*index) {
|
|
||||||
(
|
|
||||||
contents.finished_functions[def_index],
|
|
||||||
&mut contents.vmctx as *mut VMContext,
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
let import = contents.imported_function(*index);
|
|
||||||
(import.body, import.vmctx)
|
|
||||||
};
|
|
||||||
Export::Function {
|
|
||||||
address,
|
|
||||||
signature,
|
|
||||||
vmctx,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
wasmtime_environ::Export::Table(index) => {
|
|
||||||
let (definition, vmctx) =
|
|
||||||
if let Some(def_index) = self.module.defined_table_index(*index) {
|
|
||||||
(
|
|
||||||
contents.table_mut(def_index) as *mut VMTableDefinition,
|
|
||||||
&mut contents.vmctx as *mut VMContext,
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
let import = contents.imported_table(*index);
|
|
||||||
(import.from, import.vmctx)
|
|
||||||
};
|
|
||||||
Export::Table {
|
|
||||||
definition,
|
|
||||||
vmctx,
|
|
||||||
table: self.module.table_plans[*index].clone(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
wasmtime_environ::Export::Memory(index) => {
|
|
||||||
let (definition, vmctx) =
|
|
||||||
if let Some(def_index) = self.module.defined_memory_index(*index) {
|
|
||||||
(
|
|
||||||
contents.memory_mut(def_index) as *mut VMMemoryDefinition,
|
|
||||||
&mut contents.vmctx as *mut VMContext,
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
let import = contents.imported_memory(*index);
|
|
||||||
(import.from, import.vmctx)
|
|
||||||
};
|
|
||||||
Export::Memory {
|
|
||||||
definition,
|
|
||||||
vmctx,
|
|
||||||
memory: self.module.memory_plans[*index].clone(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
wasmtime_environ::Export::Global(index) => Export::Global {
|
|
||||||
definition: if let Some(def_index) = self.module.defined_global_index(*index) {
|
|
||||||
contents.global_mut(def_index)
|
|
||||||
} else {
|
|
||||||
contents.imported_global(*index).from
|
|
||||||
},
|
|
||||||
global: self.module.globals[*index],
|
|
||||||
},
|
|
||||||
})
|
|
||||||
} else {
|
} else {
|
||||||
None
|
return None;
|
||||||
}
|
};
|
||||||
|
Some(self.lookup_by_declaration(&export))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Lookup an export with the given name. This takes an immutable reference,
|
/// Lookup an export with the given name. This takes an immutable reference,
|
||||||
/// and the result is an `Export` that can only be used to read, not write.
|
/// and the result is an `Export` that the type system doesn't prevent from
|
||||||
/// This requirement is not enforced in the type system, so this function is
|
/// being used to mutate the instance, so this function is unsafe.
|
||||||
/// unsafe.
|
|
||||||
pub unsafe fn lookup_immutable(&self, field: &str) -> Option<Export> {
|
pub unsafe fn lookup_immutable(&self, field: &str) -> Option<Export> {
|
||||||
|
#[allow(clippy::cast_ref_to_mut)]
|
||||||
let temporary_mut = &mut *(self as *const Self as *mut Self);
|
let temporary_mut = &mut *(self as *const Self as *mut Self);
|
||||||
temporary_mut.lookup(field)
|
temporary_mut.lookup(field)
|
||||||
}
|
}
|
||||||
@@ -693,6 +791,104 @@ impl Instance {
|
|||||||
pub fn host_state(&mut self) -> &mut Any {
|
pub fn host_state(&mut self) -> &mut Any {
|
||||||
self.mmap_field.contents_mut().host_state()
|
self.mmap_field.contents_mut().host_state()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Lookup an export with the given export declaration.
|
||||||
|
pub fn lookup_by_declaration(&mut self, export: &wasmtime_environ::Export) -> Export {
|
||||||
|
let contents = self.mmap_field.contents_mut();
|
||||||
|
lookup_by_declaration(
|
||||||
|
&self.module,
|
||||||
|
&mut contents.vmctx,
|
||||||
|
&contents.offsets,
|
||||||
|
&contents.finished_functions,
|
||||||
|
export,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Lookup an export with the given export declaration. This takes an immutable
|
||||||
|
/// reference, and the result is an `Export` that the type system doesn't prevent
|
||||||
|
/// from being used to mutate the instance, so this function is unsafe.
|
||||||
|
pub unsafe fn lookup_immutable_by_declaration(
|
||||||
|
&self,
|
||||||
|
export: &wasmtime_environ::Export,
|
||||||
|
) -> Export {
|
||||||
|
#[allow(clippy::cast_ref_to_mut)]
|
||||||
|
let temporary_mut = &mut *(self as *const Self as *mut Self);
|
||||||
|
temporary_mut.lookup_by_declaration(export)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Return an iterator over the exports of this instance.
|
||||||
|
///
|
||||||
|
/// Specifically, it provides access to the key-value pairs, where they keys
|
||||||
|
/// are export names, and the values are export declarations which can be
|
||||||
|
/// resolved `lookup_by_declaration`.
|
||||||
|
pub fn exports(&self) -> indexmap::map::Iter<String, wasmtime_environ::Export> {
|
||||||
|
self.module.exports.iter()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn lookup_by_declaration(
|
||||||
|
module: &Module,
|
||||||
|
vmctx: &mut VMContext,
|
||||||
|
offsets: &VMOffsets,
|
||||||
|
finished_functions: &BoxedSlice<DefinedFuncIndex, *const VMFunctionBody>,
|
||||||
|
export: &wasmtime_environ::Export,
|
||||||
|
) -> Export {
|
||||||
|
match export {
|
||||||
|
wasmtime_environ::Export::Function(index) => {
|
||||||
|
let signature = module.signatures[module.functions[*index]].clone();
|
||||||
|
let (address, vmctx) = if let Some(def_index) = module.defined_func_index(*index) {
|
||||||
|
(finished_functions[def_index], vmctx as *mut VMContext)
|
||||||
|
} else {
|
||||||
|
let import = imported_function(vmctx, offsets, *index);
|
||||||
|
(import.body, import.vmctx)
|
||||||
|
};
|
||||||
|
Export::Function {
|
||||||
|
address,
|
||||||
|
signature,
|
||||||
|
vmctx,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
wasmtime_environ::Export::Table(index) => {
|
||||||
|
let (definition, vmctx) = if let Some(def_index) = module.defined_table_index(*index) {
|
||||||
|
(
|
||||||
|
table_mut(vmctx, offsets, def_index) as *mut VMTableDefinition,
|
||||||
|
vmctx as *mut VMContext,
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
let import = imported_table(vmctx, offsets, *index);
|
||||||
|
(import.from, import.vmctx)
|
||||||
|
};
|
||||||
|
Export::Table {
|
||||||
|
definition,
|
||||||
|
vmctx,
|
||||||
|
table: module.table_plans[*index].clone(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
wasmtime_environ::Export::Memory(index) => {
|
||||||
|
let (definition, vmctx) = if let Some(def_index) = module.defined_memory_index(*index) {
|
||||||
|
(
|
||||||
|
memory_mut(vmctx, offsets, def_index) as *mut VMMemoryDefinition,
|
||||||
|
vmctx as *mut VMContext,
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
let import = imported_memory(vmctx, offsets, *index);
|
||||||
|
(import.from, import.vmctx)
|
||||||
|
};
|
||||||
|
Export::Memory {
|
||||||
|
definition,
|
||||||
|
vmctx,
|
||||||
|
memory: module.memory_plans[*index].clone(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
wasmtime_environ::Export::Global(index) => Export::Global {
|
||||||
|
definition: if let Some(def_index) = module.defined_global_index(*index) {
|
||||||
|
global_mut(vmctx, offsets, def_index)
|
||||||
|
} else {
|
||||||
|
imported_global(vmctx, offsets, *index).from
|
||||||
|
},
|
||||||
|
global: module.globals[*index],
|
||||||
|
},
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn check_table_init_bounds(
|
fn check_table_init_bounds(
|
||||||
|
|||||||
@@ -21,20 +21,6 @@
|
|||||||
clippy::use_self
|
clippy::use_self
|
||||||
)
|
)
|
||||||
)]
|
)]
|
||||||
#![no_std]
|
|
||||||
#![cfg_attr(not(feature = "std"), feature(alloc))]
|
|
||||||
|
|
||||||
#[cfg(not(feature = "std"))]
|
|
||||||
#[macro_use]
|
|
||||||
extern crate alloc as std;
|
|
||||||
#[cfg(feature = "std")]
|
|
||||||
#[macro_use]
|
|
||||||
extern crate std;
|
|
||||||
|
|
||||||
#[cfg(not(feature = "std"))]
|
|
||||||
use hashbrown::{map as hash_map, HashMap};
|
|
||||||
#[cfg(feature = "std")]
|
|
||||||
use std::collections::{hash_map, HashMap};
|
|
||||||
|
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate lazy_static;
|
extern crate lazy_static;
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
//! Implement a registry of function signatures, for fast indirect call
|
//! Implement a registry of function signatures, for fast indirect call
|
||||||
//! signature checking.
|
//! signature checking.
|
||||||
|
|
||||||
use super::{hash_map, HashMap};
|
|
||||||
use crate::vmcontext::VMSharedSignatureIndex;
|
use crate::vmcontext::VMSharedSignatureIndex;
|
||||||
use cast;
|
use cast;
|
||||||
use cranelift_codegen::ir;
|
use cranelift_codegen::ir;
|
||||||
|
use std::collections::{hash_map, HashMap};
|
||||||
|
|
||||||
/// 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
|
||||||
|
|||||||
@@ -409,7 +409,7 @@ mod test_vmshared_signature_index {
|
|||||||
impl VMSharedSignatureIndex {
|
impl VMSharedSignatureIndex {
|
||||||
/// Create a new `VMSharedSignatureIndex`.
|
/// Create a new `VMSharedSignatureIndex`.
|
||||||
pub fn new(value: u32) -> Self {
|
pub fn new(value: u32) -> Self {
|
||||||
VMSharedSignatureIndex(value)
|
Self(value)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -482,8 +482,9 @@ impl VMContext {
|
|||||||
///
|
///
|
||||||
/// This is unsafe because it doesn't work on just any `VMContext`, it must
|
/// This is unsafe because it doesn't work on just any `VMContext`, it must
|
||||||
/// be a `VMContext` allocated as part of an `Instance`.
|
/// be a `VMContext` allocated as part of an `Instance`.
|
||||||
|
/// FIXME: make this pub(crate)?
|
||||||
#[allow(clippy::cast_ptr_alignment)]
|
#[allow(clippy::cast_ptr_alignment)]
|
||||||
pub(crate) unsafe fn instance_contents(&mut self) -> &mut InstanceContents {
|
pub unsafe fn instance_contents(&mut self) -> &mut InstanceContents {
|
||||||
&mut *((self as *mut Self as *mut u8).offset(-InstanceContents::vmctx_offset())
|
&mut *((self as *mut Self as *mut u8).offset(-InstanceContents::vmctx_offset())
|
||||||
as *mut InstanceContents)
|
as *mut InstanceContents)
|
||||||
}
|
}
|
||||||
@@ -495,4 +496,9 @@ impl VMContext {
|
|||||||
pub unsafe fn host_state(&mut self) -> &mut Any {
|
pub unsafe fn host_state(&mut self) -> &mut Any {
|
||||||
self.instance_contents().host_state()
|
self.instance_contents().host_state()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Lookup an export in the global exports namespace.
|
||||||
|
pub unsafe fn lookup_global_export(&mut self, field: &str) -> Option<crate::export::Export> {
|
||||||
|
self.instance_contents().lookup_global_export(field)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,8 @@ use cranelift_codegen::ir::types;
|
|||||||
use cranelift_codegen::{ir, isa};
|
use cranelift_codegen::{ir, isa};
|
||||||
use cranelift_entity::PrimaryMap;
|
use cranelift_entity::PrimaryMap;
|
||||||
use cranelift_wasm::{DefinedFuncIndex, Global, GlobalInit, Memory, Table, TableElementType};
|
use cranelift_wasm::{DefinedFuncIndex, Global, GlobalInit, Memory, Table, TableElementType};
|
||||||
|
use std::cell::RefCell;
|
||||||
|
use std::collections::HashMap;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
use target_lexicon::HOST;
|
use target_lexicon::HOST;
|
||||||
use wasmtime_environ::{translate_signature, Export, MemoryPlan, Module, TablePlan};
|
use wasmtime_environ::{translate_signature, Export, MemoryPlan, Module, TablePlan};
|
||||||
@@ -216,6 +218,7 @@ pub fn instantiate_spectest() -> Result<Instance, InstantiationError> {
|
|||||||
|
|
||||||
Instance::new(
|
Instance::new(
|
||||||
Rc::new(module),
|
Rc::new(module),
|
||||||
|
Rc::new(RefCell::new(HashMap::new())),
|
||||||
finished_functions.into_boxed_slice(),
|
finished_functions.into_boxed_slice(),
|
||||||
imports,
|
imports,
|
||||||
&data_initializers,
|
&data_initializers,
|
||||||
|
|||||||
@@ -1,6 +1,9 @@
|
|||||||
use crate::spectest::instantiate_spectest;
|
use crate::spectest::instantiate_spectest;
|
||||||
|
use std::cell::RefCell;
|
||||||
|
use std::collections::HashMap;
|
||||||
use std::io::Read;
|
use std::io::Read;
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
|
use std::rc::Rc;
|
||||||
use std::{fmt, fs, io, str};
|
use std::{fmt, fs, io, str};
|
||||||
use wabt::script::{Action, Command, CommandKind, ModuleBinary, ScriptParser, Value};
|
use wabt::script::{Action, Command, CommandKind, ModuleBinary, ScriptParser, Value};
|
||||||
use wasmparser::{validate, OperatorValidatorConfig, ValidatingParserConfig};
|
use wasmparser::{validate, OperatorValidatorConfig, ValidatingParserConfig};
|
||||||
@@ -122,7 +125,12 @@ impl WastContext {
|
|||||||
|
|
||||||
self.validate(&data).map_err(SetupError::Validate)?;
|
self.validate(&data).map_err(SetupError::Validate)?;
|
||||||
|
|
||||||
instantiate(&mut *self.compiler, &data, &mut self.namespace)
|
instantiate(
|
||||||
|
&mut *self.compiler,
|
||||||
|
&data,
|
||||||
|
&mut self.namespace,
|
||||||
|
Rc::new(RefCell::new(HashMap::new())),
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_index(&mut self, instance_name: &Option<String>) -> Result<InstanceIndex, WastError> {
|
fn get_index(&mut self, instance_name: &Option<String>) -> Result<InstanceIndex, WastError> {
|
||||||
|
|||||||
@@ -39,6 +39,8 @@ use cranelift_native;
|
|||||||
use docopt::Docopt;
|
use docopt::Docopt;
|
||||||
use file_per_thread_logger;
|
use file_per_thread_logger;
|
||||||
use pretty_env_logger;
|
use pretty_env_logger;
|
||||||
|
use std::cell::RefCell;
|
||||||
|
use std::collections::HashMap;
|
||||||
use std::error::Error;
|
use std::error::Error;
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use std::io;
|
use std::io;
|
||||||
@@ -46,6 +48,7 @@ use std::io::prelude::*;
|
|||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
use std::process::exit;
|
use std::process::exit;
|
||||||
|
use std::rc::Rc;
|
||||||
use wabt;
|
use wabt;
|
||||||
use wasmtime_jit::{instantiate, ActionOutcome, Compiler, Namespace};
|
use wasmtime_jit::{instantiate, ActionOutcome, Compiler, Namespace};
|
||||||
use wasmtime_wast::instantiate_spectest;
|
use wasmtime_wast::instantiate_spectest;
|
||||||
@@ -121,6 +124,7 @@ fn main() {
|
|||||||
let mut compiler = Compiler::new(isa);
|
let mut compiler = Compiler::new(isa);
|
||||||
|
|
||||||
let mut namespace = Namespace::new();
|
let mut namespace = Namespace::new();
|
||||||
|
let global_exports = Rc::new(RefCell::new(HashMap::new()));
|
||||||
|
|
||||||
// Make spectest available by default.
|
// Make spectest available by default.
|
||||||
namespace.instance(
|
namespace.instance(
|
||||||
@@ -130,7 +134,13 @@ fn main() {
|
|||||||
|
|
||||||
for filename in &args.arg_file {
|
for filename in &args.arg_file {
|
||||||
let path = Path::new(&filename);
|
let path = Path::new(&filename);
|
||||||
match handle_module(&mut compiler, &mut namespace, &args, path) {
|
match handle_module(
|
||||||
|
&mut compiler,
|
||||||
|
&mut namespace,
|
||||||
|
Rc::clone(&global_exports),
|
||||||
|
&args,
|
||||||
|
path,
|
||||||
|
) {
|
||||||
Ok(()) => {}
|
Ok(()) => {}
|
||||||
Err(message) => {
|
Err(message) => {
|
||||||
let name = path.as_os_str().to_string_lossy();
|
let name = path.as_os_str().to_string_lossy();
|
||||||
@@ -144,6 +154,7 @@ fn main() {
|
|||||||
fn handle_module(
|
fn handle_module(
|
||||||
compiler: &mut Compiler,
|
compiler: &mut Compiler,
|
||||||
namespace: &mut Namespace,
|
namespace: &mut Namespace,
|
||||||
|
global_exports: Rc<RefCell<HashMap<String, Option<wasmtime_runtime::Export>>>>,
|
||||||
args: &Args,
|
args: &Args,
|
||||||
path: &Path,
|
path: &Path,
|
||||||
) -> Result<(), String> {
|
) -> Result<(), String> {
|
||||||
@@ -156,7 +167,8 @@ fn handle_module(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Create a new `Instance` by compiling and instantiating a wasm module.
|
// Create a new `Instance` by compiling and instantiating a wasm module.
|
||||||
let instance = instantiate(compiler, &data, namespace).map_err(|e| e.to_string())?;
|
let instance =
|
||||||
|
instantiate(compiler, &data, namespace, global_exports).map_err(|e| e.to_string())?;
|
||||||
|
|
||||||
// Register it in the namespace.
|
// Register it in the namespace.
|
||||||
let index = namespace.instance(None, instance);
|
let index = namespace.instance(None, instance);
|
||||||
@@ -181,7 +193,10 @@ fn handle_module(
|
|||||||
mod tests {
|
mod tests {
|
||||||
use cranelift_codegen::settings;
|
use cranelift_codegen::settings;
|
||||||
use cranelift_codegen::settings::Configurable;
|
use cranelift_codegen::settings::Configurable;
|
||||||
|
use std::cell::RefCell;
|
||||||
|
use std::collections::HashMap;
|
||||||
use std::path::PathBuf;
|
use std::path::PathBuf;
|
||||||
|
use std::rc::Rc;
|
||||||
use wabt;
|
use wabt;
|
||||||
use wasmtime_jit::{instantiate, Compiler, NullResolver};
|
use wasmtime_jit::{instantiate, Compiler, NullResolver};
|
||||||
|
|
||||||
@@ -207,7 +222,8 @@ mod tests {
|
|||||||
|
|
||||||
let mut resolver = NullResolver {};
|
let mut resolver = NullResolver {};
|
||||||
let mut compiler = Compiler::new(isa);
|
let mut compiler = Compiler::new(isa);
|
||||||
let instance = instantiate(&mut compiler, &data, &mut resolver);
|
let global_exports = Rc::new(RefCell::new(HashMap::new()));
|
||||||
|
let instance = instantiate(&mut compiler, &data, &mut resolver, global_exports);
|
||||||
assert!(instance.is_ok());
|
assert!(instance.is_ok());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user