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