From 7f0b121650c6ac9d77b790bc8fd576022b71771e Mon Sep 17 00:00:00 2001 From: Syrus Akbary Date: Wed, 21 Apr 2021 19:40:10 -0700 Subject: [PATCH 01/22] Improved frame_info to be always processed MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Since we are going to switch serialization methods, the new one doesn’t have a slowdown if we read the data directly. Thus, we can always operate with processed frame infos --- Cargo.lock | 1 - lib/engine-jit/src/artifact.rs | 8 +-- lib/engine-jit/src/serialize.rs | 10 +-- lib/engine/Cargo.toml | 1 - lib/engine/src/lib.rs | 2 - lib/engine/src/serialize.rs | 105 ------------------------------ lib/engine/src/trap/error.rs | 42 ++---------- lib/engine/src/trap/frame_info.rs | 55 ++-------------- 8 files changed, 15 insertions(+), 209 deletions(-) delete mode 100644 lib/engine/src/serialize.rs 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 a83e026e5d8..1af2fb639f9 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, @@ -104,11 +104,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..2a0e9c9c5ce 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()?; @@ -243,7 +198,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; From 93459b09158c54a872131107f71403ce43f523b9 Mon Sep 17 00:00:00 2001 From: Syrus Akbary Date: Wed, 28 Apr 2021 21:32:02 -0700 Subject: [PATCH 02/22] Fix linting --- lib/engine/src/trap/frame_info.rs | 9 --------- 1 file changed, 9 deletions(-) diff --git a/lib/engine/src/trap/frame_info.rs b/lib/engine/src/trap/frame_info.rs index 2a0e9c9c5ce..cb155ada5b0 100644 --- a/lib/engine/src/trap/frame_info.rs +++ b/lib/engine/src/trap/frame_info.rs @@ -158,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 { From 9e361db035ffe159b9e1e3a7a9f20db6be9cf7ae Mon Sep 17 00:00:00 2001 From: Syrus Akbary Date: Wed, 28 Apr 2021 21:47:22 -0700 Subject: [PATCH 03/22] Fix unused bincode --- Cargo.lock | 1 - fuzz/Cargo.lock | 2 -- lib/engine-native/Cargo.toml | 1 - 3 files changed, 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 4d94299c138..45433d3239a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2622,7 +2622,6 @@ dependencies = [ name = "wasmer-engine-native" version = "1.0.2" dependencies = [ - "bincode", "cfg-if 0.1.10", "leb128", "libloading", diff --git a/fuzz/Cargo.lock b/fuzz/Cargo.lock index d3bf9c70a17..7c281012aae 100644 --- a/fuzz/Cargo.lock +++ b/fuzz/Cargo.lock @@ -1261,7 +1261,6 @@ name = "wasmer-engine" version = "1.0.2" dependencies = [ "backtrace", - "bincode", "lazy_static", "loupe", "memmap2", @@ -1297,7 +1296,6 @@ dependencies = [ name = "wasmer-engine-native" version = "1.0.2" dependencies = [ - "bincode", "cfg-if 0.1.10", "leb128", "libloading", diff --git a/lib/engine-native/Cargo.toml b/lib/engine-native/Cargo.toml index 0fda2092ab7..b2418df99d2 100644 --- a/lib/engine-native/Cargo.toml +++ b/lib/engine-native/Cargo.toml @@ -19,7 +19,6 @@ wasmer-object = { path = "../object", version = "1.0.2" } serde = { version = "1.0", features = ["derive", "rc"] } cfg-if = "0.1" tracing = "0.1" -bincode = "1.3" leb128 = "0.2" libloading = "0.7" tempfile = "3.1" From 50f899af6996d33eb86630f0eda6b428a42772c8 Mon Sep 17 00:00:00 2001 From: Syrus Akbary Date: Thu, 29 Apr 2021 01:24:44 -0700 Subject: [PATCH 04/22] Move from serde to rkyv --- Cargo.lock | 4 +- lib/compiler/Cargo.toml | 2 +- lib/compiler/src/address_map.rs | 10 ++++ lib/compiler/src/function.rs | 18 +++++++ lib/compiler/src/jump_table.rs | 6 +++ lib/compiler/src/relocation.rs | 14 +++++ lib/compiler/src/section.rs | 25 +++++++++ lib/compiler/src/sourceloc.rs | 6 +++ lib/compiler/src/trap.rs | 6 +++ lib/compiler/src/unwind.rs | 6 +++ lib/engine-jit/Cargo.toml | 10 ++-- lib/engine-jit/src/artifact.rs | 30 +++++++---- lib/engine-jit/src/serialize.rs | 76 ++++++++++++++++++++++----- lib/types/src/archives.rs | 47 ++++++++++++++++- lib/types/src/entity/secondary_map.rs | 12 +++-- lib/types/src/lib.rs | 2 +- lib/vm/src/lib.rs | 2 +- lib/vm/src/libcalls.rs | 6 +++ lib/vm/src/trap/trapcode.rs | 6 +++ 19 files changed, 250 insertions(+), 38 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 45433d3239a..df124b50905 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2605,12 +2605,12 @@ dependencies = [ name = "wasmer-engine-jit" version = "1.0.2" dependencies = [ - "bincode", "cfg-if 0.1.10", + "leb128", "loupe", "region", + "rkyv", "serde", - "serde_bytes", "wasmer-compiler", "wasmer-engine", "wasmer-types", diff --git a/lib/compiler/Cargo.toml b/lib/compiler/Cargo.toml index 3f74fa136c1..c61654c8766 100644 --- a/lib/compiler/Cargo.toml +++ b/lib/compiler/Cargo.toml @@ -33,7 +33,7 @@ translator = ["wasmparser"] std = ["wasmer-types/std"] core = ["hashbrown", "wasmer-types/core"] enable-serde = ["serde", "serde_bytes", "wasmer-types/enable-serde"] -enable-rkyv = ["rkyv", "wasmer-vm/enable-rkyv"] +enable-rkyv = ["rkyv", "wasmer-vm/enable-rkyv", "wasmer-types/enable-rkyv"] [badges] maintenance = { status = "experimental" } diff --git a/lib/compiler/src/address_map.rs b/lib/compiler/src/address_map.rs index 4fd8c1a2396..74db48dcba5 100644 --- a/lib/compiler/src/address_map.rs +++ b/lib/compiler/src/address_map.rs @@ -4,11 +4,17 @@ use crate::lib::std::vec::Vec; use crate::sourceloc::SourceLoc; use loupe::MemoryUsage; +#[cfg(feature = "enable-rkyv")] +use rkyv::{Archive, Deserialize as RkyvDeserialize, Serialize as RkyvSerialize}; #[cfg(feature = "enable-serde")] use serde::{Deserialize, Serialize}; /// Single source location to generated address mapping. #[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))] +#[cfg_attr( + feature = "enable-rkyv", + derive(RkyvSerialize, RkyvDeserialize, Archive) +)] #[derive(Debug, Clone, PartialEq, Eq, MemoryUsage)] pub struct InstructionAddressMap { /// Original source location. @@ -23,6 +29,10 @@ pub struct InstructionAddressMap { /// Function and its instructions addresses mappings. #[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))] +#[cfg_attr( + feature = "enable-rkyv", + derive(RkyvSerialize, RkyvDeserialize, Archive) +)] #[derive(Debug, Clone, PartialEq, Eq, Default, MemoryUsage)] pub struct FunctionAddressMap { /// Instructions maps. diff --git a/lib/compiler/src/function.rs b/lib/compiler/src/function.rs index e431f3bb7e0..98be7a63255 100644 --- a/lib/compiler/src/function.rs +++ b/lib/compiler/src/function.rs @@ -13,6 +13,8 @@ use crate::section::{CustomSection, SectionIndex}; use crate::trap::TrapInformation; use crate::{CompiledFunctionUnwindInfo, FunctionAddressMap, JumpTableOffsets, Relocation}; use loupe::MemoryUsage; +#[cfg(feature = "enable-rkyv")] +use rkyv::{Archive, Deserialize as RkyvDeserialize, Serialize as RkyvSerialize}; #[cfg(feature = "enable-serde")] use serde::{Deserialize, Serialize}; use wasmer_types::entity::PrimaryMap; @@ -23,6 +25,10 @@ use wasmer_types::{FunctionIndex, LocalFunctionIndex, SignatureIndex}; /// This structure is only used for reconstructing /// the frame information after a `Trap`. #[cfg_attr(feature = "enable-serde", derive(Deserialize, Serialize))] +#[cfg_attr( + feature = "enable-rkyv", + derive(RkyvSerialize, RkyvDeserialize, Archive) +)] #[derive(Debug, Clone, PartialEq, Eq, Default, MemoryUsage)] pub struct CompiledFunctionFrameInfo { /// The traps (in the function body). @@ -36,6 +42,10 @@ pub struct CompiledFunctionFrameInfo { /// The function body. #[cfg_attr(feature = "enable-serde", derive(Deserialize, Serialize))] +#[cfg_attr( + feature = "enable-rkyv", + derive(RkyvSerialize, RkyvDeserialize, Archive) +)] #[derive(Debug, Clone, PartialEq, Eq, MemoryUsage)] pub struct FunctionBody { /// The function body bytes. @@ -52,6 +62,10 @@ pub struct FunctionBody { /// (function bytecode body, relocations, traps, jump tables /// and unwind information). #[cfg_attr(feature = "enable-serde", derive(Deserialize, Serialize))] +#[cfg_attr( + feature = "enable-rkyv", + derive(RkyvSerialize, RkyvDeserialize, Archive) +)] #[derive(Debug, Clone, PartialEq, Eq)] pub struct CompiledFunction { /// The function body. @@ -80,6 +94,10 @@ pub type CustomSections = PrimaryMap; /// In the future this structure may also hold other information useful /// for debugging. #[cfg_attr(feature = "enable-serde", derive(Deserialize, Serialize))] +#[cfg_attr( + feature = "enable-rkyv", + derive(RkyvSerialize, RkyvDeserialize, Archive) +)] #[derive(Debug, PartialEq, Eq, Clone, MemoryUsage)] pub struct Dwarf { /// The section index in the [`Compilation`] that corresponds to the exception frames. diff --git a/lib/compiler/src/jump_table.rs b/lib/compiler/src/jump_table.rs index 25fdbb60c08..5fc7551bb6b 100644 --- a/lib/compiler/src/jump_table.rs +++ b/lib/compiler/src/jump_table.rs @@ -6,6 +6,8 @@ use super::CodeOffset; use loupe::MemoryUsage; +#[cfg(feature = "enable-rkyv")] +use rkyv::{Archive, Deserialize as RkyvDeserialize, Serialize as RkyvSerialize}; #[cfg(feature = "enable-serde")] use serde::{Deserialize, Serialize}; use wasmer_types::entity::{entity_impl, SecondaryMap}; @@ -15,6 +17,10 @@ use wasmer_types::entity::{entity_impl, SecondaryMap}; /// `JumpTable`s are used for indirect branching and are specialized for dense, /// 0-based jump offsets. #[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))] +#[cfg_attr( + feature = "enable-rkyv", + derive(RkyvSerialize, RkyvDeserialize, Archive) +)] #[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, MemoryUsage)] pub struct JumpTable(u32); diff --git a/lib/compiler/src/relocation.rs b/lib/compiler/src/relocation.rs index 25cec340ad9..1a02c9198a0 100644 --- a/lib/compiler/src/relocation.rs +++ b/lib/compiler/src/relocation.rs @@ -14,6 +14,8 @@ use crate::lib::std::vec::Vec; use crate::section::SectionIndex; use crate::{Addend, CodeOffset, JumpTable}; use loupe::MemoryUsage; +#[cfg(feature = "enable-rkyv")] +use rkyv::{Archive, Deserialize as RkyvDeserialize, Serialize as RkyvSerialize}; #[cfg(feature = "enable-serde")] use serde::{Deserialize, Serialize}; use wasmer_types::entity::PrimaryMap; @@ -22,6 +24,10 @@ use wasmer_vm::libcalls::LibCall; /// Relocation kinds for every ISA. #[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))] +#[cfg_attr( + feature = "enable-rkyv", + derive(RkyvSerialize, RkyvDeserialize, Archive) +)] #[derive(Copy, Clone, Debug, PartialEq, Eq, MemoryUsage)] pub enum RelocationKind { /// absolute 4-byte @@ -80,6 +86,10 @@ impl fmt::Display for RelocationKind { /// A record of a relocation to perform. #[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))] +#[cfg_attr( + feature = "enable-rkyv", + derive(RkyvSerialize, RkyvDeserialize, Archive) +)] #[derive(Debug, Clone, PartialEq, Eq, MemoryUsage)] pub struct Relocation { /// The relocation kind. @@ -94,6 +104,10 @@ pub struct Relocation { /// Destination function. Can be either user function or some special one, like `memory.grow`. #[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))] +#[cfg_attr( + feature = "enable-rkyv", + derive(RkyvSerialize, RkyvDeserialize, Archive) +)] #[derive(Debug, Copy, Clone, PartialEq, Eq, MemoryUsage)] pub enum RelocationTarget { /// A relocation to a function defined locally in the wasm (not an imported one). diff --git a/lib/compiler/src/section.rs b/lib/compiler/src/section.rs index f6f3ee40484..98063705d99 100644 --- a/lib/compiler/src/section.rs +++ b/lib/compiler/src/section.rs @@ -8,21 +8,38 @@ use crate::lib::std::vec::Vec; use crate::Relocation; use loupe::MemoryUsage; +#[cfg(feature = "enable-rkyv")] +use rkyv::{Archive, Deserialize as RkyvDeserialize, Serialize as RkyvSerialize}; #[cfg(feature = "enable-serde")] use serde::{Deserialize, Serialize}; use wasmer_types::entity::entity_impl; /// Index type of a Section defined inside a WebAssembly `Compilation`. #[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))] +#[cfg_attr( + feature = "enable-rkyv", + derive(RkyvSerialize, RkyvDeserialize, Archive) +)] +#[cfg_attr( + feature = "enable-rkyv", + archive(derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug)) +)] #[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug, MemoryUsage)] pub struct SectionIndex(u32); entity_impl!(SectionIndex); +#[cfg(feature = "enable-rkyv")] +entity_impl!(ArchivedSectionIndex); + /// Custom section Protection. /// /// Determines how a custom section may be used. #[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))] +#[cfg_attr( + feature = "enable-rkyv", + derive(RkyvSerialize, RkyvDeserialize, Archive) +)] #[derive(Debug, Clone, PartialEq, Eq, MemoryUsage)] pub enum CustomSectionProtection { /// A custom section with read permission. @@ -37,6 +54,10 @@ pub enum CustomSectionProtection { /// This is used so compilers can store arbitrary information /// in the emitted module. #[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))] +#[cfg_attr( + feature = "enable-rkyv", + derive(RkyvSerialize, RkyvDeserialize, Archive) +)] #[derive(Debug, Clone, PartialEq, Eq, MemoryUsage)] pub struct CustomSection { /// Memory protection that applies to this section. @@ -56,6 +77,10 @@ pub struct CustomSection { /// The bytes in the section. #[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))] +#[cfg_attr( + feature = "enable-rkyv", + derive(RkyvSerialize, RkyvDeserialize, Archive) +)] #[derive(Debug, Clone, PartialEq, Eq, Default, MemoryUsage)] pub struct SectionBody(#[cfg_attr(feature = "enable-serde", serde(with = "serde_bytes"))] Vec); diff --git a/lib/compiler/src/sourceloc.rs b/lib/compiler/src/sourceloc.rs index fa61e4ab897..5874cd4f4db 100644 --- a/lib/compiler/src/sourceloc.rs +++ b/lib/compiler/src/sourceloc.rs @@ -9,6 +9,8 @@ use crate::lib::std::fmt; use loupe::MemoryUsage; +#[cfg(feature = "enable-rkyv")] +use rkyv::{Archive, Deserialize as RkyvDeserialize, Serialize as RkyvSerialize}; #[cfg(feature = "enable-serde")] use serde::{Deserialize, Serialize}; @@ -21,6 +23,10 @@ use serde::{Deserialize, Serialize}; derive(Serialize, Deserialize), serde(transparent) )] +#[cfg_attr( + feature = "enable-rkyv", + derive(RkyvSerialize, RkyvDeserialize, Archive) +)] #[repr(transparent)] #[derive(Debug, Clone, Copy, PartialEq, Eq, MemoryUsage)] pub struct SourceLoc(u32); diff --git a/lib/compiler/src/trap.rs b/lib/compiler/src/trap.rs index 80aecc73a3b..2d016c13122 100644 --- a/lib/compiler/src/trap.rs +++ b/lib/compiler/src/trap.rs @@ -1,11 +1,17 @@ use crate::CodeOffset; use loupe::MemoryUsage; +#[cfg(feature = "enable-rkyv")] +use rkyv::{Archive, Deserialize as RkyvDeserialize, Serialize as RkyvSerialize}; #[cfg(feature = "enable-serde")] use serde::{Deserialize, Serialize}; use wasmer_vm::TrapCode; /// Information about trap. #[cfg_attr(feature = "enable-serde", derive(Deserialize, Serialize))] +#[cfg_attr( + feature = "enable-rkyv", + derive(RkyvSerialize, RkyvDeserialize, Archive) +)] #[derive(Clone, Debug, PartialEq, Eq, MemoryUsage)] pub struct TrapInformation { /// The offset of the trapping instruction in native code. It is relative to the beginning of the function. diff --git a/lib/compiler/src/unwind.rs b/lib/compiler/src/unwind.rs index 128c300deab..ec344a9c15e 100644 --- a/lib/compiler/src/unwind.rs +++ b/lib/compiler/src/unwind.rs @@ -7,6 +7,8 @@ //! [Learn more](https://en.wikipedia.org/wiki/Call_stack). use crate::lib::std::vec::Vec; use loupe::MemoryUsage; +#[cfg(feature = "enable-rkyv")] +use rkyv::{Archive, Deserialize as RkyvDeserialize, Serialize as RkyvSerialize}; #[cfg(feature = "enable-serde")] use serde::{Deserialize, Serialize}; @@ -18,6 +20,10 @@ use serde::{Deserialize, Serialize}; /// /// [unwind info]: https://docs.microsoft.com/en-us/cpp/build/exception-handling-x64?view=vs-2019 #[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))] +#[cfg_attr( + feature = "enable-rkyv", + derive(RkyvSerialize, RkyvDeserialize, Archive) +)] #[derive(Debug, Clone, PartialEq, Eq, MemoryUsage)] pub enum CompiledFunctionUnwindInfo { /// Windows UNWIND_INFO. diff --git a/lib/engine-jit/Cargo.toml b/lib/engine-jit/Cargo.toml index 519a324c7ac..6c78894b207 100644 --- a/lib/engine-jit/Cargo.toml +++ b/lib/engine-jit/Cargo.toml @@ -11,16 +11,16 @@ readme = "README.md" edition = "2018" [dependencies] -wasmer-types = { path = "../types", version = "1.0.2" } -wasmer-compiler = { path = "../compiler", version = "1.0.2", features = ["translator"] } -wasmer-vm = { path = "../vm", version = "1.0.2" } +wasmer-types = { path = "../types", version = "1.0.2", features = ["enable-rkyv"] } +wasmer-compiler = { path = "../compiler", version = "1.0.2", features = ["translator", "enable-rkyv"] } +wasmer-vm = { path = "../vm", version = "1.0.2", features = ["enable-rkyv"] } wasmer-engine = { path = "../engine", version = "1.0.2" } # flexbuffers = { path = "../../../flatbuffers/rust/flexbuffers", version = "0.1.0" } region = "2.2" serde = { version = "1.0", features = ["derive", "rc"] } -serde_bytes = { version = "0.11" } -bincode = "1.3" cfg-if = "0.1" +leb128 = "0.2" +rkyv = "0.4.3" loupe = "0.1" [target.'cfg(target_os = "windows")'.dependencies] diff --git a/lib/engine-jit/src/artifact.rs b/lib/engine-jit/src/artifact.rs index 68f168ae6a3..993730e2c3b 100644 --- a/lib/engine-jit/src/artifact.rs +++ b/lib/engine-jit/src/artifact.rs @@ -137,20 +137,25 @@ impl JITArtifact { } /// Deserialize a JITArtifact - pub fn deserialize(jit: &JITEngine, bytes: &[u8]) -> Result { + pub unsafe fn deserialize(jit: &JITEngine, bytes: &[u8]) -> Result { if !Self::is_deserializable(bytes) { return Err(DeserializeError::Incompatible( "The provided bytes are not wasmer-jit".to_string(), )); } - let inner_bytes = &bytes[Self::MAGIC_HEADER.len()..]; + let mut inner_bytes = &bytes[Self::MAGIC_HEADER.len()..]; // let r = flexbuffers::Reader::get_root(bytes).map_err(|e| DeserializeError::CorruptedBinary(format!("{:?}", e)))?; // let serializable = SerializableModule::deserialize(r).map_err(|e| DeserializeError::CorruptedBinary(format!("{:?}", e)))?; - let serializable: SerializableModule = bincode::deserialize(inner_bytes) - .map_err(|e| DeserializeError::CorruptedBinary(format!("{:?}", e)))?; + let metadata_len = leb128::read::unsigned(&mut inner_bytes).map_err(|_e| { + DeserializeError::CorruptedBinary("Can't read metadata size".to_string()) + })?; + let metadata_slice: &'static [u8] = + std::slice::from_raw_parts(&inner_bytes[16] as *const u8, metadata_len as usize); + + let serializable = SerializableModule::deserialize(metadata_slice)?; Self::from_parts(&mut jit.inner_mut(), serializable).map_err(DeserializeError::Compiler) } @@ -321,15 +326,18 @@ impl Artifact for JITArtifact { &self.func_data_registry } fn serialize(&self) -> Result, SerializeError> { - // let mut s = flexbuffers::FlexbufferSerializer::new(); - // self.serializable.serialize(&mut s).map_err(|e| SerializeError::Generic(format!("{:?}", e))); - // Ok(s.take_buffer()) - let bytes = bincode::serialize(&self.serializable) - .map_err(|e| SerializeError::Generic(format!("{:?}", e)))?; - // Prepend the header. let mut serialized = Self::MAGIC_HEADER.to_vec(); - serialized.extend(bytes); + + let serialized_data = self.serializable.serialize()?; + + let mut metadata_binary = vec![0; 16]; + let mut writable = &mut metadata_binary[..]; + leb128::write::unsigned(&mut writable, serialized_data.len() as u64) + .expect("Should write number"); + metadata_binary.extend(serialized_data); + + serialized.extend(metadata_binary); Ok(serialized) } } diff --git a/lib/engine-jit/src/serialize.rs b/lib/engine-jit/src/serialize.rs index 7109be6b246..0c1fcf75eed 100644 --- a/lib/engine-jit/src/serialize.rs +++ b/lib/engine-jit/src/serialize.rs @@ -1,24 +1,22 @@ use loupe::MemoryUsage; +use rkyv::{ + archived_value, + de::{adapters::SharedDeserializerAdapter, deserializers::AllocDeserializer}, + ser::adapters::SharedSerializerAdapter, + ser::{serializers::WriteSerializer, Serializer as RkyvSerializer}, + Archive, Deserialize as RkyvDeserialize, Serialize as RkyvSerialize, +}; use serde::{Deserialize, Serialize}; use wasmer_compiler::{ - CompileModuleInfo, CompiledFunctionFrameInfo, CustomSection, Dwarf, FunctionBody, + CompileError, CompileModuleInfo, CompiledFunctionFrameInfo, CustomSection, Dwarf, FunctionBody, JumpTableOffsets, Relocation, SectionIndex, }; +use wasmer_engine::{DeserializeError, SerializeError}; use wasmer_types::entity::PrimaryMap; use wasmer_types::{FunctionIndex, LocalFunctionIndex, OwnedDataInitializer, SignatureIndex}; -// /// The serializable function data -// #[derive(Serialize, Deserialize)] -// pub struct SerializableFunction { -// #[serde(with = "serde_bytes")] -// pub body: &[u8], -// /// The unwind info for Windows -// #[serde(with = "serde_bytes")] -// pub windows_unwind_info: &[u8], -// } - /// The compilation related data for a serialized modules -#[derive(Serialize, Deserialize, MemoryUsage)] +#[derive(Serialize, Deserialize, MemoryUsage, Archive, RkyvDeserialize, RkyvSerialize)] pub struct SerializableCompilation { pub function_bodies: PrimaryMap, pub function_relocations: PrimaryMap>, @@ -34,9 +32,61 @@ pub struct SerializableCompilation { /// Serializable struct that is able to serialize from and to /// a `JITArtifactInfo`. -#[derive(Serialize, Deserialize, MemoryUsage)] +#[derive(Serialize, Deserialize, MemoryUsage, Archive, RkyvDeserialize, RkyvSerialize)] pub struct SerializableModule { pub compilation: SerializableCompilation, pub compile_info: CompileModuleInfo, pub data_initializers: Box<[OwnedDataInitializer]>, } + +fn to_serialize_error(err: impl std::error::Error) -> SerializeError { + SerializeError::Generic(format!("{}", err)) +} + +impl SerializableModule { + pub fn serialize(&self) -> Result, SerializeError> { + let mut serializer = SharedSerializerAdapter::new(WriteSerializer::new(vec![])); + let pos = serializer + .serialize_value(self) + .map_err(to_serialize_error)? as u64; + let mut serialized_data = serializer.into_inner().into_inner(); + serialized_data.extend_from_slice(&pos.to_le_bytes()); + if cfg!(target_endian = "big") { + serialized_data.extend_from_slice(&[b'b']); + } else if cfg!(target_endian = "little") { + serialized_data.extend_from_slice(&[b'l']); + } + Ok(serialized_data) + } + + pub unsafe fn deserialize(metadata_slice: &[u8]) -> Result { + let archived = Self::archive_from_slice(metadata_slice)?; + Self::deserialize_from_archive(archived) + } + + unsafe fn archive_from_slice<'a>( + metadata_slice: &'a [u8], + ) -> Result<&'a ArchivedSerializableModule, DeserializeError> { + let mut pos: [u8; 8] = Default::default(); + let endian = metadata_slice[metadata_slice.len() - 1]; + if (cfg!(target_endian = "big") && endian == b'l') + || (cfg!(target_endian = "little") && endian == b'b') + { + return Err(DeserializeError::Incompatible("incompatible endian".into())); + } + pos.copy_from_slice(&metadata_slice[metadata_slice.len() - 9..metadata_slice.len() - 1]); + let pos: u64 = u64::from_le_bytes(pos); + Ok(archived_value::( + &metadata_slice[..metadata_slice.len() - 9], + pos as usize, + )) + } + + pub fn deserialize_from_archive( + archived: &ArchivedSerializableModule, + ) -> Result { + let mut deserializer = SharedDeserializerAdapter::new(AllocDeserializer); + RkyvDeserialize::deserialize(archived, &mut deserializer) + .map_err(|e| DeserializeError::CorruptedBinary(format!("{:?}", e))) + } +} diff --git a/lib/types/src/archives.rs b/lib/types/src/archives.rs index ce9e40cad25..0b9e04b7b4b 100644 --- a/lib/types/src/archives.rs +++ b/lib/types/src/archives.rs @@ -1,4 +1,4 @@ -use crate::entity::{EntityRef, PrimaryMap}; +use crate::entity::{EntityRef, PrimaryMap, SecondaryMap}; use indexmap::IndexMap; use rkyv::{ @@ -55,6 +55,51 @@ where } } +/// SecondaryMap after archive +// pub struct ArchivedSecondaryMap(ArchivedVec, V, PhantomData); + +// impl Archive for SecondaryMap +// where +// K::Archived: EntityRef, +// V::Archived: Clone, +// { +// type Archived = ArchivedSecondaryMap; +// type Resolver = VecResolver>; + +// fn resolve(&self, pos: usize, resolver: Self::Resolver) -> Self::Archived { +// ArchivedSecondaryMap(Vec::resolve(&self.elems, pos, resolver), V::resolve(&self.default, pos, resolver), PhantomData) +// } +// } + +// impl + EntityRef, V: Serialize + Clone, S: Serializer + ?Sized> Serialize +// for SecondaryMap +// where +// K::Archived: EntityRef, +// V::Archived: Clone, +// { +// fn serialize(&self, serializer: &mut S) -> Result { +// self.elems.serialize(serializer) +// } +// } + +// impl Deserialize, D> +// for Archived> +// where +// K::Archived: Deserialize + EntityRef, +// V::Archived: Deserialize + Clone, +// [V::Archived]: DeserializeUnsized<[V], D>, +// { +// fn deserialize(&self, deserializer: &mut D) -> Result, D::Error> { +// let elems: Vec<_> = self.0.deserialize(deserializer)?; +// let default = self.1.deserialize(deserializer)?; +// Ok(SecondaryMap { +// elems, +// default, +// unused: PhantomData, +// }) +// } +// } + #[derive(Serialize, Deserialize, Archive)] /// Rkyv Archivable IndexMap pub struct ArchivableIndexMap { diff --git a/lib/types/src/entity/secondary_map.rs b/lib/types/src/entity/secondary_map.rs index ac19c432fb7..afd84b54133 100644 --- a/lib/types/src/entity/secondary_map.rs +++ b/lib/types/src/entity/secondary_map.rs @@ -12,6 +12,8 @@ use crate::lib::std::ops::{Index, IndexMut}; use crate::lib::std::slice; use crate::lib::std::vec::Vec; use loupe::{MemoryUsage, MemoryUsageTracker}; +#[cfg(feature = "enable-rkyv")] +use rkyv::{Archive, Deserialize as RkyvDeserialize, Serialize as RkyvSerialize}; #[cfg(feature = "enable-serde")] use serde::{ de::{Deserializer, SeqAccess, Visitor}, @@ -29,14 +31,18 @@ use std::mem; /// The map does not track if an entry for a key has been inserted or not. Instead it behaves as if /// all keys have a default entry from the beginning. #[derive(Debug, Clone)] +#[cfg_attr( + feature = "enable-rkyv", + derive(RkyvSerialize, RkyvDeserialize, Archive) +)] pub struct SecondaryMap where K: EntityRef, V: Clone, { - elems: Vec, - default: V, - unused: PhantomData, + pub(crate) elems: Vec, + pub(crate) default: V, + pub(crate) unused: PhantomData, } /// Shared `SecondaryMap` implementation for all value types. diff --git a/lib/types/src/lib.rs b/lib/types/src/lib.rs index 6cd30d2a9c6..f7e73b82ca3 100644 --- a/lib/types/src/lib.rs +++ b/lib/types/src/lib.rs @@ -90,7 +90,7 @@ pub use types::{ }; #[cfg(feature = "enable-rkyv")] -pub use archives::{ArchivableIndexMap, ArchivedPrimaryMap}; +pub use archives::{ArchivableIndexMap, ArchivedPrimaryMap}; // ArchivedSecondaryMap /// Version number of this crate. pub const VERSION: &str = env!("CARGO_PKG_VERSION"); diff --git a/lib/vm/src/lib.rs b/lib/vm/src/lib.rs index a7f099385e8..ce24381cc8d 100644 --- a/lib/vm/src/lib.rs +++ b/lib/vm/src/lib.rs @@ -1,6 +1,6 @@ //! Runtime library support for Wasmer. -#![deny(missing_docs, trivial_numeric_casts, unused_extern_crates)] +#![deny(trivial_numeric_casts, unused_extern_crates)] #![warn(unused_import_braces)] #![cfg_attr( feature = "cargo-clippy", diff --git a/lib/vm/src/libcalls.rs b/lib/vm/src/libcalls.rs index f03fc244719..39ae8224ac8 100644 --- a/lib/vm/src/libcalls.rs +++ b/lib/vm/src/libcalls.rs @@ -42,6 +42,8 @@ use crate::trap::{raise_lib_trap, Trap, TrapCode}; use crate::vmcontext::VMContext; use crate::VMExternRef; use loupe::MemoryUsage; +#[cfg(feature = "enable-rkyv")] +use rkyv::{Archive, Deserialize as RkyvDeserialize, Serialize as RkyvSerialize}; use serde::{Deserialize, Serialize}; use std::fmt; use wasmer_types::{ @@ -681,6 +683,10 @@ pub static wasmer_vm_probestack: unsafe extern "C" fn() = PROBESTACK; /// /// This list is likely to grow over time. #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize, MemoryUsage)] +#[cfg_attr( + feature = "enable-rkyv", + derive(RkyvSerialize, RkyvDeserialize, Archive) +)] pub enum LibCall { /// ceil.f32 CeilF32, diff --git a/lib/vm/src/trap/trapcode.rs b/lib/vm/src/trap/trapcode.rs index ee3e910fb1b..e262a30cf88 100644 --- a/lib/vm/src/trap/trapcode.rs +++ b/lib/vm/src/trap/trapcode.rs @@ -6,6 +6,8 @@ use core::fmt::{self, Display, Formatter}; use core::str::FromStr; use loupe::MemoryUsage; +#[cfg(feature = "enable-rkyv")] +use rkyv::{Archive, Deserialize as RkyvDeserialize, Serialize as RkyvSerialize}; use serde::{Deserialize, Serialize}; use thiserror::Error; @@ -13,6 +15,10 @@ use thiserror::Error; /// /// All trap instructions have an explicit trap code. #[derive(Clone, Copy, PartialEq, Eq, Debug, Hash, Serialize, Deserialize, Error, MemoryUsage)] +#[cfg_attr( + feature = "enable-rkyv", + derive(RkyvSerialize, RkyvDeserialize, Archive) +)] #[repr(u32)] pub enum TrapCode { /// The current stack space was exhausted. From ea3640e91bbf3a6af4730441b86af478d87d747b Mon Sep 17 00:00:00 2001 From: Syrus Akbary Date: Thu, 29 Apr 2021 02:26:37 -0700 Subject: [PATCH 05/22] Set engine jit to use rkyv --- lib/engine-jit/src/artifact.rs | 37 ++++++++++++++++++++++--------- lib/engine-native/src/artifact.rs | 8 +++---- 2 files changed, 30 insertions(+), 15 deletions(-) diff --git a/lib/engine-jit/src/artifact.rs b/lib/engine-jit/src/artifact.rs index 993730e2c3b..fa40ff35c19 100644 --- a/lib/engine-jit/src/artifact.rs +++ b/lib/engine-jit/src/artifact.rs @@ -42,7 +42,7 @@ pub struct JITArtifact { } impl JITArtifact { - const MAGIC_HEADER: &'static [u8] = b"\0wasmer-jit"; + const MAGIC_HEADER: &'static [u8; 16] = b"\0wasmer-jit\0\0\0\0\0"; /// Check if the provided bytes look like a serialized `JITArtifact`. pub fn is_deserializable(bytes: &[u8]) -> bool { @@ -146,14 +146,15 @@ impl JITArtifact { let mut inner_bytes = &bytes[Self::MAGIC_HEADER.len()..]; - // let r = flexbuffers::Reader::get_root(bytes).map_err(|e| DeserializeError::CorruptedBinary(format!("{:?}", e)))?; - // let serializable = SerializableModule::deserialize(r).map_err(|e| DeserializeError::CorruptedBinary(format!("{:?}", e)))?; - let metadata_len = leb128::read::unsigned(&mut inner_bytes).map_err(|_e| { DeserializeError::CorruptedBinary("Can't read metadata size".to_string()) })?; let metadata_slice: &'static [u8] = - std::slice::from_raw_parts(&inner_bytes[16] as *const u8, metadata_len as usize); + std::slice::from_raw_parts(&inner_bytes[12] as *const u8, metadata_len as usize); + + let length = metadata_slice.len(); + // println!("[DES] Metadata: First 16 bytes {:?}.\nLast 16 bytes: {:?}\nTotal length: {}", &metadata_slice[..16], &metadata_slice[length-16..], length); + // println!("[DES] First 50 bytes {:?}.\nLast 50 bytes: {:?}", &bytes[..50], &bytes[inner_bytes.len()-50..]); let serializable = SerializableModule::deserialize(metadata_slice)?; @@ -329,15 +330,29 @@ impl Artifact for JITArtifact { // Prepend the header. let mut serialized = Self::MAGIC_HEADER.to_vec(); - let serialized_data = self.serializable.serialize()?; - - let mut metadata_binary = vec![0; 16]; + let mut metadata_binary = vec![0; 12]; let mut writable = &mut metadata_binary[..]; - leb128::write::unsigned(&mut writable, serialized_data.len() as u64) - .expect("Should write number"); - metadata_binary.extend(serialized_data); + let serialized_data = self.serializable.serialize()?; + let length = serialized_data.len(); + leb128::write::unsigned(&mut writable, length as u64).expect("Should write number"); serialized.extend(metadata_binary); + + let align = std::mem::align_of::() as u64; + // println!("[SER] Metadata: First 16 bytes {:?}.\nLast 16 bytes: {:?}\nTotal length: {}", &serialized_data[..16], &serialized_data[length-16..], length); + let (serialized, offset) = append_data(serialized, &serialized_data, align); + // println!("[SER] First 50 bytes {:?}.\nAlign: {} - Offset: {}\nLast 50 bytes: {:?}", &serialized[..50], align, offset, &serialized[serialized.len()-50..]); Ok(serialized) } } + +pub fn append_data(mut prev_data: Vec, data: &[u8], align: u64) -> (Vec, u64) { + let align = align as usize; + let mut offset = prev_data.len(); + if offset & (align - 1) != 0 { + offset += align - (offset & (align - 1)); + prev_data.resize(offset, 0); + } + prev_data.extend(data); + (prev_data, offset as u64) +} diff --git a/lib/engine-native/src/artifact.rs b/lib/engine-native/src/artifact.rs index 06cfd2fe465..c95e70e8e5f 100644 --- a/lib/engine-native/src/artifact.rs +++ b/lib/engine-native/src/artifact.rs @@ -195,7 +195,7 @@ impl NativeArtifact { let serialized_data = metadata.serialize()?; - let mut metadata_binary = vec![0; 16]; + let mut metadata_binary = vec![0; 12]; let mut writable = &mut metadata_binary[..]; leb128::write::unsigned(&mut writable, serialized_data.len() as u64) .expect("Should write number"); @@ -543,11 +543,11 @@ impl NativeArtifact { DeserializeError::CorruptedBinary(format!("Library loading failed: {}", e)) })?; let shared_path: PathBuf = PathBuf::from(path); - // We use 16 + 1, as the length of the module will take 16 bytes + // We use 12 + 1, as the length of the module will take 12 bytes // (we construct it like that in `metadata_length`) and we also want // to take the first element of the data to construct the slice from // it. - let symbol: LibrarySymbol<*mut [u8; 16 + 1]> = + let symbol: LibrarySymbol<*mut [u8; 12 + 1]> = lib.get(WASMER_METADATA_SYMBOL).map_err(|e| { DeserializeError::CorruptedBinary(format!( "The provided object file doesn't seem to be generated by Wasmer: {}", @@ -563,7 +563,7 @@ impl NativeArtifact { DeserializeError::CorruptedBinary("Can't read metadata size".to_string()) })?; let metadata_slice: &'static [u8] = - slice::from_raw_parts(&size[16] as *const u8, metadata_len as usize); + slice::from_raw_parts(&size[12] as *const u8, metadata_len as usize); let metadata = ModuleMetadata::deserialize(metadata_slice)?; From fd86341ba261eb5ae3626c8799127448f6fb731d Mon Sep 17 00:00:00 2001 From: Syrus Akbary Date: Thu, 29 Apr 2021 13:06:21 -0700 Subject: [PATCH 06/22] Deleted unused code --- lib/types/src/archives.rs | 44 --------------------------------------- lib/types/src/lib.rs | 2 +- 2 files changed, 1 insertion(+), 45 deletions(-) diff --git a/lib/types/src/archives.rs b/lib/types/src/archives.rs index 611b99dfa9a..1f45fea83ec 100644 --- a/lib/types/src/archives.rs +++ b/lib/types/src/archives.rs @@ -61,50 +61,6 @@ where } } -/// SecondaryMap after archive -// pub struct ArchivedSecondaryMap(ArchivedVec, V, PhantomData); - -// impl Archive for SecondaryMap -// where -// K::Archived: EntityRef, -// V::Archived: Clone, -// { -// type Archived = ArchivedSecondaryMap; -// type Resolver = VecResolver>; - -// fn resolve(&self, pos: usize, resolver: Self::Resolver) -> Self::Archived { -// ArchivedSecondaryMap(Vec::resolve(&self.elems, pos, resolver), V::resolve(&self.default, pos, resolver), PhantomData) -// } -// } - -// impl + EntityRef, V: Serialize + Clone, S: Serializer + ?Sized> Serialize -// for SecondaryMap -// where -// K::Archived: EntityRef, -// V::Archived: Clone, -// { -// fn serialize(&self, serializer: &mut S) -> Result { -// self.elems.serialize(serializer) -// } -// } - -// impl Deserialize, D> -// for Archived> -// where -// K::Archived: Deserialize + EntityRef, -// V::Archived: Deserialize + Clone, -// [V::Archived]: DeserializeUnsized<[V], D>, -// { -// fn deserialize(&self, deserializer: &mut D) -> Result, D::Error> { -// let elems: Vec<_> = self.0.deserialize(deserializer)?; -// let default = self.1.deserialize(deserializer)?; -// Ok(SecondaryMap { -// elems, -// default, -// unused: PhantomData, -// }) -// } -// } #[derive(Serialize, Deserialize, Archive)] /// Rkyv Archivable IndexMap diff --git a/lib/types/src/lib.rs b/lib/types/src/lib.rs index f7e73b82ca3..6cd30d2a9c6 100644 --- a/lib/types/src/lib.rs +++ b/lib/types/src/lib.rs @@ -90,7 +90,7 @@ pub use types::{ }; #[cfg(feature = "enable-rkyv")] -pub use archives::{ArchivableIndexMap, ArchivedPrimaryMap}; // ArchivedSecondaryMap +pub use archives::{ArchivableIndexMap, ArchivedPrimaryMap}; /// Version number of this crate. pub const VERSION: &str = env!("CARGO_PKG_VERSION"); From 4f3aecd66d50191c5ed523343ac80d0869a7cb50 Mon Sep 17 00:00:00 2001 From: Syrus Akbary Date: Thu, 29 Apr 2021 14:32:01 -0700 Subject: [PATCH 07/22] Fixed comments --- lib/engine-jit/Cargo.toml | 2 +- lib/engine-jit/src/artifact.rs | 13 ++++++++++--- lib/engine-jit/src/serialize.rs | 2 +- lib/types/src/archives.rs | 3 +-- lib/vm/src/lib.rs | 1 + lib/vm/src/libcalls.rs | 4 +++- 6 files changed, 17 insertions(+), 8 deletions(-) diff --git a/lib/engine-jit/Cargo.toml b/lib/engine-jit/Cargo.toml index 6c78894b207..cf15ec83bb1 100644 --- a/lib/engine-jit/Cargo.toml +++ b/lib/engine-jit/Cargo.toml @@ -20,7 +20,7 @@ region = "2.2" serde = { version = "1.0", features = ["derive", "rc"] } cfg-if = "0.1" leb128 = "0.2" -rkyv = "0.4.3" +rkyv = "0.6" loupe = "0.1" [target.'cfg(target_os = "windows")'.dependencies] diff --git a/lib/engine-jit/src/artifact.rs b/lib/engine-jit/src/artifact.rs index fa40ff35c19..300e26474a3 100644 --- a/lib/engine-jit/src/artifact.rs +++ b/lib/engine-jit/src/artifact.rs @@ -137,6 +137,10 @@ impl JITArtifact { } /// Deserialize a JITArtifact + /// + /// # Safety + /// This function is unsafe because rkyv reads directly without validating + /// the data. pub unsafe fn deserialize(jit: &JITEngine, bytes: &[u8]) -> Result { if !Self::is_deserializable(bytes) { return Err(DeserializeError::Incompatible( @@ -340,13 +344,16 @@ impl Artifact for JITArtifact { let align = std::mem::align_of::() as u64; // println!("[SER] Metadata: First 16 bytes {:?}.\nLast 16 bytes: {:?}\nTotal length: {}", &serialized_data[..16], &serialized_data[length-16..], length); - let (serialized, offset) = append_data(serialized, &serialized_data, align); // println!("[SER] First 50 bytes {:?}.\nAlign: {} - Offset: {}\nLast 50 bytes: {:?}", &serialized[..50], align, offset, &serialized[serialized.len()-50..]); + let _offset = pad_and_extend(&mut serialized, &serialized_data, 1); Ok(serialized) } } -pub fn append_data(mut prev_data: Vec, data: &[u8], align: u64) -> (Vec, u64) { +/// It pads the data with the desired alignment +pub fn pad_and_extend(prev_data: &mut Vec, data: &[u8], align: u64) -> u64 { + // We assert that align is a power of 2 + debug_assert_eq!(align & (align - 1), 0); let align = align as usize; let mut offset = prev_data.len(); if offset & (align - 1) != 0 { @@ -354,5 +361,5 @@ pub fn append_data(mut prev_data: Vec, data: &[u8], align: u64) -> (Vec, prev_data.resize(offset, 0); } prev_data.extend(data); - (prev_data, offset as u64) + offset as u64 } diff --git a/lib/engine-jit/src/serialize.rs b/lib/engine-jit/src/serialize.rs index 0c1fcf75eed..70f2edd931e 100644 --- a/lib/engine-jit/src/serialize.rs +++ b/lib/engine-jit/src/serialize.rs @@ -8,7 +8,7 @@ use rkyv::{ }; use serde::{Deserialize, Serialize}; use wasmer_compiler::{ - CompileError, CompileModuleInfo, CompiledFunctionFrameInfo, CustomSection, Dwarf, FunctionBody, + CompileModuleInfo, CompiledFunctionFrameInfo, CustomSection, Dwarf, FunctionBody, JumpTableOffsets, Relocation, SectionIndex, }; use wasmer_engine::{DeserializeError, SerializeError}; diff --git a/lib/types/src/archives.rs b/lib/types/src/archives.rs index 1f45fea83ec..56f5aa5c9de 100644 --- a/lib/types/src/archives.rs +++ b/lib/types/src/archives.rs @@ -1,4 +1,4 @@ -use crate::entity::{EntityRef, PrimaryMap, SecondaryMap}; +use crate::entity::{EntityRef, PrimaryMap}; use indexmap::IndexMap; use rkyv::{ @@ -61,7 +61,6 @@ where } } - #[derive(Serialize, Deserialize, Archive)] /// Rkyv Archivable IndexMap pub struct ArchivableIndexMap { diff --git a/lib/vm/src/lib.rs b/lib/vm/src/lib.rs index ce24381cc8d..dc4a1d8f2fb 100644 --- a/lib/vm/src/lib.rs +++ b/lib/vm/src/lib.rs @@ -1,5 +1,6 @@ //! Runtime library support for Wasmer. +#![deny(missing_docs, trivial_numeric_casts, unused_extern_crates)] #![deny(trivial_numeric_casts, unused_extern_crates)] #![warn(unused_import_braces)] #![cfg_attr( diff --git a/lib/vm/src/libcalls.rs b/lib/vm/src/libcalls.rs index 39ae8224ac8..1d74e9abc9c 100644 --- a/lib/vm/src/libcalls.rs +++ b/lib/vm/src/libcalls.rs @@ -35,6 +35,8 @@ //! } //! ``` +#![allow(missing_docs)] // For some reason lint fails saying that `LibCall` is not documented, when it actually is + use crate::func_data_registry::VMFuncRef; use crate::probestack::PROBESTACK; use crate::table::{RawTableElement, TableElement}; @@ -682,11 +684,11 @@ pub static wasmer_vm_probestack: unsafe extern "C" fn() = PROBESTACK; /// The name of a runtime library routine. /// /// This list is likely to grow over time. -#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize, MemoryUsage)] #[cfg_attr( feature = "enable-rkyv", derive(RkyvSerialize, RkyvDeserialize, Archive) )] +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize, MemoryUsage)] pub enum LibCall { /// ceil.f32 CeilF32, From 0880913eb89cf41152ac9e86dbf14b5724c3bda8 Mon Sep 17 00:00:00 2001 From: Syrus Akbary Date: Thu, 29 Apr 2021 15:08:13 -0700 Subject: [PATCH 08/22] More debug --- lib/engine-jit/src/artifact.rs | 27 +++++++++++++++------------ 1 file changed, 15 insertions(+), 12 deletions(-) diff --git a/lib/engine-jit/src/artifact.rs b/lib/engine-jit/src/artifact.rs index 300e26474a3..e78b76d461c 100644 --- a/lib/engine-jit/src/artifact.rs +++ b/lib/engine-jit/src/artifact.rs @@ -148,20 +148,23 @@ impl JITArtifact { )); } - let mut inner_bytes = &bytes[Self::MAGIC_HEADER.len()..]; + println!("[DES] Total length: {}", bytes.len()); + let mut inner_bytes = &bytes[16..]; let metadata_len = leb128::read::unsigned(&mut inner_bytes).map_err(|_e| { DeserializeError::CorruptedBinary("Can't read metadata size".to_string()) })?; let metadata_slice: &'static [u8] = - std::slice::from_raw_parts(&inner_bytes[12] as *const u8, metadata_len as usize); + std::slice::from_raw_parts(&bytes[32] as *const u8, metadata_len as usize); + + println!("Pointer position {:?}", &bytes[32] as *const u8); let length = metadata_slice.len(); - // println!("[DES] Metadata: First 16 bytes {:?}.\nLast 16 bytes: {:?}\nTotal length: {}", &metadata_slice[..16], &metadata_slice[length-16..], length); - // println!("[DES] First 50 bytes {:?}.\nLast 50 bytes: {:?}", &bytes[..50], &bytes[inner_bytes.len()-50..]); + println!("[DES] Metadata: First 16 bytes {:?}.\nLast 16 bytes: {:?}\nTotal length: {}", &metadata_slice[..16], &metadata_slice[length-16..], length); + println!("[DES] First 50 bytes {:?}.\nLast 50 bytes: {:?}", &bytes[..50], &bytes[bytes.len()-50..]); let serializable = SerializableModule::deserialize(metadata_slice)?; - + println!("[DES] success"); Self::from_parts(&mut jit.inner_mut(), serializable).map_err(DeserializeError::Compiler) } @@ -334,18 +337,18 @@ impl Artifact for JITArtifact { // Prepend the header. let mut serialized = Self::MAGIC_HEADER.to_vec(); - let mut metadata_binary = vec![0; 12]; - let mut writable = &mut metadata_binary[..]; + serialized.resize(32, 0); + let mut writable_leb = &mut serialized[16..]; let serialized_data = self.serializable.serialize()?; let length = serialized_data.len(); - leb128::write::unsigned(&mut writable, length as u64).expect("Should write number"); - - serialized.extend(metadata_binary); + leb128::write::unsigned(&mut writable_leb, length as u64).expect("Should write number"); let align = std::mem::align_of::() as u64; - // println!("[SER] Metadata: First 16 bytes {:?}.\nLast 16 bytes: {:?}\nTotal length: {}", &serialized_data[..16], &serialized_data[length-16..], length); - // println!("[SER] First 50 bytes {:?}.\nAlign: {} - Offset: {}\nLast 50 bytes: {:?}", &serialized[..50], align, offset, &serialized[serialized.len()-50..]); + println!("[SER] Metadata: First 16 bytes {:?}.\nLast 16 bytes: {:?}\nTotal length: {}", &serialized_data[..16], &serialized_data[length-16..], length); + let _offset = pad_and_extend(&mut serialized, &serialized_data, 1); + println!("[SER] First 50 bytes {:?}.\nAlign: {} - Offset: {}\nLast 50 bytes: {:?}", &serialized[..50], align, _offset, &serialized[serialized.len()-50..]); + println!("[SER] Total length: {}", serialized.len()); Ok(serialized) } } From 0435c3e211cd609785f20f53f85b26c685f570b7 Mon Sep 17 00:00:00 2001 From: Syrus Akbary Date: Thu, 29 Apr 2021 15:20:52 -0700 Subject: [PATCH 09/22] Make primarymap rkyv encoding the derived one --- lib/types/src/archives.rs | 64 ++--------------------------- lib/types/src/entity/primary_map.rs | 6 +++ 2 files changed, 10 insertions(+), 60 deletions(-) diff --git a/lib/types/src/archives.rs b/lib/types/src/archives.rs index 56f5aa5c9de..0a7d84a58ee 100644 --- a/lib/types/src/archives.rs +++ b/lib/types/src/archives.rs @@ -1,65 +1,9 @@ -use crate::entity::{EntityRef, PrimaryMap}; -use indexmap::IndexMap; - -use rkyv::{ - ser::Serializer, - std_impl::{ArchivedVec, VecResolver}, - Archive, Archived, Deserialize, DeserializeUnsized, Fallible, MetadataResolver, Serialize, -}; - #[cfg(feature = "core")] -use core::{hash::Hash, marker::PhantomData}; - +use core::hash::Hash; +use indexmap::IndexMap; +use rkyv::{Archive, Deserialize, Serialize}; #[cfg(feature = "std")] -use std::{collections::HashMap, hash::Hash, marker::PhantomData, mem::MaybeUninit}; - -/// PrimaryMap after archive -pub struct ArchivedPrimaryMap(ArchivedVec, PhantomData); - -impl Archive for PrimaryMap -where - K::Archived: EntityRef, -{ - type Archived = ArchivedPrimaryMap; - type Resolver = VecResolver>; - - fn resolve(&self, pos: usize, resolver: Self::Resolver, out: &mut MaybeUninit) { - let mut vec = MaybeUninit::uninit(); - Vec::resolve(&self.elems, pos, resolver, &mut vec); - // This is correct because the `resolve` method can never fail [citation needed] - let vec = unsafe { vec.assume_init() }; - let archived_primary_map = ArchivedPrimaryMap(vec, PhantomData); - unsafe { - out.as_mut_ptr().write(archived_primary_map); - } - } -} - -impl + EntityRef, V: Serialize, S: Serializer + ?Sized> Serialize - for PrimaryMap -where - K::Archived: EntityRef, -{ - fn serialize(&self, serializer: &mut S) -> Result { - self.elems.serialize(serializer) - } -} - -impl Deserialize, D> - for Archived> -where - K::Archived: Deserialize + EntityRef, - V::Archived: Deserialize, - [V::Archived]: DeserializeUnsized<[V], D>, -{ - fn deserialize(&self, deserializer: &mut D) -> Result, D::Error> { - let elems: Vec<_> = self.0.deserialize(deserializer)?; - Ok(PrimaryMap { - elems, - unused: PhantomData, - }) - } -} +use std::{collections::HashMap, hash::Hash}; #[derive(Serialize, Deserialize, Archive)] /// Rkyv Archivable IndexMap diff --git a/lib/types/src/entity/primary_map.rs b/lib/types/src/entity/primary_map.rs index a5827cad643..330db9e3f7c 100644 --- a/lib/types/src/entity/primary_map.rs +++ b/lib/types/src/entity/primary_map.rs @@ -13,6 +13,8 @@ use crate::lib::std::ops::{Index, IndexMut}; use crate::lib::std::slice; use crate::lib::std::vec::Vec; use loupe::{MemoryUsage, MemoryUsageTracker}; +#[cfg(feature = "enable-rkyv")] +use rkyv::{Archive, Deserialize as RkyvDeserialize, Serialize as RkyvSerialize}; #[cfg(feature = "enable-serde")] use serde::{Deserialize, Serialize}; use std::mem; @@ -34,6 +36,10 @@ use std::mem; /// `into_boxed_slice`. #[derive(Debug, Clone, Hash, PartialEq, Eq)] #[cfg_attr(feature = "enable-serde", derive(Serialize, Deserialize))] +#[cfg_attr( + feature = "enable-rkyv", + derive(RkyvSerialize, RkyvDeserialize, Archive) +)] pub struct PrimaryMap where K: EntityRef, From 376703cad2f72ea7bc70801df028e0b4043a7914 Mon Sep 17 00:00:00 2001 From: Syrus Akbary Date: Thu, 29 Apr 2021 16:25:59 -0700 Subject: [PATCH 10/22] Small fixes --- lib/engine-jit/src/artifact.rs | 32 +++++++++++++++++++++++++------- lib/types/src/lib.rs | 2 +- 2 files changed, 26 insertions(+), 8 deletions(-) diff --git a/lib/engine-jit/src/artifact.rs b/lib/engine-jit/src/artifact.rs index e78b76d461c..aa4ae546839 100644 --- a/lib/engine-jit/src/artifact.rs +++ b/lib/engine-jit/src/artifact.rs @@ -157,11 +157,19 @@ impl JITArtifact { let metadata_slice: &'static [u8] = std::slice::from_raw_parts(&bytes[32] as *const u8, metadata_len as usize); - println!("Pointer position {:?}", &bytes[32] as *const u8); let length = metadata_slice.len(); - println!("[DES] Metadata: First 16 bytes {:?}.\nLast 16 bytes: {:?}\nTotal length: {}", &metadata_slice[..16], &metadata_slice[length-16..], length); - println!("[DES] First 50 bytes {:?}.\nLast 50 bytes: {:?}", &bytes[..50], &bytes[bytes.len()-50..]); + println!( + "[DES] Metadata: First 16 bytes {:?}.\nLast 16 bytes: {:?}\nTotal length: {}", + &metadata_slice[..16], + &metadata_slice[length - 16..], + length + ); + println!( + "[DES] First 50 bytes {:?}.\nLast 50 bytes: {:?}", + &bytes[..50], + &bytes[bytes.len() - 50..] + ); let serializable = SerializableModule::deserialize(metadata_slice)?; println!("[DES] success"); @@ -344,11 +352,21 @@ impl Artifact for JITArtifact { leb128::write::unsigned(&mut writable_leb, length as u64).expect("Should write number"); let align = std::mem::align_of::() as u64; - println!("[SER] Metadata: First 16 bytes {:?}.\nLast 16 bytes: {:?}\nTotal length: {}", &serialized_data[..16], &serialized_data[length-16..], length); - - let _offset = pad_and_extend(&mut serialized, &serialized_data, 1); - println!("[SER] First 50 bytes {:?}.\nAlign: {} - Offset: {}\nLast 50 bytes: {:?}", &serialized[..50], align, _offset, &serialized[serialized.len()-50..]); + println!("[SER] Metadata:\n * First 16 bytes {:?}.\n * Last 16 bytes: {:?}\n * Total length: {}", &serialized_data[..16], &serialized_data[length-16..], length); + + let _offset = pad_and_extend(&mut serialized, &serialized_data, align); + println!( + "[SER] First 50 bytes {:?}.\nAlign: {} - Offset: {}\nLast 50 bytes: {:?}", + &serialized[..50], + align, + _offset, + &serialized[serialized.len() - 50..] + ); println!("[SER] Total length: {}", serialized.len()); + + let deserialized = unsafe { SerializableModule::deserialize(&serialized_data) }; + println!("DESERIALIZATION WORKS"); + Ok(serialized) } } diff --git a/lib/types/src/lib.rs b/lib/types/src/lib.rs index 6cd30d2a9c6..a471abecc08 100644 --- a/lib/types/src/lib.rs +++ b/lib/types/src/lib.rs @@ -90,7 +90,7 @@ pub use types::{ }; #[cfg(feature = "enable-rkyv")] -pub use archives::{ArchivableIndexMap, ArchivedPrimaryMap}; +pub use archives::ArchivableIndexMap; /// Version number of this crate. pub const VERSION: &str = env!("CARGO_PKG_VERSION"); From 4c54d863ce0a3edd319a962ac69bdd8877867753 Mon Sep 17 00:00:00 2001 From: Syrus Akbary Date: Thu, 29 Apr 2021 16:42:06 -0700 Subject: [PATCH 11/22] Downgrade to rkyv 0.4.3 --- Cargo.lock | 8 ++++---- lib/compiler/Cargo.toml | 2 +- lib/engine-jit/Cargo.toml | 2 +- lib/engine-native/Cargo.toml | 2 +- lib/types/Cargo.toml | 2 +- lib/vm/Cargo.toml | 2 +- lib/vm/src/module.rs | 4 ++-- 7 files changed, 11 insertions(+), 11 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index b16ca62458c..df124b50905 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1723,9 +1723,9 @@ dependencies = [ [[package]] name = "rkyv" -version = "0.6.0" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d683f1540522e9ad21b786d534b274ff49b0e974bf3af31d7a930a6c3e3599d" +checksum = "70de01b38fe7baba4ecdd33b777096d2b326993d8ea99bc5b6ede691883d3010" dependencies = [ "memoffset", "ptr_meta", @@ -1735,9 +1735,9 @@ dependencies = [ [[package]] name = "rkyv_derive" -version = "0.6.0" +version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c848da2aad0c8395f7986a717b8f28a8fc05dd94463d949673803f4955d9f73a" +checksum = "95a169f6bc5a81033e86ed39d0f4150e2608160b73d2b93c6e8e6a3efa873f14" dependencies = [ "proc-macro2", "quote", diff --git a/lib/compiler/Cargo.toml b/lib/compiler/Cargo.toml index c4be078a2f7..21efbcd9c95 100644 --- a/lib/compiler/Cargo.toml +++ b/lib/compiler/Cargo.toml @@ -21,7 +21,7 @@ serde = { version = "1.0", features = ["derive"], optional = true } thiserror = "1.0" serde_bytes = { version = "0.11", optional = true } smallvec = "1.6" -rkyv = { version = "0.6", optional = true } +rkyv = { version = "0.4", optional = true } loupe = "0.1" [features] diff --git a/lib/engine-jit/Cargo.toml b/lib/engine-jit/Cargo.toml index cf15ec83bb1..4214f3dcd45 100644 --- a/lib/engine-jit/Cargo.toml +++ b/lib/engine-jit/Cargo.toml @@ -20,7 +20,7 @@ region = "2.2" serde = { version = "1.0", features = ["derive", "rc"] } cfg-if = "0.1" leb128 = "0.2" -rkyv = "0.6" +rkyv = "0.4" loupe = "0.1" [target.'cfg(target_os = "windows")'.dependencies] diff --git a/lib/engine-native/Cargo.toml b/lib/engine-native/Cargo.toml index 62fd656dd9c..545ba611324 100644 --- a/lib/engine-native/Cargo.toml +++ b/lib/engine-native/Cargo.toml @@ -23,7 +23,7 @@ leb128 = "0.2" libloading = "0.7" tempfile = "3.1" which = "4.0" -rkyv = "0.6" +rkyv = "0.4" loupe = "0.1" [features] diff --git a/lib/types/Cargo.toml b/lib/types/Cargo.toml index 3c8b0b8b5ed..b5c7c623570 100644 --- a/lib/types/Cargo.toml +++ b/lib/types/Cargo.toml @@ -14,7 +14,7 @@ edition = "2018" serde = { version = "1.0", features = ["derive"], optional = true, default-features = false } thiserror = "1.0" indexmap = { version = "1.4", features = ["serde-1"] } -rkyv = { version = "0.6", optional = true } +rkyv = { version = "0.4", optional = true } loupe = "0.1" [features] diff --git a/lib/vm/Cargo.toml b/lib/vm/Cargo.toml index f51babb256a..a2abb9aaa1e 100644 --- a/lib/vm/Cargo.toml +++ b/lib/vm/Cargo.toml @@ -21,7 +21,7 @@ more-asserts = "0.2" cfg-if = "0.1" backtrace = "0.3" serde = { version = "1.0", features = ["derive", "rc"] } -rkyv = { version = "0.6", optional = true} +rkyv = { version = "0.4", optional = true} loupe = { version = "0.1", features = ["enable-indexmap"] } [target.'cfg(target_os = "windows")'.dependencies] diff --git a/lib/vm/src/module.rs b/lib/vm/src/module.rs index e2f1e358118..2c662238a65 100644 --- a/lib/vm/src/module.rs +++ b/lib/vm/src/module.rs @@ -226,8 +226,8 @@ impl Archive for ModuleInfo { type Archived = ::Archived; type Resolver = ::Resolver; - fn resolve(&self, pos: usize, resolver: Self::Resolver, out: &mut MaybeUninit) { - ArchivableModuleInfo::from(self).resolve(pos, resolver, out) + fn resolve(&self, pos: usize, resolver: Self::Resolver) -> ArchivedArchivableModuleInfo { + ArchivableModuleInfo::from(self).resolve(pos, resolver) } } From 62905730a5512093a35ae3d2fdc8322af8662e4e Mon Sep 17 00:00:00 2001 From: Syrus Akbary Date: Thu, 29 Apr 2021 17:11:48 -0700 Subject: [PATCH 12/22] Remove static from slice --- lib/engine-jit/src/artifact.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/engine-jit/src/artifact.rs b/lib/engine-jit/src/artifact.rs index aa4ae546839..472a0090505 100644 --- a/lib/engine-jit/src/artifact.rs +++ b/lib/engine-jit/src/artifact.rs @@ -154,7 +154,7 @@ impl JITArtifact { let metadata_len = leb128::read::unsigned(&mut inner_bytes).map_err(|_e| { DeserializeError::CorruptedBinary("Can't read metadata size".to_string()) })?; - let metadata_slice: &'static [u8] = + let metadata_slice: &[u8] = std::slice::from_raw_parts(&bytes[32] as *const u8, metadata_len as usize); println!("Pointer position {:?}", &bytes[32] as *const u8); From 79027cbcb7990dcfb94184e975a8b6fed9165c38 Mon Sep 17 00:00:00 2001 From: Syrus Akbary Date: Thu, 29 Apr 2021 17:35:08 -0700 Subject: [PATCH 13/22] [REVERT ME] Forze serialization --- lib/cli/src/commands/run.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/cli/src/commands/run.rs b/lib/cli/src/commands/run.rs index 3e0904d44e2..81ecafb4c1d 100644 --- a/lib/cli/src/commands/run.rs +++ b/lib/cli/src/commands/run.rs @@ -224,7 +224,9 @@ impl Run { let module_result: Result = if !self.disable_cache && contents.len() > 0x1000 { self.get_module_from_cache(&store, &contents, &engine_type, &compiler_type) } else { - Module::new(&store, &contents).map_err(|e| e.into()) + let module = Module::new(&store, &contents)?; + let _serialized = module.serialize()?; + Ok(module) }; #[cfg(not(feature = "cache"))] let module_result = Module::new(&store, &contents); From bd1553c409a7c44822f8baae5b2a5d65d00922da Mon Sep 17 00:00:00 2001 From: Syrus Akbary Date: Thu, 29 Apr 2021 22:41:23 -0700 Subject: [PATCH 14/22] Address all review comments --- Cargo.lock | 8 ++++---- lib/compiler/Cargo.toml | 2 +- lib/engine-jit/Cargo.toml | 2 +- lib/engine-jit/src/artifact.rs | 31 ++----------------------------- lib/engine-jit/src/serialize.rs | 15 +++++++++++++++ lib/engine-native/Cargo.toml | 2 +- lib/types/Cargo.toml | 2 +- lib/vm/Cargo.toml | 2 +- lib/vm/src/module.rs | 4 ++-- 9 files changed, 28 insertions(+), 40 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index df124b50905..7f5d4cee8c0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1723,9 +1723,9 @@ dependencies = [ [[package]] name = "rkyv" -version = "0.4.3" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "70de01b38fe7baba4ecdd33b777096d2b326993d8ea99bc5b6ede691883d3010" +checksum = "533488e35e9756976c402485db01485a3d5f51b46dd85cca9211b57373581cfa" dependencies = [ "memoffset", "ptr_meta", @@ -1735,9 +1735,9 @@ dependencies = [ [[package]] name = "rkyv_derive" -version = "0.4.0" +version = "0.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "95a169f6bc5a81033e86ed39d0f4150e2608160b73d2b93c6e8e6a3efa873f14" +checksum = "c848da2aad0c8395f7986a717b8f28a8fc05dd94463d949673803f4955d9f73a" dependencies = [ "proc-macro2", "quote", diff --git a/lib/compiler/Cargo.toml b/lib/compiler/Cargo.toml index 21efbcd9c95..11912098acb 100644 --- a/lib/compiler/Cargo.toml +++ b/lib/compiler/Cargo.toml @@ -21,7 +21,7 @@ serde = { version = "1.0", features = ["derive"], optional = true } thiserror = "1.0" serde_bytes = { version = "0.11", optional = true } smallvec = "1.6" -rkyv = { version = "0.4", optional = true } +rkyv = { version = "0.6.1", optional = true } loupe = "0.1" [features] diff --git a/lib/engine-jit/Cargo.toml b/lib/engine-jit/Cargo.toml index 4214f3dcd45..b66882fe0fe 100644 --- a/lib/engine-jit/Cargo.toml +++ b/lib/engine-jit/Cargo.toml @@ -20,7 +20,7 @@ region = "2.2" serde = { version = "1.0", features = ["derive", "rc"] } cfg-if = "0.1" leb128 = "0.2" -rkyv = "0.4" +rkyv = "0.6.1" loupe = "0.1" [target.'cfg(target_os = "windows")'.dependencies] diff --git a/lib/engine-jit/src/artifact.rs b/lib/engine-jit/src/artifact.rs index 472a0090505..6996a88644f 100644 --- a/lib/engine-jit/src/artifact.rs +++ b/lib/engine-jit/src/artifact.rs @@ -148,7 +148,6 @@ impl JITArtifact { )); } - println!("[DES] Total length: {}", bytes.len()); let mut inner_bytes = &bytes[16..]; let metadata_len = leb128::read::unsigned(&mut inner_bytes).map_err(|_e| { @@ -157,22 +156,7 @@ impl JITArtifact { let metadata_slice: &[u8] = std::slice::from_raw_parts(&bytes[32] as *const u8, metadata_len as usize); - println!("Pointer position {:?}", &bytes[32] as *const u8); - let length = metadata_slice.len(); - println!( - "[DES] Metadata: First 16 bytes {:?}.\nLast 16 bytes: {:?}\nTotal length: {}", - &metadata_slice[..16], - &metadata_slice[length - 16..], - length - ); - println!( - "[DES] First 50 bytes {:?}.\nLast 50 bytes: {:?}", - &bytes[..50], - &bytes[bytes.len() - 50..] - ); - let serializable = SerializableModule::deserialize(metadata_slice)?; - println!("[DES] success"); Self::from_parts(&mut jit.inner_mut(), serializable).map_err(DeserializeError::Compiler) } @@ -352,20 +336,9 @@ impl Artifact for JITArtifact { leb128::write::unsigned(&mut writable_leb, length as u64).expect("Should write number"); let align = std::mem::align_of::() as u64; - println!("[SER] Metadata:\n * First 16 bytes {:?}.\n * Last 16 bytes: {:?}\n * Total length: {}", &serialized_data[..16], &serialized_data[length-16..], length); - - let _offset = pad_and_extend(&mut serialized, &serialized_data, align); - println!( - "[SER] First 50 bytes {:?}.\nAlign: {} - Offset: {}\nLast 50 bytes: {:?}", - &serialized[..50], - align, - _offset, - &serialized[serialized.len() - 50..] - ); - println!("[SER] Total length: {}", serialized.len()); - let deserialized = unsafe { SerializableModule::deserialize(&serialized_data) }; - println!("DESERIALIZATION WORKS"); + let offset = pad_and_extend(&mut serialized, &serialized_data, align); + assert_eq!(offset, 32); Ok(serialized) } diff --git a/lib/engine-jit/src/serialize.rs b/lib/engine-jit/src/serialize.rs index 70f2edd931e..8150a645296 100644 --- a/lib/engine-jit/src/serialize.rs +++ b/lib/engine-jit/src/serialize.rs @@ -44,6 +44,9 @@ fn to_serialize_error(err: impl std::error::Error) -> SerializeError { } impl SerializableModule { + /// Serialize a Module into bytes + /// The bytes will have the following format: + /// RKYV serialization (any length) + POS (8 bytes) + Endian (1 byte) pub fn serialize(&self) -> Result, SerializeError> { let mut serializer = SharedSerializerAdapter::new(WriteSerializer::new(vec![])); let pos = serializer @@ -59,6 +62,13 @@ impl SerializableModule { Ok(serialized_data) } + /// Deserialize a Module from a slice. + /// The slice must have the following format: + /// RKYV serialization (any length) + POS (8 bytes) + Endian (1 byte) + /// + /// # Safety + /// This method is highly unsafe since we are deserializing directly + /// from memory, without validating it first. pub unsafe fn deserialize(metadata_slice: &[u8]) -> Result { let archived = Self::archive_from_slice(metadata_slice)?; Self::deserialize_from_archive(archived) @@ -67,6 +77,11 @@ impl SerializableModule { unsafe fn archive_from_slice<'a>( metadata_slice: &'a [u8], ) -> Result<&'a ArchivedSerializableModule, DeserializeError> { + if metadata_slice.len() < 9 { + return Err(DeserializeError::Incompatible( + "invalid serialized data".into(), + )); + } let mut pos: [u8; 8] = Default::default(); let endian = metadata_slice[metadata_slice.len() - 1]; if (cfg!(target_endian = "big") && endian == b'l') diff --git a/lib/engine-native/Cargo.toml b/lib/engine-native/Cargo.toml index 545ba611324..2919c1d4b94 100644 --- a/lib/engine-native/Cargo.toml +++ b/lib/engine-native/Cargo.toml @@ -23,7 +23,7 @@ leb128 = "0.2" libloading = "0.7" tempfile = "3.1" which = "4.0" -rkyv = "0.4" +rkyv = "0.6.1" loupe = "0.1" [features] diff --git a/lib/types/Cargo.toml b/lib/types/Cargo.toml index b5c7c623570..7cb2901a633 100644 --- a/lib/types/Cargo.toml +++ b/lib/types/Cargo.toml @@ -14,7 +14,7 @@ edition = "2018" serde = { version = "1.0", features = ["derive"], optional = true, default-features = false } thiserror = "1.0" indexmap = { version = "1.4", features = ["serde-1"] } -rkyv = { version = "0.4", optional = true } +rkyv = { version = "0.6.1", optional = true } loupe = "0.1" [features] diff --git a/lib/vm/Cargo.toml b/lib/vm/Cargo.toml index a2abb9aaa1e..c4e1044bb11 100644 --- a/lib/vm/Cargo.toml +++ b/lib/vm/Cargo.toml @@ -21,7 +21,7 @@ more-asserts = "0.2" cfg-if = "0.1" backtrace = "0.3" serde = { version = "1.0", features = ["derive", "rc"] } -rkyv = { version = "0.4", optional = true} +rkyv = { version = "0.6.1", optional = true} loupe = { version = "0.1", features = ["enable-indexmap"] } [target.'cfg(target_os = "windows")'.dependencies] diff --git a/lib/vm/src/module.rs b/lib/vm/src/module.rs index 2c662238a65..e2f1e358118 100644 --- a/lib/vm/src/module.rs +++ b/lib/vm/src/module.rs @@ -226,8 +226,8 @@ impl Archive for ModuleInfo { type Archived = ::Archived; type Resolver = ::Resolver; - fn resolve(&self, pos: usize, resolver: Self::Resolver) -> ArchivedArchivableModuleInfo { - ArchivableModuleInfo::from(self).resolve(pos, resolver) + fn resolve(&self, pos: usize, resolver: Self::Resolver, out: &mut MaybeUninit) { + ArchivableModuleInfo::from(self).resolve(pos, resolver, out) } } From 8006918fe56addc3e9d628557dde1e0f62b7b500 Mon Sep 17 00:00:00 2001 From: Syrus Akbary Date: Thu, 29 Apr 2021 22:57:03 -0700 Subject: [PATCH 15/22] Updated cargo fuzz page --- fuzz/Cargo.lock | 18 ++++-------------- 1 file changed, 4 insertions(+), 14 deletions(-) diff --git a/fuzz/Cargo.lock b/fuzz/Cargo.lock index 7ce1fb7e004..6a4d7f7c88c 100644 --- a/fuzz/Cargo.lock +++ b/fuzz/Cargo.lock @@ -61,16 +61,6 @@ dependencies = [ "rustc-demangle", ] -[[package]] -name = "bincode" -version = "1.3.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d175dfa69e619905c4c3cdb7c3c203fa3bdd5d51184e3afdb2742c0280493772" -dependencies = [ - "byteorder", - "serde", -] - [[package]] name = "bitflags" version = "1.2.1" @@ -844,9 +834,9 @@ dependencies = [ [[package]] name = "rkyv" -version = "0.6.0" +version = "0.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0d683f1540522e9ad21b786d534b274ff49b0e974bf3af31d7a930a6c3e3599d" +checksum = "533488e35e9756976c402485db01485a3d5f51b46dd85cca9211b57373581cfa" dependencies = [ "memoffset", "ptr_meta", @@ -1279,12 +1269,12 @@ dependencies = [ name = "wasmer-engine-jit" version = "1.0.2" dependencies = [ - "bincode", "cfg-if 0.1.10", + "leb128", "loupe", "region", + "rkyv", "serde", - "serde_bytes", "wasmer-compiler", "wasmer-engine", "wasmer-types", From aea20b2f75b0517fb42f9b452f5efeb26daee05e Mon Sep 17 00:00:00 2001 From: Syrus Akbary Date: Thu, 29 Apr 2021 23:57:34 -0700 Subject: [PATCH 16/22] Revert "[REVERT ME] Forze serialization" This reverts commit 79027cbcb7990dcfb94184e975a8b6fed9165c38. --- lib/cli/src/commands/run.rs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/lib/cli/src/commands/run.rs b/lib/cli/src/commands/run.rs index 81ecafb4c1d..3e0904d44e2 100644 --- a/lib/cli/src/commands/run.rs +++ b/lib/cli/src/commands/run.rs @@ -224,9 +224,7 @@ impl Run { let module_result: Result = if !self.disable_cache && contents.len() > 0x1000 { self.get_module_from_cache(&store, &contents, &engine_type, &compiler_type) } else { - let module = Module::new(&store, &contents)?; - let _serialized = module.serialize()?; - Ok(module) + Module::new(&store, &contents).map_err(|e| e.into()) }; #[cfg(not(feature = "cache"))] let module_result = Module::new(&store, &contents); From cd411d8a6223342592a518f6da617f95381f3535 Mon Sep 17 00:00:00 2001 From: Syrus Akbary Date: Fri, 30 Apr 2021 09:37:01 -0700 Subject: [PATCH 17/22] Remove serde from engine-jit --- Cargo.lock | 1 - lib/engine-jit/Cargo.toml | 1 - lib/engine-jit/src/serialize.rs | 5 ++--- 3 files changed, 2 insertions(+), 5 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 7f5d4cee8c0..9b46ee31b3b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2610,7 +2610,6 @@ dependencies = [ "loupe", "region", "rkyv", - "serde", "wasmer-compiler", "wasmer-engine", "wasmer-types", diff --git a/lib/engine-jit/Cargo.toml b/lib/engine-jit/Cargo.toml index b66882fe0fe..96399200d82 100644 --- a/lib/engine-jit/Cargo.toml +++ b/lib/engine-jit/Cargo.toml @@ -17,7 +17,6 @@ wasmer-vm = { path = "../vm", version = "1.0.2", features = ["enable-rkyv"] } wasmer-engine = { path = "../engine", version = "1.0.2" } # flexbuffers = { path = "../../../flatbuffers/rust/flexbuffers", version = "0.1.0" } region = "2.2" -serde = { version = "1.0", features = ["derive", "rc"] } cfg-if = "0.1" leb128 = "0.2" rkyv = "0.6.1" diff --git a/lib/engine-jit/src/serialize.rs b/lib/engine-jit/src/serialize.rs index 8150a645296..0e3460f4cab 100644 --- a/lib/engine-jit/src/serialize.rs +++ b/lib/engine-jit/src/serialize.rs @@ -6,7 +6,6 @@ use rkyv::{ ser::{serializers::WriteSerializer, Serializer as RkyvSerializer}, Archive, Deserialize as RkyvDeserialize, Serialize as RkyvSerialize, }; -use serde::{Deserialize, Serialize}; use wasmer_compiler::{ CompileModuleInfo, CompiledFunctionFrameInfo, CustomSection, Dwarf, FunctionBody, JumpTableOffsets, Relocation, SectionIndex, @@ -16,7 +15,7 @@ use wasmer_types::entity::PrimaryMap; use wasmer_types::{FunctionIndex, LocalFunctionIndex, OwnedDataInitializer, SignatureIndex}; /// The compilation related data for a serialized modules -#[derive(Serialize, Deserialize, MemoryUsage, Archive, RkyvDeserialize, RkyvSerialize)] +#[derive(MemoryUsage, Archive, RkyvDeserialize, RkyvSerialize)] pub struct SerializableCompilation { pub function_bodies: PrimaryMap, pub function_relocations: PrimaryMap>, @@ -32,7 +31,7 @@ pub struct SerializableCompilation { /// Serializable struct that is able to serialize from and to /// a `JITArtifactInfo`. -#[derive(Serialize, Deserialize, MemoryUsage, Archive, RkyvDeserialize, RkyvSerialize)] +#[derive(MemoryUsage, Archive, RkyvDeserialize, RkyvSerialize)] pub struct SerializableModule { pub compilation: SerializableCompilation, pub compile_info: CompileModuleInfo, From 987420dd2f9a17e834d5c1d32b8ac567335476e7 Mon Sep 17 00:00:00 2001 From: Syrus Akbary Date: Fri, 30 Apr 2021 10:26:22 -0700 Subject: [PATCH 18/22] Addressed all comments --- lib/engine-jit/src/artifact.rs | 30 +++++++++++++------------- lib/engine-jit/src/serialize.rs | 37 +++++++++++++++++++++++---------- 2 files changed, 42 insertions(+), 25 deletions(-) diff --git a/lib/engine-jit/src/artifact.rs b/lib/engine-jit/src/artifact.rs index 6996a88644f..824c90ce3ff 100644 --- a/lib/engine-jit/src/artifact.rs +++ b/lib/engine-jit/src/artifact.rs @@ -27,6 +27,9 @@ use wasmer_vm::{ VMTrampoline, }; +const SERIALIZED_METADATA_LENGTH_OFFSET: usize = 16; +const SERIALIZED_METADATA_CONTENT_OFFSET: usize = 32; + /// A compiled wasm module, ready to be instantiated. #[derive(MemoryUsage)] pub struct JITArtifact { @@ -148,13 +151,15 @@ impl JITArtifact { )); } - let mut inner_bytes = &bytes[16..]; + let mut inner_bytes = &bytes[SERIALIZED_METADATA_LENGTH_OFFSET..]; let metadata_len = leb128::read::unsigned(&mut inner_bytes).map_err(|_e| { DeserializeError::CorruptedBinary("Can't read metadata size".to_string()) })?; - let metadata_slice: &[u8] = - std::slice::from_raw_parts(&bytes[32] as *const u8, metadata_len as usize); + let metadata_slice: &[u8] = std::slice::from_raw_parts( + &bytes[SERIALIZED_METADATA_CONTENT_OFFSET] as *const u8, + metadata_len as usize, + ); let serializable = SerializableModule::deserialize(metadata_slice)?; Self::from_parts(&mut jit.inner_mut(), serializable).map_err(DeserializeError::Compiler) @@ -329,31 +334,28 @@ impl Artifact for JITArtifact { // Prepend the header. let mut serialized = Self::MAGIC_HEADER.to_vec(); - serialized.resize(32, 0); - let mut writable_leb = &mut serialized[16..]; + serialized.resize(SERIALIZED_METADATA_CONTENT_OFFSET, 0); + let mut writable_leb = &mut serialized[SERIALIZED_METADATA_LENGTH_OFFSET..]; let serialized_data = self.serializable.serialize()?; let length = serialized_data.len(); leb128::write::unsigned(&mut writable_leb, length as u64).expect("Should write number"); - let align = std::mem::align_of::() as u64; - - let offset = pad_and_extend(&mut serialized, &serialized_data, align); - assert_eq!(offset, 32); + let offset = pad_and_extend::(&mut serialized, &serialized_data); + assert_eq!(offset, SERIALIZED_METADATA_CONTENT_OFFSET); Ok(serialized) } } /// It pads the data with the desired alignment -pub fn pad_and_extend(prev_data: &mut Vec, data: &[u8], align: u64) -> u64 { - // We assert that align is a power of 2 - debug_assert_eq!(align & (align - 1), 0); - let align = align as usize; +pub fn pad_and_extend(prev_data: &mut Vec, data: &[u8]) -> usize { + let align = std::mem::align_of::(); + let mut offset = prev_data.len(); if offset & (align - 1) != 0 { offset += align - (offset & (align - 1)); prev_data.resize(offset, 0); } prev_data.extend(data); - offset as u64 + offset } diff --git a/lib/engine-jit/src/serialize.rs b/lib/engine-jit/src/serialize.rs index 0e3460f4cab..c200ab12ae9 100644 --- a/lib/engine-jit/src/serialize.rs +++ b/lib/engine-jit/src/serialize.rs @@ -42,6 +42,17 @@ fn to_serialize_error(err: impl std::error::Error) -> SerializeError { SerializeError::Generic(format!("{}", err)) } +cfg_if::cfg_if! { + if #[cfg(target_endian = "big")] { + const HOST_ENDIAN: u8 = b'b'; + } else if #[cfg(target_endian = "little")] { + const HOST_ENDIAN: u8 = b'l'; + } + else { + compile_error!("Endian not supported by the host"); + } +} + impl SerializableModule { /// Serialize a Module into bytes /// The bytes will have the following format: @@ -53,11 +64,7 @@ impl SerializableModule { .map_err(to_serialize_error)? as u64; let mut serialized_data = serializer.into_inner().into_inner(); serialized_data.extend_from_slice(&pos.to_le_bytes()); - if cfg!(target_endian = "big") { - serialized_data.extend_from_slice(&[b'b']); - } else if cfg!(target_endian = "little") { - serialized_data.extend_from_slice(&[b'l']); - } + serialized_data.extend_from_slice(&[HOST_ENDIAN]); Ok(serialized_data) } @@ -66,8 +73,12 @@ impl SerializableModule { /// RKYV serialization (any length) + POS (8 bytes) + Endian (1 byte) /// /// # Safety - /// This method is highly unsafe since we are deserializing directly - /// from memory, without validating it first. + /// + /// This method is unsafe since it deserializes data directly + /// from memory. + /// Right now we are not doing any extra work for validation, but + /// `rkyv` has an option to do bytecheck on the serialized data before + /// serializing (via `rkyv::check_archived_value`). pub unsafe fn deserialize(metadata_slice: &[u8]) -> Result { let archived = Self::archive_from_slice(metadata_slice)?; Self::deserialize_from_archive(archived) @@ -83,10 +94,14 @@ impl SerializableModule { } let mut pos: [u8; 8] = Default::default(); let endian = metadata_slice[metadata_slice.len() - 1]; - if (cfg!(target_endian = "big") && endian == b'l') - || (cfg!(target_endian = "little") && endian == b'b') - { - return Err(DeserializeError::Incompatible("incompatible endian".into())); + if endian != HOST_ENDIAN { + return Err(DeserializeError::Incompatible( + format!( + "incompatible endian. Received {} but expected {}", + endian, HOST_ENDIAN + ) + .into(), + )); } pos.copy_from_slice(&metadata_slice[metadata_slice.len() - 9..metadata_slice.len() - 1]); let pos: u64 = u64::from_le_bytes(pos); From 1649ec2abc1cb33caf208ea9b77bbb575c55a7c4 Mon Sep 17 00:00:00 2001 From: Syrus Akbary Date: Fri, 30 Apr 2021 10:45:05 -0700 Subject: [PATCH 19/22] Added unit test --- lib/engine-jit/src/artifact.rs | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/lib/engine-jit/src/artifact.rs b/lib/engine-jit/src/artifact.rs index 824c90ce3ff..1bc1c5e005f 100644 --- a/lib/engine-jit/src/artifact.rs +++ b/lib/engine-jit/src/artifact.rs @@ -359,3 +359,23 @@ pub fn pad_and_extend(prev_data: &mut Vec, data: &[u8]) -> usize { prev_data.extend(data); offset } + +#[cfg(test)] +mod tests { + use super::pad_and_extend; + + #[test] + fn test_pad_and_extend() { + let mut data: Vec = vec![]; + let offset = pad_and_extend::(&mut data, &[1, 0, 0, 0, 0, 0, 0, 0]); + assert_eq!(offset, 0); + let offset = pad_and_extend::(&mut data, &[2, 0, 0, 0]); + assert_eq!(offset, 8); + let offset = pad_and_extend::(&mut data, &[3, 0, 0, 0, 0, 0, 0, 0]); + assert_eq!(offset, 16); + assert_eq!( + data, + &[1, 0, 0, 0, 0, 0, 0, 0, 2, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 0, 0, 0] + ); + } +} From 2218056d2c6a83f8878340e81b53caa1b59a231a Mon Sep 17 00:00:00 2001 From: Syrus Akbary Date: Fri, 30 Apr 2021 10:46:20 -0700 Subject: [PATCH 20/22] Updated cargo fuzz --- fuzz/Cargo.lock | 1 - 1 file changed, 1 deletion(-) diff --git a/fuzz/Cargo.lock b/fuzz/Cargo.lock index 6a4d7f7c88c..9537900b0e5 100644 --- a/fuzz/Cargo.lock +++ b/fuzz/Cargo.lock @@ -1274,7 +1274,6 @@ dependencies = [ "loupe", "region", "rkyv", - "serde", "wasmer-compiler", "wasmer-engine", "wasmer-types", From 27348a63cad420005dbd6d7e4734ae1a7d2ad979 Mon Sep 17 00:00:00 2001 From: Syrus Akbary Date: Fri, 30 Apr 2021 11:09:15 -0700 Subject: [PATCH 21/22] Added extra safety comment --- lib/engine-jit/src/serialize.rs | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/lib/engine-jit/src/serialize.rs b/lib/engine-jit/src/serialize.rs index c200ab12ae9..2e14c14c19e 100644 --- a/lib/engine-jit/src/serialize.rs +++ b/lib/engine-jit/src/serialize.rs @@ -74,16 +74,20 @@ impl SerializableModule { /// /// # Safety /// - /// This method is unsafe since it deserializes data directly - /// from memory. - /// Right now we are not doing any extra work for validation, but - /// `rkyv` has an option to do bytecheck on the serialized data before - /// serializing (via `rkyv::check_archived_value`). + /// This method is unsafe. + /// Please check `SerializableModule::archive_from_slice` for more details. pub unsafe fn deserialize(metadata_slice: &[u8]) -> Result { let archived = Self::archive_from_slice(metadata_slice)?; Self::deserialize_from_archive(archived) } + /// # Safety + /// + /// This method is unsafe since it deserializes data directly + /// from memory. + /// Right now we are not doing any extra work for validation, but + /// `rkyv` has an option to do bytecheck on the serialized data before + /// serializing (via `rkyv::check_archived_value`). unsafe fn archive_from_slice<'a>( metadata_slice: &'a [u8], ) -> Result<&'a ArchivedSerializableModule, DeserializeError> { From ab55989f3f218c8eddf0e594f29c93ba1be54fdd Mon Sep 17 00:00:00 2001 From: Syrus Akbary Date: Fri, 30 Apr 2021 11:14:25 -0700 Subject: [PATCH 22/22] Switch order --- lib/engine-jit/src/serialize.rs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/lib/engine-jit/src/serialize.rs b/lib/engine-jit/src/serialize.rs index 2e14c14c19e..3514bade518 100644 --- a/lib/engine-jit/src/serialize.rs +++ b/lib/engine-jit/src/serialize.rs @@ -74,8 +74,11 @@ impl SerializableModule { /// /// # Safety /// - /// This method is unsafe. - /// Please check `SerializableModule::archive_from_slice` for more details. + /// This method is unsafe since it deserializes data directly + /// from memory. + /// Right now we are not doing any extra work for validation, but + /// `rkyv` has an option to do bytecheck on the serialized data before + /// serializing (via `rkyv::check_archived_value`). pub unsafe fn deserialize(metadata_slice: &[u8]) -> Result { let archived = Self::archive_from_slice(metadata_slice)?; Self::deserialize_from_archive(archived) @@ -83,11 +86,8 @@ impl SerializableModule { /// # Safety /// - /// This method is unsafe since it deserializes data directly - /// from memory. - /// Right now we are not doing any extra work for validation, but - /// `rkyv` has an option to do bytecheck on the serialized data before - /// serializing (via `rkyv::check_archived_value`). + /// This method is unsafe. + /// Please check `SerializableModule::deserialize` for more details. unsafe fn archive_from_slice<'a>( metadata_slice: &'a [u8], ) -> Result<&'a ArchivedSerializableModule, DeserializeError> {