wasmer_engine_universal_artifact/
serialize.rs

1use loupe::MemoryUsage;
2use rkyv::{
3    archived_value, de::deserializers::SharedDeserializeMap, ser::serializers::AllocSerializer,
4    ser::Serializer as RkyvSerializer, Archive, Deserialize as RkyvDeserialize,
5    Serialize as RkyvSerialize,
6};
7use wasmer_artifact::{DeserializeError, SerializeError};
8use wasmer_compiler::{
9    CompileModuleInfo, CompiledFunctionFrameInfo, CustomSection, Dwarf, FunctionBody, Relocation,
10    SectionIndex,
11};
12use wasmer_types::entity::PrimaryMap;
13use wasmer_types::{FunctionIndex, LocalFunctionIndex, OwnedDataInitializer, SignatureIndex};
14
15/// The compilation related data for a serialized modules
16#[derive(MemoryUsage, Archive, RkyvDeserialize, RkyvSerialize)]
17pub struct SerializableCompilation {
18    pub function_bodies: PrimaryMap<LocalFunctionIndex, FunctionBody>,
19    pub function_relocations: PrimaryMap<LocalFunctionIndex, Vec<Relocation>>,
20    pub function_frame_info: PrimaryMap<LocalFunctionIndex, CompiledFunctionFrameInfo>,
21    pub function_call_trampolines: PrimaryMap<SignatureIndex, FunctionBody>,
22    pub dynamic_function_trampolines: PrimaryMap<FunctionIndex, FunctionBody>,
23    pub custom_sections: PrimaryMap<SectionIndex, CustomSection>,
24    pub custom_section_relocations: PrimaryMap<SectionIndex, Vec<Relocation>>,
25    // The section indices corresponding to the Dwarf debug info
26    pub debug: Option<Dwarf>,
27    // Custom section containing libcall trampolines.
28    pub libcall_trampolines: SectionIndex,
29    // Length of each libcall trampoline.
30    pub libcall_trampoline_len: u32,
31}
32
33/// Serializable struct that is able to serialize from and to
34/// a `UniversalArtifactInfo`.
35#[derive(MemoryUsage, Archive, RkyvDeserialize, RkyvSerialize)]
36pub struct SerializableModule {
37    /// The main serializable compilation object
38    pub compilation: SerializableCompilation,
39    /// Compilation informations
40    pub compile_info: CompileModuleInfo,
41    /// Datas initializers
42    pub data_initializers: Box<[OwnedDataInitializer]>,
43    /// CPU Feature flags for this compilation
44    pub cpu_features: u64,
45}
46
47fn to_serialize_error(err: impl std::error::Error) -> SerializeError {
48    SerializeError::Generic(format!("{}", err))
49}
50
51impl SerializableModule {
52    /// Serialize a Module into bytes
53    /// The bytes will have the following format:
54    /// RKYV serialization (any length) + POS (8 bytes)
55    pub fn serialize(&self) -> Result<Vec<u8>, SerializeError> {
56        let mut serializer = AllocSerializer::<4096>::default();
57        let pos = serializer
58            .serialize_value(self)
59            .map_err(to_serialize_error)? as u64;
60        let mut serialized_data = serializer.into_serializer().into_inner();
61        serialized_data.extend_from_slice(&pos.to_le_bytes());
62        Ok(serialized_data.to_vec())
63    }
64
65    /// Deserialize a Module from a slice.
66    /// The slice must have the following format:
67    /// RKYV serialization (any length) + POS (8 bytes)
68    ///
69    /// # Safety
70    ///
71    /// This method is unsafe since it deserializes data directly
72    /// from memory.
73    /// Right now we are not doing any extra work for validation, but
74    /// `rkyv` has an option to do bytecheck on the serialized data before
75    /// serializing (via `rkyv::check_archived_value`).
76    pub unsafe fn deserialize(metadata_slice: &[u8]) -> Result<Self, DeserializeError> {
77        let archived = Self::archive_from_slice(metadata_slice)?;
78        Self::deserialize_from_archive(archived)
79    }
80
81    /// # Safety
82    ///
83    /// This method is unsafe.
84    /// Please check `SerializableModule::deserialize` for more details.
85    unsafe fn archive_from_slice<'a>(
86        metadata_slice: &'a [u8],
87    ) -> Result<&'a ArchivedSerializableModule, DeserializeError> {
88        if metadata_slice.len() < 8 {
89            return Err(DeserializeError::Incompatible(
90                "invalid serialized data".into(),
91            ));
92        }
93        let mut pos: [u8; 8] = Default::default();
94        pos.copy_from_slice(&metadata_slice[metadata_slice.len() - 8..metadata_slice.len()]);
95        let pos: u64 = u64::from_le_bytes(pos);
96        Ok(archived_value::<SerializableModule>(
97            &metadata_slice[..metadata_slice.len() - 8],
98            pos as usize,
99        ))
100    }
101
102    /// Deserialize a compilation module from an archive
103    pub fn deserialize_from_archive(
104        archived: &ArchivedSerializableModule,
105    ) -> Result<Self, DeserializeError> {
106        let mut deserializer = SharedDeserializeMap::new();
107        RkyvDeserialize::deserialize(archived, &mut deserializer)
108            .map_err(|e| DeserializeError::CorruptedBinary(format!("{:?}", e)))
109    }
110}