wasmer_cli/
backend.rs

1//! Common module with common used structures across different
2//! commands.
3
4// NOTE: A lot of this code depends on feature flags.
5// To not go crazy with annotations, some lints are disabled for the whole
6// module.
7#![allow(dead_code, unused_imports, unused_variables)]
8
9use std::num::NonZero;
10use std::string::ToString;
11use std::sync::Arc;
12use std::{path::PathBuf, str::FromStr};
13
14use anyhow::{Context, Result, bail};
15#[cfg(feature = "sys")]
16use wasmer::sys::*;
17use wasmer::*;
18use wasmer_types::{Features, target::Target};
19
20#[cfg(feature = "compiler")]
21use wasmer_compiler::CompilerConfig;
22
23use wasmer::Engine;
24
25#[derive(Debug, clap::Parser, Clone, Default)]
26/// The WebAssembly features that can be passed through the
27/// Command Line args.
28pub struct WasmFeatures {
29    /// Enable support for the SIMD proposal.
30    #[clap(long = "enable-simd")]
31    pub simd: bool,
32
33    /// Disable support for the threads proposal.
34    #[clap(long = "disable-threads")]
35    pub disable_threads: bool,
36
37    /// Deprecated, threads are enabled by default.
38    #[clap(long = "enable-threads")]
39    pub _threads: bool,
40
41    /// Enable support for the reference types proposal.
42    #[clap(long = "enable-reference-types")]
43    pub reference_types: bool,
44
45    /// Enable support for the multi value proposal.
46    #[clap(long = "enable-multi-value")]
47    pub multi_value: bool,
48
49    /// Enable support for the bulk memory proposal.
50    #[clap(long = "enable-bulk-memory")]
51    pub bulk_memory: bool,
52
53    /// Enable support for the tail call proposal.
54    #[clap(long = "enable-tail-call")]
55    pub tail_call: bool,
56
57    /// Enable support for the module linking proposal.
58    #[clap(long = "enable-module-linking")]
59    pub module_linking: bool,
60
61    /// Enable support for the multi memory proposal.
62    #[clap(long = "enable-multi-memory")]
63    pub multi_memory: bool,
64
65    /// Enable support for the memory64 proposal.
66    #[clap(long = "enable-memory64")]
67    pub memory64: bool,
68
69    /// Enable support for the exceptions proposal.
70    #[clap(long = "enable-exceptions")]
71    pub exceptions: bool,
72
73    /// Enable support for the relaxed SIMD proposal.
74    #[clap(long = "enable-relaxed-simd")]
75    pub relaxed_simd: bool,
76
77    /// Enable support for the extended constant expressions proposal.
78    #[clap(long = "enable-extended-const")]
79    pub extended_const: bool,
80
81    /// Enable support for the wide arithmetic proposal.
82    #[clap(long = "wide-arithmetic")]
83    pub wide_arithmetic: bool,
84
85    /// Enable support for all pre-standard proposals.
86    #[clap(long = "enable-all")]
87    pub all: bool,
88}
89
90#[derive(Debug, Clone, clap::Parser, Default)]
91/// The compiler options
92pub struct RuntimeOptions {
93    /// Use Singlepass compiler.
94    #[cfg(feature = "singlepass")]
95    #[clap(short, long, conflicts_with_all = &Vec::<&str>::from_iter([
96        #[cfg(feature = "llvm")]
97        "llvm", 
98        #[cfg(feature = "v8")]
99        "v8", 
100        #[cfg(feature = "cranelift")]
101        "cranelift", 
102        #[cfg(feature = "wamr")]
103        "wamr", 
104        #[cfg(feature = "wasmi")]
105        "wasmi"
106    ]))]
107    singlepass: bool,
108
109    /// Use Cranelift compiler.
110    #[cfg(feature = "cranelift")]
111    #[clap(short, long, conflicts_with_all = &Vec::<&str>::from_iter([
112        #[cfg(feature = "llvm")]
113        "llvm", 
114        #[cfg(feature = "v8")]
115        "v8", 
116        #[cfg(feature = "singlepass")]
117        "singlepass", 
118        #[cfg(feature = "wamr")]
119        "wamr", 
120        #[cfg(feature = "wasmi")]
121        "wasmi"
122    ]))]
123    cranelift: bool,
124
125    /// Use LLVM compiler.
126    #[cfg(feature = "llvm")]
127    #[clap(short, long, conflicts_with_all = &Vec::<&str>::from_iter([
128        #[cfg(feature = "cranelift")]
129        "cranelift", 
130        #[cfg(feature = "v8")]
131        "v8", 
132        #[cfg(feature = "singlepass")]
133        "singlepass", 
134        #[cfg(feature = "wamr")]
135        "wamr", 
136        #[cfg(feature = "wasmi")]
137        "wasmi"
138    ]))]
139    llvm: bool,
140
141    /// Use the V8 runtime.
142    #[cfg(feature = "v8")]
143    #[clap(long, conflicts_with_all = &Vec::<&str>::from_iter([
144        #[cfg(feature = "cranelift")]
145        "cranelift", 
146        #[cfg(feature = "llvm")]
147        "llvm", 
148        #[cfg(feature = "singlepass")]
149        "singlepass", 
150        #[cfg(feature = "wamr")]
151        "wamr", 
152        #[cfg(feature = "wasmi")]
153        "wasmi"
154    ]))]
155    v8: bool,
156
157    /// Use WAMR.
158    #[cfg(feature = "wamr")]
159    #[clap(long, conflicts_with_all = &Vec::<&str>::from_iter([
160        #[cfg(feature = "cranelift")]
161        "cranelift", 
162        #[cfg(feature = "llvm")]
163        "llvm", 
164        #[cfg(feature = "singlepass")]
165        "singlepass", 
166        #[cfg(feature = "v8")]
167        "v8", 
168        #[cfg(feature = "wasmi")]
169        "wasmi"
170    ]))]
171    wamr: bool,
172
173    /// Use the wasmi runtime.
174    #[cfg(feature = "wasmi")]
175    #[clap(long, conflicts_with_all = &Vec::<&str>::from_iter([
176        #[cfg(feature = "cranelift")]
177        "cranelift", 
178        #[cfg(feature = "llvm")]
179        "llvm", 
180        #[cfg(feature = "singlepass")]
181        "singlepass", 
182        #[cfg(feature = "v8")]
183        "v8", 
184        #[cfg(feature = "wamr")]
185        "wamr"
186    ]))]
187    wasmi: bool,
188
189    /// Enable compiler internal verification.
190    ///
191    /// Available for cranelift, LLVM and singlepass.
192    #[clap(long)]
193    enable_verifier: bool,
194
195    /// Debug directory, where IR and object files will be written to.
196    ///
197    /// Available for cranelift, LLVM and singlepass.
198    #[clap(long, alias = "llvm-debug-dir")]
199    pub(crate) compiler_debug_dir: Option<PathBuf>,
200
201    /// Enable a profiler.
202    ///
203    /// Available for cranelift, LLVM and singlepass.
204    #[clap(long, value_enum)]
205    profiler: Option<Profiler>,
206
207    /// Deprecated option as m0 optimization always play role if we use a static memory
208    #[cfg(feature = "llvm")]
209    #[clap(long)]
210    _enable_pass_params_opt: bool,
211
212    /// Sets the number of threads used to compile the input module(s).
213    #[clap(long, alias = "llvm-num-threads")]
214    compiler_threads: Option<NonZero<usize>>,
215
216    #[clap(flatten)]
217    features: WasmFeatures,
218}
219
220#[derive(Clone, Debug)]
221pub enum Profiler {
222    /// Perfmap-based profilers.
223    Perfmap,
224}
225
226impl FromStr for Profiler {
227    type Err = anyhow::Error;
228
229    fn from_str(s: &str) -> std::result::Result<Self, Self::Err> {
230        match s.to_lowercase().as_str() {
231            "perfmap" => Ok(Self::Perfmap),
232            _ => Err(anyhow::anyhow!("Unrecognized profiler: {s}")),
233        }
234    }
235}
236
237impl RuntimeOptions {
238    pub fn get_available_backends(&self) -> Result<Vec<BackendType>> {
239        // If a specific backend is explicitly requested, use it
240        #[cfg(feature = "cranelift")]
241        {
242            if self.cranelift {
243                return Ok(vec![BackendType::Cranelift]);
244            }
245        }
246
247        #[cfg(feature = "llvm")]
248        {
249            if self.llvm {
250                return Ok(vec![BackendType::LLVM]);
251            }
252        }
253
254        #[cfg(feature = "singlepass")]
255        {
256            if self.singlepass {
257                return Ok(vec![BackendType::Singlepass]);
258            }
259        }
260
261        #[cfg(feature = "wamr")]
262        {
263            if self.wamr {
264                return Ok(vec![BackendType::Wamr]);
265            }
266        }
267
268        #[cfg(feature = "v8")]
269        {
270            if self.v8 {
271                return Ok(vec![BackendType::V8]);
272            }
273        }
274
275        #[cfg(feature = "wasmi")]
276        {
277            if self.wasmi {
278                return Ok(vec![BackendType::Wasmi]);
279            }
280        }
281
282        Ok(BackendType::enabled())
283    }
284
285    /// Filter enabled backends based on required WebAssembly features
286    pub fn filter_backends_by_features(
287        backends: Vec<BackendType>,
288        required_features: &Features,
289        target: &Target,
290    ) -> Vec<BackendType> {
291        backends
292            .into_iter()
293            .filter(|backend| backend.supports_features(required_features, target))
294            .collect()
295    }
296
297    pub fn get_store(&self) -> Result<Store> {
298        let engine = self.get_engine(&Target::default())?;
299        Ok(Store::new(engine))
300    }
301
302    pub fn get_engine(&self, target: &Target) -> Result<Engine> {
303        let backends = self.get_available_backends()?;
304        let backend = backends.first().context("no compiler backend enabled")?;
305        backend.get_engine(target, self)
306    }
307
308    pub fn get_engine_for_module(&self, module_contents: &[u8], target: &Target) -> Result<Engine> {
309        let required_features = self
310            .detect_features_from_wasm(module_contents)
311            .unwrap_or_default();
312
313        self.get_engine_for_features(&required_features, target)
314    }
315
316    pub fn get_engine_for_features(
317        &self,
318        required_features: &Features,
319        target: &Target,
320    ) -> Result<Engine> {
321        let backends = self.get_available_backends()?;
322        let filtered_backends =
323            Self::filter_backends_by_features(backends.clone(), required_features, target);
324
325        if filtered_backends.is_empty() {
326            let enabled_backends = BackendType::enabled();
327            if backends.len() == 1 && enabled_backends.len() > 1 {
328                // If the user has chosen an specific backend, we can suggest to use another one
329                let filtered_backends =
330                    Self::filter_backends_by_features(enabled_backends, required_features, target);
331                let extra_text: String = if !filtered_backends.is_empty() {
332                    format!(". You can use --{} instead", filtered_backends[0])
333                } else {
334                    "".to_string()
335                };
336                bail!(
337                    "The {} backend does not support the required features for the Wasm module{}",
338                    backends[0],
339                    extra_text
340                );
341            } else {
342                bail!(
343                    "No backends support the required features for the Wasm module. Feel free to open an issue at https://github.com/wasmerio/wasmer/issues"
344                );
345            }
346        }
347        filtered_backends.first().unwrap().get_engine(target, self)
348    }
349
350    #[cfg(feature = "compiler")]
351    /// Get the enabled Wasm features.
352    pub fn get_features(&self, default_features: &Features) -> Result<Features> {
353        if self.features.all {
354            return Ok(Features::all());
355        }
356
357        let mut result = default_features.clone();
358        if !self.features.disable_threads {
359            result.threads(true);
360        }
361        if self.features.disable_threads {
362            result.threads(false);
363        }
364        if self.features.multi_value {
365            result.multi_value(true);
366        }
367        if self.features.simd {
368            result.simd(true);
369        }
370        if self.features.bulk_memory {
371            result.bulk_memory(true);
372        }
373        if self.features.reference_types {
374            result.reference_types(true);
375        }
376        Ok(result)
377    }
378
379    #[cfg(feature = "compiler")]
380    /// Get a copy of the default features with user-configured options
381    pub fn get_configured_features(&self) -> Result<Features> {
382        let features = Features::default();
383        self.get_features(&features)
384    }
385
386    /// Detect features from a WebAssembly module binary.
387    pub fn detect_features_from_wasm(
388        &self,
389        wasm_bytes: &[u8],
390    ) -> Result<Features, wasmparser::BinaryReaderError> {
391        if self.features.all {
392            return Ok(Features::all());
393        }
394
395        let mut features = Features::detect_from_wasm(wasm_bytes)?;
396
397        // Merge with user-configured features
398        if !self.features.disable_threads {
399            features.threads(true);
400        }
401        if self.features.reference_types {
402            features.reference_types(true);
403        }
404        if self.features.simd {
405            features.simd(true);
406        }
407        if self.features.bulk_memory {
408            features.bulk_memory(true);
409        }
410        if self.features.multi_value {
411            features.multi_value(true);
412        }
413        if self.features.tail_call {
414            features.tail_call(true);
415        }
416        if self.features.module_linking {
417            features.module_linking(true);
418        }
419        if self.features.multi_memory {
420            features.multi_memory(true);
421        }
422        if self.features.memory64 {
423            features.memory64(true);
424        }
425        if self.features.exceptions {
426            features.exceptions(true);
427        }
428
429        Ok(features)
430    }
431
432    #[cfg(feature = "compiler")]
433    pub fn get_sys_compiler_engine_for_target(
434        &self,
435        target: Target,
436    ) -> std::result::Result<Engine, anyhow::Error> {
437        let backends = self.get_available_backends()?;
438        let compiler_config = self.get_sys_compiler_config(backends.first().unwrap())?;
439        let default_features = compiler_config.default_features_for_target(&target);
440        let features = self.get_features(&default_features)?;
441        Ok(wasmer_compiler::EngineBuilder::new(compiler_config)
442            .set_features(Some(features))
443            .set_target(Some(target))
444            .engine()
445            .into())
446    }
447
448    #[allow(unused_variables)]
449    #[cfg(feature = "compiler")]
450    pub(crate) fn get_sys_compiler_config(
451        &self,
452        rt: &BackendType,
453    ) -> Result<Box<dyn CompilerConfig>> {
454        let compiler_config: Box<dyn CompilerConfig> = match rt {
455            BackendType::Headless => bail!("The headless engine can't be chosen"),
456            #[cfg(feature = "singlepass")]
457            BackendType::Singlepass => {
458                let mut config = wasmer_compiler_singlepass::Singlepass::new();
459                if self.enable_verifier {
460                    config.enable_verifier();
461                }
462                if let Some(p) = &self.profiler {
463                    match p {
464                        Profiler::Perfmap => config.enable_perfmap(),
465                    }
466                }
467                if let Some(mut debug_dir) = self.compiler_debug_dir.clone() {
468                    use wasmer_compiler_singlepass::SinglepassCallbacks;
469
470                    debug_dir.push("singlepass");
471                    config.callbacks(Some(SinglepassCallbacks::new(debug_dir)?));
472                }
473                if let Some(num_threads) = self.compiler_threads {
474                    config.num_threads(num_threads);
475                }
476                Box::new(config)
477            }
478            #[cfg(feature = "cranelift")]
479            BackendType::Cranelift => {
480                let mut config = wasmer_compiler_cranelift::Cranelift::new();
481                if self.enable_verifier {
482                    config.enable_verifier();
483                }
484                if let Some(p) = &self.profiler {
485                    match p {
486                        Profiler::Perfmap => config.enable_perfmap(),
487                    }
488                }
489                if let Some(mut debug_dir) = self.compiler_debug_dir.clone() {
490                    use wasmer_compiler_cranelift::CraneliftCallbacks;
491
492                    debug_dir.push("cranelift");
493                    config.callbacks(Some(CraneliftCallbacks::new(debug_dir)?));
494                }
495                if let Some(num_threads) = self.compiler_threads {
496                    config.num_threads(num_threads);
497                }
498                Box::new(config)
499            }
500            #[cfg(feature = "llvm")]
501            BackendType::LLVM => {
502                use wasmer_compiler_llvm::LLVMCallbacks;
503                use wasmer_types::entity::EntityRef;
504                let mut config = LLVM::new();
505                config.enable_non_volatile_memops();
506
507                if let Some(num_threads) = self.compiler_threads {
508                    config.num_threads(num_threads);
509                }
510
511                if let Some(mut debug_dir) = self.compiler_debug_dir.clone() {
512                    debug_dir.push("llvm");
513                    config.callbacks(Some(LLVMCallbacks::new(debug_dir)?));
514                    config.verbose_asm(true);
515                }
516                if self.enable_verifier {
517                    config.enable_verifier();
518                }
519                if let Some(p) = &self.profiler {
520                    match p {
521                        Profiler::Perfmap => config.enable_perfmap(),
522                    }
523                }
524
525                Box::new(config)
526            }
527            BackendType::V8 | BackendType::Wamr | BackendType::Wasmi => unreachable!(),
528            #[cfg(not(all(feature = "singlepass", feature = "cranelift", feature = "llvm")))]
529            compiler => {
530                bail!("The `{compiler}` compiler is not included in this binary.")
531            }
532        };
533
534        #[allow(unreachable_code)]
535        Ok(compiler_config)
536    }
537}
538
539/// The compiler used for the store
540#[derive(Debug, PartialEq, Eq, Clone, Copy)]
541#[allow(clippy::upper_case_acronyms, dead_code)]
542pub enum BackendType {
543    /// Singlepass compiler
544    Singlepass,
545
546    /// Cranelift compiler
547    Cranelift,
548
549    /// LLVM compiler
550    LLVM,
551
552    /// V8 runtime
553    V8,
554
555    /// Wamr runtime
556    Wamr,
557
558    /// Wasmi runtime
559    Wasmi,
560
561    /// Headless compiler
562    #[allow(dead_code)]
563    Headless,
564}
565
566impl BackendType {
567    /// Return all enabled compilers
568    pub fn enabled() -> Vec<Self> {
569        vec![
570            #[cfg(feature = "cranelift")]
571            Self::Cranelift,
572            #[cfg(feature = "llvm")]
573            Self::LLVM,
574            #[cfg(feature = "singlepass")]
575            Self::Singlepass,
576            #[cfg(feature = "v8")]
577            Self::V8,
578            #[cfg(feature = "wamr")]
579            Self::Wamr,
580            #[cfg(feature = "wasmi")]
581            Self::Wasmi,
582        ]
583    }
584
585    /// Returns an engine for this backend type.
586    /// We enable every feature the engine supports, since the same engine may later be used
587    /// with a module that requires more features than the one used during engine detection.
588    pub fn get_engine(&self, target: &Target, runtime_opts: &RuntimeOptions) -> Result<Engine> {
589        match self {
590            #[cfg(feature = "singlepass")]
591            Self::Singlepass => {
592                let mut config = wasmer_compiler_singlepass::Singlepass::new();
593                let supported_features = config.supported_features_for_target(target);
594                if runtime_opts.enable_verifier {
595                    config.enable_verifier();
596                }
597                if let Some(p) = &runtime_opts.profiler {
598                    match p {
599                        Profiler::Perfmap => config.enable_perfmap(),
600                    }
601                }
602                if let Some(mut debug_dir) = runtime_opts.compiler_debug_dir.clone() {
603                    use wasmer_compiler_singlepass::SinglepassCallbacks;
604
605                    debug_dir.push("singlepass");
606                    config.callbacks(Some(SinglepassCallbacks::new(debug_dir)?));
607                }
608                if let Some(num_threads) = runtime_opts.compiler_threads {
609                    config.num_threads(num_threads);
610                }
611                let engine = wasmer_compiler::EngineBuilder::new(config)
612                    .set_features(Some(supported_features))
613                    .set_target(Some(target.clone()))
614                    .engine()
615                    .into();
616                Ok(engine)
617            }
618            #[cfg(feature = "cranelift")]
619            Self::Cranelift => {
620                let mut config = wasmer_compiler_cranelift::Cranelift::new();
621                let supported_features = config.supported_features_for_target(target);
622                if runtime_opts.enable_verifier {
623                    config.enable_verifier();
624                }
625                if let Some(p) = &runtime_opts.profiler {
626                    match p {
627                        Profiler::Perfmap => config.enable_perfmap(),
628                    }
629                }
630                if let Some(mut debug_dir) = runtime_opts.compiler_debug_dir.clone() {
631                    use wasmer_compiler_cranelift::CraneliftCallbacks;
632
633                    debug_dir.push("cranelift");
634                    config.callbacks(Some(CraneliftCallbacks::new(debug_dir)?));
635                }
636                if let Some(num_threads) = runtime_opts.compiler_threads {
637                    config.num_threads(num_threads);
638                }
639                let engine = wasmer_compiler::EngineBuilder::new(config)
640                    .set_features(Some(supported_features))
641                    .set_target(Some(target.clone()))
642                    .engine()
643                    .into();
644                Ok(engine)
645            }
646            #[cfg(feature = "llvm")]
647            Self::LLVM => {
648                use wasmer_compiler_llvm::LLVMCallbacks;
649                use wasmer_types::entity::EntityRef;
650
651                let mut config = wasmer_compiler_llvm::LLVM::new();
652                config.enable_non_volatile_memops();
653
654                let supported_features = config.supported_features_for_target(target);
655                if let Some(mut debug_dir) = runtime_opts.compiler_debug_dir.clone() {
656                    debug_dir.push("llvm");
657                    config.callbacks(Some(LLVMCallbacks::new(debug_dir)?));
658                    config.verbose_asm(true);
659                }
660                if runtime_opts.enable_verifier {
661                    config.enable_verifier();
662                }
663
664                if let Some(num_threads) = runtime_opts.compiler_threads {
665                    config.num_threads(num_threads);
666                }
667
668                if let Some(p) = &runtime_opts.profiler {
669                    match p {
670                        Profiler::Perfmap => config.enable_perfmap(),
671                    }
672                }
673
674                let engine = wasmer_compiler::EngineBuilder::new(config)
675                    .set_features(Some(supported_features))
676                    .set_target(Some(target.clone()))
677                    .engine()
678                    .into();
679                Ok(engine)
680            }
681            #[cfg(feature = "v8")]
682            Self::V8 => Ok(wasmer::v8::V8::new().into()),
683            #[cfg(feature = "wamr")]
684            Self::Wamr => Ok(wasmer::wamr::Wamr::new().into()),
685            #[cfg(feature = "wasmi")]
686            Self::Wasmi => Ok(wasmer::wasmi::Wasmi::new().into()),
687            Self::Headless => bail!("Headless is not a valid runtime to instantiate directly"),
688            #[allow(unreachable_patterns)]
689            _ => bail!("Unsupported backend type"),
690        }
691    }
692
693    /// Check if this backend supports all the required WebAssembly features
694    #[allow(unreachable_code)]
695    pub fn supports_features(&self, required_features: &Features, target: &Target) -> bool {
696        // Map BackendType to the corresponding wasmer::BackendKind
697        let backend_kind = match self {
698            #[cfg(feature = "singlepass")]
699            Self::Singlepass => wasmer::BackendKind::Singlepass,
700            #[cfg(feature = "cranelift")]
701            Self::Cranelift => wasmer::BackendKind::Cranelift,
702            #[cfg(feature = "llvm")]
703            Self::LLVM => wasmer::BackendKind::LLVM,
704            #[cfg(feature = "v8")]
705            Self::V8 => wasmer::BackendKind::V8,
706            #[cfg(feature = "wamr")]
707            Self::Wamr => wasmer::BackendKind::Wamr,
708            #[cfg(feature = "wasmi")]
709            Self::Wasmi => wasmer::BackendKind::Wasmi,
710            Self::Headless => return false, // Headless can't compile
711            #[allow(unreachable_patterns)]
712            _ => return false,
713        };
714
715        // Get the supported features from the backend
716        let supported = wasmer::Engine::supported_features_for_backend(&backend_kind, target);
717
718        // Check if the backend supports all required features
719        if !supported.contains_features(required_features) {
720            return false;
721        }
722
723        true
724    }
725}
726
727impl From<&BackendType> for wasmer::BackendKind {
728    fn from(backend_type: &BackendType) -> Self {
729        match backend_type {
730            #[cfg(feature = "singlepass")]
731            BackendType::Singlepass => wasmer::BackendKind::Singlepass,
732            #[cfg(feature = "cranelift")]
733            BackendType::Cranelift => wasmer::BackendKind::Cranelift,
734            #[cfg(feature = "llvm")]
735            BackendType::LLVM => wasmer::BackendKind::LLVM,
736            #[cfg(feature = "v8")]
737            BackendType::V8 => wasmer::BackendKind::V8,
738            #[cfg(feature = "wamr")]
739            BackendType::Wamr => wasmer::BackendKind::Wamr,
740            #[cfg(feature = "wasmi")]
741            BackendType::Wasmi => wasmer::BackendKind::Wasmi,
742            _ => {
743                #[cfg(feature = "sys")]
744                {
745                    wasmer::BackendKind::Headless
746                }
747                #[cfg(not(feature = "sys"))]
748                {
749                    unreachable!("No backend enabled!")
750                }
751            }
752        }
753    }
754}
755
756impl std::fmt::Display for BackendType {
757    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
758        write!(
759            f,
760            "{}",
761            match self {
762                Self::Singlepass => "singlepass",
763                Self::Cranelift => "cranelift",
764                Self::LLVM => "llvm",
765                Self::V8 => "v8",
766                Self::Wamr => "wamr",
767                Self::Wasmi => "wasmi",
768                Self::Headless => "headless",
769            }
770        )
771    }
772}