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                    config.verbose_asm(true);
520                }
521                if self.enable_verifier {
522                    config.enable_verifier();
523                }
524                if let Some(p) = &self.profiler {
525                    match p {
526                        Profiler::Perfmap => config.enable_perfmap(),
527                    }
528                }
529
530                Box::new(config)
531            }
532            BackendType::V8 | BackendType::Wamr | BackendType::Wasmi => unreachable!(),
533            #[cfg(not(all(feature = "singlepass", feature = "cranelift", feature = "llvm")))]
534            compiler => {
535                bail!("The `{compiler}` compiler is not included in this binary.")
536            }
537        };
538
539        #[allow(unreachable_code)]
540        Ok(compiler_config)
541    }
542}
543
544/// The compiler used for the store
545#[derive(Debug, PartialEq, Eq, Clone, Copy)]
546#[allow(clippy::upper_case_acronyms, dead_code)]
547pub enum BackendType {
548    /// Singlepass compiler
549    Singlepass,
550
551    /// Cranelift compiler
552    Cranelift,
553
554    /// LLVM compiler
555    LLVM,
556
557    /// V8 runtime
558    V8,
559
560    /// Wamr runtime
561    Wamr,
562
563    /// Wasmi runtime
564    Wasmi,
565
566    /// Headless compiler
567    #[allow(dead_code)]
568    Headless,
569}
570
571impl BackendType {
572    /// Return all enabled compilers
573    pub fn enabled() -> Vec<Self> {
574        vec![
575            #[cfg(feature = "cranelift")]
576            Self::Cranelift,
577            #[cfg(feature = "llvm")]
578            Self::LLVM,
579            #[cfg(feature = "singlepass")]
580            Self::Singlepass,
581            #[cfg(feature = "v8")]
582            Self::V8,
583            #[cfg(feature = "wamr")]
584            Self::Wamr,
585            #[cfg(feature = "wasmi")]
586            Self::Wasmi,
587        ]
588    }
589
590    /// Get an engine for this backend type
591    pub fn get_engine(
592        &self,
593        target: &Target,
594        features: &Features,
595        runtime_opts: &RuntimeOptions,
596    ) -> Result<Engine> {
597        match self {
598            #[cfg(feature = "singlepass")]
599            Self::Singlepass => {
600                let mut config = wasmer_compiler_singlepass::Singlepass::new();
601                if runtime_opts.enable_verifier {
602                    config.enable_verifier();
603                }
604                if let Some(p) = &runtime_opts.profiler {
605                    match p {
606                        Profiler::Perfmap => config.enable_perfmap(),
607                    }
608                }
609                if let Some(mut debug_dir) = runtime_opts.compiler_debug_dir.clone() {
610                    use wasmer_compiler_singlepass::SinglepassCallbacks;
611
612                    debug_dir.push("singlepass");
613                    config.callbacks(Some(SinglepassCallbacks::new(debug_dir)?));
614                }
615                if let Some(num_threads) = runtime_opts.compiler_threads {
616                    config.num_threads(num_threads);
617                }
618                let engine = wasmer_compiler::EngineBuilder::new(config)
619                    .set_features(Some(features.clone()))
620                    .set_target(Some(target.clone()))
621                    .engine()
622                    .into();
623                Ok(engine)
624            }
625            #[cfg(feature = "cranelift")]
626            Self::Cranelift => {
627                let mut config = wasmer_compiler_cranelift::Cranelift::new();
628                if runtime_opts.enable_verifier {
629                    config.enable_verifier();
630                }
631                if let Some(p) = &runtime_opts.profiler {
632                    match p {
633                        Profiler::Perfmap => config.enable_perfmap(),
634                    }
635                }
636                if let Some(mut debug_dir) = runtime_opts.compiler_debug_dir.clone() {
637                    use wasmer_compiler_cranelift::CraneliftCallbacks;
638
639                    debug_dir.push("cranelift");
640                    config.callbacks(Some(CraneliftCallbacks::new(debug_dir)?));
641                }
642                if let Some(num_threads) = runtime_opts.compiler_threads {
643                    config.num_threads(num_threads);
644                }
645                let engine = wasmer_compiler::EngineBuilder::new(config)
646                    .set_features(Some(features.clone()))
647                    .set_target(Some(target.clone()))
648                    .engine()
649                    .into();
650                Ok(engine)
651            }
652            #[cfg(feature = "llvm")]
653            Self::LLVM => {
654                use wasmer_compiler_llvm::LLVMCallbacks;
655                use wasmer_types::entity::EntityRef;
656
657                let mut config = wasmer_compiler_llvm::LLVM::new();
658
659                if let Some(mut debug_dir) = runtime_opts.compiler_debug_dir.clone() {
660                    debug_dir.push("llvm");
661                    config.callbacks(Some(LLVMCallbacks::new(debug_dir)?));
662                    config.verbose_asm(true);
663                }
664                if runtime_opts.enable_verifier {
665                    config.enable_verifier();
666                }
667
668                if runtime_opts.enable_pass_params_opt {
669                    config.enable_pass_params_opt();
670                }
671
672                if let Some(num_threads) = runtime_opts.compiler_threads {
673                    config.num_threads(num_threads);
674                }
675
676                if let Some(p) = &runtime_opts.profiler {
677                    match p {
678                        Profiler::Perfmap => config.enable_perfmap(),
679                    }
680                }
681
682                let engine = wasmer_compiler::EngineBuilder::new(config)
683                    .set_features(Some(features.clone()))
684                    .set_target(Some(target.clone()))
685                    .engine()
686                    .into();
687                Ok(engine)
688            }
689            #[cfg(feature = "v8")]
690            Self::V8 => Ok(wasmer::v8::V8::new().into()),
691            #[cfg(feature = "wamr")]
692            Self::Wamr => Ok(wasmer::wamr::Wamr::new().into()),
693            #[cfg(feature = "wasmi")]
694            Self::Wasmi => Ok(wasmer::wasmi::Wasmi::new().into()),
695            Self::Headless => bail!("Headless is not a valid runtime to instantiate directly"),
696            #[allow(unreachable_patterns)]
697            _ => bail!("Unsupported backend type"),
698        }
699    }
700
701    /// Check if this backend supports all the required WebAssembly features
702    #[allow(unreachable_code)]
703    pub fn supports_features(&self, required_features: &Features, target: &Target) -> bool {
704        // Map BackendType to the corresponding wasmer::BackendKind
705        let backend_kind = match self {
706            #[cfg(feature = "singlepass")]
707            Self::Singlepass => wasmer::BackendKind::Singlepass,
708            #[cfg(feature = "cranelift")]
709            Self::Cranelift => wasmer::BackendKind::Cranelift,
710            #[cfg(feature = "llvm")]
711            Self::LLVM => wasmer::BackendKind::LLVM,
712            #[cfg(feature = "v8")]
713            Self::V8 => wasmer::BackendKind::V8,
714            #[cfg(feature = "wamr")]
715            Self::Wamr => wasmer::BackendKind::Wamr,
716            #[cfg(feature = "wasmi")]
717            Self::Wasmi => wasmer::BackendKind::Wasmi,
718            Self::Headless => return false, // Headless can't compile
719            #[allow(unreachable_patterns)]
720            _ => return false,
721        };
722
723        // Get the supported features from the backend
724        let supported = wasmer::Engine::supported_features_for_backend(&backend_kind, target);
725
726        // Check if the backend supports all required features
727        if !supported.contains_features(required_features) {
728            return false;
729        }
730
731        true
732    }
733}
734
735impl From<&BackendType> for wasmer::BackendKind {
736    fn from(backend_type: &BackendType) -> Self {
737        match backend_type {
738            #[cfg(feature = "singlepass")]
739            BackendType::Singlepass => wasmer::BackendKind::Singlepass,
740            #[cfg(feature = "cranelift")]
741            BackendType::Cranelift => wasmer::BackendKind::Cranelift,
742            #[cfg(feature = "llvm")]
743            BackendType::LLVM => wasmer::BackendKind::LLVM,
744            #[cfg(feature = "v8")]
745            BackendType::V8 => wasmer::BackendKind::V8,
746            #[cfg(feature = "wamr")]
747            BackendType::Wamr => wasmer::BackendKind::Wamr,
748            #[cfg(feature = "wasmi")]
749            BackendType::Wasmi => wasmer::BackendKind::Wasmi,
750            _ => {
751                #[cfg(feature = "sys")]
752                {
753                    wasmer::BackendKind::Headless
754                }
755                #[cfg(not(feature = "sys"))]
756                {
757                    unreachable!("No backend enabled!")
758                }
759            }
760        }
761    }
762}
763
764impl std::fmt::Display for BackendType {
765    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
766        write!(
767            f,
768            "{}",
769            match self {
770                Self::Singlepass => "singlepass",
771                Self::Cranelift => "cranelift",
772                Self::LLVM => "llvm",
773                Self::V8 => "v8",
774                Self::Wamr => "wamr",
775                Self::Wasmi => "wasmi",
776                Self::Headless => "headless",
777            }
778        )
779    }
780}