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