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