wasmer_compiler/engine/
artifact.rs

1//! Define `Artifact`, based on `ArtifactBuild`
2//! to allow compiling and instantiating to be done as separate steps.
3
4use std::sync::{
5    Arc,
6    atomic::{AtomicUsize, Ordering::SeqCst},
7};
8
9#[cfg(feature = "compiler")]
10use crate::ModuleEnvironment;
11use crate::{
12    ArtifactBuild, ArtifactBuildFromArchive, ArtifactCreate, Engine, EngineInner, Features,
13    FrameInfosVariant, FunctionExtent, GlobalFrameInfoRegistration, InstantiationError, Tunables,
14    engine::{link::link_module, resolver::resolve_tags},
15    lib::std::vec::IntoIter,
16    register_frame_info, resolve_imports,
17    serialize::{MetadataHeader, SerializableModule},
18    types::relocation::{RelocationLike, RelocationTarget},
19};
20#[cfg(feature = "static-artifact-create")]
21use crate::{Compiler, FunctionBodyData, ModuleTranslationState, types::module::CompileModuleInfo};
22#[cfg(any(feature = "static-artifact-create", feature = "static-artifact-load"))]
23use crate::{serialize::SerializableCompilation, types::symbols::ModuleMetadata};
24
25use enumset::EnumSet;
26use rkyv::option::ArchivedOption;
27use shared_buffer::OwnedBuffer;
28
29#[cfg(any(feature = "static-artifact-create", feature = "static-artifact-load"))]
30use std::mem;
31
32#[cfg(feature = "static-artifact-create")]
33use crate::object::{
34    Object, ObjectMetadataBuilder, emit_compilation, emit_data, get_object_for_target,
35};
36
37use wasmer_types::{
38    ArchivedDataInitializerLocation, ArchivedOwnedDataInitializer, CompilationProgressCallback,
39    CompileError, DataInitializer, DataInitializerLike, DataInitializerLocation,
40    DataInitializerLocationLike, DeserializeError, FunctionIndex, LocalFunctionIndex, MemoryIndex,
41    ModuleInfo, OwnedDataInitializer, SerializeError, SignatureIndex, TableIndex,
42    entity::{BoxedSlice, PrimaryMap},
43    target::{CpuFeature, Target},
44};
45
46use wasmer_types::VMOffsets;
47use wasmer_vm::{
48    FunctionBodyPtr, InstanceAllocator, MemoryStyle, StoreObjects, TableStyle, TrapHandlerFn,
49    VMConfig, VMExtern, VMInstance, VMSignatureHash, VMTrampoline,
50};
51
52#[cfg_attr(feature = "artifact-size", derive(loupe::MemoryUsage))]
53pub struct AllocatedArtifact {
54    // This shows if the frame info has been registered already or not.
55    // Because the 'GlobalFrameInfoRegistration' ownership can be transferred to EngineInner
56    // this bool is needed to track the status, as 'frame_info_registration' will be None
57    // after the ownership is transferred.
58    frame_info_registered: bool,
59    // frame_info_registered is not staying there but transferred to CodeMemory from EngineInner
60    // using 'Artifact::take_frame_info_registration' method
61    // so the GloabelFrameInfo and MMap stays in sync and get dropped at the same time
62    frame_info_registration: Option<GlobalFrameInfoRegistration>,
63    finished_functions: BoxedSlice<LocalFunctionIndex, FunctionBodyPtr>,
64
65    #[cfg_attr(feature = "artifact-size", loupe(skip))]
66    finished_function_call_trampolines: BoxedSlice<SignatureIndex, VMTrampoline>,
67    finished_dynamic_function_trampolines: BoxedSlice<FunctionIndex, FunctionBodyPtr>,
68    signatures: BoxedSlice<SignatureIndex, VMSignatureHash>,
69    finished_function_lengths: BoxedSlice<LocalFunctionIndex, usize>,
70    // The maximum stack size used for each function (available only for the Singlepass compiler).
71    function_max_stack_usage: BoxedSlice<LocalFunctionIndex, Option<usize>>,
72
73    /// Precomputed `VMOffsets` for this artifact's module, cloned by
74    /// `Artifact::instantiate` instead of recomputing on every call.
75    ///
76    /// Safe to cache because `VMOffsets::new(pointer_size, module_info)`
77    /// is deterministic, `module_info` is immutable after compile (the
78    /// only mutable field `name` is not a `VMOffsets` input), and the
79    /// host's pointer size is a runtime constant.
80    ///
81    /// Built once in `from_parts` and in the deserialization path
82    /// (`deserialize_object_native`); `VMOffsets::new` was ~9% of
83    /// `Instance::new` time on profile traces of a per-request wasm
84    /// host calling `Module::instantiate` in a tight loop.
85    #[cfg_attr(feature = "artifact-size", loupe(skip))]
86    vm_offsets: VMOffsets,
87}
88
89impl AllocatedArtifact {
90    fn function_extents(&self) -> PrimaryMap<LocalFunctionIndex, FunctionExtent> {
91        assert_eq!(
92            self.finished_functions.len(),
93            self.finished_function_lengths.len(),
94            "finished_functions and finished_function_lengths must have equal length"
95        );
96        self.finished_functions
97            .iter()
98            .map(|(index, &ptr)| {
99                let length = self.finished_function_lengths[index];
100                FunctionExtent { ptr, length }
101            })
102            .collect()
103    }
104}
105
106#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]
107#[cfg_attr(feature = "artifact-size", derive(loupe::MemoryUsage))]
108#[repr(transparent)]
109/// A unique identifier for an Artifact.
110pub struct ArtifactId {
111    id: usize,
112}
113
114impl ArtifactId {
115    /// Format this identifier as a string.
116    pub fn id(&self) -> String {
117        format!("{}", self.id)
118    }
119}
120
121impl Clone for ArtifactId {
122    fn clone(&self) -> Self {
123        Self::default()
124    }
125}
126
127impl Default for ArtifactId {
128    fn default() -> Self {
129        static NEXT_ID: AtomicUsize = AtomicUsize::new(0);
130        Self {
131            id: NEXT_ID.fetch_add(1, SeqCst),
132        }
133    }
134}
135
136/// A compiled wasm module, ready to be instantiated.
137#[cfg_attr(feature = "artifact-size", derive(loupe::MemoryUsage))]
138pub struct Artifact {
139    id: ArtifactId,
140    artifact: ArtifactBuildVariant,
141    // The artifact will only be allocated in memory in case we can execute it
142    // (that means, if the target != host then this will be None).
143    allocated: Option<AllocatedArtifact>,
144}
145
146/// Artifacts may be created as the result of the compilation of a wasm
147/// module, corresponding to `ArtifactBuildVariant::Plain`, or loaded
148/// from an archive, corresponding to `ArtifactBuildVariant::Archived`.
149#[cfg_attr(feature = "artifact-size", derive(loupe::MemoryUsage))]
150#[allow(clippy::large_enum_variant)]
151pub enum ArtifactBuildVariant {
152    Plain(ArtifactBuild),
153    Archived(ArtifactBuildFromArchive),
154}
155
156impl Artifact {
157    /// Compile a data buffer into a `ArtifactBuild`, which may then be instantiated.
158    #[cfg(feature = "compiler")]
159    pub fn new(
160        engine: &Engine,
161        data: &[u8],
162        tunables: &dyn Tunables,
163        progress_callback: Option<CompilationProgressCallback>,
164    ) -> Result<Self, CompileError> {
165        let mut inner_engine = engine.inner_mut();
166        let environ = ModuleEnvironment::new();
167        let translation = environ.translate(data).map_err(CompileError::Wasm)?;
168        let module = translation.module;
169        let memory_styles: PrimaryMap<MemoryIndex, MemoryStyle> = module
170            .memories
171            .values()
172            .map(|memory_type| tunables.memory_style(memory_type))
173            .collect();
174        let table_styles: PrimaryMap<TableIndex, TableStyle> = module
175            .tables
176            .values()
177            .map(|table_type| tunables.table_style(table_type))
178            .collect();
179
180        let artifact = ArtifactBuild::new(
181            &mut inner_engine,
182            data,
183            engine.target(),
184            memory_styles,
185            table_styles,
186            progress_callback.as_ref(),
187        )?;
188
189        Self::from_parts(
190            &mut inner_engine,
191            ArtifactBuildVariant::Plain(artifact),
192            engine.target(),
193        )
194        .map_err(|e| match e {
195            DeserializeError::Compiler(c) => c,
196
197            // `from_parts` only ever returns `CompileError`s when an
198            // `ArtifactBuildVariant::Plain` is passed in. Other cases
199            // of `DeserializeError` can only happen when an
200            // `ArtifactBuildVariant::Archived` is passed in. We don't
201            // wish to change the return type of this method because
202            // a. it makes no sense and b. it would be a breaking change,
203            // hence this match block and the other cases being
204            // unreachable.
205            _ => unreachable!(),
206        })
207    }
208
209    /// This indicates if the Artifact is allocated and can be run by the current
210    /// host. In case it can't be run (for example, if the artifact is cross compiled to
211    /// other architecture), it will return false.
212    pub fn allocated(&self) -> bool {
213        self.allocated.is_some()
214    }
215
216    /// A unique identifier for this object.
217    ///
218    /// This exists to allow us to compare two Artifacts for equality. Otherwise,
219    /// comparing two trait objects unsafely relies on implementation details
220    /// of trait representation.
221    pub fn id(&self) -> &ArtifactId {
222        &self.id
223    }
224
225    /// Compile a data buffer into a `ArtifactBuild`, which may then be instantiated.
226    #[cfg(not(feature = "compiler"))]
227    pub fn new(_engine: &Engine, _data: &[u8]) -> Result<Self, CompileError> {
228        Err(CompileError::Codegen(
229            "Compilation is not enabled in the engine".to_string(),
230        ))
231    }
232
233    /// Deserialize a serialized artifact.
234    ///
235    /// # Safety
236    /// This function loads executable code into memory.
237    /// You must trust the loaded bytes to be valid for the chosen engine and
238    /// for the host CPU architecture.
239    /// In contrast to [`Self::deserialize_unchecked`] the artifact layout is
240    /// validated, which increases safety.
241    pub unsafe fn deserialize(
242        engine: &Engine,
243        bytes: OwnedBuffer,
244    ) -> Result<Self, DeserializeError> {
245        unsafe {
246            if !ArtifactBuild::is_deserializable(bytes.as_ref()) {
247                let static_artifact = Self::deserialize_object(engine, bytes);
248                match static_artifact {
249                    Ok(v) => {
250                        return Ok(v);
251                    }
252                    Err(e) => {
253                        return Err(DeserializeError::Incompatible(format!(
254                            "The provided bytes are not a Wasmer engine artifact: {e}"
255                        )));
256                    }
257                }
258            }
259
260            let artifact = ArtifactBuildFromArchive::try_new(bytes, |bytes| {
261                let bytes =
262                    Self::get_byte_slice(bytes, ArtifactBuild::MAGIC_HEADER.len(), bytes.len())?;
263
264                let metadata_len = MetadataHeader::parse(bytes)?;
265                let metadata_slice = Self::get_byte_slice(bytes, MetadataHeader::LEN, bytes.len())?;
266                let metadata_slice = Self::get_byte_slice(metadata_slice, 0, metadata_len)?;
267
268                SerializableModule::archive_from_slice_checked(metadata_slice)
269            })?;
270
271            let mut inner_engine = engine.inner_mut();
272            Self::from_parts(
273                &mut inner_engine,
274                ArtifactBuildVariant::Archived(artifact),
275                engine.target(),
276            )
277        }
278    }
279
280    /// Deserialize a serialized artifact.
281    ///
282    /// NOTE: You should prefer [`Self::deserialize`].
283    ///
284    /// # Safety
285    /// See [`Self::deserialize`].
286    /// In contrast to the above, this function skips artifact layout validation,
287    /// which increases the risk of loading invalid artifacts.
288    pub unsafe fn deserialize_unchecked(
289        engine: &Engine,
290        bytes: OwnedBuffer,
291    ) -> Result<Self, DeserializeError> {
292        unsafe {
293            if !ArtifactBuild::is_deserializable(bytes.as_ref()) {
294                let static_artifact = Self::deserialize_object(engine, bytes);
295                match static_artifact {
296                    Ok(v) => {
297                        return Ok(v);
298                    }
299                    Err(e) => {
300                        return Err(DeserializeError::Incompatible(format!(
301                            "The provided bytes are not a Wasmer engine artifact: {e}"
302                        )));
303                    }
304                }
305            }
306
307            let artifact = ArtifactBuildFromArchive::try_new(bytes, |bytes| {
308                let bytes =
309                    Self::get_byte_slice(bytes, ArtifactBuild::MAGIC_HEADER.len(), bytes.len())?;
310
311                let metadata_len = MetadataHeader::parse(bytes)?;
312                let metadata_slice = Self::get_byte_slice(bytes, MetadataHeader::LEN, bytes.len())?;
313                let metadata_slice = Self::get_byte_slice(metadata_slice, 0, metadata_len)?;
314
315                SerializableModule::archive_from_slice(metadata_slice)
316            })?;
317
318            let mut inner_engine = engine.inner_mut();
319            Self::from_parts(
320                &mut inner_engine,
321                ArtifactBuildVariant::Archived(artifact),
322                engine.target(),
323            )
324        }
325    }
326
327    /// Construct a `ArtifactBuild` from component parts.
328    pub fn from_parts(
329        engine_inner: &mut EngineInner,
330        artifact: ArtifactBuildVariant,
331        target: &Target,
332    ) -> Result<Self, DeserializeError> {
333        if !target.is_native() {
334            return Ok(Self {
335                id: Default::default(),
336                artifact,
337                allocated: None,
338            });
339        } else {
340            // check if cpu features are compatible before anything else
341            let cpu_features = artifact.cpu_features();
342            if !target.cpu_features().is_superset(cpu_features) {
343                return Err(DeserializeError::Incompatible(format!(
344                    "Some CPU Features needed for the artifact are missing: {:?}",
345                    cpu_features.difference(*target.cpu_features())
346                )));
347            }
348        }
349        let module_info = artifact.module_info();
350        let (
351            finished_functions,
352            finished_function_call_trampolines,
353            finished_dynamic_function_trampolines,
354            custom_sections,
355        ) = match &artifact {
356            ArtifactBuildVariant::Plain(p) => engine_inner.allocate(
357                module_info,
358                p.get_function_bodies_ref().values(),
359                p.get_function_call_trampolines_ref().values(),
360                p.get_dynamic_function_trampolines_ref().values(),
361                p.get_custom_sections_ref().values(),
362            )?,
363
364            ArtifactBuildVariant::Archived(a) => engine_inner.allocate(
365                module_info,
366                a.get_function_bodies_ref().values(),
367                a.get_function_call_trampolines_ref().values(),
368                a.get_dynamic_function_trampolines_ref().values(),
369                a.get_custom_sections_ref().values(),
370            )?,
371        };
372
373        let get_got_address: Box<dyn Fn(RelocationTarget) -> Option<usize>> = match &artifact {
374            ArtifactBuildVariant::Plain(p) => {
375                if let Some(got) = p.get_got_ref().index {
376                    let relocs: Vec<_> = p.get_custom_section_relocations_ref()[got]
377                        .iter()
378                        .map(|v| (v.reloc_target, v.offset))
379                        .collect();
380                    let got_base = custom_sections[got].0 as usize;
381                    Box::new(move |t: RelocationTarget| {
382                        relocs
383                            .iter()
384                            .find(|(v, _)| v == &t)
385                            .map(|(_, o)| got_base + (*o as usize))
386                    })
387                } else {
388                    Box::new(|_: RelocationTarget| None)
389                }
390            }
391
392            ArtifactBuildVariant::Archived(p) => {
393                if let Some(got) = p.get_got_ref().index {
394                    let relocs: Vec<_> = p.get_custom_section_relocations_ref()[got]
395                        .iter()
396                        .map(|v| (v.reloc_target(), v.offset))
397                        .collect();
398                    let got_base = custom_sections[got].0 as usize;
399                    Box::new(move |t: RelocationTarget| {
400                        relocs
401                            .iter()
402                            .find(|(v, _)| v == &t)
403                            .map(|(_, o)| got_base + (o.to_native() as usize))
404                    })
405                } else {
406                    Box::new(|_: RelocationTarget| None)
407                }
408            }
409        };
410        let functions_max_stack_usage = match &artifact {
411            ArtifactBuildVariant::Plain(p) => p
412                .get_function_max_stack_usage()
413                .values()
414                .cloned()
415                .collect::<PrimaryMap<LocalFunctionIndex, _>>(),
416            ArtifactBuildVariant::Archived(a) => a
417                .get_function_max_stack_usage()
418                .values()
419                .map(|v| match v {
420                    ArchivedOption::None => None,
421                    ArchivedOption::Some(v) => Some(v.to_native() as usize),
422                })
423                .collect::<PrimaryMap<LocalFunctionIndex, _>>(),
424        };
425
426        match &artifact {
427            ArtifactBuildVariant::Plain(p) => link_module(
428                module_info,
429                &finished_functions,
430                &finished_dynamic_function_trampolines,
431                p.get_function_relocations()
432                    .iter()
433                    .map(|(k, v)| (k, v.iter())),
434                &custom_sections,
435                p.get_custom_section_relocations_ref()
436                    .iter()
437                    .map(|(k, v)| (k, v.iter())),
438                p.get_libcall_trampolines(),
439                p.get_libcall_trampoline_len(),
440                &get_got_address,
441            ),
442            ArtifactBuildVariant::Archived(a) => link_module(
443                module_info,
444                &finished_functions,
445                &finished_dynamic_function_trampolines,
446                a.get_function_relocations()
447                    .iter()
448                    .map(|(k, v)| (k, v.iter())),
449                &custom_sections,
450                a.get_custom_section_relocations_ref()
451                    .iter()
452                    .map(|(k, v)| (k, v.iter())),
453                a.get_libcall_trampolines(),
454                a.get_libcall_trampoline_len(),
455                &get_got_address,
456            ),
457        };
458
459        // Compute indices into the shared signature table.
460        let signatures = {
461            let signature_registry = engine_inner.signatures();
462            module_info
463                .signatures
464                .values()
465                .zip(module_info.signature_hashes.values())
466                .map(|(sig, sig_hash)| signature_registry.register(sig, *sig_hash))
467                .collect::<PrimaryMap<_, _>>()
468        };
469
470        #[allow(unused_variables)]
471        let eh_frame = match &artifact {
472            ArtifactBuildVariant::Plain(p) => p.get_unwind_info().eh_frame.map(|v| unsafe {
473                std::slice::from_raw_parts(
474                    *custom_sections[v],
475                    p.get_custom_sections_ref()[v].bytes.len(),
476                )
477            }),
478            ArtifactBuildVariant::Archived(a) => a.get_unwind_info().eh_frame.map(|v| unsafe {
479                std::slice::from_raw_parts(
480                    *custom_sections[v],
481                    a.get_custom_sections_ref()[v].bytes.len(),
482                )
483            }),
484        };
485        #[allow(unused_variables)]
486        let compact_unwind = match &artifact {
487            ArtifactBuildVariant::Plain(p) => p.get_unwind_info().compact_unwind.map(|v| unsafe {
488                std::slice::from_raw_parts(
489                    *custom_sections[v],
490                    p.get_custom_sections_ref()[v].bytes.len(),
491                )
492            }),
493            ArtifactBuildVariant::Archived(a) => {
494                a.get_unwind_info().compact_unwind.map(|v| unsafe {
495                    std::slice::from_raw_parts(
496                        *custom_sections[v],
497                        a.get_custom_sections_ref()[v].bytes.len(),
498                    )
499                })
500            }
501        };
502
503        #[cfg(all(not(target_arch = "wasm32"), feature = "compiler"))]
504        {
505            engine_inner.register_perfmap(&finished_functions, module_info)?;
506        }
507
508        // Make all code compiled thus far executable.
509        engine_inner.publish_compiled_code();
510
511        #[cfg(all(target_os = "macos", target_arch = "aarch64"))]
512        if let Some(compact_unwind) = compact_unwind {
513            engine_inner.publish_compact_unwind(
514                compact_unwind,
515                get_got_address(RelocationTarget::LibCall(wasmer_vm::LibCall::EHPersonality)),
516            )?;
517        }
518        #[cfg(not(any(
519            target_arch = "wasm32",
520            all(target_os = "macos", target_arch = "aarch64")
521        )))]
522        engine_inner.publish_eh_frame(eh_frame)?;
523
524        drop(get_got_address);
525
526        let finished_function_lengths = finished_functions
527            .values()
528            .map(|extent| extent.length)
529            .collect::<PrimaryMap<LocalFunctionIndex, usize>>()
530            .into_boxed_slice();
531        let finished_functions = finished_functions
532            .values()
533            .map(|extent| extent.ptr)
534            .collect::<PrimaryMap<LocalFunctionIndex, FunctionBodyPtr>>()
535            .into_boxed_slice();
536        let finished_function_call_trampolines =
537            finished_function_call_trampolines.into_boxed_slice();
538        let finished_dynamic_function_trampolines =
539            finished_dynamic_function_trampolines.into_boxed_slice();
540        let signatures = signatures.into_boxed_slice();
541
542        let vm_offsets = VMOffsets::new(std::mem::size_of::<usize>() as u8, module_info);
543
544        let mut artifact = Self {
545            id: Default::default(),
546            artifact,
547            allocated: Some(AllocatedArtifact {
548                frame_info_registered: false,
549                frame_info_registration: None,
550                finished_functions,
551                finished_function_call_trampolines,
552                finished_dynamic_function_trampolines,
553                signatures,
554                finished_function_lengths,
555                vm_offsets,
556                function_max_stack_usage: functions_max_stack_usage.into_boxed_slice(),
557            }),
558        };
559
560        artifact
561            .internal_register_frame_info()
562            .map_err(|e| DeserializeError::CorruptedBinary(format!("{e:?}")))?;
563        if let Some(frame_info) = artifact.internal_take_frame_info_registration() {
564            engine_inner.register_frame_info(frame_info);
565        }
566
567        Ok(artifact)
568    }
569
570    /// Check if the provided bytes look like a serialized `ArtifactBuild`.
571    pub fn is_deserializable(bytes: &[u8]) -> bool {
572        ArtifactBuild::is_deserializable(bytes)
573    }
574}
575
576impl PartialEq for Artifact {
577    fn eq(&self, other: &Self) -> bool {
578        self.id == other.id
579    }
580}
581impl Eq for Artifact {}
582
583impl std::fmt::Debug for Artifact {
584    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
585        f.debug_struct("Artifact")
586            .field("artifact_id", &self.id)
587            .field("module_info", &self.module_info())
588            .finish()
589    }
590}
591
592impl<'a> ArtifactCreate<'a> for Artifact {
593    type OwnedDataInitializer = <ArtifactBuildVariant as ArtifactCreate<'a>>::OwnedDataInitializer;
594    type OwnedDataInitializerIterator =
595        <ArtifactBuildVariant as ArtifactCreate<'a>>::OwnedDataInitializerIterator;
596
597    fn set_module_info_name(&mut self, name: String) -> bool {
598        self.artifact.set_module_info_name(name)
599    }
600
601    fn create_module_info(&self) -> Arc<ModuleInfo> {
602        self.artifact.create_module_info()
603    }
604
605    fn module_info(&self) -> &ModuleInfo {
606        self.artifact.module_info()
607    }
608
609    fn features(&self) -> &Features {
610        self.artifact.features()
611    }
612
613    fn cpu_features(&self) -> EnumSet<CpuFeature> {
614        self.artifact.cpu_features()
615    }
616
617    fn data_initializers(&'a self) -> Self::OwnedDataInitializerIterator {
618        self.artifact.data_initializers()
619    }
620
621    fn memory_styles(&self) -> &PrimaryMap<MemoryIndex, MemoryStyle> {
622        self.artifact.memory_styles()
623    }
624
625    fn table_styles(&self) -> &PrimaryMap<TableIndex, TableStyle> {
626        self.artifact.table_styles()
627    }
628
629    fn serialize(&self) -> Result<Vec<u8>, SerializeError> {
630        self.artifact.serialize()
631    }
632}
633
634impl<'a> ArtifactCreate<'a> for ArtifactBuildVariant {
635    type OwnedDataInitializer = OwnedDataInitializerVariant<'a>;
636    type OwnedDataInitializerIterator = IntoIter<Self::OwnedDataInitializer>;
637
638    fn create_module_info(&self) -> Arc<ModuleInfo> {
639        match self {
640            Self::Plain(artifact) => artifact.create_module_info(),
641            Self::Archived(artifact) => artifact.create_module_info(),
642        }
643    }
644
645    fn set_module_info_name(&mut self, name: String) -> bool {
646        match self {
647            Self::Plain(artifact) => artifact.set_module_info_name(name),
648            Self::Archived(artifact) => artifact.set_module_info_name(name),
649        }
650    }
651
652    fn module_info(&self) -> &ModuleInfo {
653        match self {
654            Self::Plain(artifact) => artifact.module_info(),
655            Self::Archived(artifact) => artifact.module_info(),
656        }
657    }
658
659    fn features(&self) -> &Features {
660        match self {
661            Self::Plain(artifact) => artifact.features(),
662            Self::Archived(artifact) => artifact.features(),
663        }
664    }
665
666    fn cpu_features(&self) -> EnumSet<CpuFeature> {
667        match self {
668            Self::Plain(artifact) => artifact.cpu_features(),
669            Self::Archived(artifact) => artifact.cpu_features(),
670        }
671    }
672
673    fn memory_styles(&self) -> &PrimaryMap<MemoryIndex, MemoryStyle> {
674        match self {
675            Self::Plain(artifact) => artifact.memory_styles(),
676            Self::Archived(artifact) => artifact.memory_styles(),
677        }
678    }
679
680    fn table_styles(&self) -> &PrimaryMap<TableIndex, TableStyle> {
681        match self {
682            Self::Plain(artifact) => artifact.table_styles(),
683            Self::Archived(artifact) => artifact.table_styles(),
684        }
685    }
686
687    fn data_initializers(&'a self) -> Self::OwnedDataInitializerIterator {
688        match self {
689            Self::Plain(artifact) => artifact
690                .data_initializers()
691                .map(OwnedDataInitializerVariant::Plain)
692                .collect::<Vec<_>>()
693                .into_iter(),
694            Self::Archived(artifact) => artifact
695                .data_initializers()
696                .map(OwnedDataInitializerVariant::Archived)
697                .collect::<Vec<_>>()
698                .into_iter(),
699        }
700    }
701
702    fn serialize(&self) -> Result<Vec<u8>, SerializeError> {
703        match self {
704            Self::Plain(artifact) => artifact.serialize(),
705            Self::Archived(artifact) => artifact.serialize(),
706        }
707    }
708}
709
710#[derive(Clone, Copy)]
711pub enum OwnedDataInitializerVariant<'a> {
712    Plain(&'a OwnedDataInitializer),
713    Archived(&'a ArchivedOwnedDataInitializer),
714}
715
716impl<'a> DataInitializerLike<'a> for OwnedDataInitializerVariant<'a> {
717    type Location = DataInitializerLocationVariant<'a>;
718
719    fn location(&self) -> Self::Location {
720        match self {
721            Self::Plain(plain) => DataInitializerLocationVariant::Plain(plain.location()),
722            Self::Archived(archived) => {
723                DataInitializerLocationVariant::Archived(archived.location())
724            }
725        }
726    }
727
728    fn data(&self) -> &'a [u8] {
729        match self {
730            Self::Plain(plain) => plain.data(),
731            Self::Archived(archived) => archived.data(),
732        }
733    }
734}
735
736#[derive(Clone, Copy)]
737pub enum DataInitializerLocationVariant<'a> {
738    Plain(&'a DataInitializerLocation),
739    Archived(&'a ArchivedDataInitializerLocation),
740}
741
742impl DataInitializerLocationVariant<'_> {
743    pub fn clone_to_plain(&self) -> DataInitializerLocation {
744        match self {
745            Self::Plain(p) => (*p).clone(),
746            Self::Archived(a) => DataInitializerLocation {
747                memory_index: a.memory_index(),
748                offset_expr: a.offset_expr(),
749            },
750        }
751    }
752}
753
754impl DataInitializerLocationLike for DataInitializerLocationVariant<'_> {
755    fn memory_index(&self) -> MemoryIndex {
756        match self {
757            Self::Plain(plain) => plain.memory_index(),
758            Self::Archived(archived) => archived.memory_index(),
759        }
760    }
761
762    fn offset_expr(&self) -> wasmer_types::InitExpr {
763        match self {
764            Self::Plain(plain) => plain.offset_expr(),
765            Self::Archived(archived) => archived.offset_expr(),
766        }
767    }
768}
769
770impl Artifact {
771    fn internal_register_frame_info(&mut self) -> Result<(), DeserializeError> {
772        if self
773            .allocated
774            .as_ref()
775            .expect("It must be allocated")
776            .frame_info_registered
777        {
778            return Ok(()); // already done
779        }
780
781        let finished_function_extents = self
782            .allocated
783            .as_ref()
784            .expect("It must be allocated")
785            .function_extents()
786            .into_boxed_slice();
787
788        let frame_info_registration = &mut self
789            .allocated
790            .as_mut()
791            .expect("It must be allocated")
792            .frame_info_registration;
793
794        *frame_info_registration = register_frame_info(
795            self.artifact.create_module_info(),
796            &finished_function_extents,
797            match &self.artifact {
798                ArtifactBuildVariant::Plain(p) => {
799                    FrameInfosVariant::Owned(p.get_frame_info_ref().clone())
800                }
801                ArtifactBuildVariant::Archived(a) => FrameInfosVariant::Archived(a.clone()),
802            },
803        );
804
805        self.allocated
806            .as_mut()
807            .expect("It must be allocated")
808            .frame_info_registered = true;
809
810        Ok(())
811    }
812
813    fn internal_take_frame_info_registration(&mut self) -> Option<GlobalFrameInfoRegistration> {
814        let frame_info_registration = &mut self
815            .allocated
816            .as_mut()
817            .expect("It must be allocated")
818            .frame_info_registration;
819
820        frame_info_registration.take()
821    }
822
823    /// Returns the functions allocated in memory or this `Artifact`
824    /// ready to be run.
825    pub fn finished_functions(&self) -> &BoxedSlice<LocalFunctionIndex, FunctionBodyPtr> {
826        &self
827            .allocated
828            .as_ref()
829            .expect("It must be allocated")
830            .finished_functions
831    }
832
833    /// Returns the start address and byte length of each locally-defined
834    /// function body in this artifact.
835    ///
836    /// Returns `None` for cross-compiled artifacts (where the artifact has not
837    /// been allocated into the host process).
838    ///
839    /// # Security
840    ///
841    /// The returned addresses are host-process pointers. They are not stable
842    /// across runs and must not be forwarded to untrusted parties, as they
843    /// reveal ASLR layout information.
844    pub fn finished_function_extents(&self) -> Option<Vec<(LocalFunctionIndex, FunctionExtent)>> {
845        let allocated = self.allocated.as_ref()?;
846        Some(allocated.function_extents().into_iter().collect())
847    }
848
849    /// Return the maximum stack size used for each function (available only for the Singlepass compiler).
850    pub fn finished_functions_max_stack_usage(
851        &self,
852    ) -> Option<Vec<(LocalFunctionIndex, Option<usize>)>> {
853        let allocated = self.allocated.as_ref()?;
854        Some(
855            allocated
856                .function_max_stack_usage
857                .into_iter()
858                .map(|f| (f.0, *f.1))
859                .collect(),
860        )
861    }
862
863    /// Returns the function call trampolines allocated in memory of this
864    /// `Artifact`, ready to be run.
865    pub fn finished_function_call_trampolines(&self) -> &BoxedSlice<SignatureIndex, VMTrampoline> {
866        &self
867            .allocated
868            .as_ref()
869            .expect("It must be allocated")
870            .finished_function_call_trampolines
871    }
872
873    /// Returns the dynamic function trampolines allocated in memory
874    /// of this `Artifact`, ready to be run.
875    pub fn finished_dynamic_function_trampolines(
876        &self,
877    ) -> &BoxedSlice<FunctionIndex, FunctionBodyPtr> {
878        &self
879            .allocated
880            .as_ref()
881            .expect("It must be allocated")
882            .finished_dynamic_function_trampolines
883    }
884
885    /// Returns the associated VM signatures for this `Artifact`.
886    pub fn signatures(&self) -> &BoxedSlice<SignatureIndex, VMSignatureHash> {
887        &self
888            .allocated
889            .as_ref()
890            .expect("It must be allocated")
891            .signatures
892    }
893
894    /// Do preinstantiation logic that is executed before instantiating
895    #[allow(clippy::result_large_err)]
896    pub fn preinstantiate(&self) -> Result<(), InstantiationError> {
897        Ok(())
898    }
899
900    /// Crate an `Instance` from this `Artifact`.
901    ///
902    /// # Safety
903    ///
904    /// See [`VMInstance::new`].
905    #[allow(clippy::result_large_err)]
906    pub unsafe fn instantiate(
907        &self,
908        tunables: &dyn Tunables,
909        imports: &[VMExtern],
910        context: &mut StoreObjects,
911    ) -> Result<VMInstance, InstantiationError> {
912        unsafe {
913            // Validate the CPU features this module was compiled with against the
914            // host CPU features.
915            let host_cpu_features = CpuFeature::for_host();
916            if !host_cpu_features.is_superset(self.cpu_features()) {
917                return Err(InstantiationError::CpuFeature(format!(
918                    "{:?}",
919                    self.cpu_features().difference(host_cpu_features)
920                )));
921            }
922
923            self.preinstantiate()?;
924
925            let module = self.create_module_info();
926
927            let tags = resolve_tags(&module, imports, context).map_err(InstantiationError::Link)?;
928
929            let imports = resolve_imports(
930                &module,
931                imports,
932                context,
933                self.finished_dynamic_function_trampolines(),
934                self.memory_styles(),
935                self.table_styles(),
936            )
937            .map_err(InstantiationError::Link)?;
938
939            // Get pointers to where metadata about local memories should live in VM memory.
940            // Get pointers to where metadata about local tables should live in VM memory.
941
942            let cached_offsets = self
943                .allocated
944                .as_ref()
945                .map(|a| a.vm_offsets.clone())
946                .expect("Artifact::instantiate called on a non-host artifact");
947
948            let (
949                allocator,
950                memory_definition_locations,
951                table_definition_locations,
952                global_definition_locations,
953            ) = InstanceAllocator::new_with_offsets(cached_offsets, &module);
954            let finished_memories = tunables
955                .create_memories(
956                    context,
957                    &module,
958                    self.memory_styles(),
959                    &memory_definition_locations,
960                )
961                .map_err(InstantiationError::Link)?
962                .into_boxed_slice();
963            let finished_tables = tunables
964                .create_tables(
965                    context,
966                    &module,
967                    self.table_styles(),
968                    &table_definition_locations,
969                )
970                .map_err(InstantiationError::Link)?
971                .into_boxed_slice();
972            let finished_globals = tunables
973                .create_globals(context, &module, &global_definition_locations)
974                .map_err(InstantiationError::Link)?
975                .into_boxed_slice();
976
977            let handle = VMInstance::new(
978                allocator,
979                module,
980                context,
981                self.finished_functions().clone(),
982                self.finished_function_call_trampolines().clone(),
983                finished_memories,
984                finished_tables,
985                finished_globals,
986                tags,
987                imports,
988                self.signatures().clone(),
989            )
990            .map_err(InstantiationError::Start)?;
991            Ok(handle)
992        }
993    }
994
995    /// Finishes the instantiation of a just created `VMInstance`.
996    ///
997    /// # Safety
998    ///
999    /// See [`VMInstance::finish_instantiation`].
1000    #[allow(clippy::result_large_err)]
1001    pub unsafe fn finish_instantiation(
1002        &self,
1003        config: &VMConfig,
1004        trap_handler: Option<*const TrapHandlerFn<'static>>,
1005        handle: &mut VMInstance,
1006    ) -> Result<(), InstantiationError> {
1007        unsafe {
1008            let data_initializers = self
1009                .data_initializers()
1010                .map(|init| DataInitializer {
1011                    location: init.location().clone_to_plain(),
1012                    data: init.data(),
1013                })
1014                .collect::<Vec<_>>();
1015            handle
1016                .finish_instantiation(config, trap_handler, &data_initializers)
1017                .map_err(InstantiationError::Start)
1018        }
1019    }
1020
1021    #[allow(clippy::type_complexity)]
1022    #[cfg(feature = "static-artifact-create")]
1023    /// Generate a compilation
1024    pub fn generate_metadata<'data>(
1025        data: &'data [u8],
1026        compiler: &dyn Compiler,
1027        tunables: &dyn Tunables,
1028        features: &Features,
1029    ) -> Result<
1030        (
1031            CompileModuleInfo,
1032            PrimaryMap<LocalFunctionIndex, FunctionBodyData<'data>>,
1033            Vec<DataInitializer<'data>>,
1034            Option<ModuleTranslationState>,
1035        ),
1036        CompileError,
1037    > {
1038        let environ = ModuleEnvironment::new();
1039        let translation = environ.translate(data).map_err(CompileError::Wasm)?;
1040
1041        // We try to apply the middleware first
1042        use crate::translator::ModuleMiddlewareChain;
1043        let mut module = translation.module;
1044        let middlewares = compiler.get_middlewares();
1045        middlewares
1046            .apply_on_module_info(&mut module)
1047            .map_err(|e| CompileError::MiddlewareError(e.to_string()))?;
1048
1049        let memory_styles: PrimaryMap<MemoryIndex, MemoryStyle> = module
1050            .memories
1051            .values()
1052            .map(|memory_type| tunables.memory_style(memory_type))
1053            .collect();
1054        let table_styles: PrimaryMap<TableIndex, TableStyle> = module
1055            .tables
1056            .values()
1057            .map(|table_type| tunables.table_style(table_type))
1058            .collect();
1059
1060        let compile_info = CompileModuleInfo {
1061            module: Arc::new(module),
1062            features: features.clone(),
1063            memory_styles,
1064            table_styles,
1065        };
1066        Ok((
1067            compile_info,
1068            translation.function_body_inputs,
1069            translation.data_initializers,
1070            translation.module_translation_state,
1071        ))
1072    }
1073
1074    /// Generate the metadata object for the module
1075    #[cfg(feature = "static-artifact-create")]
1076    #[allow(clippy::type_complexity)]
1077    pub fn metadata<'a>(
1078        compiler: &dyn Compiler,
1079        data: &'a [u8],
1080        metadata_prefix: Option<&str>,
1081        target: &Target,
1082        tunables: &dyn Tunables,
1083        features: &Features,
1084    ) -> Result<
1085        (
1086            ModuleMetadata,
1087            Option<ModuleTranslationState>,
1088            PrimaryMap<LocalFunctionIndex, FunctionBodyData<'a>>,
1089        ),
1090        CompileError,
1091    > {
1092        #[allow(dead_code)]
1093        let (compile_info, function_body_inputs, data_initializers, module_translation) =
1094            Self::generate_metadata(data, compiler, tunables, features)?;
1095
1096        let data_initializers = data_initializers
1097            .iter()
1098            .map(OwnedDataInitializer::new)
1099            .collect::<Vec<_>>()
1100            .into_boxed_slice();
1101
1102        // TODO: we currently supply all-zero function body lengths.
1103        // We don't know the lengths until they're compiled, yet we have to
1104        // supply the metadata as an input to the compile.
1105        let function_body_lengths = function_body_inputs
1106            .keys()
1107            .map(|_function_body| 0u64)
1108            .collect::<PrimaryMap<LocalFunctionIndex, u64>>();
1109
1110        let metadata = ModuleMetadata {
1111            compile_info,
1112            prefix: metadata_prefix.map(|s| s.to_string()).unwrap_or_default(),
1113            data_initializers,
1114            function_body_lengths,
1115            cpu_features: target.cpu_features().as_u64(),
1116        };
1117
1118        Ok((metadata, module_translation, function_body_inputs))
1119    }
1120
1121    /// Compile a module into an object file, which can be statically linked against.
1122    ///
1123    /// The `metadata_prefix` is an optional prefix for the object name to make the
1124    /// function names in the object file unique. When set, the function names will
1125    /// be `wasmer_function_{prefix}_{id}` and the object metadata will be addressable
1126    /// using `WASMER_METADATA_{prefix}_LENGTH` and `WASMER_METADATA_{prefix}_DATA`.
1127    ///
1128    #[cfg(feature = "static-artifact-create")]
1129    pub fn generate_object<'data>(
1130        compiler: &dyn Compiler,
1131        data: &[u8],
1132        metadata_prefix: Option<&str>,
1133        target: &'data Target,
1134        tunables: &dyn Tunables,
1135        features: &Features,
1136    ) -> Result<
1137        (
1138            ModuleInfo,
1139            Object<'data>,
1140            usize,
1141            Box<dyn crate::types::symbols::SymbolRegistry>,
1142        ),
1143        CompileError,
1144    > {
1145        use crate::types::symbols::{ModuleMetadataSymbolRegistry, SymbolRegistry};
1146
1147        fn to_compile_error(err: impl std::error::Error) -> CompileError {
1148            CompileError::Codegen(format!("{err}"))
1149        }
1150
1151        let target_triple = target.triple();
1152        let (mut metadata, module_translation, function_body_inputs) =
1153            Self::metadata(compiler, data, metadata_prefix, target, tunables, features)
1154                .map_err(to_compile_error)?;
1155
1156        /*
1157        In the C file we need:
1158        - imports
1159        - exports
1160
1161        to construct an api::Module which is a Store (can be passed in via argument) and an
1162        Arc<dyn Artifact> which means this struct which includes:
1163        - CompileModuleInfo
1164        - Features
1165        - ModuleInfo
1166        - MemoryIndex -> MemoryStyle
1167        - TableIndex -> TableStyle
1168        - LocalFunctionIndex -> FunctionBodyPtr // finished functions
1169        - FunctionIndex -> FunctionBodyPtr // finished dynamic function trampolines
1170        - SignatureIndex -> VMSignatureHash // signatures
1171         */
1172
1173        let mut metadata_builder =
1174            ObjectMetadataBuilder::new(&metadata, target_triple).map_err(to_compile_error)?;
1175
1176        let (_compile_info, symbol_registry) = metadata.split();
1177
1178        let compilation: crate::types::function::Compilation = compiler.compile_module(
1179            target,
1180            &metadata.compile_info,
1181            module_translation.as_ref().unwrap(),
1182            function_body_inputs,
1183            None,
1184        )?;
1185        let mut obj = get_object_for_target(target_triple).map_err(to_compile_error)?;
1186
1187        let object_name = ModuleMetadataSymbolRegistry {
1188            prefix: metadata_prefix.unwrap_or_default().to_string(),
1189        }
1190        .symbol_to_name(crate::types::symbols::Symbol::Metadata);
1191
1192        let default_align = match target_triple.architecture {
1193            target_lexicon::Architecture::Aarch64(_) => {
1194                if matches!(
1195                    target_triple.operating_system,
1196                    target_lexicon::OperatingSystem::Darwin(_)
1197                ) {
1198                    8
1199                } else {
1200                    4
1201                }
1202            }
1203            _ => 1,
1204        };
1205
1206        // MetadataHeader::parse requires that metadata must be aligned
1207        // by 8 bytes.
1208        let offset = emit_data(
1209            &mut obj,
1210            object_name.as_bytes(),
1211            metadata_builder.placeholder_data(),
1212            std::cmp::max(8, default_align),
1213        )
1214        .map_err(to_compile_error)?;
1215        metadata_builder.set_section_offset(offset);
1216
1217        emit_compilation(
1218            &mut obj,
1219            compilation,
1220            &symbol_registry,
1221            target_triple,
1222            &metadata_builder,
1223        )
1224        .map_err(to_compile_error)?;
1225        Ok((
1226            Arc::try_unwrap(metadata.compile_info.module).unwrap(),
1227            obj,
1228            metadata_builder.placeholder_data().len(),
1229            Box::new(symbol_registry),
1230        ))
1231    }
1232
1233    /// Deserialize a ArtifactBuild from an object file
1234    ///
1235    /// # Safety
1236    /// The object must be a valid static object generated by wasmer.
1237    #[cfg(not(feature = "static-artifact-load"))]
1238    pub unsafe fn deserialize_object(
1239        _engine: &Engine,
1240        _bytes: OwnedBuffer,
1241    ) -> Result<Self, DeserializeError> {
1242        Err(DeserializeError::Compiler(
1243            CompileError::UnsupportedFeature("static load is not compiled in".to_string()),
1244        ))
1245    }
1246
1247    fn get_byte_slice(input: &[u8], start: usize, end: usize) -> Result<&[u8], DeserializeError> {
1248        if (start == end && input.len() > start)
1249            || (start < end && input.len() > start && input.len() >= end)
1250        {
1251            Ok(&input[start..end])
1252        } else {
1253            Err(DeserializeError::InvalidByteLength {
1254                expected: end - start,
1255                got: input.len(),
1256            })
1257        }
1258    }
1259
1260    /// Deserialize a ArtifactBuild from an object file
1261    ///
1262    /// # Safety
1263    /// The object must be a valid static object generated by wasmer.
1264    #[cfg(feature = "static-artifact-load")]
1265    pub unsafe fn deserialize_object(
1266        engine: &Engine,
1267        bytes: OwnedBuffer,
1268    ) -> Result<Self, DeserializeError> {
1269        unsafe {
1270            let bytes = bytes.as_slice();
1271            let metadata_len = MetadataHeader::parse(bytes)?;
1272            let metadata_slice = Self::get_byte_slice(bytes, MetadataHeader::LEN, bytes.len())?;
1273            let metadata_slice = Self::get_byte_slice(metadata_slice, 0, metadata_len)?;
1274            let metadata: ModuleMetadata = ModuleMetadata::deserialize(metadata_slice)?;
1275
1276            const WORD_SIZE: usize = mem::size_of::<usize>();
1277            let mut byte_buffer = [0u8; WORD_SIZE];
1278
1279            let mut cur_offset = MetadataHeader::LEN + metadata_len;
1280
1281            let byte_buffer_slice =
1282                Self::get_byte_slice(bytes, cur_offset, cur_offset + WORD_SIZE)?;
1283            byte_buffer[0..WORD_SIZE].clone_from_slice(byte_buffer_slice);
1284            cur_offset += WORD_SIZE;
1285
1286            let num_finished_functions = usize::from_ne_bytes(byte_buffer);
1287            let mut finished_functions: PrimaryMap<LocalFunctionIndex, FunctionBodyPtr> =
1288                PrimaryMap::new();
1289
1290            let engine_inner = engine.inner();
1291            let signature_registry = engine_inner.signatures();
1292
1293            // read finished functions in order now...
1294            for _i in 0..num_finished_functions {
1295                let byte_buffer_slice =
1296                    Self::get_byte_slice(bytes, cur_offset, cur_offset + WORD_SIZE)?;
1297                byte_buffer[0..WORD_SIZE].clone_from_slice(byte_buffer_slice);
1298                let fp = FunctionBodyPtr(usize::from_ne_bytes(byte_buffer) as _);
1299                cur_offset += WORD_SIZE;
1300
1301                // TODO: we can read back the length here if we serialize it. This will improve debug output.
1302                finished_functions.push(fp);
1303            }
1304
1305            // We register all the signatures
1306            let signatures = {
1307                let module = &metadata.compile_info.module;
1308                module
1309                    .signatures
1310                    .values()
1311                    .zip(module.signature_hashes.values())
1312                    .map(|(sig, sig_hash)| signature_registry.register(sig, *sig_hash))
1313                    .collect::<PrimaryMap<_, _>>()
1314            };
1315
1316            // read trampolines in order
1317            let mut finished_function_call_trampolines = PrimaryMap::new();
1318
1319            let byte_buffer_slice =
1320                Self::get_byte_slice(bytes, cur_offset, cur_offset + WORD_SIZE)?;
1321            byte_buffer[0..WORD_SIZE].clone_from_slice(byte_buffer_slice);
1322            cur_offset += WORD_SIZE;
1323            let num_function_trampolines = usize::from_ne_bytes(byte_buffer);
1324            for _ in 0..num_function_trampolines {
1325                let byte_buffer_slice =
1326                    Self::get_byte_slice(bytes, cur_offset, cur_offset + WORD_SIZE)?;
1327                byte_buffer[0..WORD_SIZE].clone_from_slice(byte_buffer_slice);
1328                cur_offset += WORD_SIZE;
1329                let trampoline_ptr_bytes = usize::from_ne_bytes(byte_buffer);
1330                let trampoline = mem::transmute::<usize, VMTrampoline>(trampoline_ptr_bytes);
1331                finished_function_call_trampolines.push(trampoline);
1332                // TODO: we can read back the length here if we serialize it. This will improve debug output.
1333            }
1334
1335            // read dynamic function trampolines in order now...
1336            let mut finished_dynamic_function_trampolines = PrimaryMap::new();
1337            let byte_buffer_slice =
1338                Self::get_byte_slice(bytes, cur_offset, cur_offset + WORD_SIZE)?;
1339            byte_buffer[0..WORD_SIZE].clone_from_slice(byte_buffer_slice);
1340            cur_offset += WORD_SIZE;
1341            let num_dynamic_trampoline_functions = usize::from_ne_bytes(byte_buffer);
1342            for _i in 0..num_dynamic_trampoline_functions {
1343                let byte_buffer_slice =
1344                    Self::get_byte_slice(bytes, cur_offset, cur_offset + WORD_SIZE)?;
1345                byte_buffer[0..WORD_SIZE].clone_from_slice(byte_buffer_slice);
1346                let fp = FunctionBodyPtr(usize::from_ne_bytes(byte_buffer) as _);
1347                cur_offset += WORD_SIZE;
1348
1349                // TODO: we can read back the length here if we serialize it. This will improve debug output.
1350
1351                finished_dynamic_function_trampolines.push(fp);
1352            }
1353
1354            let artifact = ArtifactBuild::from_serializable(SerializableModule {
1355                compilation: SerializableCompilation::default(),
1356                compile_info: metadata.compile_info,
1357                data_initializers: metadata.data_initializers,
1358                cpu_features: metadata.cpu_features,
1359            });
1360
1361            let finished_function_lengths = finished_functions
1362                .values()
1363                .map(|_| 0)
1364                .collect::<PrimaryMap<LocalFunctionIndex, usize>>()
1365                .into_boxed_slice();
1366            let function_max_stack_usage = finished_functions
1367                .iter()
1368                .map(|_| None)
1369                .collect::<PrimaryMap<LocalFunctionIndex, Option<usize>>>()
1370                .into_boxed_slice();
1371
1372            // Variant is built first so its module_info is available for
1373            // the cached VMOffsets before it is moved into Self.
1374            let artifact_variant = ArtifactBuildVariant::Plain(artifact);
1375            let vm_offsets = VMOffsets::new(
1376                std::mem::size_of::<usize>() as u8,
1377                artifact_variant.module_info(),
1378            );
1379
1380            Ok(Self {
1381                id: Default::default(),
1382                artifact: artifact_variant,
1383                allocated: Some(AllocatedArtifact {
1384                    frame_info_registered: false,
1385                    frame_info_registration: None,
1386                    finished_functions: finished_functions.into_boxed_slice(),
1387                    finished_function_call_trampolines: finished_function_call_trampolines
1388                        .into_boxed_slice(),
1389                    finished_dynamic_function_trampolines: finished_dynamic_function_trampolines
1390                        .into_boxed_slice(),
1391                    signatures: signatures.into_boxed_slice(),
1392                    finished_function_lengths,
1393                    vm_offsets,
1394                    function_max_stack_usage,
1395                }),
1396            })
1397        }
1398    }
1399}