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:
@@ -3,6 +3,7 @@
|
||||
//! `CompiledModule` to allow compiling and instantiating to be done as separate
|
||||
//! steps.
|
||||
|
||||
use crate::code_memory::CodeMemory;
|
||||
use crate::compiler::Compiler;
|
||||
use crate::imports::resolve_imports;
|
||||
use crate::link::link_module;
|
||||
@@ -10,7 +11,6 @@ use crate::resolver::Resolver;
|
||||
use std::any::Any;
|
||||
use std::collections::HashMap;
|
||||
use std::io::Write;
|
||||
use std::rc::Rc;
|
||||
use std::sync::Arc;
|
||||
use thiserror::Error;
|
||||
use wasmtime_debug::read_debuginfo;
|
||||
@@ -24,7 +24,7 @@ use wasmtime_profiling::ProfilingAgent;
|
||||
use wasmtime_runtime::VMInterrupts;
|
||||
use wasmtime_runtime::{
|
||||
GdbJitImageRegistration, InstanceHandle, InstantiationError, RuntimeMemoryCreator,
|
||||
SignatureRegistry, VMFunctionBody, VMSharedSignatureIndex, VMTrampoline,
|
||||
SignatureRegistry, VMFunctionBody, VMTrampoline,
|
||||
};
|
||||
|
||||
/// An error condition while setting up a wasm instance, be it validation,
|
||||
@@ -49,23 +49,33 @@ pub enum SetupError {
|
||||
DebugInfo(#[from] anyhow::Error),
|
||||
}
|
||||
|
||||
/// This is similar to `CompiledModule`, but references the data initializers
|
||||
/// from the wasm buffer rather than holding its own copy.
|
||||
struct RawCompiledModule<'data> {
|
||||
module: Module,
|
||||
finished_functions: BoxedSlice<DefinedFuncIndex, *mut [VMFunctionBody]>,
|
||||
trampolines: HashMap<VMSharedSignatureIndex, VMTrampoline>,
|
||||
data_initializers: Box<[DataInitializer<'data>]>,
|
||||
signatures: BoxedSlice<SignatureIndex, VMSharedSignatureIndex>,
|
||||
struct FinishedFunctions(BoxedSlice<DefinedFuncIndex, *mut [VMFunctionBody]>);
|
||||
|
||||
unsafe impl Send for FinishedFunctions {}
|
||||
unsafe impl Sync for FinishedFunctions {}
|
||||
|
||||
/// Container for data needed for an Instance function to exist.
|
||||
pub struct ModuleCode {
|
||||
code_memory: CodeMemory,
|
||||
#[allow(dead_code)]
|
||||
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,
|
||||
address_transform: ModuleAddressMap,
|
||||
}
|
||||
|
||||
impl<'data> RawCompiledModule<'data> {
|
||||
/// Create a new `RawCompiledModule` by compiling the wasm module in `data` and instatiating it.
|
||||
fn new(
|
||||
compiler: &mut Compiler,
|
||||
impl CompiledModule {
|
||||
/// Compile a data buffer into a `CompiledModule`, which may then be instantiated.
|
||||
pub fn new<'data>(
|
||||
compiler: &Compiler,
|
||||
data: &'data [u8],
|
||||
profiler: &dyn ProfilingAgent,
|
||||
) -> Result<Self, SetupError> {
|
||||
@@ -83,26 +93,24 @@ impl<'data> RawCompiledModule<'data> {
|
||||
|
||||
let compilation = compiler.compile(&translation, debug_data)?;
|
||||
|
||||
link_module(&translation.module, &compilation);
|
||||
let module = translation.module;
|
||||
|
||||
// Compute indices into the shared signature table.
|
||||
let signatures = {
|
||||
let signature_registry = compiler.signatures();
|
||||
translation
|
||||
.module
|
||||
.local
|
||||
.signatures
|
||||
.values()
|
||||
.map(|(wasm, native)| signature_registry.register(wasm.clone(), native.clone()))
|
||||
.collect::<PrimaryMap<_, _>>()
|
||||
};
|
||||
link_module(&module, &compilation);
|
||||
|
||||
// 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
|
||||
profiler.module_load(
|
||||
&translation.module,
|
||||
&module,
|
||||
&compilation.finished_functions,
|
||||
compilation.dbg_image.as_deref(),
|
||||
);
|
||||
@@ -116,82 +124,22 @@ impl<'data> RawCompiledModule<'data> {
|
||||
None
|
||||
};
|
||||
|
||||
let finished_functions =
|
||||
FinishedFunctions(compilation.finished_functions.into_boxed_slice());
|
||||
|
||||
Ok(Self {
|
||||
module: translation.module,
|
||||
finished_functions: compilation.finished_functions.into_boxed_slice(),
|
||||
module: Arc::new(module),
|
||||
code: Arc::new(ModuleCode {
|
||||
code_memory,
|
||||
dbg_jit_registration,
|
||||
}),
|
||||
finished_functions,
|
||||
trampolines: compilation.trampolines,
|
||||
data_initializers: translation.data_initializers.into_boxed_slice(),
|
||||
signatures: signatures.into_boxed_slice(),
|
||||
dbg_jit_registration,
|
||||
data_initializers,
|
||||
traps: compilation.traps,
|
||||
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`.
|
||||
///
|
||||
@@ -205,21 +153,41 @@ impl CompiledModule {
|
||||
pub unsafe fn instantiate(
|
||||
&self,
|
||||
resolver: &mut dyn Resolver,
|
||||
sig_registry: &SignatureRegistry,
|
||||
signature_registry: &mut SignatureRegistry,
|
||||
mem_creator: Option<&dyn RuntimeMemoryCreator>,
|
||||
interrupts: Arc<VMInterrupts>,
|
||||
host_state: Box<dyn Any>,
|
||||
) -> 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(
|
||||
Arc::clone(&self.module),
|
||||
self.finished_functions.clone(),
|
||||
self.trampolines.clone(),
|
||||
self.module.clone(),
|
||||
self.code.clone(),
|
||||
finished_functions,
|
||||
trampolines,
|
||||
imports,
|
||||
mem_creator,
|
||||
self.signatures.clone(),
|
||||
self.dbg_jit_registration.as_ref().map(|r| Rc::clone(&r)),
|
||||
signatures.into_boxed_slice(),
|
||||
host_state,
|
||||
self.interrupts.clone(),
|
||||
interrupts,
|
||||
)
|
||||
}
|
||||
|
||||
@@ -239,19 +207,14 @@ impl CompiledModule {
|
||||
&self.module
|
||||
}
|
||||
|
||||
/// Return a reference-counting pointer to a module.
|
||||
pub fn module_mut(&mut self) -> &mut Arc<Module> {
|
||||
&mut self.module
|
||||
}
|
||||
|
||||
/// Return a reference to a module.
|
||||
pub fn module_ref(&self) -> &Module {
|
||||
&self.module
|
||||
/// Return a reference to a mutable module (if possible).
|
||||
pub fn module_mut(&mut self) -> Option<&mut Module> {
|
||||
Arc::get_mut(&mut self.module)
|
||||
}
|
||||
|
||||
/// Returns the map of all finished JIT functions compiled for this module
|
||||
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.
|
||||
@@ -263,6 +226,16 @@ impl CompiledModule {
|
||||
pub fn address_transform(&self) -> &ModuleAddressMap {
|
||||
&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
|
||||
@@ -276,7 +249,7 @@ pub struct OwnedDataInitializer {
|
||||
}
|
||||
|
||||
impl OwnedDataInitializer {
|
||||
fn new(borrowed: &DataInitializer<'_>) -> Self {
|
||||
fn new(borrowed: DataInitializer<'_>) -> Self {
|
||||
Self {
|
||||
location: borrowed.location.clone(),
|
||||
data: borrowed.data.to_vec().into_boxed_slice(),
|
||||
|
||||
Reference in New Issue
Block a user