Skip to main content

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