Skip to main content

wasmer_compiler/engine/
inner.rs

1use std::sync::atomic::{AtomicUsize, Ordering::SeqCst};
2use std::sync::{Arc, Mutex};
3
4use crate::engine::builder::EngineBuilder;
5#[cfg(feature = "compiler")]
6use crate::{Compiler, CompilerConfig, Debugger};
7
8#[cfg(not(target_arch = "wasm32"))]
9use wasmer_types::CompilationProgressCallback;
10#[cfg(feature = "compiler")]
11use wasmer_types::Features;
12use wasmer_types::{CompileError, target::Target};
13
14#[cfg(not(target_arch = "wasm32"))]
15use shared_buffer::OwnedBuffer;
16#[cfg(not(target_arch = "wasm32"))]
17use std::ffi::c_void;
18#[cfg(all(not(target_arch = "wasm32"), feature = "compiler"))]
19use std::io::Write;
20#[cfg(not(target_arch = "wasm32"))]
21use std::io::{Read, Seek};
22#[cfg(all(not(target_arch = "wasm32"), unix))]
23use std::os::fd::RawFd;
24#[cfg(not(target_arch = "wasm32"))]
25use std::path::Path;
26#[cfg(all(not(target_arch = "wasm32"), feature = "compiler"))]
27use wasmer_types::ModuleInfo;
28#[cfg(not(target_arch = "wasm32"))]
29use wasmer_types::{
30    DeserializeError, FunctionIndex, FunctionType, LocalFunctionIndex, SignatureHash,
31    SignatureIndex, entity::PrimaryMap,
32};
33
34#[cfg(not(target_arch = "wasm32"))]
35use crate::{
36    Artifact, BaseTunables, CodeMemory, FunctionExtent, GlobalFrameInfoRegistration, Tunables,
37    engine::mapped_binary::MemoryMappedBinary,
38    types::{
39        function::FunctionBodyLike,
40        section::{CustomSectionLike, CustomSectionProtection, SectionIndex},
41    },
42};
43
44#[cfg(not(target_arch = "wasm32"))]
45use wasmer_vm::{
46    FunctionBodyPtr, SectionBodyPtr, SignatureRegistry, VMFunctionBody, VMSignatureHash,
47    VMTrampoline,
48};
49
50/// A WebAssembly Engine.
51#[derive(Clone)]
52pub struct Engine {
53    inner: Arc<Mutex<EngineInner>>,
54    /// The target for the compiler
55    target: Arc<Target>,
56    engine_id: EngineId,
57    #[cfg(not(target_arch = "wasm32"))]
58    tunables: Arc<dyn Tunables + Send + Sync>,
59    name: String,
60}
61
62impl Engine {
63    /// Create a new `Engine` with the given config
64    #[cfg(feature = "compiler")]
65    pub fn new(
66        compiler_config: Box<dyn CompilerConfig>,
67        target: Target,
68        features: Features,
69    ) -> Self {
70        #[cfg(not(target_arch = "wasm32"))]
71        let tunables = BaseTunables::for_target(&target);
72        let compiler = compiler_config.compiler();
73        let name = format!("engine-{}", compiler.name());
74        Self {
75            inner: Arc::new(Mutex::new(EngineInner {
76                compiler: Some(compiler),
77                features,
78                #[cfg(not(target_arch = "wasm32"))]
79                code_memory: vec![],
80                #[cfg(not(target_arch = "wasm32"))]
81                elf_mapped_binary: vec![],
82                #[cfg(not(target_arch = "wasm32"))]
83                signatures: SignatureRegistry::new(),
84            })),
85            target: Arc::new(target),
86            engine_id: EngineId::default(),
87            #[cfg(not(target_arch = "wasm32"))]
88            tunables: Arc::new(tunables),
89            name,
90        }
91    }
92
93    /// Returns the name of this engine
94    pub fn name(&self) -> &str {
95        self.name.as_str()
96    }
97
98    /// Returns the deterministic id of this engine
99    pub fn deterministic_id(&self) -> String {
100        #[cfg(feature = "compiler")]
101        {
102            let i = self.inner();
103            if let Some(ref c) = i.compiler {
104                return c.deterministic_id();
105            } else {
106                return self.name.clone();
107            }
108        }
109
110        #[allow(unreachable_code)]
111        {
112            self.name.to_string()
113        }
114    }
115
116    /// Returns the format used for artifacts produced by this engine.
117    pub fn artifact_format(&self) -> String {
118        #[cfg(feature = "compiler")]
119        {
120            let i = self.inner();
121            if let Some(ref c) = i.compiler {
122                return c.artifact_format();
123            }
124        }
125
126        #[allow(unreachable_code)]
127        self.name.to_string()
128    }
129
130    /// Create a headless `Engine`
131    ///
132    /// A headless engine is an engine without any compiler attached.
133    /// This is useful for assuring a minimal runtime for running
134    /// WebAssembly modules.
135    ///
136    /// For example, for running in IoT devices where compilers are very
137    /// expensive, or also to optimize startup speed.
138    ///
139    /// # Important
140    ///
141    /// Headless engines can't compile or validate any modules,
142    /// they just take already processed Modules (via `Module::serialize`).
143    pub fn headless() -> Self {
144        let target = Target::default();
145        #[cfg(not(target_arch = "wasm32"))]
146        let tunables = BaseTunables::for_target(&target);
147        Self {
148            inner: Arc::new(Mutex::new(EngineInner {
149                #[cfg(feature = "compiler")]
150                compiler: None,
151                #[cfg(feature = "compiler")]
152                features: Features::default(),
153                #[cfg(not(target_arch = "wasm32"))]
154                code_memory: vec![],
155                #[cfg(not(target_arch = "wasm32"))]
156                elf_mapped_binary: vec![],
157                #[cfg(not(target_arch = "wasm32"))]
158                signatures: SignatureRegistry::new(),
159            })),
160            target: Arc::new(target),
161            engine_id: EngineId::default(),
162            #[cfg(not(target_arch = "wasm32"))]
163            tunables: Arc::new(tunables),
164            name: "engine-headless".to_string(),
165        }
166    }
167
168    /// Get reference to `EngineInner`.
169    pub fn inner(&self) -> std::sync::MutexGuard<'_, EngineInner> {
170        self.inner.lock().unwrap()
171    }
172
173    /// Get mutable reference to `EngineInner`.
174    pub fn inner_mut(&self) -> std::sync::MutexGuard<'_, EngineInner> {
175        self.inner.lock().unwrap()
176    }
177
178    /// Gets the target
179    pub fn target(&self) -> &Target {
180        &self.target
181    }
182
183    /// Register a signature
184    #[cfg(not(target_arch = "wasm32"))]
185    pub fn register_signature(&self, func_type: &FunctionType) -> VMSignatureHash {
186        let compiler = self.inner();
187        compiler
188            .signatures()
189            .register(func_type, SignatureHash(func_type.signature_hash()))
190    }
191
192    /// Look up a registered signature by its hash.
193    #[cfg(not(target_arch = "wasm32"))]
194    pub fn lookup_signature(&self, sig_hash: VMSignatureHash) -> Option<FunctionType> {
195        let compiler = self.inner();
196        compiler.signatures().lookup_signature(sig_hash)
197    }
198
199    /// Validates a WebAssembly module
200    #[cfg(feature = "compiler")]
201    pub fn validate(&self, binary: &[u8]) -> Result<(), CompileError> {
202        self.inner().validate(binary)
203    }
204
205    /// Compile a WebAssembly binary
206    #[cfg(feature = "compiler")]
207    #[cfg(not(target_arch = "wasm32"))]
208    pub fn compile(&self, binary: &[u8]) -> Result<Arc<Artifact>, CompileError> {
209        Ok(Arc::new(Artifact::new(
210            self,
211            binary,
212            self.tunables.as_ref(),
213            None,
214        )?))
215    }
216
217    /// Compile a WebAssembly binary with a progress callback.
218    #[cfg(feature = "compiler")]
219    pub fn compile_with_progress(
220        &self,
221        binary: &[u8],
222        progress_callback: Option<CompilationProgressCallback>,
223    ) -> Result<Arc<Artifact>, CompileError> {
224        Ok(Arc::new(Artifact::new(
225            self,
226            binary,
227            self.tunables.as_ref(),
228            progress_callback,
229        )?))
230    }
231
232    /// Compile a WebAssembly binary (the progress_callback argument is unused).
233    #[cfg(not(feature = "compiler"))]
234    #[cfg(not(target_arch = "wasm32"))]
235    pub fn compile_with_progress(
236        &self,
237        binary: &[u8],
238        _progress_callback: Option<CompilationProgressCallback>,
239    ) -> Result<Arc<Artifact>, CompileError> {
240        self.compile(binary, self.tunables.as_ref())
241    }
242
243    /// Compile a WebAssembly binary
244    #[cfg(not(feature = "compiler"))]
245    #[cfg(not(target_arch = "wasm32"))]
246    pub fn compile(
247        &self,
248        _binary: &[u8],
249        _tunables: &dyn Tunables,
250    ) -> Result<Arc<Artifact>, CompileError> {
251        Err(CompileError::Codegen(
252            "The Engine is operating in headless mode, so it can not compile Modules.".to_string(),
253        ))
254    }
255
256    #[cfg(not(target_arch = "wasm32"))]
257    /// Deserializes a WebAssembly module which was previously serialized with
258    /// [`wasmer::Module::serialize`].
259    ///
260    /// # Safety
261    ///
262    /// See [`Artifact::deserialize_unchecked`].
263    pub unsafe fn deserialize_unchecked(
264        &self,
265        bytes: OwnedBuffer,
266    ) -> Result<Arc<Artifact>, DeserializeError> {
267        unsafe { Ok(Arc::new(Artifact::deserialize_unchecked(self, bytes)?)) }
268    }
269
270    /// Deserializes a WebAssembly module which was previously serialized with
271    /// [`wasmer::Module::serialize`].
272    ///
273    /// # Safety
274    ///
275    /// See [`Artifact::deserialize`].
276    #[cfg(not(target_arch = "wasm32"))]
277    pub unsafe fn deserialize(
278        &self,
279        bytes: OwnedBuffer,
280    ) -> Result<Arc<Artifact>, DeserializeError> {
281        unsafe { Ok(Arc::new(Artifact::deserialize(self, bytes)?)) }
282    }
283
284    /// Deserializes a WebAssembly module from a path.
285    ///
286    /// # Safety
287    /// See [`Artifact::deserialize`].
288    #[cfg(not(target_arch = "wasm32"))]
289    pub unsafe fn deserialize_from_file(
290        &self,
291        file_ref: &Path,
292    ) -> Result<Arc<Artifact>, DeserializeError> {
293        unsafe {
294            let mut file = std::fs::File::open(file_ref)?;
295            let mut magic = [0; 4];
296            let is_elf = file.read_exact(&mut magic).is_ok() && magic == object::elf::ELFMAG;
297            if is_elf {
298                return Ok(Arc::new(Artifact::deserialize_file(self, file_ref)?));
299            }
300            file.rewind()?;
301            self.deserialize(
302                OwnedBuffer::from_file(&file)
303                    .map_err(|e| DeserializeError::Generic(e.to_string()))?,
304            )
305        }
306    }
307
308    /// Deserialize from a file path.
309    ///
310    /// # Safety
311    ///
312    /// See [`Artifact::deserialize_unchecked`].
313    #[cfg(not(target_arch = "wasm32"))]
314    pub unsafe fn deserialize_from_file_unchecked(
315        &self,
316        file_ref: &Path,
317    ) -> Result<Arc<Artifact>, DeserializeError> {
318        unsafe {
319            let file = std::fs::File::open(file_ref)?;
320            self.deserialize_unchecked(
321                OwnedBuffer::from_file(&file)
322                    .map_err(|e| DeserializeError::Generic(e.to_string()))?,
323            )
324        }
325    }
326
327    /// A unique identifier for this object.
328    ///
329    /// This exists to allow us to compare two Engines for equality. Otherwise,
330    /// comparing two trait objects unsafely relies on implementation details
331    /// of trait representation.
332    pub fn id(&self) -> &EngineId {
333        &self.engine_id
334    }
335
336    /// Clone the engine
337    pub fn cloned(&self) -> Self {
338        self.clone()
339    }
340
341    /// Attach a Tunable to this engine
342    #[cfg(not(target_arch = "wasm32"))]
343    pub fn set_tunables(&mut self, tunables: impl Tunables + Send + Sync + 'static) {
344        self.tunables = Arc::new(tunables);
345    }
346
347    /// Get a reference to attached Tunable of this engine
348    #[cfg(not(target_arch = "wasm32"))]
349    pub fn tunables(&self) -> &dyn Tunables {
350        self.tunables.as_ref()
351    }
352
353    /// Add suggested optimizations to this engine.
354    ///
355    /// # Note
356    ///
357    /// Not every backend supports every optimization. This function may fail (i.e. not set the
358    /// suggested optimizations) silently if the underlying engine backend does not support one or
359    /// more optimizations.
360    pub fn with_opts(
361        &mut self,
362        _suggested_opts: &wasmer_types::target::UserCompilerOptimizations,
363    ) -> Result<(), CompileError> {
364        #[cfg(feature = "compiler")]
365        {
366            let mut i = self.inner_mut();
367            if let Some(ref mut c) = i.compiler {
368                c.with_opts(_suggested_opts)?;
369            }
370        }
371
372        Ok(())
373    }
374}
375
376impl std::fmt::Debug for Engine {
377    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
378        write!(f, "{}", self.deterministic_id())
379    }
380}
381
382/// The inner contents of `Engine`
383pub struct EngineInner {
384    #[cfg(feature = "compiler")]
385    /// The compiler and cpu features
386    compiler: Option<Box<dyn Compiler>>,
387    #[cfg(feature = "compiler")]
388    /// The compiler and cpu features
389    features: Features,
390    /// The code memory is responsible of publishing the compiled
391    /// functions to memory.
392    #[cfg(not(target_arch = "wasm32"))]
393    code_memory: Vec<CodeMemory>,
394    /// Memory-mapped ELF artifact image, produced by `--experimental-artifact`.
395    #[cfg(not(target_arch = "wasm32"))]
396    elf_mapped_binary: Vec<MemoryMappedBinary>,
397    /// The signature registry is used mainly to operate with trampolines
398    /// performantly.
399    #[cfg(not(target_arch = "wasm32"))]
400    signatures: SignatureRegistry,
401}
402
403impl std::fmt::Debug for EngineInner {
404    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
405        let mut formatter = f.debug_struct("EngineInner");
406        #[cfg(feature = "compiler")]
407        {
408            formatter.field("compiler", &self.compiler);
409            formatter.field("features", &self.features);
410        }
411
412        #[cfg(not(target_arch = "wasm32"))]
413        {
414            formatter.field("signatures", &self.signatures);
415        }
416
417        formatter.finish()
418    }
419}
420
421impl EngineInner {
422    /// Gets the compiler associated to this engine.
423    #[cfg(feature = "compiler")]
424    pub fn compiler(&self) -> Result<&dyn Compiler, CompileError> {
425        match self.compiler.as_ref() {
426            None => Err(CompileError::Codegen(
427                "No compiler compiled into executable".to_string(),
428            )),
429            Some(compiler) => Ok(&**compiler),
430        }
431    }
432
433    /// Validate the module
434    #[cfg(feature = "compiler")]
435    pub fn validate(&self, data: &[u8]) -> Result<(), CompileError> {
436        let compiler = self.compiler()?;
437        compiler.validate_module(&self.features, data)
438    }
439
440    /// The Wasm features
441    #[cfg(feature = "compiler")]
442    pub fn features(&self) -> &Features {
443        &self.features
444    }
445
446    /// Allocate compiled functions into memory
447    #[cfg(not(target_arch = "wasm32"))]
448    #[allow(clippy::type_complexity)]
449    pub(crate) fn allocate<'a, FunctionBody, CustomSection>(
450        &'a mut self,
451        _module: &wasmer_types::ModuleInfo,
452        functions: impl ExactSizeIterator<Item = &'a FunctionBody> + 'a,
453        function_call_trampolines: impl ExactSizeIterator<Item = &'a FunctionBody> + 'a,
454        dynamic_function_trampolines: impl ExactSizeIterator<Item = &'a FunctionBody> + 'a,
455        custom_sections: impl ExactSizeIterator<Item = &'a CustomSection> + Clone + 'a,
456    ) -> Result<
457        (
458            PrimaryMap<LocalFunctionIndex, FunctionExtent>,
459            PrimaryMap<SignatureIndex, VMTrampoline>,
460            PrimaryMap<FunctionIndex, FunctionBodyPtr>,
461            PrimaryMap<SectionIndex, SectionBodyPtr>,
462        ),
463        CompileError,
464    >
465    where
466        FunctionBody: FunctionBodyLike<'a> + 'a,
467        CustomSection: CustomSectionLike<'a> + 'a,
468    {
469        let functions_len = functions.len();
470        let function_call_trampolines_len = function_call_trampolines.len();
471
472        let function_bodies = functions
473            .chain(function_call_trampolines)
474            .chain(dynamic_function_trampolines)
475            .collect::<Vec<_>>();
476        let (executable_sections, data_sections): (Vec<_>, _) = custom_sections
477            .clone()
478            .partition(|section| section.protection() == CustomSectionProtection::ReadExecute);
479        self.code_memory.push(CodeMemory::new());
480
481        let (mut allocated_functions, allocated_executable_sections, allocated_data_sections) =
482            self.code_memory
483                .last_mut()
484                .unwrap()
485                .allocate(
486                    function_bodies.as_slice(),
487                    executable_sections.as_slice(),
488                    data_sections.as_slice(),
489                )
490                .map_err(|message| {
491                    CompileError::Resource(format!(
492                        "failed to allocate memory for functions: {message}",
493                    ))
494                })?;
495
496        let allocated_functions_result = allocated_functions
497            .drain(0..functions_len)
498            .map(|slice| FunctionExtent {
499                ptr: FunctionBodyPtr(slice.as_ptr()),
500                length: slice.len(),
501            })
502            .collect::<PrimaryMap<LocalFunctionIndex, _>>();
503
504        let mut allocated_function_call_trampolines: PrimaryMap<SignatureIndex, VMTrampoline> =
505            PrimaryMap::new();
506        for ptr in allocated_functions
507            .drain(0..function_call_trampolines_len)
508            .map(|slice| slice.as_ptr())
509        {
510            let trampoline =
511                unsafe { std::mem::transmute::<*const VMFunctionBody, VMTrampoline>(ptr) };
512            allocated_function_call_trampolines.push(trampoline);
513        }
514
515        let allocated_dynamic_function_trampolines = allocated_functions
516            .drain(..)
517            .map(|slice| FunctionBodyPtr(slice.as_ptr()))
518            .collect::<PrimaryMap<FunctionIndex, _>>();
519
520        let mut exec_iter = allocated_executable_sections.iter();
521        let mut data_iter = allocated_data_sections.iter();
522        let allocated_custom_sections = custom_sections
523            .map(|section| {
524                SectionBodyPtr(
525                    if section.protection() == CustomSectionProtection::ReadExecute {
526                        exec_iter.next()
527                    } else {
528                        data_iter.next()
529                    }
530                    .unwrap()
531                    .as_ptr(),
532                )
533            })
534            .collect::<PrimaryMap<SectionIndex, _>>();
535        Ok((
536            allocated_functions_result,
537            allocated_function_call_trampolines,
538            allocated_dynamic_function_trampolines,
539            allocated_custom_sections,
540        ))
541    }
542
543    #[cfg(not(target_arch = "wasm32"))]
544    /// Make memory containing compiled code executable.
545    pub(crate) fn publish_compiled_code(&mut self) {
546        self.code_memory.last_mut().unwrap().publish();
547    }
548
549    #[cfg(not(target_arch = "wasm32"))]
550    #[cfg(not(all(target_os = "macos", target_arch = "aarch64")))]
551    /// Register DWARF-type exception handling information associated with the code.
552    pub(crate) fn publish_eh_frame(&mut self, eh_frame: Option<&[u8]>) -> Result<(), CompileError> {
553        self.code_memory
554            .last_mut()
555            .unwrap()
556            .unwind_registry_mut()
557            .publish_eh_frame(eh_frame)
558            .map_err(|e| {
559                CompileError::Resource(format!("Error while publishing the unwind code: {e}"))
560            })?;
561        Ok(())
562    }
563    #[cfg(all(target_os = "macos", target_arch = "aarch64"))]
564    /// Register macos-specific exception handling information associated with the code.
565    pub(crate) fn publish_compact_unwind(
566        &mut self,
567        compact_unwind: &[u8],
568        eh_personality_addr_in_got: Option<usize>,
569    ) -> Result<(), CompileError> {
570        self.code_memory
571            .last_mut()
572            .unwrap()
573            .unwind_registry_mut()
574            .publish_compact_unwind(compact_unwind, eh_personality_addr_in_got)
575            .map_err(|e| {
576                CompileError::Resource(format!("Error while publishing the unwind code: {e}"))
577            })?;
578        Ok(())
579    }
580
581    /// Memory-map a compiled ELF artifact image, keeping the mapping alive
582    /// for the lifetime of the engine. Returns the base address of the
583    /// mapping, which section/symbol offsets from the image are relative to.
584    #[cfg(not(target_arch = "wasm32"))]
585    pub(crate) fn map_elf_binary<'a, R: object::ReadRef<'a>>(
586        &mut self,
587        object_file: &object::File<'a, R>,
588        data: &[u8],
589    ) -> Result<*mut c_void, CompileError> {
590        let map = MemoryMappedBinary::try_from_bytes(object_file, data)
591            .map_err(CompileError::Resource)?;
592        let base = map.base();
593        self.elf_mapped_binary.push(map);
594        Ok(base)
595    }
596
597    /// Memory-map a compiled ELF artifact directly from a file.
598    #[cfg(all(not(target_arch = "wasm32"), unix))]
599    pub(crate) fn map_elf_binary_file<'a, R: object::ReadRef<'a>>(
600        &mut self,
601        object_file: &object::File<'a, R>,
602        file: RawFd,
603    ) -> Result<*mut c_void, CompileError> {
604        let map =
605            MemoryMappedBinary::try_from_file(object_file, file).map_err(CompileError::Resource)?;
606        let base = map.base();
607        self.elf_mapped_binary.push(map);
608        Ok(base)
609    }
610
611    #[cfg(all(not(target_arch = "wasm32"), unix, feature = "compiler"))]
612    pub(crate) fn debugger(&self) -> Option<Debugger> {
613        self.compiler
614            .as_ref()
615            .and_then(|compiler| compiler.get_debugger())
616    }
617
618    #[cfg(all(not(target_arch = "wasm32"), unix, feature = "compiler"))]
619    pub(crate) fn register_debugger(
620        &self,
621        path: &Path,
622        base: *mut c_void,
623        debugger: Debugger,
624    ) -> Result<(), CompileError> {
625        use std::io::Write as _;
626
627        let path = path
628            .canonicalize()
629            .unwrap_or_else(|_| path.to_path_buf())
630            .to_string_lossy()
631            .to_string();
632        let (command, source_command) = match debugger {
633            Debugger::Gdb => (
634                format!("add-symbol-file \"{path}\" -o 0x{:x}", base as usize),
635                "source",
636            ),
637            Debugger::Lldb => (
638                format!(
639                    "target modules add \"{path}\"\ntarget modules load --file \"{path}\" --slide 0x{:x}",
640                    base as usize
641                ),
642                "command source",
643            ),
644        };
645        let filename = format!(
646            "/tmp/wasmer-{}.{}",
647            debugger.to_string().to_lowercase(),
648            std::process::id()
649        );
650        let mut file = std::fs::OpenOptions::new()
651            .append(true)
652            .create(true)
653            .open(&filename)
654            .map_err(|error| CompileError::Resource(format!("Cannot open {filename}: {error}")))?;
655        writeln!(file, "{command}")
656            .map_err(|error| CompileError::Resource(format!("Cannot write {filename}: {error}")))?;
657
658        eprintln!("**************************");
659        eprintln!("For debugging under {debugger}, use: {source_command} {filename}");
660        eprintln!("**************************");
661        Ok(())
662    }
663
664    /// Register DWARF-type exception handling information associated with the code.
665    #[cfg(not(target_arch = "wasm32"))]
666    pub(crate) fn publish_elf_eh_frame(
667        &mut self,
668        address: u64,
669        size: u64,
670    ) -> Result<(), CompileError> {
671        self.elf_mapped_binary
672            .last_mut()
673            .unwrap()
674            .publish_eh_frame_section(address, size)
675            .map_err(|e| {
676                CompileError::Resource(format!("Error while publishing the unwind code: {e}"))
677            })
678    }
679
680    /// Shared signature registry.
681    #[cfg(not(target_arch = "wasm32"))]
682    pub fn signatures(&self) -> &SignatureRegistry {
683        &self.signatures
684    }
685
686    #[cfg(not(target_arch = "wasm32"))]
687    /// Register the frame info for the code memory
688    pub(crate) fn register_frame_info(&mut self, frame_info: GlobalFrameInfoRegistration) {
689        self.code_memory
690            .last_mut()
691            .unwrap()
692            .register_frame_info(frame_info);
693    }
694
695    #[cfg(not(target_arch = "wasm32"))]
696    /// Register the frame info for the most recently mapped ELF binary.
697    pub(crate) fn register_elf_frame_info(&mut self, frame_info: GlobalFrameInfoRegistration) {
698        self.elf_mapped_binary
699            .last_mut()
700            .unwrap()
701            .register_frame_info(frame_info);
702    }
703
704    #[cfg(all(not(target_arch = "wasm32"), feature = "compiler"))]
705    pub(crate) fn register_perfmap(
706        &self,
707        finished_functions: &PrimaryMap<LocalFunctionIndex, FunctionExtent>,
708        module_info: &ModuleInfo,
709    ) -> Result<(), CompileError> {
710        if self
711            .compiler
712            .as_ref()
713            .is_some_and(|v| v.get_perfmap_enabled())
714        {
715            use std::fs::OpenOptions;
716
717            let filename = format!("/tmp/perf-{}.map", std::process::id());
718            // We might be loading shared libraries and so we must append to the file.
719            let file = OpenOptions::new()
720                .append(true)
721                .create(true)
722                .open(&filename)
723                .map_err(|e| {
724                    CompileError::Codegen(format!("failed to open perf map file {filename}: {e}"))
725                })?;
726            let mut file = std::io::BufWriter::new(file);
727
728            for (func_index, code) in finished_functions.iter() {
729                let func_index = module_info.func_index(func_index);
730                if let Some(func_name) = module_info.function_names.get(&func_index) {
731                    let sanitized_name = func_name.replace(['\n', '\r'], "_");
732                    let line = format!(
733                        "{:p} {:x} {sanitized_name}\n",
734                        code.ptr.0 as *const _, code.length
735                    );
736                    write!(file, "{line}").map_err(|e| CompileError::Codegen(e.to_string()))?;
737                }
738            }
739
740            file.flush()
741                .map_err(|e| CompileError::Codegen(e.to_string()))?;
742        }
743
744        Ok(())
745    }
746}
747
748#[cfg(feature = "compiler")]
749impl From<Box<dyn CompilerConfig>> for Engine {
750    fn from(config: Box<dyn CompilerConfig>) -> Self {
751        EngineBuilder::new(config).engine()
752    }
753}
754
755impl From<EngineBuilder> for Engine {
756    fn from(engine_builder: EngineBuilder) -> Self {
757        engine_builder.engine()
758    }
759}
760
761impl From<&Self> for Engine {
762    fn from(engine_ref: &Self) -> Self {
763        engine_ref.cloned()
764    }
765}
766
767#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]
768#[repr(transparent)]
769/// A unique identifier for an Engine.
770pub struct EngineId {
771    id: usize,
772}
773
774impl EngineId {
775    /// Format this identifier as a string.
776    pub fn id(&self) -> String {
777        format!("{}", self.id)
778    }
779}
780
781impl Clone for EngineId {
782    fn clone(&self) -> Self {
783        Self::default()
784    }
785}
786
787impl Default for EngineId {
788    fn default() -> Self {
789        static NEXT_ID: AtomicUsize = AtomicUsize::new(0);
790        Self {
791            id: NEXT_ID.fetch_add(1, SeqCst),
792        }
793    }
794}