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