linera_wasmer_compiler/artifact_builders/
artifact_builder.rs

1//! Define `ArtifactBuild` to allow compiling and instantiating to be
2//! done as separate steps.
3
4#[cfg(feature = "compiler")]
5use super::trampoline::{libcall_trampoline_len, make_libcall_trampolines};
6use crate::ArtifactCreate;
7#[cfg(feature = "compiler")]
8use crate::EngineInner;
9use crate::Features;
10#[cfg(feature = "compiler")]
11use crate::{ModuleEnvironment, ModuleMiddlewareChain};
12use core::mem::MaybeUninit;
13use enumset::EnumSet;
14use rkyv::de::deserializers::SharedDeserializeMap;
15use rkyv::option::ArchivedOption;
16use self_cell::self_cell;
17use shared_buffer::OwnedBuffer;
18use std::sync::Arc;
19use wasmer_types::entity::{ArchivedPrimaryMap, PrimaryMap};
20use wasmer_types::ArchivedOwnedDataInitializer;
21use wasmer_types::ArchivedSerializableCompilation;
22use wasmer_types::ArchivedSerializableModule;
23use wasmer_types::CompileModuleInfo;
24use wasmer_types::DeserializeError;
25use wasmer_types::{
26    CompileError, CpuFeature, CustomSection, Dwarf, FunctionIndex, LocalFunctionIndex, MemoryIndex,
27    MemoryStyle, ModuleHash, ModuleInfo, OwnedDataInitializer, Relocation, SectionIndex,
28    SignatureIndex, TableIndex, TableStyle, Target,
29};
30use wasmer_types::{
31    CompiledFunctionFrameInfo, FunctionBody, HashAlgorithm, SerializableCompilation,
32    SerializableModule,
33};
34use wasmer_types::{MetadataHeader, SerializeError};
35
36/// A compiled wasm module, ready to be instantiated.
37#[cfg_attr(feature = "artifact-size", derive(loupe::MemoryUsage))]
38pub struct ArtifactBuild {
39    serializable: SerializableModule,
40}
41
42impl ArtifactBuild {
43    /// Header signature for wasmu binary
44    pub const MAGIC_HEADER: &'static [u8; 16] = b"wasmer-universal";
45
46    /// Check if the provided bytes look like a serialized `ArtifactBuild`.
47    pub fn is_deserializable(bytes: &[u8]) -> bool {
48        bytes.starts_with(Self::MAGIC_HEADER)
49    }
50
51    /// Compile a data buffer into a `ArtifactBuild`, which may then be instantiated.
52    #[cfg(feature = "compiler")]
53    pub fn new(
54        inner_engine: &mut EngineInner,
55        data: &[u8],
56        target: &Target,
57        memory_styles: PrimaryMap<MemoryIndex, MemoryStyle>,
58        table_styles: PrimaryMap<TableIndex, TableStyle>,
59        hash_algorithm: Option<HashAlgorithm>,
60    ) -> Result<Self, CompileError> {
61        let environ = ModuleEnvironment::new();
62        let features = inner_engine.features().clone();
63
64        let translation = environ.translate(data).map_err(CompileError::Wasm)?;
65
66        let compiler = inner_engine.compiler()?;
67
68        // We try to apply the middleware first
69        let mut module = translation.module;
70        let middlewares = compiler.get_middlewares();
71        middlewares
72            .apply_on_module_info(&mut module)
73            .map_err(|err| CompileError::MiddlewareError(err.to_string()))?;
74
75        if let Some(hash_algorithm) = hash_algorithm {
76            let hash = match hash_algorithm {
77                HashAlgorithm::Sha256 => ModuleHash::sha256(data),
78                HashAlgorithm::XXHash => ModuleHash::xxhash(data),
79            };
80
81            module.hash = Some(hash);
82        }
83
84        let compile_info = CompileModuleInfo {
85            module: Arc::new(module),
86            features,
87            memory_styles,
88            table_styles,
89        };
90
91        // Compile the Module
92        let compilation = compiler.compile_module(
93            target,
94            &compile_info,
95            // SAFETY: Calling `unwrap` is correct since
96            // `environ.translate()` above will write some data into
97            // `module_translation_state`.
98            translation.module_translation_state.as_ref().unwrap(),
99            translation.function_body_inputs,
100        )?;
101
102        let data_initializers = translation
103            .data_initializers
104            .iter()
105            .map(OwnedDataInitializer::new)
106            .collect::<Vec<_>>()
107            .into_boxed_slice();
108
109        // Synthesize a custom section to hold the libcall trampolines.
110        let mut function_frame_info = PrimaryMap::with_capacity(compilation.functions.len());
111        let mut function_bodies = PrimaryMap::with_capacity(compilation.functions.len());
112        let mut function_relocations = PrimaryMap::with_capacity(compilation.functions.len());
113        for (_, func) in compilation.functions.into_iter() {
114            function_bodies.push(func.body);
115            function_relocations.push(func.relocations);
116            function_frame_info.push(func.frame_info);
117        }
118        let mut custom_sections = compilation.custom_sections.clone();
119        let mut custom_section_relocations = compilation
120            .custom_sections
121            .iter()
122            .map(|(_, section)| section.relocations.clone())
123            .collect::<PrimaryMap<SectionIndex, _>>();
124        let libcall_trampolines_section = make_libcall_trampolines(target);
125        custom_section_relocations.push(libcall_trampolines_section.relocations.clone());
126        let libcall_trampolines = custom_sections.push(libcall_trampolines_section);
127        let libcall_trampoline_len = libcall_trampoline_len(target) as u32;
128        let cpu_features = compiler.get_cpu_features_used(target.cpu_features());
129
130        let serializable_compilation = SerializableCompilation {
131            function_bodies,
132            function_relocations,
133            function_frame_info,
134            function_call_trampolines: compilation.function_call_trampolines,
135            dynamic_function_trampolines: compilation.dynamic_function_trampolines,
136            custom_sections,
137            custom_section_relocations,
138            debug: compilation.debug,
139            libcall_trampolines,
140            libcall_trampoline_len,
141        };
142        let serializable = SerializableModule {
143            compilation: serializable_compilation,
144            compile_info,
145            data_initializers,
146            cpu_features: cpu_features.as_u64(),
147        };
148        Ok(Self { serializable })
149    }
150
151    /// Create a new ArtifactBuild from a SerializableModule
152    pub fn from_serializable(serializable: SerializableModule) -> Self {
153        Self { serializable }
154    }
155
156    /// Get Functions Bodies ref
157    pub fn get_function_bodies_ref(&self) -> &PrimaryMap<LocalFunctionIndex, FunctionBody> {
158        &self.serializable.compilation.function_bodies
159    }
160
161    /// Get Functions Call Trampolines ref
162    pub fn get_function_call_trampolines_ref(&self) -> &PrimaryMap<SignatureIndex, FunctionBody> {
163        &self.serializable.compilation.function_call_trampolines
164    }
165
166    /// Get Dynamic Functions Call Trampolines ref
167    pub fn get_dynamic_function_trampolines_ref(&self) -> &PrimaryMap<FunctionIndex, FunctionBody> {
168        &self.serializable.compilation.dynamic_function_trampolines
169    }
170
171    /// Get Custom Sections ref
172    pub fn get_custom_sections_ref(&self) -> &PrimaryMap<SectionIndex, CustomSection> {
173        &self.serializable.compilation.custom_sections
174    }
175
176    /// Get Function Relocations
177    pub fn get_function_relocations(&self) -> &PrimaryMap<LocalFunctionIndex, Vec<Relocation>> {
178        &self.serializable.compilation.function_relocations
179    }
180
181    /// Get Function Relocations ref
182    pub fn get_custom_section_relocations_ref(&self) -> &PrimaryMap<SectionIndex, Vec<Relocation>> {
183        &self.serializable.compilation.custom_section_relocations
184    }
185
186    /// Get LibCall Trampoline Section Index
187    pub fn get_libcall_trampolines(&self) -> SectionIndex {
188        self.serializable.compilation.libcall_trampolines
189    }
190
191    /// Get LibCall Trampoline Length
192    pub fn get_libcall_trampoline_len(&self) -> usize {
193        self.serializable.compilation.libcall_trampoline_len as usize
194    }
195
196    /// Get Debug optional Dwarf ref
197    pub fn get_debug_ref(&self) -> Option<&Dwarf> {
198        self.serializable.compilation.debug.as_ref()
199    }
200
201    /// Get Function Relocations ref
202    pub fn get_frame_info_ref(&self) -> &PrimaryMap<LocalFunctionIndex, CompiledFunctionFrameInfo> {
203        &self.serializable.compilation.function_frame_info
204    }
205}
206
207impl<'a> ArtifactCreate<'a> for ArtifactBuild {
208    type OwnedDataInitializer = &'a OwnedDataInitializer;
209    type OwnedDataInitializerIterator = core::slice::Iter<'a, OwnedDataInitializer>;
210
211    fn create_module_info(&self) -> Arc<ModuleInfo> {
212        self.serializable.compile_info.module.clone()
213    }
214
215    fn set_module_info_name(&mut self, name: String) -> bool {
216        Arc::get_mut(&mut self.serializable.compile_info.module).map_or(false, |module_info| {
217            module_info.name = Some(name.to_string());
218            true
219        })
220    }
221
222    fn module_info(&self) -> &ModuleInfo {
223        &self.serializable.compile_info.module
224    }
225
226    fn features(&self) -> &Features {
227        &self.serializable.compile_info.features
228    }
229
230    fn cpu_features(&self) -> EnumSet<CpuFeature> {
231        EnumSet::from_u64(self.serializable.cpu_features)
232    }
233
234    fn data_initializers(&'a self) -> Self::OwnedDataInitializerIterator {
235        self.serializable.data_initializers.iter()
236    }
237
238    fn memory_styles(&self) -> &PrimaryMap<MemoryIndex, MemoryStyle> {
239        &self.serializable.compile_info.memory_styles
240    }
241
242    fn table_styles(&self) -> &PrimaryMap<TableIndex, TableStyle> {
243        &self.serializable.compile_info.table_styles
244    }
245
246    fn serialize(&self) -> Result<Vec<u8>, SerializeError> {
247        serialize_module(&self.serializable)
248    }
249}
250
251/// Module loaded from an archive. Since `CompileModuleInfo` is part of the public
252/// interface of this crate and has to be mutable, it has to be deserialized completely.
253#[derive(Debug)]
254pub struct ModuleFromArchive<'a> {
255    /// The main serializable compilation object
256    pub compilation: &'a ArchivedSerializableCompilation,
257    /// Datas initializers
258    pub data_initializers: &'a rkyv::Archived<Box<[OwnedDataInitializer]>>,
259    /// CPU Feature flags for this compilation
260    pub cpu_features: u64,
261
262    // Keep the original module around for re-serialization
263    original_module: &'a ArchivedSerializableModule,
264}
265
266impl<'a> ModuleFromArchive<'a> {
267    /// Create a new `ModuleFromArchive` from the archived version of a `SerializableModule`
268    pub fn from_serializable_module(
269        module: &'a ArchivedSerializableModule,
270    ) -> Result<Self, DeserializeError> {
271        Ok(Self {
272            compilation: &module.compilation,
273            data_initializers: &module.data_initializers,
274            cpu_features: module.cpu_features,
275            original_module: module,
276        })
277    }
278}
279
280self_cell!(
281    struct ArtifactBuildFromArchiveCell {
282        owner: OwnedBuffer,
283
284        #[covariant]
285        dependent: ModuleFromArchive,
286    }
287
288    impl {Debug}
289);
290
291#[cfg(feature = "artifact-size")]
292impl loupe::MemoryUsage for ArtifactBuildFromArchiveCell {
293    fn size_of_val(&self, _tracker: &mut dyn loupe::MemoryUsageTracker) -> usize {
294        std::mem::size_of_val(self.borrow_owner()) + std::mem::size_of_val(self.borrow_dependent())
295    }
296}
297
298/// A compiled wasm module that was loaded from a serialized archive.
299#[derive(Clone, Debug)]
300#[cfg_attr(feature = "artifact-size", derive(loupe::MemoryUsage))]
301pub struct ArtifactBuildFromArchive {
302    cell: Arc<ArtifactBuildFromArchiveCell>,
303
304    /// Compilation informations
305    compile_info: CompileModuleInfo,
306}
307
308impl ArtifactBuildFromArchive {
309    pub(crate) fn try_new(
310        buffer: OwnedBuffer,
311        module_builder: impl FnOnce(
312            &OwnedBuffer,
313        ) -> Result<&ArchivedSerializableModule, DeserializeError>,
314    ) -> Result<Self, DeserializeError> {
315        let mut compile_info = MaybeUninit::uninit();
316
317        let cell = ArtifactBuildFromArchiveCell::try_new(buffer, |buffer| {
318            let module = module_builder(buffer)?;
319            let mut deserializer = SharedDeserializeMap::new();
320            compile_info = MaybeUninit::new(
321                rkyv::Deserialize::deserialize(&module.compile_info, &mut deserializer)
322                    .map_err(|e| DeserializeError::CorruptedBinary(format!("{:?}", e)))?,
323            );
324            ModuleFromArchive::from_serializable_module(module)
325        })?;
326
327        // Safety: we know the lambda will execute before getting here and assign both values
328        let compile_info = unsafe { compile_info.assume_init() };
329        Ok(Self {
330            cell: Arc::new(cell),
331            compile_info,
332        })
333    }
334
335    /// Gets the owned buffer
336    pub fn owned_buffer(&self) -> &OwnedBuffer {
337        self.cell.borrow_owner()
338    }
339
340    /// Get Functions Bodies ref
341    pub fn get_function_bodies_ref(&self) -> &ArchivedPrimaryMap<LocalFunctionIndex, FunctionBody> {
342        &self.cell.borrow_dependent().compilation.function_bodies
343    }
344
345    /// Get Functions Call Trampolines ref
346    pub fn get_function_call_trampolines_ref(
347        &self,
348    ) -> &ArchivedPrimaryMap<SignatureIndex, FunctionBody> {
349        &self
350            .cell
351            .borrow_dependent()
352            .compilation
353            .function_call_trampolines
354    }
355
356    /// Get Dynamic Functions Call Trampolines ref
357    pub fn get_dynamic_function_trampolines_ref(
358        &self,
359    ) -> &ArchivedPrimaryMap<FunctionIndex, FunctionBody> {
360        &self
361            .cell
362            .borrow_dependent()
363            .compilation
364            .dynamic_function_trampolines
365    }
366
367    /// Get Custom Sections ref
368    pub fn get_custom_sections_ref(&self) -> &ArchivedPrimaryMap<SectionIndex, CustomSection> {
369        &self.cell.borrow_dependent().compilation.custom_sections
370    }
371
372    /// Get Function Relocations
373    pub fn get_function_relocations(
374        &self,
375    ) -> &ArchivedPrimaryMap<LocalFunctionIndex, Vec<Relocation>> {
376        &self
377            .cell
378            .borrow_dependent()
379            .compilation
380            .function_relocations
381    }
382
383    /// Get Function Relocations ref
384    pub fn get_custom_section_relocations_ref(
385        &self,
386    ) -> &ArchivedPrimaryMap<SectionIndex, Vec<Relocation>> {
387        &self
388            .cell
389            .borrow_dependent()
390            .compilation
391            .custom_section_relocations
392    }
393
394    /// Get LibCall Trampoline Section Index
395    pub fn get_libcall_trampolines(&self) -> SectionIndex {
396        self.cell.borrow_dependent().compilation.libcall_trampolines
397    }
398
399    /// Get LibCall Trampoline Length
400    pub fn get_libcall_trampoline_len(&self) -> usize {
401        self.cell
402            .borrow_dependent()
403            .compilation
404            .libcall_trampoline_len as usize
405    }
406
407    /// Get Debug optional Dwarf ref
408    pub fn get_debug_ref(&self) -> Option<&Dwarf> {
409        match self.cell.borrow_dependent().compilation.debug {
410            ArchivedOption::Some(ref x) => Some(x),
411            ArchivedOption::None => None,
412        }
413    }
414
415    /// Get Function Relocations ref
416    pub fn get_frame_info_ref(
417        &self,
418    ) -> &ArchivedPrimaryMap<LocalFunctionIndex, CompiledFunctionFrameInfo> {
419        &self.cell.borrow_dependent().compilation.function_frame_info
420    }
421
422    /// Get Function Relocations ref
423    pub fn deserialize_frame_info_ref(
424        &self,
425    ) -> Result<PrimaryMap<LocalFunctionIndex, CompiledFunctionFrameInfo>, DeserializeError> {
426        let mut deserializer = SharedDeserializeMap::new();
427        rkyv::Deserialize::deserialize(
428            &self.cell.borrow_dependent().compilation.function_frame_info,
429            &mut deserializer,
430        )
431        .map_err(|e| DeserializeError::CorruptedBinary(format!("{:?}", e)))
432    }
433}
434
435impl<'a> ArtifactCreate<'a> for ArtifactBuildFromArchive {
436    type OwnedDataInitializer = &'a ArchivedOwnedDataInitializer;
437    type OwnedDataInitializerIterator = core::slice::Iter<'a, ArchivedOwnedDataInitializer>;
438
439    fn create_module_info(&self) -> Arc<ModuleInfo> {
440        self.compile_info.module.clone()
441    }
442
443    fn set_module_info_name(&mut self, name: String) -> bool {
444        Arc::get_mut(&mut self.compile_info.module).map_or(false, |module_info| {
445            module_info.name = Some(name.to_string());
446            true
447        })
448    }
449
450    fn module_info(&self) -> &ModuleInfo {
451        &self.compile_info.module
452    }
453
454    fn features(&self) -> &Features {
455        &self.compile_info.features
456    }
457
458    fn cpu_features(&self) -> EnumSet<CpuFeature> {
459        EnumSet::from_u64(self.cell.borrow_dependent().cpu_features)
460    }
461
462    fn data_initializers(&'a self) -> Self::OwnedDataInitializerIterator {
463        self.cell.borrow_dependent().data_initializers.iter()
464    }
465
466    fn memory_styles(&self) -> &PrimaryMap<MemoryIndex, MemoryStyle> {
467        &self.compile_info.memory_styles
468    }
469
470    fn table_styles(&self) -> &PrimaryMap<TableIndex, TableStyle> {
471        &self.compile_info.table_styles
472    }
473
474    fn serialize(&self) -> Result<Vec<u8>, SerializeError> {
475        // We could have stored the original bytes, but since the module info name
476        // is mutable, we have to assume the data may have changed and serialize
477        // everything all over again. Also, to be able to serialize, first we have
478        // to deserialize completely. Luckily, serializing a module that was already
479        // deserialized from a file makes little sense, so hopefully, this is not a
480        // common use-case.
481
482        let mut deserializer = SharedDeserializeMap::new();
483        let mut module: SerializableModule = rkyv::Deserialize::deserialize(
484            self.cell.borrow_dependent().original_module,
485            &mut deserializer,
486        )
487        .map_err(|e| SerializeError::Generic(e.to_string()))?;
488        module.compile_info = self.compile_info.clone();
489        serialize_module(&module)
490    }
491}
492
493fn serialize_module(module: &SerializableModule) -> Result<Vec<u8>, SerializeError> {
494    let serialized_data = module.serialize()?;
495    assert!(std::mem::align_of::<SerializableModule>() <= MetadataHeader::ALIGN);
496
497    let mut metadata_binary = vec![];
498    metadata_binary.extend(ArtifactBuild::MAGIC_HEADER);
499    metadata_binary.extend(MetadataHeader::new(serialized_data.len()).into_bytes());
500    metadata_binary.extend(serialized_data);
501    Ok(metadata_binary)
502}