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 SerializableCompilation {
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 SerializableCompilation {
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/// Serializable struct that is able to serialize from and to a `ArtifactInfo`.
57#[derive(Archive, RkyvDeserialize, RkyvSerialize)]
58#[cfg_attr(feature = "artifact-size", derive(loupe::MemoryUsage))]
59#[allow(missing_docs)]
60#[rkyv(derive(Debug))]
61pub struct SerializableModule {
62    /// The main serializable compilation object
63    pub compilation: SerializableCompilation,
64    /// Compilation informations
65    pub compile_info: CompileModuleInfo,
66    /// Datas initializers
67    pub data_initializers: Box<[OwnedDataInitializer]>,
68    /// CPU Feature flags for this compilation
69    pub cpu_features: u64,
70}
71
72impl SerializableModule {
73    /// Serialize a Module into bytes
74    /// The bytes will have the following format:
75    /// RKYV serialization (any length) + POS (8 bytes)
76    pub fn serialize(&self) -> Result<Vec<u8>, SerializeError> {
77        rkyv::to_bytes::<rkyv::rancor::Error>(self)
78            .map(|v| v.into_vec())
79            .map_err(|e| SerializeError::Generic(e.to_string()))
80    }
81
82    /// Deserialize a Module from a slice.
83    /// The slice must have the following format:
84    /// RKYV serialization (any length) + POS (8 bytes)
85    ///
86    /// # Safety
87    ///
88    /// This method is unsafe since it deserializes data directly
89    /// from memory.
90    /// Right now we are not doing any extra work for validation, but
91    /// `rkyv` has an option to do bytecheck on the serialized data before
92    /// serializing (via `rkyv::check_archived_value`).
93    pub unsafe fn deserialize_unchecked(metadata_slice: &[u8]) -> Result<Self, DeserializeError> {
94        unsafe {
95            let archived = Self::archive_from_slice(metadata_slice)?;
96            Self::deserialize_from_archive(archived)
97        }
98    }
99
100    /// Deserialize a Module from a slice.
101    /// The slice must have the following format:
102    /// RKYV serialization (any length) + POS (8 bytes)
103    ///
104    /// Unlike [`Self::deserialize`], this function will validate the data.
105    ///
106    /// # Safety
107    /// Unsafe because it loads executable code into memory.
108    /// The loaded bytes must be trusted.
109    pub unsafe fn deserialize(metadata_slice: &[u8]) -> Result<Self, DeserializeError> {
110        let archived = Self::archive_from_slice_checked(metadata_slice)?;
111        Self::deserialize_from_archive(archived)
112    }
113
114    /// # Safety
115    ///
116    /// This method is unsafe.
117    /// Please check `SerializableModule::deserialize` for more details.
118    pub unsafe fn archive_from_slice(
119        metadata_slice: &[u8],
120    ) -> Result<&ArchivedSerializableModule, DeserializeError> {
121        unsafe { Ok(rkyv::access_unchecked(metadata_slice)) }
122    }
123
124    /// Deserialize an archived module.
125    ///
126    /// In contrast to [`Self::deserialize`], this method performs validation
127    /// and is not unsafe.
128    pub fn archive_from_slice_checked(
129        metadata_slice: &[u8],
130    ) -> Result<&ArchivedSerializableModule, DeserializeError> {
131        rkyv::access::<_, rkyv::rancor::Error>(metadata_slice)
132            .map_err(|e| DeserializeError::CorruptedBinary(e.to_string()))
133    }
134
135    /// Deserialize a compilation module from an archive
136    pub fn deserialize_from_archive(
137        archived: &ArchivedSerializableModule,
138    ) -> Result<Self, DeserializeError> {
139        rkyv::deserialize::<_, rkyv::rancor::Error>(archived)
140            .map_err(|e| DeserializeError::CorruptedBinary(e.to_string()))
141    }
142
143    /// Create a `ModuleInfo` for instantiation
144    pub fn create_module_info(&self) -> ModuleInfo {
145        self.compile_info.module.as_ref().clone()
146    }
147
148    /// Returns the `ModuleInfo` for instantiation
149    pub fn module_info(&self) -> &ModuleInfo {
150        &self.compile_info.module
151    }
152
153    /// Returns the features for this Artifact
154    pub fn features(&self) -> &Features {
155        &self.compile_info.features
156    }
157
158    /// Returns the CPU features for this Artifact
159    pub fn cpu_features(&self) -> EnumSet<CpuFeature> {
160        EnumSet::from_u64(self.cpu_features)
161    }
162
163    /// Returns data initializers to pass to `VMInstance::initialize`
164    pub fn data_initializers(&self) -> &[OwnedDataInitializer] {
165        &self.data_initializers
166    }
167
168    /// Returns the memory styles associated with this `Artifact`.
169    pub fn memory_styles(&self) -> &PrimaryMap<MemoryIndex, MemoryStyle> {
170        &self.compile_info.memory_styles
171    }
172
173    /// Returns the table plans associated with this `Artifact`.
174    pub fn table_styles(&self) -> &PrimaryMap<TableIndex, TableStyle> {
175        &self.compile_info.table_styles
176    }
177}