diff --git a/Cargo.lock b/Cargo.lock index 46036a44113..4d94299c138 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2573,7 +2573,6 @@ name = "wasmer-engine" version = "1.0.2" dependencies = [ "backtrace", - "bincode", "lazy_static", "loupe", "memmap2", diff --git a/lib/engine-jit/src/artifact.rs b/lib/engine-jit/src/artifact.rs index 9b8a6c3d803..68f168ae6a3 100644 --- a/lib/engine-jit/src/artifact.rs +++ b/lib/engine-jit/src/artifact.rs @@ -16,7 +16,7 @@ use wasmer_engine::{ SerializeError, }; #[cfg(feature = "compiler")] -use wasmer_engine::{Engine, SerializableFunctionFrameInfo, Tunables}; +use wasmer_engine::{Engine, Tunables}; use wasmer_types::entity::{BoxedSlice, PrimaryMap}; use wasmer_types::{ FunctionIndex, LocalFunctionIndex, MemoryIndex, OwnedDataInitializer, SignatureIndex, @@ -107,11 +107,7 @@ impl JITArtifact { .collect::>() .into_boxed_slice(); - let frame_infos = compilation - .get_frame_info() - .values() - .map(|frame_info| SerializableFunctionFrameInfo::Processed(frame_info.clone())) - .collect::>(); + let frame_infos = compilation.get_frame_info(); let serializable_compilation = SerializableCompilation { function_bodies: compilation.get_function_bodies(), diff --git a/lib/engine-jit/src/serialize.rs b/lib/engine-jit/src/serialize.rs index c924381b9a0..7109be6b246 100644 --- a/lib/engine-jit/src/serialize.rs +++ b/lib/engine-jit/src/serialize.rs @@ -1,10 +1,9 @@ use loupe::MemoryUsage; use serde::{Deserialize, Serialize}; use wasmer_compiler::{ - CompileModuleInfo, CustomSection, Dwarf, FunctionBody, JumpTableOffsets, Relocation, - SectionIndex, + CompileModuleInfo, CompiledFunctionFrameInfo, CustomSection, Dwarf, FunctionBody, + JumpTableOffsets, Relocation, SectionIndex, }; -use wasmer_engine::SerializableFunctionFrameInfo; use wasmer_types::entity::PrimaryMap; use wasmer_types::{FunctionIndex, LocalFunctionIndex, OwnedDataInitializer, SignatureIndex}; @@ -24,10 +23,7 @@ pub struct SerializableCompilation { pub function_bodies: PrimaryMap, pub function_relocations: PrimaryMap>, pub function_jt_offsets: PrimaryMap, - // This is `SerializableFunctionFrameInfo` instead of `CompiledFunctionFrameInfo`, - // to allow lazy frame_info deserialization, we convert it to it's lazy binary - // format upon serialization. - pub function_frame_info: PrimaryMap, + pub function_frame_info: PrimaryMap, pub function_call_trampolines: PrimaryMap, pub dynamic_function_trampolines: PrimaryMap, pub custom_sections: PrimaryMap, diff --git a/lib/engine/Cargo.toml b/lib/engine/Cargo.toml index 81ea2b18f08..83d80f9c70d 100644 --- a/lib/engine/Cargo.toml +++ b/lib/engine/Cargo.toml @@ -23,7 +23,6 @@ more-asserts = "0.2" thiserror = "1.0" serde = { version = "1.0", features = ["derive", "rc"] } serde_bytes = { version = "0.11" } -bincode = "1.3" lazy_static = "1.4" loupe = "0.1" diff --git a/lib/engine/src/lib.rs b/lib/engine/src/lib.rs index e5754535823..203d84e868b 100644 --- a/lib/engine/src/lib.rs +++ b/lib/engine/src/lib.rs @@ -25,7 +25,6 @@ mod engine; mod error; mod export; mod resolver; -mod serialize; mod trap; mod tunables; @@ -41,7 +40,6 @@ pub use crate::resolver::{ resolve_imports, ChainableNamedResolver, NamedResolver, NamedResolverChain, NullResolver, Resolver, }; -pub use crate::serialize::SerializableFunctionFrameInfo; pub use crate::trap::*; pub use crate::tunables::Tunables; diff --git a/lib/engine/src/serialize.rs b/lib/engine/src/serialize.rs deleted file mode 100644 index a36b47da320..00000000000 --- a/lib/engine/src/serialize.rs +++ /dev/null @@ -1,105 +0,0 @@ -use loupe::MemoryUsage; -use serde::de::{Deserializer, Visitor}; -use serde::ser::Serializer; -use serde::{Deserialize, Serialize}; -use std::fmt; -use wasmer_compiler::CompiledFunctionFrameInfo; - -/// This is the unserialized verison of `CompiledFunctionFrameInfo`. -#[derive(Clone, Serialize, Deserialize, MemoryUsage)] -#[serde(transparent)] -#[repr(transparent)] -pub struct UnprocessedFunctionFrameInfo { - #[serde(with = "serde_bytes")] - bytes: Vec, -} - -impl UnprocessedFunctionFrameInfo { - /// Converts the `UnprocessedFunctionFrameInfo` to a `CompiledFunctionFrameInfo` - pub fn deserialize(&self) -> CompiledFunctionFrameInfo { - // let r = flexbuffers::Reader::get_root(&self.bytes).expect("Can't deserialize the info"); - // CompiledFunctionFrameInfo::deserialize(r).expect("Can't deserialize the info") - bincode::deserialize(&self.bytes).expect("Can't deserialize the info") - } - - /// Converts the `CompiledFunctionFrameInfo` to a `UnprocessedFunctionFrameInfo` - pub fn serialize(processed: &CompiledFunctionFrameInfo) -> Self { - // let mut s = flexbuffers::FlexbufferSerializer::new(); - // processed - // .serialize(&mut s) - // .expect("Can't serialize the info"); - // let bytes = s.take_buffer(); - let bytes = bincode::serialize(&processed).expect("Can't serialize the info"); - Self { bytes } - } -} - -/// We hold the frame info in two states, mainly because we want to -/// process it lazily to speed up execution. -/// -/// When a Trap occurs, we process the frame info lazily for each -/// function in the frame. That way we minimize as much as we can -/// the upfront effort. -/// -/// The data can also be processed upfront. This will happen in the case -/// 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, MemoryUsage)] -pub enum SerializableFunctionFrameInfo { - /// The unprocessed frame info (binary) - Unprocessed(UnprocessedFunctionFrameInfo), - /// The processed frame info (memory struct) - Processed(CompiledFunctionFrameInfo), -} - -impl SerializableFunctionFrameInfo { - /// Returns true if the extra function info is not yet - /// processed - pub fn is_unprocessed(&self) -> bool { - matches!(self, Self::Unprocessed(_)) - } -} - -// Below: -// The custom ser/de for `SerializableFunctionFrameInfo`. - -impl Serialize for SerializableFunctionFrameInfo { - fn serialize(&self, s: S) -> Result - where - S: Serializer, - { - let unprocessed = match self { - Self::Processed(processed) => UnprocessedFunctionFrameInfo::serialize(processed), - Self::Unprocessed(unprocessed) => unprocessed.clone(), - }; - s.serialize_bytes(&unprocessed.bytes) - } -} - -struct FunctionFrameInfoVisitor; - -impl<'de> Visitor<'de> for FunctionFrameInfoVisitor { - type Value = UnprocessedFunctionFrameInfo; - - fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("bytes") - } - fn visit_byte_buf(self, v: Vec) -> Result { - Ok(UnprocessedFunctionFrameInfo { bytes: v }) - } - fn visit_bytes(self, v: &[u8]) -> Result { - Ok(UnprocessedFunctionFrameInfo { bytes: v.to_vec() }) - } -} - -impl<'de> Deserialize<'de> for SerializableFunctionFrameInfo { - fn deserialize(deserializer: D) -> Result - where - D: Deserializer<'de>, - { - Ok(Self::Unprocessed( - deserializer.deserialize_byte_buf(FunctionFrameInfoVisitor)?, - )) - } -} diff --git a/lib/engine/src/trap/error.rs b/lib/engine/src/trap/error.rs index 36cdb7e49bc..98c2effeb94 100644 --- a/lib/engine/src/trap/error.rs +++ b/lib/engine/src/trap/error.rs @@ -3,7 +3,6 @@ use backtrace::Backtrace; use std::error::Error; use std::fmt; use std::sync::Arc; -use std::sync::RwLockReadGuard; use wasmer_vm::{raise_user_trap, Trap, TrapCode}; /// A struct representing an aborted instruction execution, with a message @@ -56,7 +55,7 @@ impl RuntimeError { let info = FRAME_INFO.read().unwrap(); let msg = message.into(); Self::new_with_trace( - info, + &info, None, RuntimeErrorSource::Generic(msg), Backtrace::new_unresolved(), @@ -72,7 +71,7 @@ impl RuntimeError { // The error is already a RuntimeError, we return it directly Ok(runtime_error) => *runtime_error, Err(e) => Self::new_with_trace( - info, + &info, None, RuntimeErrorSource::User(e), Backtrace::new_unresolved(), @@ -85,27 +84,18 @@ impl RuntimeError { signal_trap, backtrace, } => { - let info = if info.should_process_frame(pc).unwrap_or(false) { - drop(info); - let mut info = FRAME_INFO.write().unwrap(); - info.maybe_process_frame(pc).unwrap(); - drop(info); - FRAME_INFO.read().unwrap() - } else { - info - }; let code = info .lookup_trap_info(pc) .map_or(signal_trap.unwrap_or(TrapCode::StackOverflow), |info| { info.trap_code }); - Self::new_with_trace(info, Some(pc), RuntimeErrorSource::Trap(code), backtrace) + Self::new_with_trace(&info, Some(pc), RuntimeErrorSource::Trap(code), backtrace) } // A trap triggered manually from the Wasmer runtime Trap::Runtime { trap_code, backtrace, - } => Self::new_with_trace(info, None, RuntimeErrorSource::Trap(trap_code), backtrace), + } => Self::new_with_trace(&info, None, RuntimeErrorSource::Trap(trap_code), backtrace), } } @@ -115,7 +105,7 @@ impl RuntimeError { } fn new_with_trace( - info: RwLockReadGuard, + info: &GlobalFrameInfo, trap_pc: Option, source: RuntimeErrorSource, native_trace: Backtrace, @@ -144,28 +134,6 @@ impl RuntimeError { }) .collect(); - // If any of the frames is not processed, we adquire the lock to - // modify the GlobalFrameInfo module. - let info = if frames - .iter() - .any(|pc| info.should_process_frame(*pc).unwrap_or(false)) - { - // We drop the read lock, to get a write one. - // Note: this is not guaranteed because it's a RwLock: - // the following code may cause deadlocks. - // TODO: clean up this code - drop(info); - { - let mut info = FRAME_INFO.write().unwrap(); - for pc in frames.iter() { - info.maybe_process_frame(*pc); - } - } - FRAME_INFO.read().unwrap() - } else { - info - }; - // Let's construct the trace let wasm_trace = frames .into_iter() diff --git a/lib/engine/src/trap/frame_info.rs b/lib/engine/src/trap/frame_info.rs index 3407ab742db..cb155ada5b0 100644 --- a/lib/engine/src/trap/frame_info.rs +++ b/lib/engine/src/trap/frame_info.rs @@ -10,7 +10,6 @@ //! let module: ModuleInfo = ...; //! FRAME_INFO.register(module, compiled_functions); //! ``` -use crate::serialize::SerializableFunctionFrameInfo; use loupe::MemoryUsage; use std::cmp; use std::collections::BTreeMap; @@ -56,39 +55,14 @@ struct ModuleInfoFrameInfo { start: usize, functions: BTreeMap, module: Arc, - frame_infos: PrimaryMap, + frame_infos: PrimaryMap, } impl ModuleInfoFrameInfo { - fn function_debug_info( - &self, - local_index: LocalFunctionIndex, - ) -> &SerializableFunctionFrameInfo { + fn function_debug_info(&self, local_index: LocalFunctionIndex) -> &CompiledFunctionFrameInfo { &self.frame_infos.get(local_index).unwrap() } - fn process_function_debug_info(&mut self, local_index: LocalFunctionIndex) { - let func = self.frame_infos.get_mut(local_index).unwrap(); - let processed: CompiledFunctionFrameInfo = match func { - SerializableFunctionFrameInfo::Processed(_) => { - // This should be a no-op on processed info - return; - } - SerializableFunctionFrameInfo::Unprocessed(unprocessed) => unprocessed.deserialize(), - }; - *func = SerializableFunctionFrameInfo::Processed(processed) - } - - fn processed_function_frame_info( - &self, - local_index: LocalFunctionIndex, - ) -> &CompiledFunctionFrameInfo { - match self.function_debug_info(local_index) { - SerializableFunctionFrameInfo::Processed(di) => &di, - _ => unreachable!("frame info should already be processed"), - } - } - /// Gets a function given a pc fn function_info(&self, pc: usize) -> Option<&FunctionInfo> { let (end, func) = self.functions.range(pc..).next()?; @@ -118,9 +92,7 @@ impl GlobalFrameInfo { // machine instruction that corresponds to `pc`, which then allows us to // map that to a wasm original source location. let rel_pos = pc - func.start; - let instr_map = &module - .processed_function_frame_info(func.local_index) - .address_map; + let instr_map = &module.function_debug_info(func.local_index).address_map; let pos = match instr_map .instructions .binary_search_by_key(&rel_pos, |map| map.code_offset) @@ -171,30 +143,13 @@ impl GlobalFrameInfo { pub fn lookup_trap_info(&self, pc: usize) -> Option<&TrapInformation> { let module = self.module_info(pc)?; let func = module.function_info(pc)?; - let traps = &module.processed_function_frame_info(func.local_index).traps; + let traps = &module.function_debug_info(func.local_index).traps; let idx = traps .binary_search_by_key(&((pc - func.start) as u32), |info| info.code_offset) .ok()?; Some(&traps[idx]) } - /// Should process the frame before anything? - pub fn should_process_frame(&self, pc: usize) -> Option { - let module = self.module_info(pc)?; - let func = module.function_info(pc)?; - let extra_func_info = module.function_debug_info(func.local_index); - Some(extra_func_info.is_unprocessed()) - } - - /// Process the frame info in case is not yet processed - pub fn maybe_process_frame(&mut self, pc: usize) -> Option<()> { - let module = self.module_info_mut(pc)?; - let func = module.function_info(pc)?; - let func_local_index = func.local_index; - module.process_function_debug_info(func_local_index); - Some(()) - } - /// Gets a module given a pc fn module_info(&self, pc: usize) -> Option<&ModuleInfoFrameInfo> { let (end, module_info) = self.ranges.range(pc..).next()?; @@ -203,15 +158,6 @@ impl GlobalFrameInfo { } Some(module_info) } - - /// Gets a module given a pc - fn module_info_mut(&mut self, pc: usize) -> Option<&mut ModuleInfoFrameInfo> { - let (end, module_info) = self.ranges.range_mut(pc..).next()?; - if pc < module_info.start || *end < pc { - return None; - } - Some(module_info) - } } impl Drop for GlobalFrameInfoRegistration { @@ -243,7 +189,7 @@ pub struct FunctionExtent { pub fn register( module: Arc, finished_functions: &BoxedSlice, - frame_infos: PrimaryMap, + frame_infos: PrimaryMap, ) -> Option { let mut min = usize::max_value(); let mut max = 0;