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