Improve handling of strings for backtraces (#843)
* Improve handling of strings for backtraces Largely avoid storing strings at all in the `wasmtime-*` internal crates, and instead only store strings in a separate global cache specific to the `wasmtime` crate itself. This global cache is inserted and removed from dynamically as modules are created and deallocated, and the global cache is consulted whenever a `Trap` is created to symbolicate any wasm frames. This also avoids the need to thread `module_name` through the jit crates and back, and additionally removes the need for `ModuleSyncString`. * Run rustfmt
This commit is contained in:
1
Cargo.lock
generated
1
Cargo.lock
generated
@@ -2032,6 +2032,7 @@ dependencies = [
|
|||||||
"backtrace",
|
"backtrace",
|
||||||
"cfg-if",
|
"cfg-if",
|
||||||
"file-per-thread-logger",
|
"file-per-thread-logger",
|
||||||
|
"lazy_static",
|
||||||
"libc",
|
"libc",
|
||||||
"pretty_env_logger",
|
"pretty_env_logger",
|
||||||
"rayon",
|
"rayon",
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ libc = "0.2"
|
|||||||
cfg-if = "0.1.9"
|
cfg-if = "0.1.9"
|
||||||
backtrace = "0.3.42"
|
backtrace = "0.3.42"
|
||||||
rustc-demangle = "0.1.16"
|
rustc-demangle = "0.1.16"
|
||||||
|
lazy_static = "1.4"
|
||||||
|
|
||||||
[target.'cfg(target_os = "windows")'.dependencies]
|
[target.'cfg(target_os = "windows")'.dependencies]
|
||||||
winapi = "0.3.7"
|
winapi = "0.3.7"
|
||||||
|
|||||||
@@ -108,8 +108,7 @@ impl Instance {
|
|||||||
/// [issue]: https://github.com/bytecodealliance/wasmtime/issues/727
|
/// [issue]: https://github.com/bytecodealliance/wasmtime/issues/727
|
||||||
pub fn new(module: &Module, imports: &[Extern]) -> Result<Instance, Error> {
|
pub fn new(module: &Module, imports: &[Extern]) -> Result<Instance, Error> {
|
||||||
let store = module.store();
|
let store = module.store();
|
||||||
let mut instance_handle =
|
let mut instance_handle = instantiate(module.compiled_module(), imports)?;
|
||||||
instantiate(module.compiled_module().expect("compiled_module"), imports)?;
|
|
||||||
|
|
||||||
let exports = {
|
let exports = {
|
||||||
let mut exports = Vec::with_capacity(module.exports().len());
|
let mut exports = Vec::with_capacity(module.exports().len());
|
||||||
@@ -124,6 +123,7 @@ impl Instance {
|
|||||||
}
|
}
|
||||||
exports.into_boxed_slice()
|
exports.into_boxed_slice()
|
||||||
};
|
};
|
||||||
|
module.register_names();
|
||||||
Ok(Instance {
|
Ok(Instance {
|
||||||
instance_handle,
|
instance_handle,
|
||||||
module: module.clone(),
|
module: module.clone(),
|
||||||
|
|||||||
@@ -4,7 +4,11 @@ use crate::types::{
|
|||||||
TableType, ValType,
|
TableType, ValType,
|
||||||
};
|
};
|
||||||
use anyhow::{Error, Result};
|
use anyhow::{Error, Result};
|
||||||
|
use lazy_static::lazy_static;
|
||||||
|
use std::cell::Cell;
|
||||||
|
use std::collections::HashMap;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
use std::sync::{Arc, RwLock};
|
||||||
use wasmparser::{
|
use wasmparser::{
|
||||||
validate, CustomSectionKind, ExternalKind, ImportSectionEntryType, ModuleReader, Name,
|
validate, CustomSectionKind, ExternalKind, ImportSectionEntryType, ModuleReader, Name,
|
||||||
OperatorValidatorConfig, SectionCode, ValidatingParserConfig,
|
OperatorValidatorConfig, SectionCode, ValidatingParserConfig,
|
||||||
@@ -81,8 +85,25 @@ struct ModuleInner {
|
|||||||
store: Store,
|
store: Store,
|
||||||
imports: Box<[ImportType]>,
|
imports: Box<[ImportType]>,
|
||||||
exports: Box<[ExportType]>,
|
exports: Box<[ExportType]>,
|
||||||
name: Option<String>,
|
compiled: CompiledModule,
|
||||||
compiled: Option<CompiledModule>,
|
registered_names: Cell<bool>,
|
||||||
|
names: Arc<Names>,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Names {
|
||||||
|
pub module: Arc<wasmtime_environ::Module>,
|
||||||
|
pub module_name: Option<String>,
|
||||||
|
}
|
||||||
|
|
||||||
|
lazy_static! {
|
||||||
|
/// This is a global cache of names known for all compiled modules in this
|
||||||
|
/// process.
|
||||||
|
///
|
||||||
|
/// This global cache is used during `Trap` creation to symbolicate frames.
|
||||||
|
/// This is populated on module compilation, and it is cleared out whenever
|
||||||
|
/// all references to a module are dropped, aka the `Drop for ModuleInner`
|
||||||
|
/// below.
|
||||||
|
pub static ref NAMES: RwLock<HashMap<usize, Arc<Names>>> = RwLock::default();
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Module {
|
impl Module {
|
||||||
@@ -123,10 +144,7 @@ impl Module {
|
|||||||
/// [binary]: https://webassembly.github.io/spec/core/binary/index.html
|
/// [binary]: https://webassembly.github.io/spec/core/binary/index.html
|
||||||
pub fn new(store: &Store, binary: &[u8]) -> Result<Module> {
|
pub fn new(store: &Store, binary: &[u8]) -> Result<Module> {
|
||||||
Module::validate(store, binary)?;
|
Module::validate(store, binary)?;
|
||||||
// Note that the call to `unsafe` here should be ok because we
|
unsafe { Module::new_unchecked(store, binary) }
|
||||||
// previously validated the binary, meaning we're guaranteed to pass a
|
|
||||||
// valid binary for `store`.
|
|
||||||
unsafe { Module::new_internal(store, binary, None) }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates a new WebAssembly `Module` from the given in-memory `binary`
|
/// Creates a new WebAssembly `Module` from the given in-memory `binary`
|
||||||
@@ -134,11 +152,10 @@ impl Module {
|
|||||||
///
|
///
|
||||||
/// See [`Module::new`] for other details.
|
/// See [`Module::new`] for other details.
|
||||||
pub fn new_with_name(store: &Store, binary: &[u8], name: &str) -> Result<Module> {
|
pub fn new_with_name(store: &Store, binary: &[u8], name: &str) -> Result<Module> {
|
||||||
Module::validate(store, binary)?;
|
let mut module = Module::new(store, binary)?;
|
||||||
// Note that the call to `unsafe` here should be ok because we
|
let inner = Rc::get_mut(&mut module.inner).unwrap();
|
||||||
// previously validated the binary, meaning we're guaranteed to pass a
|
Arc::get_mut(&mut inner.names).unwrap().module_name = Some(name.to_string());
|
||||||
// valid binary for `store`.
|
Ok(module)
|
||||||
unsafe { Module::new_internal(store, binary, Some(name)) }
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates a new WebAssembly `Module` from the given in-memory `binary`
|
/// Creates a new WebAssembly `Module` from the given in-memory `binary`
|
||||||
@@ -168,20 +185,8 @@ impl Module {
|
|||||||
/// 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 new_unchecked(store: &Store, binary: &[u8]) -> Result<Module> {
|
pub unsafe fn new_unchecked(store: &Store, binary: &[u8]) -> Result<Module> {
|
||||||
Module::new_internal(store, binary, None)
|
let mut ret = Module::compile(store, binary)?;
|
||||||
}
|
|
||||||
|
|
||||||
/// Creates a new `Module` and compiles it without doing any validation.
|
|
||||||
unsafe fn new_internal(store: &Store, binary: &[u8], name: Option<&str>) -> Result<Module> {
|
|
||||||
let mut ret = Module::empty(store);
|
|
||||||
ret.read_imports_and_exports(binary)?;
|
ret.read_imports_and_exports(binary)?;
|
||||||
|
|
||||||
let inner = Rc::get_mut(&mut ret.inner).unwrap();
|
|
||||||
if let Some(name) = name {
|
|
||||||
// Assign or override the module's name if supplied.
|
|
||||||
inner.name = Some(name.to_string());
|
|
||||||
}
|
|
||||||
inner.compiled = Some(compile(store, binary, inner.name.as_deref())?);
|
|
||||||
Ok(ret)
|
Ok(ret)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -220,31 +225,42 @@ impl Module {
|
|||||||
|
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
pub fn from_exports(store: &Store, exports: Box<[ExportType]>) -> Self {
|
pub fn from_exports(store: &Store, exports: Box<[ExportType]>) -> Self {
|
||||||
let mut ret = Module::empty(store);
|
let mut ret = unsafe { Module::compile(store, b"\0asm\x01\0\0\0").unwrap() };
|
||||||
Rc::get_mut(&mut ret.inner).unwrap().exports = exports;
|
Rc::get_mut(&mut ret.inner).unwrap().exports = exports;
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn empty(store: &Store) -> Self {
|
unsafe fn compile(store: &Store, binary: &[u8]) -> Result<Self> {
|
||||||
Module {
|
let compiled = CompiledModule::new(
|
||||||
|
&mut store.compiler_mut(),
|
||||||
|
binary,
|
||||||
|
store.engine().config().debug_info,
|
||||||
|
)?;
|
||||||
|
|
||||||
|
let names = Arc::new(Names {
|
||||||
|
module_name: None,
|
||||||
|
module: compiled.module().clone(),
|
||||||
|
});
|
||||||
|
Ok(Module {
|
||||||
inner: Rc::new(ModuleInner {
|
inner: Rc::new(ModuleInner {
|
||||||
store: store.clone(),
|
store: store.clone(),
|
||||||
imports: Box::new([]),
|
imports: Box::new([]),
|
||||||
exports: Box::new([]),
|
exports: Box::new([]),
|
||||||
name: None,
|
names,
|
||||||
compiled: None,
|
compiled,
|
||||||
|
registered_names: Cell::new(false),
|
||||||
}),
|
}),
|
||||||
}
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn compiled_module(&self) -> Option<&CompiledModule> {
|
pub(crate) fn compiled_module(&self) -> &CompiledModule {
|
||||||
self.inner.compiled.as_ref()
|
&self.inner.compiled
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns identifier/name that this [`Module`] has. This name
|
/// Returns identifier/name that this [`Module`] has. This name
|
||||||
/// is used in traps/backtrace details.
|
/// is used in traps/backtrace details.
|
||||||
pub fn name(&self) -> Option<&str> {
|
pub fn name(&self) -> Option<&str> {
|
||||||
self.inner.name.as_deref()
|
self.inner.names.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
|
||||||
@@ -375,7 +391,8 @@ impl Module {
|
|||||||
while let Ok(entry) = reader.read() {
|
while let Ok(entry) = reader.read() {
|
||||||
if let Name::Module(name) = entry {
|
if let Name::Module(name) = entry {
|
||||||
if let Ok(name) = name.get_name() {
|
if let Ok(name) = name.get_name() {
|
||||||
inner.name = Some(name.to_string());
|
Arc::get_mut(&mut inner.names).unwrap().module_name =
|
||||||
|
Some(name.to_string());
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@@ -392,14 +409,24 @@ impl Module {
|
|||||||
inner.exports = exports.into();
|
inner.exports = exports.into();
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Register this module's names in the global map of module names.
|
||||||
|
///
|
||||||
|
/// This is required to ensure that any traps can be properly symbolicated.
|
||||||
|
pub(crate) fn register_names(&self) {
|
||||||
|
if self.inner.registered_names.get() {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let names = self.inner.names.clone();
|
||||||
|
NAMES.write().unwrap().insert(names.module.id, names);
|
||||||
|
self.inner.registered_names.set(true);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn compile(store: &Store, binary: &[u8], module_name: Option<&str>) -> Result<CompiledModule> {
|
impl Drop for ModuleInner {
|
||||||
let compiled_module = CompiledModule::new(
|
fn drop(&mut self) {
|
||||||
&mut store.compiler_mut(),
|
if self.registered_names.get() {
|
||||||
binary,
|
NAMES.write().unwrap().remove(&self.names.module.id);
|
||||||
module_name,
|
}
|
||||||
store.engine().config().debug_info,
|
}
|
||||||
)?;
|
|
||||||
Ok(compiled_module)
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ use crate::runtime::Store;
|
|||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use std::any::Any;
|
use std::any::Any;
|
||||||
use std::collections::HashSet;
|
use std::collections::HashSet;
|
||||||
use std::rc::Rc;
|
use std::sync::Arc;
|
||||||
use wasmtime_environ::entity::PrimaryMap;
|
use wasmtime_environ::entity::PrimaryMap;
|
||||||
use wasmtime_environ::wasm::DefinedFuncIndex;
|
use wasmtime_environ::wasm::DefinedFuncIndex;
|
||||||
use wasmtime_environ::Module;
|
use wasmtime_environ::Module;
|
||||||
@@ -37,7 +37,7 @@ pub(crate) fn create_handle(
|
|||||||
.unwrap_or_else(PrimaryMap::new);
|
.unwrap_or_else(PrimaryMap::new);
|
||||||
|
|
||||||
Ok(InstanceHandle::new(
|
Ok(InstanceHandle::new(
|
||||||
Rc::new(module),
|
Arc::new(module),
|
||||||
finished_functions.into_boxed_slice(),
|
finished_functions.into_boxed_slice(),
|
||||||
imports,
|
imports,
|
||||||
&data_initializers,
|
&data_initializers,
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
|
use crate::module::NAMES;
|
||||||
use backtrace::Backtrace;
|
use backtrace::Backtrace;
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
use wasmtime_environ::entity::EntityRef;
|
||||||
|
|
||||||
/// A struct representing an aborted instruction execution, with a message
|
/// A struct representing an aborted instruction execution, with a message
|
||||||
/// indicating the cause.
|
/// indicating the cause.
|
||||||
@@ -36,16 +38,23 @@ impl Trap {
|
|||||||
|
|
||||||
fn new_with_trace(message: String, native_trace: Backtrace) -> Self {
|
fn new_with_trace(message: String, native_trace: Backtrace) -> Self {
|
||||||
let mut wasm_trace = Vec::new();
|
let mut wasm_trace = Vec::new();
|
||||||
|
let names = NAMES.read().unwrap();
|
||||||
for frame in native_trace.frames() {
|
for frame in native_trace.frames() {
|
||||||
let pc = frame.ip() as usize;
|
let pc = frame.ip() as usize;
|
||||||
if let Some(info) = wasmtime_runtime::jit_function_registry::find(pc) {
|
let info = match wasmtime_runtime::jit_function_registry::find(pc) {
|
||||||
|
Some(info) => info,
|
||||||
|
None => continue,
|
||||||
|
};
|
||||||
|
let names = match names.get(&info.module_id) {
|
||||||
|
Some(names) => names,
|
||||||
|
None => continue,
|
||||||
|
};
|
||||||
wasm_trace.push(FrameInfo {
|
wasm_trace.push(FrameInfo {
|
||||||
func_index: info.func_index as u32,
|
func_index: info.func_index.index() as u32,
|
||||||
module_name: info.module_id.get().map(|s| s.to_string()),
|
module_name: names.module_name.clone(),
|
||||||
func_name: info.func_name.get().map(|s| s.to_string()),
|
func_name: names.module.func_names.get(&info.func_index).cloned(),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
|
||||||
Trap {
|
Trap {
|
||||||
inner: Arc::new(TrapInner {
|
inner: Arc::new(TrapInner {
|
||||||
message,
|
message,
|
||||||
|
|||||||
@@ -54,7 +54,7 @@ pub use crate::func_environ::BuiltinFunctionIndex;
|
|||||||
#[cfg(feature = "lightbeam")]
|
#[cfg(feature = "lightbeam")]
|
||||||
pub use crate::lightbeam::Lightbeam;
|
pub use crate::lightbeam::Lightbeam;
|
||||||
pub use crate::module::{
|
pub use crate::module::{
|
||||||
Export, MemoryPlan, MemoryStyle, Module, ModuleSyncString, TableElements, TablePlan, TableStyle,
|
Export, MemoryPlan, MemoryStyle, Module, TableElements, TablePlan, TableStyle,
|
||||||
};
|
};
|
||||||
pub use crate::module_environ::{
|
pub use crate::module_environ::{
|
||||||
translate_signature, DataInitializer, DataInitializerLocation, FunctionBodyData,
|
translate_signature, DataInitializer, DataInitializerLocation, FunctionBodyData,
|
||||||
|
|||||||
@@ -3,15 +3,16 @@
|
|||||||
use crate::module_environ::FunctionBodyData;
|
use crate::module_environ::FunctionBodyData;
|
||||||
use crate::tunables::Tunables;
|
use crate::tunables::Tunables;
|
||||||
use cranelift_codegen::ir;
|
use cranelift_codegen::ir;
|
||||||
use cranelift_entity::{EntityRef, PrimaryMap, SecondaryMap};
|
use cranelift_entity::{EntityRef, PrimaryMap};
|
||||||
use cranelift_wasm::{
|
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 indexmap::IndexMap;
|
||||||
use more_asserts::assert_ge;
|
use more_asserts::assert_ge;
|
||||||
|
use std::collections::HashMap;
|
||||||
use std::hash::{Hash, Hasher};
|
use std::hash::{Hash, Hasher};
|
||||||
use std::sync::Arc;
|
use std::sync::atomic::{AtomicUsize, Ordering::SeqCst};
|
||||||
|
|
||||||
/// A WebAssembly table initializer.
|
/// A WebAssembly table initializer.
|
||||||
#[derive(Clone, Debug, Hash)]
|
#[derive(Clone, Debug, Hash)]
|
||||||
@@ -129,33 +130,14 @@ impl TablePlan {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Allows module strings to be cached as reused across
|
|
||||||
/// multiple threads. Useful for debug/trace information.
|
|
||||||
#[derive(Debug, Clone)]
|
|
||||||
pub struct ModuleSyncString(Option<Arc<String>>);
|
|
||||||
|
|
||||||
impl ModuleSyncString {
|
|
||||||
/// Gets optional string reference.
|
|
||||||
pub fn get(&self) -> Option<&str> {
|
|
||||||
self.0.as_deref().map(|s| s.as_str())
|
|
||||||
}
|
|
||||||
/// Constructs the string.
|
|
||||||
pub fn new(s: Option<&str>) -> Self {
|
|
||||||
ModuleSyncString(s.map(|s| Arc::new(s.to_string())))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Default for ModuleSyncString {
|
|
||||||
fn default() -> Self {
|
|
||||||
ModuleSyncString(None)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A translated WebAssembly module, excluding the function bodies and
|
/// A translated WebAssembly module, excluding the function bodies and
|
||||||
/// memory initializers.
|
/// memory initializers.
|
||||||
// WARNING: when modifying, make sure that `hash_for_cache` is still valid!
|
// WARNING: when modifying, make sure that `hash_for_cache` is still valid!
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct Module {
|
pub struct Module {
|
||||||
|
/// A unique identifier (within this process) for this module.
|
||||||
|
pub id: usize,
|
||||||
|
|
||||||
/// Unprocessed signatures exactly as provided by `declare_signature()`.
|
/// Unprocessed signatures exactly as provided by `declare_signature()`.
|
||||||
pub signatures: PrimaryMap<SignatureIndex, ir::Signature>,
|
pub signatures: PrimaryMap<SignatureIndex, ir::Signature>,
|
||||||
|
|
||||||
@@ -193,17 +175,17 @@ pub struct Module {
|
|||||||
/// WebAssembly table initializers.
|
/// WebAssembly table initializers.
|
||||||
pub table_elements: Vec<TableElements>,
|
pub table_elements: Vec<TableElements>,
|
||||||
|
|
||||||
/// Module name.
|
/// WebAssembly table initializers.
|
||||||
pub name: ModuleSyncString,
|
pub func_names: HashMap<FuncIndex, String>,
|
||||||
|
|
||||||
/// Function names.
|
|
||||||
pub func_names: SecondaryMap<FuncIndex, ModuleSyncString>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Module {
|
impl Module {
|
||||||
/// Allocates the module data structures.
|
/// Allocates the module data structures.
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
|
static NEXT_ID: AtomicUsize = AtomicUsize::new(0);
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
|
id: NEXT_ID.fetch_add(1, SeqCst),
|
||||||
signatures: PrimaryMap::new(),
|
signatures: PrimaryMap::new(),
|
||||||
imported_funcs: PrimaryMap::new(),
|
imported_funcs: PrimaryMap::new(),
|
||||||
imported_tables: PrimaryMap::new(),
|
imported_tables: PrimaryMap::new(),
|
||||||
@@ -216,8 +198,7 @@ impl Module {
|
|||||||
exports: IndexMap::new(),
|
exports: IndexMap::new(),
|
||||||
start_func: None,
|
start_func: None,
|
||||||
table_elements: Vec::new(),
|
table_elements: Vec::new(),
|
||||||
name: Default::default(),
|
func_names: HashMap::new(),
|
||||||
func_names: SecondaryMap::new(),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
use crate::func_environ::FuncEnvironment;
|
use crate::func_environ::FuncEnvironment;
|
||||||
use crate::module::{Export, MemoryPlan, Module, ModuleSyncString, TableElements, TablePlan};
|
use crate::module::{Export, MemoryPlan, Module, TableElements, TablePlan};
|
||||||
use crate::tunables::Tunables;
|
use crate::tunables::Tunables;
|
||||||
use cranelift_codegen::ir;
|
use cranelift_codegen::ir;
|
||||||
use cranelift_codegen::ir::{AbiParam, ArgumentPurpose};
|
use cranelift_codegen::ir::{AbiParam, ArgumentPurpose};
|
||||||
@@ -371,7 +371,10 @@ impl<'data> cranelift_wasm::ModuleEnvironment<'data> for ModuleEnvironment<'data
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn declare_func_name(&mut self, func_index: FuncIndex, name: &'data str) -> WasmResult<()> {
|
fn declare_func_name(&mut self, func_index: FuncIndex, name: &'data str) -> WasmResult<()> {
|
||||||
self.result.module.func_names[func_index] = ModuleSyncString::new(Some(name));
|
self.result
|
||||||
|
.module
|
||||||
|
.func_names
|
||||||
|
.insert(func_index, name.to_string());
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -167,15 +167,9 @@ impl Compiler {
|
|||||||
self.jit_function_ranges
|
self.jit_function_ranges
|
||||||
.push((ptr as usize, ptr as usize + body_len));
|
.push((ptr as usize, ptr as usize + body_len));
|
||||||
let func_index = module.func_index(i);
|
let func_index = module.func_index(i);
|
||||||
let func_name = module
|
|
||||||
.func_names
|
|
||||||
.get(func_index)
|
|
||||||
.cloned()
|
|
||||||
.unwrap_or_else(Default::default);
|
|
||||||
let tag = jit_function_registry::JITFunctionTag {
|
let tag = jit_function_registry::JITFunctionTag {
|
||||||
module_id: module.name.clone(),
|
module_id: module.id,
|
||||||
func_index: func_index.index(),
|
func_index,
|
||||||
func_name,
|
|
||||||
};
|
};
|
||||||
jit_function_registry::register(ptr as usize, ptr as usize + body_len, tag);
|
jit_function_registry::register(ptr as usize, ptr as usize + body_len, tag);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -109,13 +109,7 @@ impl Context {
|
|||||||
self.validate(&data).map_err(SetupError::Validate)?;
|
self.validate(&data).map_err(SetupError::Validate)?;
|
||||||
let debug_info = self.debug_info();
|
let debug_info = self.debug_info();
|
||||||
|
|
||||||
instantiate(
|
instantiate(&mut *self.compiler, &data, &mut self.namespace, debug_info)
|
||||||
&mut *self.compiler,
|
|
||||||
&data,
|
|
||||||
None,
|
|
||||||
&mut self.namespace,
|
|
||||||
debug_info,
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return the instance associated with the given name.
|
/// Return the instance associated with the given name.
|
||||||
@@ -146,7 +140,7 @@ impl Context {
|
|||||||
self.validate(&data).map_err(SetupError::Validate)?;
|
self.validate(&data).map_err(SetupError::Validate)?;
|
||||||
let debug_info = self.debug_info();
|
let debug_info = self.debug_info();
|
||||||
|
|
||||||
CompiledModule::new(&mut *self.compiler, data, None, debug_info)
|
CompiledModule::new(&mut *self.compiler, data, debug_info)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// If `name` isn't None, register it for the given instance.
|
/// If `name` isn't None, register it for the given instance.
|
||||||
|
|||||||
@@ -9,13 +9,13 @@ use crate::link::link_module;
|
|||||||
use crate::resolver::Resolver;
|
use crate::resolver::Resolver;
|
||||||
use std::io::Write;
|
use std::io::Write;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
use std::sync::Arc;
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
use wasmtime_debug::read_debuginfo;
|
use wasmtime_debug::read_debuginfo;
|
||||||
use wasmtime_environ::entity::{BoxedSlice, PrimaryMap};
|
use wasmtime_environ::entity::{BoxedSlice, PrimaryMap};
|
||||||
use wasmtime_environ::wasm::{DefinedFuncIndex, SignatureIndex};
|
use wasmtime_environ::wasm::{DefinedFuncIndex, SignatureIndex};
|
||||||
use wasmtime_environ::{
|
use wasmtime_environ::{
|
||||||
CompileError, DataInitializer, DataInitializerLocation, Module, ModuleEnvironment,
|
CompileError, DataInitializer, DataInitializerLocation, Module, ModuleEnvironment,
|
||||||
ModuleSyncString,
|
|
||||||
};
|
};
|
||||||
use wasmtime_runtime::{
|
use wasmtime_runtime::{
|
||||||
GdbJitImageRegistration, InstanceHandle, InstantiationError, VMFunctionBody,
|
GdbJitImageRegistration, InstanceHandle, InstantiationError, VMFunctionBody,
|
||||||
@@ -59,12 +59,11 @@ impl<'data> RawCompiledModule<'data> {
|
|||||||
fn new(
|
fn new(
|
||||||
compiler: &mut Compiler,
|
compiler: &mut Compiler,
|
||||||
data: &'data [u8],
|
data: &'data [u8],
|
||||||
module_name: Option<&str>,
|
|
||||||
debug_info: bool,
|
debug_info: bool,
|
||||||
) -> Result<Self, SetupError> {
|
) -> Result<Self, SetupError> {
|
||||||
let environ = ModuleEnvironment::new(compiler.frontend_config(), compiler.tunables());
|
let environ = ModuleEnvironment::new(compiler.frontend_config(), compiler.tunables());
|
||||||
|
|
||||||
let mut translation = environ
|
let translation = environ
|
||||||
.translate(data)
|
.translate(data)
|
||||||
.map_err(|error| SetupError::Compile(CompileError::Wasm(error)))?;
|
.map_err(|error| SetupError::Compile(CompileError::Wasm(error)))?;
|
||||||
|
|
||||||
@@ -74,8 +73,6 @@ impl<'data> RawCompiledModule<'data> {
|
|||||||
None
|
None
|
||||||
};
|
};
|
||||||
|
|
||||||
translation.module.name = ModuleSyncString::new(module_name);
|
|
||||||
|
|
||||||
let (allocated_functions, jt_offsets, relocations, dbg_image) = compiler.compile(
|
let (allocated_functions, jt_offsets, relocations, dbg_image) = compiler.compile(
|
||||||
&translation.module,
|
&translation.module,
|
||||||
translation.module_translation.as_ref().unwrap(),
|
translation.module_translation.as_ref().unwrap(),
|
||||||
@@ -136,7 +133,7 @@ impl<'data> RawCompiledModule<'data> {
|
|||||||
|
|
||||||
/// A compiled wasm module, ready to be instantiated.
|
/// A compiled wasm module, ready to be instantiated.
|
||||||
pub struct CompiledModule {
|
pub struct CompiledModule {
|
||||||
module: Rc<Module>,
|
module: Arc<Module>,
|
||||||
finished_functions: BoxedSlice<DefinedFuncIndex, *const VMFunctionBody>,
|
finished_functions: BoxedSlice<DefinedFuncIndex, *const VMFunctionBody>,
|
||||||
data_initializers: Box<[OwnedDataInitializer]>,
|
data_initializers: Box<[OwnedDataInitializer]>,
|
||||||
signatures: BoxedSlice<SignatureIndex, VMSharedSignatureIndex>,
|
signatures: BoxedSlice<SignatureIndex, VMSharedSignatureIndex>,
|
||||||
@@ -148,10 +145,9 @@ impl CompiledModule {
|
|||||||
pub fn new<'data>(
|
pub fn new<'data>(
|
||||||
compiler: &mut Compiler,
|
compiler: &mut Compiler,
|
||||||
data: &'data [u8],
|
data: &'data [u8],
|
||||||
module_name: Option<&str>,
|
|
||||||
debug_info: bool,
|
debug_info: bool,
|
||||||
) -> Result<Self, SetupError> {
|
) -> Result<Self, SetupError> {
|
||||||
let raw = RawCompiledModule::<'data>::new(compiler, data, module_name, debug_info)?;
|
let raw = RawCompiledModule::<'data>::new(compiler, data, debug_info)?;
|
||||||
|
|
||||||
Ok(Self::from_parts(
|
Ok(Self::from_parts(
|
||||||
raw.module,
|
raw.module,
|
||||||
@@ -175,7 +171,7 @@ impl CompiledModule {
|
|||||||
dbg_jit_registration: Option<GdbJitImageRegistration>,
|
dbg_jit_registration: Option<GdbJitImageRegistration>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Self {
|
Self {
|
||||||
module: Rc::new(module),
|
module: Arc::new(module),
|
||||||
finished_functions,
|
finished_functions,
|
||||||
data_initializers,
|
data_initializers,
|
||||||
signatures,
|
signatures,
|
||||||
@@ -202,7 +198,7 @@ impl CompiledModule {
|
|||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
let imports = resolve_imports(&self.module, resolver)?;
|
let imports = resolve_imports(&self.module, resolver)?;
|
||||||
InstanceHandle::new(
|
InstanceHandle::new(
|
||||||
Rc::clone(&self.module),
|
Arc::clone(&self.module),
|
||||||
self.finished_functions.clone(),
|
self.finished_functions.clone(),
|
||||||
imports,
|
imports,
|
||||||
&data_initializers,
|
&data_initializers,
|
||||||
@@ -213,8 +209,8 @@ impl CompiledModule {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Return a reference-counting pointer to a module.
|
/// Return a reference-counting pointer to a module.
|
||||||
pub fn module(&self) -> Rc<Module> {
|
pub fn module(&self) -> &Arc<Module> {
|
||||||
self.module.clone()
|
&self.module
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return a reference to a module.
|
/// Return a reference to a module.
|
||||||
@@ -250,21 +246,9 @@ impl OwnedDataInitializer {
|
|||||||
pub fn instantiate(
|
pub fn instantiate(
|
||||||
compiler: &mut Compiler,
|
compiler: &mut Compiler,
|
||||||
data: &[u8],
|
data: &[u8],
|
||||||
module_name: Option<&str>,
|
|
||||||
resolver: &mut dyn Resolver,
|
resolver: &mut dyn Resolver,
|
||||||
debug_info: bool,
|
debug_info: bool,
|
||||||
) -> Result<InstanceHandle, SetupError> {
|
) -> Result<InstanceHandle, SetupError> {
|
||||||
let raw = RawCompiledModule::new(compiler, data, module_name, debug_info)?;
|
let instance = CompiledModule::new(compiler, data, debug_info)?.instantiate(resolver)?;
|
||||||
let imports = resolve_imports(&raw.module, resolver)
|
Ok(instance)
|
||||||
.map_err(|err| SetupError::Instantiate(InstantiationError::Link(err)))?;
|
|
||||||
InstanceHandle::new(
|
|
||||||
Rc::new(raw.module),
|
|
||||||
raw.finished_functions,
|
|
||||||
imports,
|
|
||||||
&*raw.data_initializers,
|
|
||||||
raw.signatures,
|
|
||||||
raw.dbg_jit_registration.map(Rc::new),
|
|
||||||
Box::new(()),
|
|
||||||
)
|
|
||||||
.map_err(SetupError::Instantiate)
|
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ use std::collections::HashSet;
|
|||||||
use std::convert::TryFrom;
|
use std::convert::TryFrom;
|
||||||
use std::ptr::NonNull;
|
use std::ptr::NonNull;
|
||||||
use std::rc::Rc;
|
use std::rc::Rc;
|
||||||
|
use std::sync::Arc;
|
||||||
use std::{mem, ptr, slice};
|
use std::{mem, ptr, slice};
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
use wasmtime_environ::entity::{BoxedSlice, EntityRef, PrimaryMap};
|
use wasmtime_environ::entity::{BoxedSlice, EntityRef, PrimaryMap};
|
||||||
@@ -288,7 +289,7 @@ pub(crate) struct Instance {
|
|||||||
mmap: Mmap,
|
mmap: Mmap,
|
||||||
|
|
||||||
/// The `Module` this `Instance` was instantiated from.
|
/// The `Module` this `Instance` was instantiated from.
|
||||||
module: Rc<Module>,
|
module: Arc<Module>,
|
||||||
|
|
||||||
/// Offsets in the `vmctx` region.
|
/// Offsets in the `vmctx` region.
|
||||||
offsets: VMOffsets,
|
offsets: VMOffsets,
|
||||||
@@ -748,7 +749,7 @@ impl InstanceHandle {
|
|||||||
|
|
||||||
/// Create a new `InstanceHandle` pointing at a new `Instance`.
|
/// Create a new `InstanceHandle` pointing at a new `Instance`.
|
||||||
pub fn new(
|
pub fn new(
|
||||||
module: Rc<Module>,
|
module: Arc<Module>,
|
||||||
finished_functions: BoxedSlice<DefinedFuncIndex, *const VMFunctionBody>,
|
finished_functions: BoxedSlice<DefinedFuncIndex, *const VMFunctionBody>,
|
||||||
imports: Imports,
|
imports: Imports,
|
||||||
data_initializers: &[DataInitializer<'_>],
|
data_initializers: &[DataInitializer<'_>],
|
||||||
@@ -895,8 +896,8 @@ impl InstanceHandle {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Return a reference-counting pointer to a module.
|
/// Return a reference-counting pointer to a module.
|
||||||
pub fn module(&self) -> Rc<Module> {
|
pub fn module(&self) -> &Arc<Module> {
|
||||||
self.instance().module.clone()
|
&self.instance().module
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return a reference to a module.
|
/// Return a reference to a module.
|
||||||
@@ -1110,7 +1111,7 @@ fn lookup_by_declaration(
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn check_table_init_bounds(instance: &mut Instance) -> Result<(), InstantiationError> {
|
fn check_table_init_bounds(instance: &mut Instance) -> Result<(), InstantiationError> {
|
||||||
let module = Rc::clone(&instance.module);
|
let module = Arc::clone(&instance.module);
|
||||||
for init in &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 slice = get_table_slice(
|
let slice = get_table_slice(
|
||||||
@@ -1234,7 +1235,7 @@ fn get_table_slice<'instance>(
|
|||||||
/// Initialize the table memory from the provided initializers.
|
/// Initialize the table memory from the provided initializers.
|
||||||
fn initialize_tables(instance: &mut Instance) -> Result<(), InstantiationError> {
|
fn initialize_tables(instance: &mut Instance) -> Result<(), InstantiationError> {
|
||||||
let vmctx: *mut VMContext = instance.vmctx_mut();
|
let vmctx: *mut VMContext = instance.vmctx_mut();
|
||||||
let module = Rc::clone(&instance.module);
|
let module = Arc::clone(&instance.module);
|
||||||
for init in &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 slice = get_table_slice(
|
let slice = get_table_slice(
|
||||||
@@ -1311,7 +1312,7 @@ fn create_globals(module: &Module) -> BoxedSlice<DefinedGlobalIndex, VMGlobalDef
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn initialize_globals(instance: &mut Instance) {
|
fn initialize_globals(instance: &mut Instance) {
|
||||||
let module = Rc::clone(&instance.module);
|
let module = Arc::clone(&instance.module);
|
||||||
let num_imports = module.imported_globals.len();
|
let num_imports = module.imported_globals.len();
|
||||||
for (index, global) in module.globals.iter().skip(num_imports) {
|
for (index, global) in module.globals.iter().skip(num_imports) {
|
||||||
let def_index = module.defined_global_index(index).unwrap();
|
let def_index = module.defined_global_index(index).unwrap();
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
use lazy_static::lazy_static;
|
use lazy_static::lazy_static;
|
||||||
use std::collections::BTreeMap;
|
use std::collections::BTreeMap;
|
||||||
use std::sync::{Arc, RwLock};
|
use std::sync::{Arc, RwLock};
|
||||||
use wasmtime_environ::ModuleSyncString;
|
use wasmtime_environ::wasm::FuncIndex;
|
||||||
|
|
||||||
lazy_static! {
|
lazy_static! {
|
||||||
static ref REGISTRY: RwLock<JITFunctionRegistry> = RwLock::new(JITFunctionRegistry::default());
|
static ref REGISTRY: RwLock<JITFunctionRegistry> = RwLock::new(JITFunctionRegistry::default());
|
||||||
@@ -11,20 +11,8 @@ lazy_static! {
|
|||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct JITFunctionTag {
|
pub struct JITFunctionTag {
|
||||||
pub module_id: ModuleSyncString,
|
pub module_id: usize,
|
||||||
pub func_index: usize,
|
pub func_index: FuncIndex,
|
||||||
pub func_name: ModuleSyncString,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl std::fmt::Debug for JITFunctionTag {
|
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
|
||||||
if let Some(ref module_id) = self.module_id.get() {
|
|
||||||
write!(f, "{}", module_id)?;
|
|
||||||
} else {
|
|
||||||
write!(f, "(module)")?;
|
|
||||||
}
|
|
||||||
write!(f, ":{}", self.func_index)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
struct JITFunctionRegistry {
|
struct JITFunctionRegistry {
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ use cranelift_codegen::{ir, isa};
|
|||||||
use cranelift_entity::PrimaryMap;
|
use cranelift_entity::PrimaryMap;
|
||||||
use cranelift_wasm::DefinedFuncIndex;
|
use cranelift_wasm::DefinedFuncIndex;
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use std::rc::Rc;
|
use std::sync::Arc;
|
||||||
use target_lexicon::HOST;
|
use target_lexicon::HOST;
|
||||||
use wasi_common::hostcalls;
|
use wasi_common::hostcalls;
|
||||||
use wasi_common::wasi;
|
use wasi_common::wasi;
|
||||||
@@ -79,7 +79,7 @@ pub fn instantiate_wasi_with_context(
|
|||||||
let signatures = PrimaryMap::new();
|
let signatures = PrimaryMap::new();
|
||||||
|
|
||||||
InstanceHandle::new(
|
InstanceHandle::new(
|
||||||
Rc::new(module),
|
Arc::new(module),
|
||||||
finished_functions.into_boxed_slice(),
|
finished_functions.into_boxed_slice(),
|
||||||
imports,
|
imports,
|
||||||
&data_initializers,
|
&data_initializers,
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ use cranelift_codegen::{ir, isa};
|
|||||||
use cranelift_entity::PrimaryMap;
|
use cranelift_entity::PrimaryMap;
|
||||||
use cranelift_wasm::DefinedFuncIndex;
|
use cranelift_wasm::DefinedFuncIndex;
|
||||||
use std::fs::File;
|
use std::fs::File;
|
||||||
use std::rc::Rc;
|
use std::sync::Arc;
|
||||||
use target_lexicon::HOST;
|
use target_lexicon::HOST;
|
||||||
use wasi_common::old::snapshot_0::hostcalls;
|
use wasi_common::old::snapshot_0::hostcalls;
|
||||||
use wasi_common::old::snapshot_0::{WasiCtx, WasiCtxBuilder};
|
use wasi_common::old::snapshot_0::{WasiCtx, WasiCtxBuilder};
|
||||||
@@ -79,7 +79,7 @@ pub fn instantiate_wasi_with_context(
|
|||||||
let signatures = PrimaryMap::new();
|
let signatures = PrimaryMap::new();
|
||||||
|
|
||||||
InstanceHandle::new(
|
InstanceHandle::new(
|
||||||
Rc::new(module),
|
Arc::new(module),
|
||||||
finished_functions.into_boxed_slice(),
|
finished_functions.into_boxed_slice(),
|
||||||
imports,
|
imports,
|
||||||
&data_initializers,
|
&data_initializers,
|
||||||
|
|||||||
@@ -21,6 +21,6 @@ fn test_environ_translate() {
|
|||||||
|
|
||||||
let mut resolver = NullResolver {};
|
let mut resolver = NullResolver {};
|
||||||
let mut compiler = Compiler::new(isa, CompilationStrategy::Auto);
|
let mut compiler = Compiler::new(isa, CompilationStrategy::Auto);
|
||||||
let instance = instantiate(&mut compiler, &data, None, &mut resolver, false);
|
let instance = instantiate(&mut compiler, &data, &mut resolver, false);
|
||||||
assert!(instance.is_ok());
|
assert!(instance.is_ok());
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user