wasmer_compiler/engine/
artifact.rs

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