mirror of
https://github.com/mii443/wasmer.git
synced 2025-12-09 06:08:29 +00:00
Move serialize into it’s own module
This commit is contained in:
@@ -14,15 +14,13 @@ use serde::{Deserialize, Serialize};
|
||||
use wasm_common::entity::PrimaryMap;
|
||||
use wasm_common::LocalFuncIndex;
|
||||
|
||||
type FunctionBody = Vec<u8>;
|
||||
|
||||
/// The frame info for a Compiled function.
|
||||
///
|
||||
/// This structure is only used for reconstructing
|
||||
/// the frame information after a `Trap`.
|
||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, Default)]
|
||||
pub struct CompiledFunctionFrameInfo {
|
||||
/// The traps (in the body)
|
||||
/// The traps (in the function body)
|
||||
pub traps: Vec<TrapInformation>,
|
||||
|
||||
/// The address map.
|
||||
|
||||
@@ -8,9 +8,10 @@ use crate::error::{DeserializeError, SerializeError};
|
||||
use crate::error::{InstantiationError, LinkError};
|
||||
use crate::link::link_module;
|
||||
use crate::resolver::{resolve_imports, Resolver};
|
||||
use crate::trap::register as register_frame_info;
|
||||
use crate::serialize::CacheRawCompiledModule;
|
||||
use crate::trap::GlobalFrameInfoRegistration;
|
||||
use crate::trap::RuntimeError;
|
||||
use crate::trap::{register as register_frame_info, ExtraFunctionInfo};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::any::Any;
|
||||
use std::sync::{Arc, Mutex};
|
||||
@@ -20,7 +21,9 @@ use wasm_common::{
|
||||
LocalTableIndex, MemoryIndex, SignatureIndex, TableIndex,
|
||||
};
|
||||
use wasmer_compiler::ModuleEnvironment;
|
||||
use wasmer_compiler::{Compilation, CompileError, FunctionAddressMap, TrapInformation};
|
||||
use wasmer_compiler::{
|
||||
Compilation, CompileError, CompiledFunctionFrameInfo, FunctionAddressMap, TrapInformation,
|
||||
};
|
||||
use wasmer_runtime::{
|
||||
InstanceHandle, LinearMemory, Module, SignatureRegistry, Table, VMFunctionBody,
|
||||
VMGlobalDefinition, VMSharedSignatureIndex,
|
||||
@@ -28,17 +31,6 @@ use wasmer_runtime::{
|
||||
|
||||
use wasmer_runtime::{MemoryPlan, TablePlan};
|
||||
|
||||
/// Structure to cache the content ot the compilation
|
||||
#[derive(Serialize, Deserialize)]
|
||||
struct CacheRawCompiledModule {
|
||||
compilation: Arc<Compilation>,
|
||||
module: Arc<Module>,
|
||||
data_initializers: Arc<Box<[OwnedDataInitializer]>>,
|
||||
// Plans for that module
|
||||
memory_plans: PrimaryMap<MemoryIndex, MemoryPlan>,
|
||||
table_plans: PrimaryMap<TableIndex, TablePlan>,
|
||||
}
|
||||
|
||||
/// This is similar to `CompiledModule`, but references the data initializers
|
||||
/// from the wasm buffer rather than holding its own copy.
|
||||
struct RawCompiledModule {
|
||||
@@ -337,7 +329,20 @@ impl CompiledModule {
|
||||
if info.is_some() {
|
||||
return;
|
||||
}
|
||||
*info = Some(register_frame_info(&self));
|
||||
|
||||
let extra_functions = self
|
||||
.traps()
|
||||
.values()
|
||||
.zip(self.address_transform().values())
|
||||
.map(|(traps, instrs)| {
|
||||
ExtraFunctionInfo::Processed(CompiledFunctionFrameInfo {
|
||||
traps: traps.to_vec(),
|
||||
address_map: (*instrs).clone(),
|
||||
})
|
||||
})
|
||||
.collect::<PrimaryMap<LocalFuncIndex, _>>();
|
||||
|
||||
*info = Some(register_frame_info(&self, extra_functions));
|
||||
}
|
||||
|
||||
/// Returns the a map for all traps in this module.
|
||||
|
||||
@@ -32,6 +32,7 @@ mod function_table;
|
||||
mod instantiate;
|
||||
mod link;
|
||||
mod resolver;
|
||||
mod serialize;
|
||||
mod trap;
|
||||
mod tunables;
|
||||
|
||||
|
||||
39
lib/jit/src/serialize.rs
Normal file
39
lib/jit/src/serialize.rs
Normal file
@@ -0,0 +1,39 @@
|
||||
use crate::instantiate::OwnedDataInitializer;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::sync::Arc;
|
||||
use wasmer_compiler::Compilation;
|
||||
use wasmer_runtime::Module;
|
||||
|
||||
use wasm_common::entity::PrimaryMap;
|
||||
use wasm_common::{MemoryIndex, TableIndex};
|
||||
use wasmer_runtime::{MemoryPlan, TablePlan};
|
||||
|
||||
// #[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)]
|
||||
// pub struct CompiledFunction {
|
||||
// /// The function body.
|
||||
// #[serde(with = "serde_bytes")]
|
||||
// pub body: Vec<u8>,
|
||||
|
||||
// /// The relocations (in the body)
|
||||
// pub relocations: Vec<Relocation>,
|
||||
|
||||
// /// The jump tables offsets (in the body).
|
||||
// pub jt_offsets: JumpTableOffsets,
|
||||
|
||||
// /// The unwind information.
|
||||
// pub unwind_info: CompiledFunctionUnwindInfo,
|
||||
|
||||
// /// The frame information.
|
||||
// pub frame_info: CompiledFunctionFrameInfo,
|
||||
// }
|
||||
|
||||
/// Structure to cache the content ot the compilation
|
||||
#[derive(Serialize, Deserialize)]
|
||||
pub struct CacheRawCompiledModule {
|
||||
pub compilation: Arc<Compilation>,
|
||||
pub module: Arc<Module>,
|
||||
pub data_initializers: Arc<Box<[OwnedDataInitializer]>>,
|
||||
// Plans for that module
|
||||
pub memory_plans: PrimaryMap<MemoryIndex, MemoryPlan>,
|
||||
pub table_plans: PrimaryMap<TableIndex, TablePlan>,
|
||||
}
|
||||
@@ -73,7 +73,24 @@ impl RuntimeError {
|
||||
code: TrapCode,
|
||||
backtrace: Backtrace,
|
||||
) -> Self {
|
||||
let desc = code.message();
|
||||
let desc = match code {
|
||||
TrapCode::StackOverflow => "call stack exhausted",
|
||||
TrapCode::HeapSetterOutOfBounds => "memory out of bounds: data segment does not fit",
|
||||
TrapCode::HeapAccessOutOfBounds => "out of bounds memory access",
|
||||
TrapCode::TableSetterOutOfBounds => {
|
||||
"table out of bounds: elements segment does not fit"
|
||||
}
|
||||
TrapCode::TableAccessOutOfBounds => "undefined element: out of bounds table access",
|
||||
TrapCode::OutOfBounds => "out of bounds",
|
||||
TrapCode::IndirectCallToNull => "uninitialized element",
|
||||
TrapCode::BadSignature => "indirect call type mismatch",
|
||||
TrapCode::IntegerOverflow => "integer overflow",
|
||||
TrapCode::IntegerDivisionByZero => "integer divide by zero",
|
||||
TrapCode::BadConversionToInteger => "invalid conversion to integer",
|
||||
TrapCode::UnreachableCodeReached => "unreachable",
|
||||
TrapCode::Interrupt => "interrupt",
|
||||
TrapCode::User(_) => unreachable!(),
|
||||
};
|
||||
let msg = format!("{}", desc);
|
||||
Self::new_with_trace(info, trap_pc, msg, backtrace)
|
||||
}
|
||||
|
||||
@@ -52,7 +52,7 @@ pub struct GlobalFrameInfoRegistration {
|
||||
}
|
||||
|
||||
/// The function debug info, but unprocessed
|
||||
#[derive(Serialize, Deserialize)]
|
||||
#[derive(Clone, Serialize, Deserialize)]
|
||||
pub struct ExtraFunctionInfoUnprocessed {
|
||||
#[serde(with = "serde_bytes")]
|
||||
bytes: Vec<u8>,
|
||||
@@ -85,11 +85,25 @@ impl Into<CompiledFunctionFrameInfo> for ExtraFunctionInfoUnprocessed {
|
||||
/// of compiling at the same time that emiting the JIT.
|
||||
/// In that case, we don't need to deserialize/process anything
|
||||
/// as the data is already in memory.
|
||||
#[derive(Clone)]
|
||||
pub enum ExtraFunctionInfo {
|
||||
/// the processed function
|
||||
Processed(CompiledFunctionFrameInfo),
|
||||
/// the unprocessed
|
||||
Unprocessed(ExtraFunctionInfoUnprocessed),
|
||||
}
|
||||
|
||||
impl ExtraFunctionInfo {
|
||||
/// Returns true if the extra function info is not yet
|
||||
/// processed
|
||||
pub fn is_unprocessed(&self) -> bool {
|
||||
match self {
|
||||
Self::Unprocessed(_) => true,
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct ModuleFrameInfo {
|
||||
start: usize,
|
||||
functions: BTreeMap<usize, FunctionInfo>,
|
||||
@@ -102,6 +116,19 @@ impl ModuleFrameInfo {
|
||||
&self.extra_functions.get(local_index).unwrap()
|
||||
}
|
||||
|
||||
fn process_function_debug_info(&mut self, local_index: LocalFuncIndex) {
|
||||
let mut func = self.extra_functions.get_mut(local_index).unwrap();
|
||||
let processed: CompiledFunctionFrameInfo = match func {
|
||||
ExtraFunctionInfo::Processed(_) => {
|
||||
// This should be a no-op on processed info
|
||||
return;
|
||||
}
|
||||
ExtraFunctionInfo::Unprocessed(unprocessed) => {
|
||||
bincode::deserialize(&unprocessed.bytes).expect("Can't deserialize the info")
|
||||
}
|
||||
};
|
||||
*func = ExtraFunctionInfo::Processed(processed)
|
||||
}
|
||||
fn instr_map(&self, local_index: LocalFuncIndex) -> &FunctionAddressMap {
|
||||
match self.function_debug_info(local_index) {
|
||||
ExtraFunctionInfo::Processed(di) => &di.address_map,
|
||||
@@ -138,8 +165,7 @@ impl GlobalFrameInfo {
|
||||
/// Returns an object if this `pc` is known to some previously registered
|
||||
/// module, or returns `None` if no information can be found.
|
||||
pub fn lookup_frame_info(&self, pc: usize) -> Option<FrameInfo> {
|
||||
let module = self.module_info(pc)?;
|
||||
let func = module.function_info(pc)?;
|
||||
let (module, func) = self.maybe_process_frame(pc)?;
|
||||
|
||||
// Use our relative position from the start of the function to find the
|
||||
// machine instruction that corresponds to `pc`, which then allows us to
|
||||
@@ -194,8 +220,7 @@ impl GlobalFrameInfo {
|
||||
|
||||
/// Fetches trap information about a program counter in a backtrace.
|
||||
pub fn lookup_trap_info(&self, pc: usize) -> Option<&TrapInformation> {
|
||||
let module = self.module_info(pc)?;
|
||||
let func = module.function_info(pc)?;
|
||||
let (module, func) = self.maybe_process_frame(pc)?;
|
||||
let traps = module.traps(func.local_index);
|
||||
let idx = traps
|
||||
.binary_search_by_key(&((pc - func.start) as u32), |info| info.code_offset)
|
||||
@@ -203,6 +228,21 @@ impl GlobalFrameInfo {
|
||||
Some(&traps[idx])
|
||||
}
|
||||
|
||||
/// Get an process a Frame in case is not yet processed
|
||||
fn maybe_process_frame(&self, pc: usize) -> Option<(&ModuleFrameInfo, &FunctionInfo)> {
|
||||
let module = self.module_info(pc)?;
|
||||
let func = module.function_info(pc)?;
|
||||
let extra_func_info = module.function_debug_info(func.local_index);
|
||||
if extra_func_info.is_unprocessed() {
|
||||
let mut mutable_info = FRAME_INFO.write().unwrap();
|
||||
let mut mutable_module = mutable_info.module_info_mut(pc)?;
|
||||
mutable_module.process_function_debug_info(func.local_index);
|
||||
let module = self.module_info(pc)?;
|
||||
return Some((module, func));
|
||||
}
|
||||
Some((module, func))
|
||||
}
|
||||
|
||||
/// Gets a module given a pc
|
||||
fn module_info(&self, pc: usize) -> Option<&ModuleFrameInfo> {
|
||||
let (end, module_info) = self.ranges.range(pc..).next()?;
|
||||
@@ -236,7 +276,10 @@ impl Drop for GlobalFrameInfoRegistration {
|
||||
/// compiled functions within `module`. If the `module` has no functions
|
||||
/// then `None` will be returned. Otherwise the returned object, when
|
||||
/// dropped, will be used to unregister all name information from this map.
|
||||
pub fn register(module: &CompiledModule) -> Option<GlobalFrameInfoRegistration> {
|
||||
pub fn register(
|
||||
module: &CompiledModule,
|
||||
extra_functions: PrimaryMap<LocalFuncIndex, ExtraFunctionInfo>,
|
||||
) -> Option<GlobalFrameInfoRegistration> {
|
||||
let mut min = usize::max_value();
|
||||
let mut max = 0;
|
||||
let mut functions = BTreeMap::new();
|
||||
@@ -268,18 +311,6 @@ pub fn register(module: &CompiledModule) -> Option<GlobalFrameInfoRegistration>
|
||||
assert!(*prev_end < min);
|
||||
}
|
||||
|
||||
let extra_functions = module
|
||||
.traps()
|
||||
.values()
|
||||
.zip(module.address_transform().values())
|
||||
.map(|(traps, instrs)| {
|
||||
ExtraFunctionInfo::Processed(CompiledFunctionFrameInfo {
|
||||
traps: traps.to_vec(),
|
||||
address_map: (*instrs).clone(),
|
||||
})
|
||||
})
|
||||
.collect::<PrimaryMap<LocalFuncIndex, _>>();
|
||||
|
||||
// ... then insert our range and assert nothing was there previously
|
||||
let prev = info.ranges.insert(
|
||||
max,
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
mod error;
|
||||
mod frame_info;
|
||||
pub use error::RuntimeError;
|
||||
pub use frame_info::{register, FrameInfo, GlobalFrameInfoRegistration, FRAME_INFO};
|
||||
pub use frame_info::{
|
||||
register, ExtraFunctionInfo, ExtraFunctionInfoUnprocessed, FrameInfo,
|
||||
GlobalFrameInfoRegistration, FRAME_INFO,
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user