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::{
5    fs::File,
6    io::BufReader,
7    path::{Path, PathBuf},
8    sync::{
9        Arc,
10        atomic::{AtomicUsize, Ordering::SeqCst},
11    },
12};
13
14#[cfg(feature = "compiler")]
15use crate::ModuleEnvironment;
16use crate::{
17    ArtifactBuild, ArtifactBuildFromArchive, ArtifactCreate, Engine, EngineInner, Features,
18    FrameInfosVariant, FunctionExtent, GlobalFrameInfoRegistration, InstantiationError, Tunables,
19    engine::{link::link_module, resolver::resolve_tags, trap::register_frame_info_source},
20    lib::std::vec::IntoIter,
21    resolve_imports,
22    serialize::{MetadataHeader, SerializableCompilation, SerializableModule},
23    types::relocation::{RelocationLike, RelocationTarget},
24};
25#[cfg(feature = "static-artifact-create")]
26use crate::{Compiler, FunctionBodyData, ModuleTranslationState, types::module::CompileModuleInfo};
27#[cfg(any(feature = "static-artifact-create", feature = "static-artifact-load"))]
28use crate::{serialize::RkyvSerializableCompilation, types::symbols::ModuleMetadata};
29use itertools::Itertools;
30#[cfg(unix)]
31use std::os::fd::AsRawFd;
32#[cfg(feature = "compiler")]
33use wasmer_types::CompilationProgressCallback;
34
35use enumset::EnumSet;
36use object::{Object as _, ObjectSection as _, ReadCache};
37use rkyv::option::ArchivedOption;
38use shared_buffer::OwnedBuffer;
39
40use crate::engine::mapped_binary::DebugInfoSource;
41
42#[cfg(any(feature = "static-artifact-create", feature = "static-artifact-load"))]
43use std::mem;
44
45#[cfg(feature = "static-artifact-create")]
46use crate::object::{
47    Object, ObjectMetadataBuilder, emit_compilation, emit_data, get_object_for_target,
48};
49
50use wasmer_types::{
51    ArchivedDataInitializerLocation, ArchivedOwnedDataInitializer, CompileError, DataInitializer,
52    DataInitializerLike, DataInitializerLocation, DataInitializerLocationLike, DeserializeError,
53    FunctionIndex, LocalFunctionIndex, MemoryIndex, ModuleInfo, OwnedDataInitializer,
54    SerializeError, SignatureIndex, TableIndex,
55    entity::{BoxedSlice, PrimaryMap},
56    target::{CpuFeature, Target},
57};
58
59use wasmer_types::VMOffsets;
60use wasmer_vm::{
61    FunctionBodyPtr, InstanceAllocator, MemoryStyle, StoreObjects, TableStyle, TrapHandlerFn,
62    VMConfig, VMExtern, VMInstance, VMSignatureHash, VMTrampoline,
63};
64
65#[cfg_attr(feature = "artifact-size", derive(loupe::MemoryUsage))]
66pub struct AllocatedArtifact {
67    // This shows if the frame info has been registered already or not.
68    // Because the 'GlobalFrameInfoRegistration' ownership can be transferred to EngineInner
69    // this bool is needed to track the status, as 'frame_info_registration' will be None
70    // after the ownership is transferred.
71    frame_info_registered: bool,
72    // frame_info_registered is not staying there but transferred to CodeMemory from EngineInner
73    // using 'Artifact::take_frame_info_registration' method
74    // so the GloabelFrameInfo and MMap stays in sync and get dropped at the same time
75    frame_info_registration: Option<GlobalFrameInfoRegistration>,
76    finished_functions: BoxedSlice<LocalFunctionIndex, FunctionBodyPtr>,
77
78    #[cfg_attr(feature = "artifact-size", loupe(skip))]
79    finished_function_call_trampolines: BoxedSlice<SignatureIndex, VMTrampoline>,
80    finished_dynamic_function_trampolines: BoxedSlice<FunctionIndex, FunctionBodyPtr>,
81    signatures: BoxedSlice<SignatureIndex, VMSignatureHash>,
82    finished_function_lengths: BoxedSlice<LocalFunctionIndex, usize>,
83    // The maximum stack size used for each function (available only for the Singlepass compiler).
84    function_max_stack_usage: BoxedSlice<LocalFunctionIndex, Option<usize>>,
85
86    /// Precomputed `VMOffsets` for this artifact's module, cloned by
87    /// `Artifact::instantiate` instead of recomputing on every call.
88    ///
89    /// Safe to cache because `VMOffsets::new(pointer_size, module_info)`
90    /// is deterministic, `module_info` is immutable after compile (the
91    /// only mutable field `name` is not a `VMOffsets` input), and the
92    /// host's pointer size is a runtime constant.
93    ///
94    /// Built once in `from_parts` and in the deserialization path
95    /// (`deserialize_object_native`); `VMOffsets::new` was ~9% of
96    /// `Instance::new` time on profile traces of a per-request wasm
97    /// host calling `Module::instantiate` in a tight loop.
98    #[cfg_attr(feature = "artifact-size", loupe(skip))]
99    vm_offsets: VMOffsets,
100
101    /// The base address the module's code was loaded at, and the raw ELF
102    /// image bytes it was loaded from, when this artifact was built from a
103    /// native ELF image. Used to lazily build DWARF debug info for frame
104    /// symbolication. `None` for non-ELF artifacts.
105    #[cfg_attr(feature = "artifact-size", loupe(skip))]
106    elf_image: Option<(usize, DebugInfoSource)>,
107}
108
109impl AllocatedArtifact {
110    fn function_extents(&self) -> PrimaryMap<LocalFunctionIndex, FunctionExtent> {
111        assert_eq!(
112            self.finished_functions.len(),
113            self.finished_function_lengths.len(),
114            "finished_functions and finished_function_lengths must have equal length"
115        );
116        self.finished_functions
117            .iter()
118            .map(|(index, &ptr)| {
119                let length = self.finished_function_lengths[index];
120                FunctionExtent { ptr, length }
121            })
122            .collect()
123    }
124}
125
126#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]
127#[cfg_attr(feature = "artifact-size", derive(loupe::MemoryUsage))]
128#[repr(transparent)]
129/// A unique identifier for an Artifact.
130pub struct ArtifactId {
131    id: usize,
132}
133
134impl ArtifactId {
135    /// Format this identifier as a string.
136    pub fn id(&self) -> String {
137        format!("{}", self.id)
138    }
139}
140
141impl Clone for ArtifactId {
142    fn clone(&self) -> Self {
143        Self::default()
144    }
145}
146
147impl Default for ArtifactId {
148    fn default() -> Self {
149        static NEXT_ID: AtomicUsize = AtomicUsize::new(0);
150        Self {
151            id: NEXT_ID.fetch_add(1, SeqCst),
152        }
153    }
154}
155
156/// A compiled wasm module, ready to be instantiated.
157#[cfg_attr(feature = "artifact-size", derive(loupe::MemoryUsage))]
158pub struct Artifact {
159    id: ArtifactId,
160    artifact: ArtifactBuildVariant,
161    #[cfg_attr(feature = "artifact-size", loupe(skip))]
162    module_file: Option<PathBuf>,
163    // The artifact will only be allocated in memory in case we can execute it
164    // (that means, if the target != host then this will be None).
165    allocated: Option<AllocatedArtifact>,
166}
167
168/// Artifacts may be created as the result of the compilation of a wasm
169/// module, corresponding to `ArtifactBuildVariant::Plain`, or loaded
170/// from an archive, corresponding to `ArtifactBuildVariant::Archived`.
171#[cfg_attr(feature = "artifact-size", derive(loupe::MemoryUsage))]
172#[allow(clippy::large_enum_variant)]
173pub enum ArtifactBuildVariant {
174    Plain(ArtifactBuild),
175    Archived(ArtifactBuildFromArchive),
176}
177
178impl Artifact {
179    /// Compile a data buffer into a `ArtifactBuild`, which may then be instantiated.
180    #[cfg(feature = "compiler")]
181    pub fn new(
182        engine: &Engine,
183        data: &[u8],
184        tunables: &dyn Tunables,
185        progress_callback: Option<CompilationProgressCallback>,
186    ) -> Result<Self, CompileError> {
187        let mut inner_engine = engine.inner_mut();
188        let environ = ModuleEnvironment::new();
189        let translation = environ.translate(data).map_err(CompileError::Wasm)?;
190        let module = translation.module;
191        let memory_styles: PrimaryMap<MemoryIndex, MemoryStyle> = module
192            .memories
193            .values()
194            .map(|memory_type| tunables.memory_style(memory_type))
195            .collect();
196        let table_styles: PrimaryMap<TableIndex, TableStyle> = module
197            .tables
198            .values()
199            .map(|table_type| tunables.table_style(table_type))
200            .collect();
201
202        let artifact = ArtifactBuild::new(
203            &mut inner_engine,
204            data,
205            engine.target(),
206            memory_styles,
207            table_styles,
208            progress_callback.as_ref(),
209        )?;
210
211        Self::from_parts_with_module_file(
212            &mut inner_engine,
213            ArtifactBuildVariant::Plain(artifact),
214            engine.target(),
215            None,
216        )
217        .map_err(|e| match e {
218            DeserializeError::Compiler(c) => c,
219
220            // `from_parts` only ever returns `CompileError`s when an
221            // `ArtifactBuildVariant::Plain` is passed in. Other cases
222            // of `DeserializeError` can only happen when an
223            // `ArtifactBuildVariant::Archived` is passed in. We don't
224            // wish to change the return type of this method because
225            // a. it makes no sense and b. it would be a breaking change,
226            // hence this match block and the other cases being
227            // unreachable.
228            _ => unreachable!(),
229        })
230    }
231
232    /// This indicates if the Artifact is allocated and can be run by the current
233    /// host. In case it can't be run (for example, if the artifact is cross compiled to
234    /// other architecture), it will return false.
235    pub fn allocated(&self) -> bool {
236        self.allocated.is_some()
237    }
238
239    /// A unique identifier for this object.
240    ///
241    /// This exists to allow us to compare two Artifacts for equality. Otherwise,
242    /// comparing two trait objects unsafely relies on implementation details
243    /// of trait representation.
244    pub fn id(&self) -> &ArtifactId {
245        &self.id
246    }
247
248    /// Compile a data buffer into a `ArtifactBuild`, which may then be instantiated.
249    #[cfg(not(feature = "compiler"))]
250    pub fn new(_engine: &Engine, _data: &[u8]) -> Result<Self, CompileError> {
251        Err(CompileError::Codegen(
252            "Compilation is not enabled in the engine".to_string(),
253        ))
254    }
255
256    /// Load an ELF artifact directly from a file-backed memory map.
257    ///
258    /// Unlike [`Self::deserialize`], this entrypoint only accepts ELF artifacts.
259    ///
260    /// # Safety
261    /// This function loads executable code into memory. The file must be trusted
262    /// and must not be modified while the returned artifact is in use.
263    pub unsafe fn deserialize_file(
264        engine: &Engine,
265        path: impl AsRef<Path>,
266    ) -> Result<Self, DeserializeError> {
267        let path = path.as_ref().to_path_buf();
268        let file = File::open(&path)?;
269        let cache = ReadCache::new(BufReader::new(file));
270        let image = object::File::parse(&cache)
271            .map_err(|e| DeserializeError::CorruptedBinary(format!("cannot parse image: {e}")))?;
272        if image.format() != object::BinaryFormat::Elf {
273            return Err(DeserializeError::Incompatible(
274                "Artifact::deserialize_file only supports ELF artifacts".to_string(),
275            ));
276        }
277
278        let module_info = image
279            .section_by_name_bytes(crate::WASMER_MODULE_INFO_SECTION_NAME)
280            .ok_or_else(|| {
281                DeserializeError::CorruptedBinary("missing ModuleInfo section".to_string())
282            })?
283            .data()
284            .map_err(|e| {
285                DeserializeError::CorruptedBinary(format!(
286                    "cannot load ModuleInfo section data: {e}"
287                ))
288            })?;
289        let serializable = unsafe { SerializableModule::deserialize(module_info)? };
290        if !matches!(serializable.compilation, SerializableCompilation::Elf(_)) {
291            return Err(DeserializeError::Incompatible(
292                "file does not contain an ELF artifact".to_string(),
293            ));
294        }
295
296        let artifact = ArtifactBuildVariant::Plain(ArtifactBuild::from_serializable(serializable));
297        let mut inner_engine = engine.inner_mut();
298        Self::from_parts_with_module_file(&mut inner_engine, artifact, engine.target(), Some(path))
299    }
300
301    /// Deserialize an ELF artifact held in memory, if the bytes contain one.
302    fn deserialize_elf(
303        engine: &Engine,
304        bytes: &[u8],
305    ) -> Result<Option<Self>, DeserializeError> {
306        if !bytes.starts_with(&object::elf::ELFMAG) {
307            return Ok(None);
308        }
309
310        let image = object::File::parse(bytes).map_err(|e| {
311            DeserializeError::CorruptedBinary(format!("cannot parse image: {e}"))
312        })?;
313        let module_info = image
314            .section_by_name_bytes(crate::WASMER_MODULE_INFO_SECTION_NAME)
315            .ok_or_else(|| {
316                DeserializeError::CorruptedBinary("missing ModuleInfo section".to_string())
317            })?
318            .data()
319            .map_err(|e| {
320                DeserializeError::CorruptedBinary(format!(
321                    "cannot load ModuleInfo section data: {e}"
322                ))
323            })?;
324        let mut serializable = unsafe { SerializableModule::deserialize(module_info)? };
325        let SerializableCompilation::Elf(elf) = &mut serializable.compilation else {
326            return Err(DeserializeError::Incompatible(
327                "ELF image does not contain an ELF artifact".to_string(),
328            ));
329        };
330        // The copy embedded in the image has an empty ELF placeholder to avoid
331        // embedding the image in itself. Restore it for allocation and reserialization.
332        *elf = bytes.to_vec();
333
334        let artifact = ArtifactBuildVariant::Plain(ArtifactBuild::from_serializable(serializable));
335        let mut inner_engine = engine.inner_mut();
336        Self::from_parts(&mut inner_engine, artifact, engine.target()).map(Some)
337    }
338
339    /// Deserialize a serialized artifact.
340    ///
341    /// # Safety
342    /// This function loads executable code into memory.
343    /// You must trust the loaded bytes to be valid for the chosen engine and
344    /// for the host CPU architecture.
345    /// In contrast to [`Self::deserialize_unchecked`] the artifact layout is
346    /// validated, which increases safety.
347    pub unsafe fn deserialize(
348        engine: &Engine,
349        bytes: OwnedBuffer,
350    ) -> Result<Self, DeserializeError> {
351        unsafe {
352            if !ArtifactBuild::is_deserializable(bytes.as_ref()) {
353                if let Some(artifact) = Self::deserialize_elf(engine, bytes.as_ref())? {
354                    return Ok(artifact);
355                }
356
357                let static_artifact = Self::deserialize_object(engine, bytes);
358                match static_artifact {
359                    Ok(v) => {
360                        return Ok(v);
361                    }
362                    Err(e) => {
363                        return Err(DeserializeError::Incompatible(format!(
364                            "The provided bytes are not a Wasmer engine artifact: {e}"
365                        )));
366                    }
367                }
368            }
369
370            let artifact = ArtifactBuildFromArchive::try_new(bytes, |bytes| {
371                let bytes =
372                    Self::get_byte_slice(bytes, ArtifactBuild::MAGIC_HEADER.len(), bytes.len())?;
373
374                let metadata_len = MetadataHeader::parse(bytes)?;
375                let metadata_slice = Self::get_byte_slice(bytes, MetadataHeader::LEN, bytes.len())?;
376                let metadata_slice = Self::get_byte_slice(metadata_slice, 0, metadata_len)?;
377
378                SerializableModule::archive_from_slice_checked(metadata_slice)
379            })?;
380
381            let mut inner_engine = engine.inner_mut();
382            Self::from_parts(
383                &mut inner_engine,
384                ArtifactBuildVariant::Archived(artifact),
385                engine.target(),
386            )
387        }
388    }
389
390    /// Deserialize a serialized artifact.
391    ///
392    /// NOTE: You should prefer [`Self::deserialize`].
393    ///
394    /// # Safety
395    /// See [`Self::deserialize`].
396    /// In contrast to the above, this function skips artifact layout validation,
397    /// which increases the risk of loading invalid artifacts.
398    pub unsafe fn deserialize_unchecked(
399        engine: &Engine,
400        bytes: OwnedBuffer,
401    ) -> Result<Self, DeserializeError> {
402        unsafe {
403            if !ArtifactBuild::is_deserializable(bytes.as_ref()) {
404                if let Some(artifact) = Self::deserialize_elf(engine, bytes.as_ref())? {
405                    return Ok(artifact);
406                }
407
408                let static_artifact = Self::deserialize_object(engine, bytes);
409                match static_artifact {
410                    Ok(v) => {
411                        return Ok(v);
412                    }
413                    Err(e) => {
414                        return Err(DeserializeError::Incompatible(format!(
415                            "The provided bytes are not a Wasmer engine artifact: {e}"
416                        )));
417                    }
418                }
419            }
420
421            let artifact = ArtifactBuildFromArchive::try_new(bytes, |bytes| {
422                let bytes =
423                    Self::get_byte_slice(bytes, ArtifactBuild::MAGIC_HEADER.len(), bytes.len())?;
424
425                let metadata_len = MetadataHeader::parse(bytes)?;
426                let metadata_slice = Self::get_byte_slice(bytes, MetadataHeader::LEN, bytes.len())?;
427                let metadata_slice = Self::get_byte_slice(metadata_slice, 0, metadata_len)?;
428
429                SerializableModule::archive_from_slice(metadata_slice)
430            })?;
431
432            let mut inner_engine = engine.inner_mut();
433            Self::from_parts(
434                &mut inner_engine,
435                ArtifactBuildVariant::Archived(artifact),
436                engine.target(),
437            )
438        }
439    }
440
441    /// Construct a `ArtifactBuild` from component parts.
442    pub fn from_parts(
443        engine_inner: &mut EngineInner,
444        artifact: ArtifactBuildVariant,
445        target: &Target,
446    ) -> Result<Self, DeserializeError> {
447        Self::from_parts_with_module_file(engine_inner, artifact, target, None)
448    }
449
450    fn from_parts_with_module_file(
451        engine_inner: &mut EngineInner,
452        artifact: ArtifactBuildVariant,
453        target: &Target,
454        module_file: Option<PathBuf>,
455    ) -> Result<Self, DeserializeError> {
456        if !target.is_native() {
457            return Ok(Self {
458                id: Default::default(),
459                artifact,
460                module_file,
461                allocated: None,
462            });
463        } else {
464            // check if cpu features are compatible before anything else
465            let cpu_features = artifact.cpu_features();
466            if !target.cpu_features().is_superset(cpu_features) {
467                return Err(DeserializeError::Incompatible(format!(
468                    "Some CPU Features needed for the artifact are missing: {:?}",
469                    cpu_features.difference(*target.cpu_features())
470                )));
471            }
472        }
473        let module_info = artifact.module_info();
474
475        let elf_file_data = match &artifact {
476            ArtifactBuildVariant::Plain(p) => {
477                if let SerializableCompilation::Elf(data) = &p.serializable.compilation {
478                    Some(data.as_ref())
479                } else {
480                    None
481                }
482            }
483            ArtifactBuildVariant::Archived(a) => a.get_elf_file(),
484        };
485        let allocated = if let Some(module_file) = module_file.as_ref() {
486            if elf_file_data.is_none() {
487                return Err(DeserializeError::Incompatible(
488                    "file-backed loading only supports ELF artifacts".to_string(),
489                ));
490            }
491            Self::allocate_elf_artifact_from_path(engine_inner, module_info, module_file)?
492        } else if let Some(elf_file_data) = elf_file_data {
493            Self::allocate_elf_artifact(engine_inner, module_info, elf_file_data)?
494        } else {
495            let (
496                finished_functions,
497                finished_function_call_trampolines,
498                finished_dynamic_function_trampolines,
499                custom_sections,
500            ) = match &artifact {
501                ArtifactBuildVariant::Plain(p) => engine_inner.allocate(
502                    module_info,
503                    p.get_function_bodies_ref()
504                        .expect("RKYV path expected")
505                        .values(),
506                    p.get_function_call_trampolines_ref()
507                        .expect("RKYV path expected")
508                        .values(),
509                    p.get_dynamic_function_trampolines_ref()
510                        .expect("RKYV path expected")
511                        .values(),
512                    p.get_custom_sections_ref()
513                        .expect("RKYV path expected")
514                        .values(),
515                )?,
516
517                ArtifactBuildVariant::Archived(a) => engine_inner.allocate(
518                    module_info,
519                    a.get_function_bodies_ref()
520                        .expect("RKYV path expected")
521                        .values(),
522                    a.get_function_call_trampolines_ref()
523                        .expect("RKYV path expected")
524                        .values(),
525                    a.get_dynamic_function_trampolines_ref()
526                        .expect("RKYV path expected")
527                        .values(),
528                    a.get_custom_sections_ref()
529                        .expect("RKYV path expected")
530                        .values(),
531                )?,
532            };
533
534            let get_got_address: Box<dyn Fn(RelocationTarget) -> Option<usize>> = match &artifact {
535                ArtifactBuildVariant::Plain(p) => {
536                    if let Some(got) = p.get_got_ref().expect("RKYV path expected").index {
537                        let relocs: Vec<_> = p
538                            .get_custom_section_relocations_ref()
539                            .expect("RKYV path expected")[got]
540                            .iter()
541                            .map(|v| (v.reloc_target, v.offset))
542                            .collect();
543                        let got_base = custom_sections[got].0 as usize;
544                        Box::new(move |t: RelocationTarget| {
545                            relocs
546                                .iter()
547                                .find(|(v, _)| v == &t)
548                                .map(|(_, o)| got_base + (*o as usize))
549                        })
550                    } else {
551                        Box::new(|_: RelocationTarget| None)
552                    }
553                }
554
555                ArtifactBuildVariant::Archived(p) => {
556                    if let Some(got) = p.get_got_ref().expect("RKYV path expected").index {
557                        let relocs: Vec<_> = p
558                            .get_custom_section_relocations_ref()
559                            .expect("RKYV path expected")[got]
560                            .iter()
561                            .map(|v| (v.reloc_target(), v.offset))
562                            .collect();
563                        let got_base = custom_sections[got].0 as usize;
564                        Box::new(move |t: RelocationTarget| {
565                            relocs
566                                .iter()
567                                .find(|(v, _)| v == &t)
568                                .map(|(_, o)| got_base + (o.to_native() as usize))
569                        })
570                    } else {
571                        Box::new(|_: RelocationTarget| None)
572                    }
573                }
574            };
575            let functions_max_stack_usage = match &artifact {
576                ArtifactBuildVariant::Plain(p) => p
577                    .get_function_max_stack_usage()
578                    .expect("RKYV path expected")
579                    .values()
580                    .cloned()
581                    .collect::<PrimaryMap<LocalFunctionIndex, _>>(),
582                ArtifactBuildVariant::Archived(a) => a
583                    .get_function_max_stack_usage()
584                    .expect("RKYV path expected")
585                    .values()
586                    .map(|v| match v {
587                        ArchivedOption::None => None,
588                        ArchivedOption::Some(v) => Some(v.to_native() as usize),
589                    })
590                    .collect::<PrimaryMap<LocalFunctionIndex, _>>(),
591            };
592
593            match &artifact {
594                ArtifactBuildVariant::Plain(p) => link_module(
595                    module_info,
596                    &finished_functions,
597                    &finished_dynamic_function_trampolines,
598                    p.get_function_relocations()
599                        .expect("RKYV path expected")
600                        .iter()
601                        .map(|(k, v)| (k, v.iter())),
602                    &custom_sections,
603                    p.get_custom_section_relocations_ref()
604                        .expect("RKYV path expected")
605                        .iter()
606                        .map(|(k, v)| (k, v.iter())),
607                    p.get_libcall_trampolines().expect("RKYV path expected"),
608                    p.get_libcall_trampoline_len().expect("RKYV path expected"),
609                    &get_got_address,
610                ),
611                ArtifactBuildVariant::Archived(a) => link_module(
612                    module_info,
613                    &finished_functions,
614                    &finished_dynamic_function_trampolines,
615                    a.get_function_relocations()
616                        .expect("RKYV path expected")
617                        .iter()
618                        .map(|(k, v)| (k, v.iter())),
619                    &custom_sections,
620                    a.get_custom_section_relocations_ref()
621                        .expect("RKYV path expected")
622                        .iter()
623                        .map(|(k, v)| (k, v.iter())),
624                    a.get_libcall_trampolines().expect("RKYV path expected"),
625                    a.get_libcall_trampoline_len().expect("RKYV path expected"),
626                    &get_got_address,
627                ),
628            };
629
630            // Compute indices into the shared signature table.
631            let signatures = {
632                let signature_registry = engine_inner.signatures();
633                module_info
634                    .signatures
635                    .values()
636                    .zip(module_info.signature_hashes.values())
637                    .map(|(sig, sig_hash)| signature_registry.register(sig, *sig_hash))
638                    .collect::<PrimaryMap<_, _>>()
639            };
640
641            #[allow(unused_variables)]
642            let eh_frame = match &artifact {
643                ArtifactBuildVariant::Plain(p) => p
644                    .get_unwind_info()
645                    .expect("RKYV path expected")
646                    .eh_frame
647                    .map(|v| unsafe {
648                        std::slice::from_raw_parts(
649                            *custom_sections[v],
650                            p.get_custom_sections_ref().expect("RKYV path expected")[v]
651                                .bytes
652                                .len(),
653                        )
654                    }),
655                ArtifactBuildVariant::Archived(a) => a
656                    .get_unwind_info()
657                    .expect("RKYV path expected")
658                    .eh_frame
659                    .map(|v| unsafe {
660                        std::slice::from_raw_parts(
661                            *custom_sections[v],
662                            a.get_custom_sections_ref().expect("RKYV path expected")[v]
663                                .bytes
664                                .len(),
665                        )
666                    }),
667            };
668            #[allow(unused_variables)]
669            let compact_unwind = match &artifact {
670                ArtifactBuildVariant::Plain(p) => p
671                    .get_unwind_info()
672                    .expect("RKYV path expected")
673                    .compact_unwind
674                    .map(|v| unsafe {
675                        std::slice::from_raw_parts(
676                            *custom_sections[v],
677                            p.get_custom_sections_ref().expect("RKYV path expected")[v]
678                                .bytes
679                                .len(),
680                        )
681                    }),
682                ArtifactBuildVariant::Archived(a) => a
683                    .get_unwind_info()
684                    .expect("RKYV path expected")
685                    .compact_unwind
686                    .map(|v| unsafe {
687                        std::slice::from_raw_parts(
688                            *custom_sections[v],
689                            a.get_custom_sections_ref().expect("RKYV path expected")[v]
690                                .bytes
691                                .len(),
692                        )
693                    }),
694            };
695
696            #[cfg(all(not(target_arch = "wasm32"), feature = "compiler"))]
697            {
698                engine_inner.register_perfmap(&finished_functions, module_info)?;
699            }
700
701            // Make all code compiled thus far executable.
702            engine_inner.publish_compiled_code();
703
704            #[cfg(all(target_os = "macos", target_arch = "aarch64"))]
705            if let Some(compact_unwind) = compact_unwind {
706                engine_inner.publish_compact_unwind(
707                    compact_unwind,
708                    get_got_address(RelocationTarget::LibCall(wasmer_vm::LibCall::EHPersonality)),
709                )?;
710            }
711            #[cfg(not(any(
712                target_arch = "wasm32",
713                all(target_os = "macos", target_arch = "aarch64")
714            )))]
715            engine_inner.publish_eh_frame(eh_frame)?;
716
717            drop(get_got_address);
718
719            let finished_function_lengths = finished_functions
720                .values()
721                .map(|extent| extent.length)
722                .collect::<PrimaryMap<LocalFunctionIndex, usize>>()
723                .into_boxed_slice();
724            let finished_functions = finished_functions
725                .values()
726                .map(|extent| extent.ptr)
727                .collect::<PrimaryMap<LocalFunctionIndex, FunctionBodyPtr>>()
728                .into_boxed_slice();
729            let finished_function_call_trampolines =
730                finished_function_call_trampolines.into_boxed_slice();
731            let finished_dynamic_function_trampolines =
732                finished_dynamic_function_trampolines.into_boxed_slice();
733            let signatures = signatures.into_boxed_slice();
734
735            let vm_offsets = VMOffsets::new(std::mem::size_of::<usize>() as u8, module_info);
736
737            AllocatedArtifact {
738                frame_info_registered: false,
739                frame_info_registration: None,
740                finished_functions,
741                finished_function_call_trampolines,
742                finished_dynamic_function_trampolines,
743                signatures,
744                finished_function_lengths,
745                vm_offsets,
746                function_max_stack_usage: functions_max_stack_usage.into_boxed_slice(),
747                elf_image: None,
748            }
749        };
750
751        let mut artifact = Self {
752            id: Default::default(),
753            artifact,
754            module_file,
755            allocated: Some(allocated),
756        };
757
758        let is_elf = artifact
759            .allocated
760            .as_ref()
761            .expect("It must be allocated")
762            .elf_image
763            .is_some();
764
765        artifact
766            .internal_register_frame_info()
767            .map_err(|e| DeserializeError::CorruptedBinary(format!("{e:?}")))?;
768        if let Some(frame_info) = artifact.internal_take_frame_info_registration() {
769            if is_elf {
770                engine_inner.register_elf_frame_info(frame_info);
771            } else {
772                engine_inner.register_frame_info(frame_info);
773            }
774        }
775
776        Ok(artifact)
777    }
778
779    /// Build an [`AllocatedArtifact`] from a compiled native ELF image.
780    fn allocate_elf_artifact(
781        engine_inner: &mut EngineInner,
782        module_info: &ModuleInfo,
783        elf_file_data: &[u8],
784    ) -> Result<AllocatedArtifact, DeserializeError> {
785        let image = object::File::parse(elf_file_data)
786            .map_err(|e| DeserializeError::CorruptedBinary(format!("cannot parse image: {e}")))?;
787        let base = engine_inner.map_elf_binary(&image, elf_file_data)?;
788        Self::allocate_elf_artifact_from_image(
789            engine_inner,
790            module_info,
791            &image,
792            base,
793            DebugInfoSource::Bytes(Arc::from(elf_file_data)),
794        )
795    }
796
797    #[cfg(unix)]
798    fn allocate_elf_artifact_from_path(
799        engine_inner: &mut EngineInner,
800        module_info: &ModuleInfo,
801        path: &Path,
802    ) -> Result<AllocatedArtifact, DeserializeError> {
803        let file = File::open(path)?;
804        let fd = file.as_raw_fd();
805        let debug_file = Arc::new(file.try_clone()?);
806        let cache = ReadCache::new(BufReader::new(file));
807        let image = object::File::parse(&cache)
808            .map_err(|e| DeserializeError::CorruptedBinary(format!("cannot parse image: {e}")))?;
809        if image.format() != object::BinaryFormat::Elf {
810            return Err(DeserializeError::Incompatible(
811                "file-backed Artifact is not ELF".to_string(),
812            ));
813        }
814        let base = engine_inner.map_elf_binary_file(&image, fd)?;
815        Self::allocate_elf_artifact_from_image(
816            engine_inner,
817            module_info,
818            &image,
819            base,
820            DebugInfoSource::File(debug_file),
821        )
822    }
823
824    #[cfg(not(unix))]
825    fn allocate_elf_artifact_from_path(
826        _engine_inner: &mut EngineInner,
827        _module_info: &ModuleInfo,
828        _path: &Path,
829    ) -> Result<AllocatedArtifact, DeserializeError> {
830        Err(DeserializeError::Incompatible(
831            "file-backed ELF artifacts are only supported on Unix".to_string(),
832        ))
833    }
834
835    fn allocate_elf_artifact_from_image<'a, R: object::ReadRef<'a>>(
836        engine_inner: &mut EngineInner,
837        module_info: &ModuleInfo,
838        image: &object::File<'a, R>,
839        base: *mut std::ffi::c_void,
840        debug_info: DebugInfoSource,
841    ) -> Result<AllocatedArtifact, DeserializeError> {
842        let mut function_offsets = None;
843        for section in image.sections() {
844            let Ok(section_name) = section.name_bytes() else {
845                continue;
846            };
847            match section_name {
848                crate::WASMER_FUNCTION_OFFSETS_SECTION_NAME => {
849                    let data = section.data().map_err(|e| {
850                        DeserializeError::CorruptedBinary(format!(
851                            "cannot load image section data: {e}"
852                        ))
853                    })?;
854                    function_offsets = Some(
855                        data.chunks_exact(std::mem::size_of::<usize>())
856                            .map(|chunk| usize::from_le_bytes(chunk.try_into().unwrap()))
857                            .collect_vec(),
858                    );
859                }
860                crate::EH_FRAME_SECTION_NAME => {
861                    engine_inner.publish_elf_eh_frame(section.address(), section.size())?;
862                }
863                _ => {}
864            }
865        }
866
867        let Some(function_offsets) = function_offsets else {
868            return Err(DeserializeError::CorruptedBinary(
869                "missing function offset section in the image".to_string(),
870            ));
871        };
872
873        let local_function_count = module_info.local_func_count();
874        let corrupted_offsets = || {
875            DeserializeError::CorruptedBinary(format!(
876                "corrupted {} section",
877                String::from_utf8_lossy(crate::WASMER_FUNCTION_OFFSETS_SECTION_NAME)
878            ))
879        };
880        let signature_count = module_info.signatures.len();
881        let dynamic_trampoline_count = module_info.imported_function_types().count();
882        let expected_offset_count = local_function_count
883            .checked_add(signature_count)
884            .and_then(|count| count.checked_add(dynamic_trampoline_count))
885            .ok_or_else(&corrupted_offsets)?;
886        if function_offsets.len() != expected_offset_count {
887            return Err(corrupted_offsets());
888        }
889
890        let (local_fn_offsets, rest) = function_offsets.split_at(local_function_count);
891        let (trampoline_offsets, dynamic_trampoline_offsets) = rest.split_at(signature_count);
892
893        // Right now, we calculate function sizes as the difference from the next function.
894        let local_fn_sizes = function_offsets
895            .iter()
896            .skip(1)
897            .take(local_function_count)
898            .zip(function_offsets.iter())
899            .map(|(f1, f0)| f1.checked_sub(*f0).ok_or_else(&corrupted_offsets))
900            .collect::<Result<Vec<_>, _>>()?;
901
902        let signatures = {
903            let signature_registry = engine_inner.signatures();
904            module_info
905                .signatures
906                .values()
907                .zip(module_info.signature_hashes.values())
908                .map(|(sig, sig_hash)| signature_registry.register(sig, *sig_hash))
909                .collect::<PrimaryMap<_, _>>()
910                .into_boxed_slice()
911        };
912
913        let finished_functions = local_fn_offsets
914            .iter()
915            .map(|&offset| FunctionBodyPtr(unsafe { base.add(offset) as _ }))
916            .collect::<PrimaryMap<LocalFunctionIndex, _>>();
917
918        #[cfg(all(not(target_arch = "wasm32"), feature = "compiler"))]
919        let finished_function_extents = local_fn_offsets
920            .iter()
921            .zip(local_fn_sizes.iter())
922            .map(|(&ptr, &length)| FunctionExtent {
923                ptr: FunctionBodyPtr(unsafe { base.add(ptr) as _ }),
924                length,
925            })
926            .collect::<PrimaryMap<LocalFunctionIndex, _>>();
927        #[cfg(all(not(target_arch = "wasm32"), feature = "compiler"))]
928        engine_inner.register_perfmap(&finished_function_extents, module_info)?;
929        let finished_function_call_trampolines = trampoline_offsets
930            .iter()
931            .map(|&offset| unsafe {
932                std::mem::transmute::<*mut std::ffi::c_void, VMTrampoline>(base.add(offset))
933            })
934            .collect::<PrimaryMap<SignatureIndex, _>>()
935            .into_boxed_slice();
936        let finished_dynamic_function_trampolines = dynamic_trampoline_offsets
937            .iter()
938            .map(|&offset| FunctionBodyPtr(unsafe { base.add(offset) as _ }))
939            .collect::<PrimaryMap<FunctionIndex, _>>()
940            .into_boxed_slice();
941        let finished_function_lengths =
942            PrimaryMap::<LocalFunctionIndex, _>::from_iter(local_fn_sizes).into_boxed_slice();
943        let function_max_stack_usage = finished_functions
944            .iter()
945            .map(|_| None)
946            .collect::<PrimaryMap<LocalFunctionIndex, Option<usize>>>()
947            .into_boxed_slice();
948
949        let vm_offsets = VMOffsets::new(std::mem::size_of::<usize>() as u8, module_info);
950
951        Ok(AllocatedArtifact {
952            frame_info_registered: false,
953            frame_info_registration: None,
954            finished_functions: finished_functions.into_boxed_slice(),
955            finished_function_call_trampolines,
956            finished_dynamic_function_trampolines,
957            signatures,
958            finished_function_lengths,
959            vm_offsets,
960            function_max_stack_usage,
961            elf_image: Some((base as usize, debug_info)),
962        })
963    }
964
965    /// Check if the provided bytes look like a serialized `ArtifactBuild`.
966    pub fn is_deserializable(bytes: &[u8]) -> bool {
967        ArtifactBuild::is_deserializable(bytes)
968    }
969}
970
971impl PartialEq for Artifact {
972    fn eq(&self, other: &Self) -> bool {
973        self.id == other.id
974    }
975}
976impl Eq for Artifact {}
977
978impl std::fmt::Debug for Artifact {
979    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
980        f.debug_struct("Artifact")
981            .field("artifact_id", &self.id)
982            .field("module_info", &self.module_info())
983            .finish()
984    }
985}
986
987impl<'a> ArtifactCreate<'a> for Artifact {
988    type OwnedDataInitializer = <ArtifactBuildVariant as ArtifactCreate<'a>>::OwnedDataInitializer;
989    type OwnedDataInitializerIterator =
990        <ArtifactBuildVariant as ArtifactCreate<'a>>::OwnedDataInitializerIterator;
991
992    fn set_module_info_name(&mut self, name: String) -> bool {
993        self.artifact.set_module_info_name(name)
994    }
995
996    fn create_module_info(&self) -> Arc<ModuleInfo> {
997        self.artifact.create_module_info()
998    }
999
1000    fn module_info(&self) -> &ModuleInfo {
1001        self.artifact.module_info()
1002    }
1003
1004    fn features(&self) -> &Features {
1005        self.artifact.features()
1006    }
1007
1008    fn cpu_features(&self) -> EnumSet<CpuFeature> {
1009        self.artifact.cpu_features()
1010    }
1011
1012    fn data_initializers(&'a self) -> Self::OwnedDataInitializerIterator {
1013        self.artifact.data_initializers()
1014    }
1015
1016    fn memory_styles(&self) -> &PrimaryMap<MemoryIndex, MemoryStyle> {
1017        self.artifact.memory_styles()
1018    }
1019
1020    fn table_styles(&self) -> &PrimaryMap<TableIndex, TableStyle> {
1021        self.artifact.table_styles()
1022    }
1023
1024    fn serialize(&self) -> Result<Vec<u8>, SerializeError> {
1025        if let Some(module_file) = &self.module_file {
1026            return std::fs::read(module_file).map_err(|e| {
1027                SerializeError::Generic(format!("Failed to serialize Artifact file: {e}"))
1028            });
1029        }
1030        self.artifact.serialize()
1031    }
1032}
1033
1034impl<'a> ArtifactCreate<'a> for ArtifactBuildVariant {
1035    type OwnedDataInitializer = OwnedDataInitializerVariant<'a>;
1036    type OwnedDataInitializerIterator = IntoIter<Self::OwnedDataInitializer>;
1037
1038    fn create_module_info(&self) -> Arc<ModuleInfo> {
1039        match self {
1040            Self::Plain(artifact) => artifact.create_module_info(),
1041            Self::Archived(artifact) => artifact.create_module_info(),
1042        }
1043    }
1044
1045    fn set_module_info_name(&mut self, name: String) -> bool {
1046        match self {
1047            Self::Plain(artifact) => artifact.set_module_info_name(name),
1048            Self::Archived(artifact) => artifact.set_module_info_name(name),
1049        }
1050    }
1051
1052    fn module_info(&self) -> &ModuleInfo {
1053        match self {
1054            Self::Plain(artifact) => artifact.module_info(),
1055            Self::Archived(artifact) => artifact.module_info(),
1056        }
1057    }
1058
1059    fn features(&self) -> &Features {
1060        match self {
1061            Self::Plain(artifact) => artifact.features(),
1062            Self::Archived(artifact) => artifact.features(),
1063        }
1064    }
1065
1066    fn cpu_features(&self) -> EnumSet<CpuFeature> {
1067        match self {
1068            Self::Plain(artifact) => artifact.cpu_features(),
1069            Self::Archived(artifact) => artifact.cpu_features(),
1070        }
1071    }
1072
1073    fn memory_styles(&self) -> &PrimaryMap<MemoryIndex, MemoryStyle> {
1074        match self {
1075            Self::Plain(artifact) => artifact.memory_styles(),
1076            Self::Archived(artifact) => artifact.memory_styles(),
1077        }
1078    }
1079
1080    fn table_styles(&self) -> &PrimaryMap<TableIndex, TableStyle> {
1081        match self {
1082            Self::Plain(artifact) => artifact.table_styles(),
1083            Self::Archived(artifact) => artifact.table_styles(),
1084        }
1085    }
1086
1087    fn data_initializers(&'a self) -> Self::OwnedDataInitializerIterator {
1088        match self {
1089            Self::Plain(artifact) => artifact
1090                .data_initializers()
1091                .map(OwnedDataInitializerVariant::Plain)
1092                .collect::<Vec<_>>()
1093                .into_iter(),
1094            Self::Archived(artifact) => artifact
1095                .data_initializers()
1096                .map(OwnedDataInitializerVariant::Archived)
1097                .collect::<Vec<_>>()
1098                .into_iter(),
1099        }
1100    }
1101
1102    fn serialize(&self) -> Result<Vec<u8>, SerializeError> {
1103        match self {
1104            Self::Plain(artifact) => artifact.serialize(),
1105            Self::Archived(artifact) => artifact.serialize(),
1106        }
1107    }
1108}
1109
1110#[derive(Clone, Copy)]
1111pub enum OwnedDataInitializerVariant<'a> {
1112    Plain(&'a OwnedDataInitializer),
1113    Archived(&'a ArchivedOwnedDataInitializer),
1114}
1115
1116impl<'a> DataInitializerLike<'a> for OwnedDataInitializerVariant<'a> {
1117    type Location = DataInitializerLocationVariant<'a>;
1118
1119    fn location(&self) -> Self::Location {
1120        match self {
1121            Self::Plain(plain) => DataInitializerLocationVariant::Plain(plain.location()),
1122            Self::Archived(archived) => {
1123                DataInitializerLocationVariant::Archived(archived.location())
1124            }
1125        }
1126    }
1127
1128    fn data(&self) -> &'a [u8] {
1129        match self {
1130            Self::Plain(plain) => plain.data(),
1131            Self::Archived(archived) => archived.data(),
1132        }
1133    }
1134}
1135
1136#[derive(Clone, Copy)]
1137pub enum DataInitializerLocationVariant<'a> {
1138    Plain(&'a DataInitializerLocation),
1139    Archived(&'a ArchivedDataInitializerLocation),
1140}
1141
1142impl DataInitializerLocationVariant<'_> {
1143    pub fn clone_to_plain(&self) -> DataInitializerLocation {
1144        match self {
1145            Self::Plain(p) => (*p).clone(),
1146            Self::Archived(a) => DataInitializerLocation {
1147                memory_index: a.memory_index(),
1148                offset_expr: a.offset_expr(),
1149            },
1150        }
1151    }
1152}
1153
1154impl DataInitializerLocationLike for DataInitializerLocationVariant<'_> {
1155    fn memory_index(&self) -> MemoryIndex {
1156        match self {
1157            Self::Plain(plain) => plain.memory_index(),
1158            Self::Archived(archived) => archived.memory_index(),
1159        }
1160    }
1161
1162    fn offset_expr(&self) -> wasmer_types::InitExpr {
1163        match self {
1164            Self::Plain(plain) => plain.offset_expr(),
1165            Self::Archived(archived) => archived.offset_expr(),
1166        }
1167    }
1168}
1169
1170impl Artifact {
1171    fn internal_register_frame_info(&mut self) -> Result<(), DeserializeError> {
1172        if self
1173            .allocated
1174            .as_ref()
1175            .expect("It must be allocated")
1176            .frame_info_registered
1177        {
1178            return Ok(()); // already done
1179        }
1180
1181        // ELF artifacts don't carry the RKYV frame-info section (per-instruction
1182        // address maps); they get symbolicated from DWARF debug info instead,
1183        // lazily loaded from the ELF image (see `elf_image` below).
1184        let frame_infos = match &self.artifact {
1185            ArtifactBuildVariant::Plain(p) => p
1186                .get_frame_info_ref()
1187                .map(|f| FrameInfosVariant::Owned(f.clone())),
1188            ArtifactBuildVariant::Archived(a) => a
1189                .get_frame_info_ref()
1190                .map(|_| FrameInfosVariant::Archived(a.clone())),
1191        };
1192
1193        let elf_image = self
1194            .allocated
1195            .as_ref()
1196            .expect("It must be allocated")
1197            .elf_image
1198            .clone();
1199
1200        if frame_infos.is_some() || elf_image.is_some() {
1201            let finished_function_extents = self
1202                .allocated
1203                .as_ref()
1204                .expect("It must be allocated")
1205                .function_extents()
1206                .into_boxed_slice();
1207
1208            let (image_base, elf_data) = match elf_image {
1209                Some((base, data)) => (base, Some(data)),
1210                None => (0, None),
1211            };
1212
1213            let frame_info_registration = &mut self
1214                .allocated
1215                .as_mut()
1216                .expect("It must be allocated")
1217                .frame_info_registration;
1218
1219            *frame_info_registration = register_frame_info_source(
1220                self.artifact.create_module_info(),
1221                &finished_function_extents,
1222                frame_infos,
1223                image_base,
1224                elf_data,
1225            );
1226        }
1227
1228        self.allocated
1229            .as_mut()
1230            .expect("It must be allocated")
1231            .frame_info_registered = true;
1232
1233        Ok(())
1234    }
1235
1236    fn internal_take_frame_info_registration(&mut self) -> Option<GlobalFrameInfoRegistration> {
1237        let frame_info_registration = &mut self
1238            .allocated
1239            .as_mut()
1240            .expect("It must be allocated")
1241            .frame_info_registration;
1242
1243        frame_info_registration.take()
1244    }
1245
1246    /// Returns the functions allocated in memory or this `Artifact`
1247    /// ready to be run.
1248    pub fn finished_functions(&self) -> &BoxedSlice<LocalFunctionIndex, FunctionBodyPtr> {
1249        &self
1250            .allocated
1251            .as_ref()
1252            .expect("It must be allocated")
1253            .finished_functions
1254    }
1255
1256    /// Returns the start address and byte length of each locally-defined
1257    /// function body in this artifact.
1258    ///
1259    /// Returns `None` for cross-compiled artifacts (where the artifact has not
1260    /// been allocated into the host process).
1261    ///
1262    /// # Security
1263    ///
1264    /// The returned addresses are host-process pointers. They are not stable
1265    /// across runs and must not be forwarded to untrusted parties, as they
1266    /// reveal ASLR layout information.
1267    pub fn finished_function_extents(&self) -> Option<Vec<(LocalFunctionIndex, FunctionExtent)>> {
1268        let allocated = self.allocated.as_ref()?;
1269        Some(allocated.function_extents().into_iter().collect())
1270    }
1271
1272    /// Return the maximum stack size used for each function (available only for the Singlepass compiler).
1273    pub fn finished_functions_max_stack_usage(
1274        &self,
1275    ) -> Option<Vec<(LocalFunctionIndex, Option<usize>)>> {
1276        let allocated = self.allocated.as_ref()?;
1277        Some(
1278            allocated
1279                .function_max_stack_usage
1280                .into_iter()
1281                .map(|f| (f.0, *f.1))
1282                .collect(),
1283        )
1284    }
1285
1286    /// Returns the function call trampolines allocated in memory of this
1287    /// `Artifact`, ready to be run.
1288    pub fn finished_function_call_trampolines(&self) -> &BoxedSlice<SignatureIndex, VMTrampoline> {
1289        &self
1290            .allocated
1291            .as_ref()
1292            .expect("It must be allocated")
1293            .finished_function_call_trampolines
1294    }
1295
1296    /// Returns the dynamic function trampolines allocated in memory
1297    /// of this `Artifact`, ready to be run.
1298    pub fn finished_dynamic_function_trampolines(
1299        &self,
1300    ) -> &BoxedSlice<FunctionIndex, FunctionBodyPtr> {
1301        &self
1302            .allocated
1303            .as_ref()
1304            .expect("It must be allocated")
1305            .finished_dynamic_function_trampolines
1306    }
1307
1308    /// Returns the associated VM signatures for this `Artifact`.
1309    pub fn signatures(&self) -> &BoxedSlice<SignatureIndex, VMSignatureHash> {
1310        &self
1311            .allocated
1312            .as_ref()
1313            .expect("It must be allocated")
1314            .signatures
1315    }
1316
1317    /// Do preinstantiation logic that is executed before instantiating
1318    #[allow(clippy::result_large_err)]
1319    pub fn preinstantiate(&self) -> Result<(), InstantiationError> {
1320        Ok(())
1321    }
1322
1323    /// Crate an `Instance` from this `Artifact`.
1324    ///
1325    /// # Safety
1326    ///
1327    /// See [`VMInstance::new`].
1328    #[allow(clippy::result_large_err)]
1329    pub unsafe fn instantiate(
1330        &self,
1331        tunables: &dyn Tunables,
1332        imports: &[VMExtern],
1333        context: &mut StoreObjects,
1334    ) -> Result<VMInstance, InstantiationError> {
1335        unsafe {
1336            // Validate the CPU features this module was compiled with against the
1337            // host CPU features.
1338            let host_cpu_features = CpuFeature::for_host();
1339            if !host_cpu_features.is_superset(self.cpu_features()) {
1340                return Err(InstantiationError::CpuFeature(format!(
1341                    "{:?}",
1342                    self.cpu_features().difference(host_cpu_features)
1343                )));
1344            }
1345
1346            self.preinstantiate()?;
1347
1348            let module = self.create_module_info();
1349
1350            let tags = resolve_tags(&module, imports, context).map_err(InstantiationError::Link)?;
1351
1352            let imports = resolve_imports(
1353                &module,
1354                imports,
1355                context,
1356                self.finished_dynamic_function_trampolines(),
1357                self.memory_styles(),
1358                self.table_styles(),
1359            )
1360            .map_err(InstantiationError::Link)?;
1361
1362            // Get pointers to where metadata about local memories should live in VM memory.
1363            // Get pointers to where metadata about local tables should live in VM memory.
1364
1365            let cached_offsets = self
1366                .allocated
1367                .as_ref()
1368                .map(|a| a.vm_offsets.clone())
1369                .expect("Artifact::instantiate called on a non-host artifact");
1370
1371            let (
1372                allocator,
1373                memory_definition_locations,
1374                table_definition_locations,
1375                global_definition_locations,
1376            ) = InstanceAllocator::new_with_offsets(cached_offsets, &module);
1377            let finished_memories = tunables
1378                .create_memories(
1379                    context,
1380                    &module,
1381                    self.memory_styles(),
1382                    &memory_definition_locations,
1383                )
1384                .map_err(InstantiationError::Link)?
1385                .into_boxed_slice();
1386            let finished_tables = tunables
1387                .create_tables(
1388                    context,
1389                    &module,
1390                    self.table_styles(),
1391                    &table_definition_locations,
1392                )
1393                .map_err(InstantiationError::Link)?
1394                .into_boxed_slice();
1395            let finished_globals = tunables
1396                .create_globals(context, &module, &global_definition_locations)
1397                .map_err(InstantiationError::Link)?
1398                .into_boxed_slice();
1399
1400            let handle = VMInstance::new(
1401                allocator,
1402                module,
1403                context,
1404                self.finished_functions().clone(),
1405                self.finished_function_call_trampolines().clone(),
1406                finished_memories,
1407                finished_tables,
1408                finished_globals,
1409                tags,
1410                imports,
1411                self.signatures().clone(),
1412            )
1413            .map_err(InstantiationError::Start)?;
1414            Ok(handle)
1415        }
1416    }
1417
1418    /// Finishes the instantiation of a just created `VMInstance`.
1419    ///
1420    /// # Safety
1421    ///
1422    /// See [`VMInstance::finish_instantiation`].
1423    #[allow(clippy::result_large_err)]
1424    pub unsafe fn finish_instantiation(
1425        &self,
1426        config: &VMConfig,
1427        trap_handler: Option<*const TrapHandlerFn<'static>>,
1428        handle: &mut VMInstance,
1429    ) -> Result<(), InstantiationError> {
1430        unsafe {
1431            let data_initializers = self
1432                .data_initializers()
1433                .map(|init| DataInitializer {
1434                    location: init.location().clone_to_plain(),
1435                    data: init.data(),
1436                })
1437                .collect::<Vec<_>>();
1438            handle
1439                .finish_instantiation(config, trap_handler, &data_initializers)
1440                .map_err(InstantiationError::Start)
1441        }
1442    }
1443
1444    #[allow(clippy::type_complexity)]
1445    #[cfg(feature = "static-artifact-create")]
1446    /// Generate a compilation
1447    pub fn generate_metadata<'data>(
1448        data: &'data [u8],
1449        compiler: &dyn Compiler,
1450        tunables: &dyn Tunables,
1451        features: &Features,
1452    ) -> Result<
1453        (
1454            CompileModuleInfo,
1455            PrimaryMap<LocalFunctionIndex, FunctionBodyData<'data>>,
1456            Vec<DataInitializer<'data>>,
1457            Option<ModuleTranslationState>,
1458        ),
1459        CompileError,
1460    > {
1461        let environ = ModuleEnvironment::new();
1462        let translation = environ.translate(data).map_err(CompileError::Wasm)?;
1463
1464        // We try to apply the middleware first
1465        use crate::translator::ModuleMiddlewareChain;
1466        let mut module = translation.module;
1467        let middlewares = compiler.get_middlewares();
1468        middlewares
1469            .apply_on_module_info(&mut module)
1470            .map_err(|e| CompileError::MiddlewareError(e.to_string()))?;
1471
1472        let memory_styles: PrimaryMap<MemoryIndex, MemoryStyle> = module
1473            .memories
1474            .values()
1475            .map(|memory_type| tunables.memory_style(memory_type))
1476            .collect();
1477        let table_styles: PrimaryMap<TableIndex, TableStyle> = module
1478            .tables
1479            .values()
1480            .map(|table_type| tunables.table_style(table_type))
1481            .collect();
1482
1483        let compile_info = CompileModuleInfo {
1484            module: Arc::new(module),
1485            features: features.clone(),
1486            memory_styles,
1487            table_styles,
1488        };
1489        Ok((
1490            compile_info,
1491            translation.function_body_inputs,
1492            translation.data_initializers,
1493            translation.module_translation_state,
1494        ))
1495    }
1496
1497    /// Generate the metadata object for the module
1498    #[cfg(feature = "static-artifact-create")]
1499    #[allow(clippy::type_complexity)]
1500    pub fn metadata<'a>(
1501        compiler: &dyn Compiler,
1502        data: &'a [u8],
1503        metadata_prefix: Option<&str>,
1504        target: &Target,
1505        tunables: &dyn Tunables,
1506        features: &Features,
1507    ) -> Result<
1508        (
1509            ModuleMetadata,
1510            Option<ModuleTranslationState>,
1511            PrimaryMap<LocalFunctionIndex, FunctionBodyData<'a>>,
1512        ),
1513        CompileError,
1514    > {
1515        #[allow(dead_code)]
1516        let (compile_info, function_body_inputs, data_initializers, module_translation) =
1517            Self::generate_metadata(data, compiler, tunables, features)?;
1518
1519        let data_initializers = data_initializers
1520            .iter()
1521            .map(OwnedDataInitializer::new)
1522            .collect::<Vec<_>>()
1523            .into_boxed_slice();
1524
1525        // TODO: we currently supply all-zero function body lengths.
1526        // We don't know the lengths until they're compiled, yet we have to
1527        // supply the metadata as an input to the compile.
1528        let function_body_lengths = function_body_inputs
1529            .keys()
1530            .map(|_function_body| 0u64)
1531            .collect::<PrimaryMap<LocalFunctionIndex, u64>>();
1532
1533        let metadata = ModuleMetadata {
1534            compile_info,
1535            prefix: metadata_prefix.map(|s| s.to_string()).unwrap_or_default(),
1536            data_initializers,
1537            function_body_lengths,
1538            cpu_features: target.cpu_features().as_u64(),
1539        };
1540
1541        Ok((metadata, module_translation, function_body_inputs))
1542    }
1543
1544    /// Compile a module into an object file, which can be statically linked against.
1545    ///
1546    /// The `metadata_prefix` is an optional prefix for the object name to make the
1547    /// function names in the object file unique. When set, the function names will
1548    /// be `wasmer_function_{prefix}_{id}` and the object metadata will be addressable
1549    /// using `WASMER_METADATA_{prefix}_LENGTH` and `WASMER_METADATA_{prefix}_DATA`.
1550    ///
1551    #[cfg(feature = "static-artifact-create")]
1552    pub fn generate_object<'data>(
1553        compiler: &dyn Compiler,
1554        data: &[u8],
1555        metadata_prefix: Option<&str>,
1556        target: &'data Target,
1557        tunables: &dyn Tunables,
1558        features: &Features,
1559    ) -> Result<
1560        (
1561            ModuleInfo,
1562            Object<'data>,
1563            usize,
1564            Box<dyn crate::types::symbols::SymbolRegistry>,
1565        ),
1566        CompileError,
1567    > {
1568        use crate::types::{
1569            function::Compilation,
1570            symbols::{ModuleMetadataSymbolRegistry, SymbolRegistry},
1571        };
1572
1573        fn to_compile_error(err: impl std::error::Error) -> CompileError {
1574            CompileError::Codegen(format!("{err}"))
1575        }
1576
1577        let target_triple = target.triple();
1578        let (mut metadata, module_translation, function_body_inputs) =
1579            Self::metadata(compiler, data, metadata_prefix, target, tunables, features)
1580                .map_err(to_compile_error)?;
1581
1582        /*
1583        In the C file we need:
1584        - imports
1585        - exports
1586
1587        to construct an api::Module which is a Store (can be passed in via argument) and an
1588        Arc<dyn Artifact> which means this struct which includes:
1589        - CompileModuleInfo
1590        - Features
1591        - ModuleInfo
1592        - MemoryIndex -> MemoryStyle
1593        - TableIndex -> TableStyle
1594        - LocalFunctionIndex -> FunctionBodyPtr // finished functions
1595        - FunctionIndex -> FunctionBodyPtr // finished dynamic function trampolines
1596        - SignatureIndex -> VMSignatureHash // signatures
1597         */
1598
1599        let mut metadata_builder =
1600            ObjectMetadataBuilder::new(&metadata, target_triple).map_err(to_compile_error)?;
1601
1602        let (_compile_info, symbol_registry) = metadata.split();
1603
1604        let compilation = compiler.compile_module(
1605            target,
1606            &metadata.compile_info,
1607            &[],
1608            module_translation.as_ref().unwrap(),
1609            function_body_inputs,
1610            None,
1611        )?;
1612        let Compilation::Rkyv(compilation) = compilation else {
1613            return Err(CompileError::Codegen(
1614                "ELF compilation unsupported yet".to_string(),
1615            ));
1616        };
1617        let mut obj = get_object_for_target(target_triple).map_err(to_compile_error)?;
1618
1619        let object_name = ModuleMetadataSymbolRegistry {
1620            prefix: metadata_prefix.unwrap_or_default().to_string(),
1621        }
1622        .symbol_to_name(crate::types::symbols::Symbol::Metadata);
1623
1624        let default_align = match target_triple.architecture {
1625            target_lexicon::Architecture::Aarch64(_) => {
1626                if matches!(
1627                    target_triple.operating_system,
1628                    target_lexicon::OperatingSystem::Darwin(_)
1629                ) {
1630                    8
1631                } else {
1632                    4
1633                }
1634            }
1635            _ => 1,
1636        };
1637
1638        // MetadataHeader::parse requires that metadata must be aligned
1639        // by 8 bytes.
1640        let offset = emit_data(
1641            &mut obj,
1642            object_name.as_bytes(),
1643            metadata_builder.placeholder_data(),
1644            std::cmp::max(8, default_align),
1645        )
1646        .map_err(to_compile_error)?;
1647        metadata_builder.set_section_offset(offset);
1648
1649        emit_compilation(
1650            &mut obj,
1651            compilation,
1652            &symbol_registry,
1653            target_triple,
1654            &metadata_builder,
1655        )
1656        .map_err(to_compile_error)?;
1657        Ok((
1658            Arc::try_unwrap(metadata.compile_info.module).unwrap(),
1659            obj,
1660            metadata_builder.placeholder_data().len(),
1661            Box::new(symbol_registry),
1662        ))
1663    }
1664
1665    /// Deserialize a ArtifactBuild from an object file
1666    ///
1667    /// # Safety
1668    /// The object must be a valid static object generated by wasmer.
1669    #[cfg(not(feature = "static-artifact-load"))]
1670    pub unsafe fn deserialize_object(
1671        _engine: &Engine,
1672        _bytes: OwnedBuffer,
1673    ) -> Result<Self, DeserializeError> {
1674        Err(DeserializeError::Compiler(
1675            CompileError::UnsupportedFeature("static load is not compiled in".to_string()),
1676        ))
1677    }
1678
1679    fn get_byte_slice(input: &[u8], start: usize, end: usize) -> Result<&[u8], DeserializeError> {
1680        if (start == end && input.len() > start)
1681            || (start < end && input.len() > start && input.len() >= end)
1682        {
1683            Ok(&input[start..end])
1684        } else {
1685            Err(DeserializeError::InvalidByteLength {
1686                expected: end - start,
1687                got: input.len(),
1688            })
1689        }
1690    }
1691
1692    /// Deserialize a ArtifactBuild from an object file
1693    ///
1694    /// # Safety
1695    /// The object must be a valid static object generated by wasmer.
1696    #[cfg(feature = "static-artifact-load")]
1697    pub unsafe fn deserialize_object(
1698        engine: &Engine,
1699        bytes: OwnedBuffer,
1700    ) -> Result<Self, DeserializeError> {
1701        unsafe {
1702            use crate::serialize::SerializableCompilation;
1703
1704            let bytes = bytes.as_slice();
1705            let metadata_len = MetadataHeader::parse(bytes)?;
1706            let metadata_slice = Self::get_byte_slice(bytes, MetadataHeader::LEN, bytes.len())?;
1707            let metadata_slice = Self::get_byte_slice(metadata_slice, 0, metadata_len)?;
1708            let metadata: ModuleMetadata = ModuleMetadata::deserialize(metadata_slice)?;
1709
1710            const WORD_SIZE: usize = mem::size_of::<usize>();
1711            let mut byte_buffer = [0u8; WORD_SIZE];
1712
1713            let mut cur_offset = MetadataHeader::LEN + metadata_len;
1714
1715            let byte_buffer_slice =
1716                Self::get_byte_slice(bytes, cur_offset, cur_offset + WORD_SIZE)?;
1717            byte_buffer[0..WORD_SIZE].clone_from_slice(byte_buffer_slice);
1718            cur_offset += WORD_SIZE;
1719
1720            let num_finished_functions = usize::from_ne_bytes(byte_buffer);
1721            let mut finished_functions: PrimaryMap<LocalFunctionIndex, FunctionBodyPtr> =
1722                PrimaryMap::new();
1723
1724            let engine_inner = engine.inner();
1725            let signature_registry = engine_inner.signatures();
1726
1727            // read finished functions in order now...
1728            for _i in 0..num_finished_functions {
1729                let byte_buffer_slice =
1730                    Self::get_byte_slice(bytes, cur_offset, cur_offset + WORD_SIZE)?;
1731                byte_buffer[0..WORD_SIZE].clone_from_slice(byte_buffer_slice);
1732                let fp = FunctionBodyPtr(usize::from_ne_bytes(byte_buffer) as _);
1733                cur_offset += WORD_SIZE;
1734
1735                // TODO: we can read back the length here if we serialize it. This will improve debug output.
1736                finished_functions.push(fp);
1737            }
1738
1739            // We register all the signatures
1740            let signatures = {
1741                let module = &metadata.compile_info.module;
1742                module
1743                    .signatures
1744                    .values()
1745                    .zip(module.signature_hashes.values())
1746                    .map(|(sig, sig_hash)| signature_registry.register(sig, *sig_hash))
1747                    .collect::<PrimaryMap<_, _>>()
1748            };
1749
1750            // read trampolines in order
1751            let mut finished_function_call_trampolines = PrimaryMap::new();
1752
1753            let byte_buffer_slice =
1754                Self::get_byte_slice(bytes, cur_offset, cur_offset + WORD_SIZE)?;
1755            byte_buffer[0..WORD_SIZE].clone_from_slice(byte_buffer_slice);
1756            cur_offset += WORD_SIZE;
1757            let num_function_trampolines = usize::from_ne_bytes(byte_buffer);
1758            for _ in 0..num_function_trampolines {
1759                let byte_buffer_slice =
1760                    Self::get_byte_slice(bytes, cur_offset, cur_offset + WORD_SIZE)?;
1761                byte_buffer[0..WORD_SIZE].clone_from_slice(byte_buffer_slice);
1762                cur_offset += WORD_SIZE;
1763                let trampoline_ptr_bytes = usize::from_ne_bytes(byte_buffer);
1764                let trampoline = mem::transmute::<usize, VMTrampoline>(trampoline_ptr_bytes);
1765                finished_function_call_trampolines.push(trampoline);
1766                // TODO: we can read back the length here if we serialize it. This will improve debug output.
1767            }
1768
1769            // read dynamic function trampolines in order now...
1770            let mut finished_dynamic_function_trampolines = PrimaryMap::new();
1771            let byte_buffer_slice =
1772                Self::get_byte_slice(bytes, cur_offset, cur_offset + WORD_SIZE)?;
1773            byte_buffer[0..WORD_SIZE].clone_from_slice(byte_buffer_slice);
1774            cur_offset += WORD_SIZE;
1775            let num_dynamic_trampoline_functions = usize::from_ne_bytes(byte_buffer);
1776            for _i in 0..num_dynamic_trampoline_functions {
1777                let byte_buffer_slice =
1778                    Self::get_byte_slice(bytes, cur_offset, cur_offset + WORD_SIZE)?;
1779                byte_buffer[0..WORD_SIZE].clone_from_slice(byte_buffer_slice);
1780                let fp = FunctionBodyPtr(usize::from_ne_bytes(byte_buffer) as _);
1781                cur_offset += WORD_SIZE;
1782
1783                // TODO: we can read back the length here if we serialize it. This will improve debug output.
1784
1785                finished_dynamic_function_trampolines.push(fp);
1786            }
1787
1788            let artifact = ArtifactBuild::from_serializable(SerializableModule {
1789                compilation: SerializableCompilation::Rkyv(RkyvSerializableCompilation::default()),
1790                compile_info: metadata.compile_info,
1791                data_initializers: metadata.data_initializers,
1792                cpu_features: metadata.cpu_features,
1793            });
1794
1795            let finished_function_lengths = finished_functions
1796                .values()
1797                .map(|_| 0)
1798                .collect::<PrimaryMap<LocalFunctionIndex, usize>>()
1799                .into_boxed_slice();
1800            let function_max_stack_usage = finished_functions
1801                .iter()
1802                .map(|_| None)
1803                .collect::<PrimaryMap<LocalFunctionIndex, Option<usize>>>()
1804                .into_boxed_slice();
1805
1806            // Variant is built first so its module_info is available for
1807            // the cached VMOffsets before it is moved into Self.
1808            let artifact_variant = ArtifactBuildVariant::Plain(artifact);
1809            let vm_offsets = VMOffsets::new(
1810                std::mem::size_of::<usize>() as u8,
1811                artifact_variant.module_info(),
1812            );
1813
1814            Ok(Self {
1815                id: Default::default(),
1816                artifact: artifact_variant,
1817                module_file: None,
1818                allocated: Some(AllocatedArtifact {
1819                    frame_info_registered: false,
1820                    frame_info_registration: None,
1821                    finished_functions: finished_functions.into_boxed_slice(),
1822                    finished_function_call_trampolines: finished_function_call_trampolines
1823                        .into_boxed_slice(),
1824                    finished_dynamic_function_trampolines: finished_dynamic_function_trampolines
1825                        .into_boxed_slice(),
1826                    signatures: signatures.into_boxed_slice(),
1827                    finished_function_lengths,
1828                    vm_offsets,
1829                    function_max_stack_usage,
1830                    elf_image: None,
1831                }),
1832            })
1833        }
1834    }
1835}