Skip to main content

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