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