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