Move serialize into it’s own module

This commit is contained in:
Syrus
2020-05-01 12:58:23 -07:00
parent baf5e04f6b
commit 901b0d8571
7 changed files with 131 additions and 37 deletions

View File

@@ -14,15 +14,13 @@ use serde::{Deserialize, Serialize};
use wasm_common::entity::PrimaryMap; use wasm_common::entity::PrimaryMap;
use wasm_common::LocalFuncIndex; use wasm_common::LocalFuncIndex;
type FunctionBody = Vec<u8>;
/// The frame info for a Compiled function. /// The frame info for a Compiled function.
/// ///
/// This structure is only used for reconstructing /// This structure is only used for reconstructing
/// the frame information after a `Trap`. /// the frame information after a `Trap`.
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, Default)] #[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, Default)]
pub struct CompiledFunctionFrameInfo { pub struct CompiledFunctionFrameInfo {
/// The traps (in the body) /// The traps (in the function body)
pub traps: Vec<TrapInformation>, pub traps: Vec<TrapInformation>,
/// The address map. /// The address map.

View File

@@ -8,9 +8,10 @@ use crate::error::{DeserializeError, SerializeError};
use crate::error::{InstantiationError, LinkError}; use crate::error::{InstantiationError, LinkError};
use crate::link::link_module; use crate::link::link_module;
use crate::resolver::{resolve_imports, Resolver}; 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::GlobalFrameInfoRegistration;
use crate::trap::RuntimeError; use crate::trap::RuntimeError;
use crate::trap::{register as register_frame_info, ExtraFunctionInfo};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::any::Any; use std::any::Any;
use std::sync::{Arc, Mutex}; use std::sync::{Arc, Mutex};
@@ -20,7 +21,9 @@ use wasm_common::{
LocalTableIndex, MemoryIndex, SignatureIndex, TableIndex, LocalTableIndex, MemoryIndex, SignatureIndex, TableIndex,
}; };
use wasmer_compiler::ModuleEnvironment; use wasmer_compiler::ModuleEnvironment;
use wasmer_compiler::{Compilation, CompileError, FunctionAddressMap, TrapInformation}; use wasmer_compiler::{
Compilation, CompileError, CompiledFunctionFrameInfo, FunctionAddressMap, TrapInformation,
};
use wasmer_runtime::{ use wasmer_runtime::{
InstanceHandle, LinearMemory, Module, SignatureRegistry, Table, VMFunctionBody, InstanceHandle, LinearMemory, Module, SignatureRegistry, Table, VMFunctionBody,
VMGlobalDefinition, VMSharedSignatureIndex, VMGlobalDefinition, VMSharedSignatureIndex,
@@ -28,17 +31,6 @@ use wasmer_runtime::{
use wasmer_runtime::{MemoryPlan, TablePlan}; 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 /// This is similar to `CompiledModule`, but references the data initializers
/// from the wasm buffer rather than holding its own copy. /// from the wasm buffer rather than holding its own copy.
struct RawCompiledModule { struct RawCompiledModule {
@@ -337,7 +329,20 @@ impl CompiledModule {
if info.is_some() { if info.is_some() {
return; 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. /// Returns the a map for all traps in this module.

View File

@@ -32,6 +32,7 @@ mod function_table;
mod instantiate; mod instantiate;
mod link; mod link;
mod resolver; mod resolver;
mod serialize;
mod trap; mod trap;
mod tunables; mod tunables;

39
lib/jit/src/serialize.rs Normal file
View 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>,
}

View File

@@ -73,7 +73,24 @@ impl RuntimeError {
code: TrapCode, code: TrapCode,
backtrace: Backtrace, backtrace: Backtrace,
) -> Self { ) -> 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); let msg = format!("{}", desc);
Self::new_with_trace(info, trap_pc, msg, backtrace) Self::new_with_trace(info, trap_pc, msg, backtrace)
} }

View File

@@ -52,7 +52,7 @@ pub struct GlobalFrameInfoRegistration {
} }
/// The function debug info, but unprocessed /// The function debug info, but unprocessed
#[derive(Serialize, Deserialize)] #[derive(Clone, Serialize, Deserialize)]
pub struct ExtraFunctionInfoUnprocessed { pub struct ExtraFunctionInfoUnprocessed {
#[serde(with = "serde_bytes")] #[serde(with = "serde_bytes")]
bytes: Vec<u8>, bytes: Vec<u8>,
@@ -85,11 +85,25 @@ impl Into<CompiledFunctionFrameInfo> for ExtraFunctionInfoUnprocessed {
/// of compiling at the same time that emiting the JIT. /// of compiling at the same time that emiting the JIT.
/// In that case, we don't need to deserialize/process anything /// In that case, we don't need to deserialize/process anything
/// as the data is already in memory. /// as the data is already in memory.
#[derive(Clone)]
pub enum ExtraFunctionInfo { pub enum ExtraFunctionInfo {
/// the processed function
Processed(CompiledFunctionFrameInfo), Processed(CompiledFunctionFrameInfo),
/// the unprocessed
Unprocessed(ExtraFunctionInfoUnprocessed), 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 { struct ModuleFrameInfo {
start: usize, start: usize,
functions: BTreeMap<usize, FunctionInfo>, functions: BTreeMap<usize, FunctionInfo>,
@@ -102,6 +116,19 @@ impl ModuleFrameInfo {
&self.extra_functions.get(local_index).unwrap() &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 { fn instr_map(&self, local_index: LocalFuncIndex) -> &FunctionAddressMap {
match self.function_debug_info(local_index) { match self.function_debug_info(local_index) {
ExtraFunctionInfo::Processed(di) => &di.address_map, ExtraFunctionInfo::Processed(di) => &di.address_map,
@@ -138,8 +165,7 @@ impl GlobalFrameInfo {
/// Returns an object if this `pc` is known to some previously registered /// Returns an object if this `pc` is known to some previously registered
/// module, or returns `None` if no information can be found. /// module, or returns `None` if no information can be found.
pub fn lookup_frame_info(&self, pc: usize) -> Option<FrameInfo> { pub fn lookup_frame_info(&self, pc: usize) -> Option<FrameInfo> {
let module = self.module_info(pc)?; let (module, func) = self.maybe_process_frame(pc)?;
let func = module.function_info(pc)?;
// Use our relative position from the start of the function to find the // Use our relative position from the start of the function to find the
// machine instruction that corresponds to `pc`, which then allows us to // 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. /// Fetches trap information about a program counter in a backtrace.
pub fn lookup_trap_info(&self, pc: usize) -> Option<&TrapInformation> { pub fn lookup_trap_info(&self, pc: usize) -> Option<&TrapInformation> {
let module = self.module_info(pc)?; let (module, func) = self.maybe_process_frame(pc)?;
let func = module.function_info(pc)?;
let traps = module.traps(func.local_index); let traps = module.traps(func.local_index);
let idx = traps let idx = traps
.binary_search_by_key(&((pc - func.start) as u32), |info| info.code_offset) .binary_search_by_key(&((pc - func.start) as u32), |info| info.code_offset)
@@ -203,6 +228,21 @@ impl GlobalFrameInfo {
Some(&traps[idx]) 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 /// Gets a module given a pc
fn module_info(&self, pc: usize) -> Option<&ModuleFrameInfo> { fn module_info(&self, pc: usize) -> Option<&ModuleFrameInfo> {
let (end, module_info) = self.ranges.range(pc..).next()?; 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 /// compiled functions within `module`. If the `module` has no functions
/// then `None` will be returned. Otherwise the returned object, when /// then `None` will be returned. Otherwise the returned object, when
/// dropped, will be used to unregister all name information from this map. /// 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 min = usize::max_value();
let mut max = 0; let mut max = 0;
let mut functions = BTreeMap::new(); let mut functions = BTreeMap::new();
@@ -268,18 +311,6 @@ pub fn register(module: &CompiledModule) -> Option<GlobalFrameInfoRegistration>
assert!(*prev_end < min); 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 // ... then insert our range and assert nothing was there previously
let prev = info.ranges.insert( let prev = info.ranges.insert(
max, max,

View File

@@ -1,4 +1,7 @@
mod error; mod error;
mod frame_info; mod frame_info;
pub use error::RuntimeError; pub use error::RuntimeError;
pub use frame_info::{register, FrameInfo, GlobalFrameInfoRegistration, FRAME_INFO}; pub use frame_info::{
register, ExtraFunctionInfo, ExtraFunctionInfoUnprocessed, FrameInfo,
GlobalFrameInfoRegistration, FRAME_INFO,
};