wasmer_compiler/
serialize.rs

1/*
2 * ! Remove me once rkyv generates doc-comments for fields or generates an #[allow(missing_docs)]
3 * on their own.
4 */
5#![allow(missing_docs)]
6
7use crate::types::{
8    function::{CompiledFunctionFrameInfo, FunctionBody, GOT, UnwindInfo},
9    module::CompileModuleInfo,
10    relocation::Relocation,
11    section::{CustomSection, SectionIndex},
12};
13use enumset::EnumSet;
14use rkyv::{Archive, Deserialize as RkyvDeserialize, Serialize as RkyvSerialize};
15use wasmer_types::{
16    DeserializeError, Features, FunctionIndex, LocalFunctionIndex, MemoryIndex, MemoryStyle,
17    ModuleInfo, OwnedDataInitializer, SerializeError, SignatureIndex, TableIndex, TableStyle,
18    entity::PrimaryMap, target::CpuFeature,
19};
20
21pub use wasmer_types::MetadataHeader;
22
23/// The compilation related data for a serialized modules
24#[derive(Archive, Default, RkyvDeserialize, RkyvSerialize)]
25#[cfg_attr(feature = "artifact-size", derive(loupe::MemoryUsage))]
26#[allow(missing_docs)]
27#[rkyv(derive(Debug))]
28pub struct RkyvSerializableCompilation {
29    pub function_bodies: PrimaryMap<LocalFunctionIndex, FunctionBody>,
30    pub function_relocations: PrimaryMap<LocalFunctionIndex, Vec<Relocation>>,
31    pub function_frame_info: PrimaryMap<LocalFunctionIndex, CompiledFunctionFrameInfo>,
32    pub function_call_trampolines: PrimaryMap<SignatureIndex, FunctionBody>,
33    pub dynamic_function_trampolines: PrimaryMap<FunctionIndex, FunctionBody>,
34    pub custom_sections: PrimaryMap<SectionIndex, CustomSection>,
35    pub custom_section_relocations: PrimaryMap<SectionIndex, Vec<Relocation>>,
36    // The section indices corresponding to the Dwarf debug info
37    pub unwind_info: UnwindInfo,
38    pub got: GOT,
39    // Custom section containing libcall trampolines.
40    pub libcall_trampolines: SectionIndex,
41    // Length of each libcall trampoline.
42    pub libcall_trampoline_len: u32,
43}
44
45impl RkyvSerializableCompilation {
46    /// Serialize a Compilation into bytes
47    /// The bytes will have the following format:
48    /// RKYV serialization (any length) + POS (8 bytes)
49    pub fn serialize(&self) -> Result<Vec<u8>, SerializeError> {
50        rkyv::to_bytes::<rkyv::rancor::Error>(self)
51            .map(|v| v.into_vec())
52            .map_err(|e| SerializeError::Generic(e.to_string()))
53    }
54}
55
56#[derive(Archive, RkyvDeserialize, RkyvSerialize)]
57#[cfg_attr(feature = "artifact-size", derive(loupe::MemoryUsage))]
58#[allow(missing_docs)]
59#[rkyv(derive(Debug))]
60pub enum SerializableCompilation {
61    Rkyv(RkyvSerializableCompilation),
62    Elf(Vec<u8>),
63}
64
65/// Serializable struct that is able to serialize from and to a `ArtifactInfo`.
66#[derive(Archive, RkyvDeserialize, RkyvSerialize)]
67#[cfg_attr(feature = "artifact-size", derive(loupe::MemoryUsage))]
68#[allow(missing_docs)]
69#[rkyv(derive(Debug))]
70pub struct SerializableModule {
71    /// The main serializable compilation object
72    pub compilation: SerializableCompilation,
73    /// Compilation information
74    pub compile_info: CompileModuleInfo,
75    /// Data initializers
76    pub data_initializers: Box<[OwnedDataInitializer]>,
77    /// CPU Feature flags for this compilation
78    pub cpu_features: u64,
79}
80
81impl SerializableModule {
82    /// Serialize a Module into bytes
83    /// The bytes will have the following format:
84    /// RKYV serialization (any length) + POS (8 bytes)
85    pub fn serialize(&self) -> Result<Vec<u8>, SerializeError> {
86        rkyv::to_bytes::<rkyv::rancor::Error>(self)
87            .map(|v| v.into_vec())
88            .map_err(|e| SerializeError::Generic(e.to_string()))
89    }
90
91    /// Deserialize a Module from a slice.
92    /// The slice must have the following format:
93    /// RKYV serialization (any length) + POS (8 bytes)
94    ///
95    /// # Safety
96    ///
97    /// This method is unsafe since it deserializes data directly
98    /// from memory.
99    /// Right now we are not doing any extra work for validation, but
100    /// `rkyv` has an option to do bytecheck on the serialized data before
101    /// serializing (via `rkyv::check_archived_value`).
102    pub unsafe fn deserialize_unchecked(metadata_slice: &[u8]) -> Result<Self, DeserializeError> {
103        unsafe {
104            let archived = Self::archive_from_slice(metadata_slice)?;
105            Self::deserialize_from_archive(archived)
106        }
107    }
108
109    /// Deserialize a Module from a slice.
110    /// The slice must have the following format:
111    /// RKYV serialization (any length) + POS (8 bytes)
112    ///
113    /// Unlike [`Self::deserialize`], this function will validate the data.
114    ///
115    /// # Safety
116    /// Unsafe because it loads executable code into memory.
117    /// The loaded bytes must be trusted.
118    pub unsafe fn deserialize(metadata_slice: &[u8]) -> Result<Self, DeserializeError> {
119        let archived = Self::archive_from_slice_checked(metadata_slice)?;
120        Self::deserialize_from_archive(archived)
121    }
122
123    /// # Safety
124    ///
125    /// This method is unsafe.
126    /// Please check `SerializableModule::deserialize` for more details.
127    pub unsafe fn archive_from_slice(
128        metadata_slice: &[u8],
129    ) -> Result<&ArchivedSerializableModule, DeserializeError> {
130        unsafe { Ok(rkyv::access_unchecked(metadata_slice)) }
131    }
132
133    /// Deserialize an archived module.
134    ///
135    /// In contrast to [`Self::deserialize`], this method performs validation
136    /// and is not unsafe.
137    pub fn archive_from_slice_checked(
138        metadata_slice: &[u8],
139    ) -> Result<&ArchivedSerializableModule, DeserializeError> {
140        rkyv::access::<_, rkyv::rancor::Error>(metadata_slice)
141            .map_err(|e| DeserializeError::CorruptedBinary(e.to_string()))
142    }
143
144    /// Deserialize a compilation module from an archive
145    pub fn deserialize_from_archive(
146        archived: &ArchivedSerializableModule,
147    ) -> Result<Self, DeserializeError> {
148        rkyv::deserialize::<_, rkyv::rancor::Error>(archived)
149            .map_err(|e| DeserializeError::CorruptedBinary(e.to_string()))
150    }
151
152    /// Create a `ModuleInfo` for instantiation
153    pub fn create_module_info(&self) -> ModuleInfo {
154        self.compile_info.module.as_ref().clone()
155    }
156
157    /// Returns the `ModuleInfo` for instantiation
158    pub fn module_info(&self) -> &ModuleInfo {
159        &self.compile_info.module
160    }
161
162    /// Returns the features for this Artifact
163    pub fn features(&self) -> &Features {
164        &self.compile_info.features
165    }
166
167    /// Returns the CPU features for this Artifact
168    pub fn cpu_features(&self) -> EnumSet<CpuFeature> {
169        EnumSet::from_u64(self.cpu_features)
170    }
171
172    /// Returns data initializers to pass to `VMInstance::initialize`
173    pub fn data_initializers(&self) -> &[OwnedDataInitializer] {
174        &self.data_initializers
175    }
176
177    /// Returns the memory styles associated with this `Artifact`.
178    pub fn memory_styles(&self) -> &PrimaryMap<MemoryIndex, MemoryStyle> {
179        &self.compile_info.memory_styles
180    }
181
182    /// Returns the table plans associated with this `Artifact`.
183    pub fn table_styles(&self) -> &PrimaryMap<TableIndex, TableStyle> {
184        &self.compile_info.table_styles
185    }
186}