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