1#![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::{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)]
26pub struct WasmFeatures {
29 #[clap(long = "enable-simd")]
31 pub simd: bool,
32
33 #[clap(long = "disable-threads")]
35 pub disable_threads: bool,
36
37 #[clap(long = "enable-threads")]
39 pub _threads: bool,
40
41 #[clap(long = "enable-reference-types")]
43 pub reference_types: bool,
44
45 #[clap(long = "enable-multi-value")]
47 pub multi_value: bool,
48
49 #[clap(long = "enable-bulk-memory")]
51 pub bulk_memory: bool,
52
53 #[clap(long = "enable-tail-call")]
55 pub tail_call: bool,
56
57 #[clap(long = "enable-module-linking")]
59 pub module_linking: bool,
60
61 #[clap(long = "enable-multi-memory")]
63 pub multi_memory: bool,
64
65 #[clap(long = "enable-memory64")]
67 pub memory64: bool,
68
69 #[clap(long = "enable-exceptions")]
71 pub exceptions: bool,
72
73 #[clap(long = "enable-relaxed-simd")]
75 pub relaxed_simd: bool,
76
77 #[clap(long = "enable-extended-const")]
79 pub extended_const: bool,
80
81 #[clap(long = "enable-all")]
83 pub all: bool,
84}
85
86#[derive(Debug, Clone, clap::Parser, Default)]
87pub struct RuntimeOptions {
89 #[cfg(feature = "singlepass")]
91 #[clap(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 #[cfg(feature = "cranelift")]
107 #[clap(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 #[cfg(feature = "llvm")]
123 #[clap(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 #[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 #[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 #[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 #[clap(long)]
189 enable_verifier: bool,
190
191 #[clap(long, value_enum)]
195 profiler: Option<Profiler>,
196
197 #[clap(long)]
201 llvm_debug_dir: Option<PathBuf>,
202
203 #[clap(long)]
206 enable_pass_params_opt: bool,
207
208 #[clap(long)]
211 llvm_num_threads: Option<NonZero<usize>>,
212
213 #[clap(flatten)]
214 features: WasmFeatures,
215}
216
217#[derive(Clone, Debug)]
218pub enum Profiler {
219 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 #[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 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().unwrap();
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 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 pub fn get_features(&self, features: &Features) -> Result<Features> {
355 let mut result = features.clone();
356 if !self.features.disable_threads || self.features.all {
357 result.threads(true);
358 }
359 if self.features.disable_threads && !self.features.all {
360 result.threads(false);
361 }
362 if self.features.multi_value || self.features.all {
363 result.multi_value(true);
364 }
365 if self.features.simd || self.features.all {
366 result.simd(true);
367 }
368 if self.features.bulk_memory || self.features.all {
369 result.bulk_memory(true);
370 }
371 if self.features.reference_types || self.features.all {
372 result.reference_types(true);
373 }
374 Ok(result)
375 }
376
377 #[cfg(feature = "compiler")]
378 pub fn get_configured_features(&self) -> Result<Features> {
380 let features = Features::default();
381 self.get_features(&features)
382 }
383
384 pub fn detect_features_from_wasm(
386 &self,
387 wasm_bytes: &[u8],
388 ) -> Result<Features, wasmparser::BinaryReaderError> {
389 let mut features = Features::detect_from_wasm(wasm_bytes)?;
390
391 if !self.features.disable_threads || self.features.all {
393 features.threads(true);
394 }
395 if self.features.reference_types || self.features.all {
396 features.reference_types(true);
397 }
398 if self.features.simd || self.features.all {
399 features.simd(true);
400 }
401 if self.features.bulk_memory || self.features.all {
402 features.bulk_memory(true);
403 }
404 if self.features.multi_value || self.features.all {
405 features.multi_value(true);
406 }
407 if self.features.tail_call || self.features.all {
408 features.tail_call(true);
409 }
410 if self.features.module_linking || self.features.all {
411 features.module_linking(true);
412 }
413 if self.features.multi_memory || self.features.all {
414 features.multi_memory(true);
415 }
416 if self.features.memory64 || self.features.all {
417 features.memory64(true);
418 }
419 if self.features.exceptions || self.features.all {
420 features.exceptions(true);
421 }
422
423 Ok(features)
424 }
425
426 #[cfg(feature = "compiler")]
427 pub fn get_sys_compiler_engine_for_target(
428 &self,
429 target: Target,
430 ) -> std::result::Result<Engine, anyhow::Error> {
431 let backends = self.get_available_backends()?;
432 let compiler_config = self.get_sys_compiler_config(backends.first().unwrap())?;
433 let default_features = compiler_config.default_features_for_target(&target);
434 let features = self.get_features(&default_features)?;
435 Ok(wasmer_compiler::EngineBuilder::new(compiler_config)
436 .set_features(Some(features))
437 .set_target(Some(target))
438 .engine()
439 .into())
440 }
441
442 #[allow(unused_variables)]
443 #[cfg(feature = "compiler")]
444 pub(crate) fn get_sys_compiler_config(
445 &self,
446 rt: &BackendType,
447 ) -> Result<Box<dyn CompilerConfig>> {
448 let compiler_config: Box<dyn CompilerConfig> = match rt {
449 BackendType::Headless => bail!("The headless engine can't be chosen"),
450 #[cfg(feature = "singlepass")]
451 BackendType::Singlepass => {
452 let mut config = wasmer_compiler_singlepass::Singlepass::new();
453 if self.enable_verifier {
454 config.enable_verifier();
455 }
456 if let Some(p) = &self.profiler {
457 match p {
458 Profiler::Perfmap => config.enable_perfmap(),
459 }
460 }
461
462 Box::new(config)
463 }
464 #[cfg(feature = "cranelift")]
465 BackendType::Cranelift => {
466 let mut config = wasmer_compiler_cranelift::Cranelift::new();
467 if self.enable_verifier {
468 config.enable_verifier();
469 }
470 if let Some(p) = &self.profiler {
471 match p {
472 Profiler::Perfmap => config.enable_perfmap(),
473 }
474 }
475 Box::new(config)
476 }
477 #[cfg(feature = "llvm")]
478 BackendType::LLVM => {
479 use std::{fmt, fs::File, io::Write};
480
481 use wasmer_compiler_llvm::{
482 CompiledKind, InkwellMemoryBuffer, InkwellModule, LLVM, LLVMCallbacks,
483 };
484 use wasmer_types::entity::EntityRef;
485 let mut config = LLVM::new();
486
487 if self.enable_pass_params_opt {
488 config.enable_pass_params_opt();
489 }
490
491 if let Some(num_threads) = self.llvm_num_threads {
492 config.num_threads(num_threads);
493 }
494
495 struct Callbacks {
496 debug_dir: PathBuf,
497 }
498 impl Callbacks {
499 fn new(debug_dir: PathBuf) -> Result<Self> {
500 std::fs::create_dir_all(&debug_dir)?;
502 Ok(Self { debug_dir })
503 }
504 }
505 fn types_to_signature(types: &[Type]) -> String {
508 types
509 .iter()
510 .map(|ty| match ty {
511 Type::I32 => "i".to_string(),
512 Type::I64 => "I".to_string(),
513 Type::F32 => "f".to_string(),
514 Type::F64 => "F".to_string(),
515 Type::V128 => "v".to_string(),
516 Type::ExternRef => "e".to_string(),
517 Type::FuncRef => "r".to_string(),
518 Type::ExceptionRef => "x".to_string(),
519 })
520 .collect::<Vec<_>>()
521 .join("")
522 }
523 fn function_kind_to_filename(kind: &CompiledKind) -> String {
526 match kind {
527 CompiledKind::Local(local_index) => {
528 format!("function_{}", local_index.index())
529 }
530 CompiledKind::FunctionCallTrampoline(func_type) => format!(
531 "trampoline_call_{}_{}",
532 types_to_signature(func_type.params()),
533 types_to_signature(func_type.results())
534 ),
535 CompiledKind::DynamicFunctionTrampoline(func_type) => format!(
536 "trampoline_dynamic_{}_{}",
537 types_to_signature(func_type.params()),
538 types_to_signature(func_type.results())
539 ),
540 CompiledKind::Module => "module".into(),
541 }
542 }
543 impl LLVMCallbacks for Callbacks {
544 fn preopt_ir(&self, kind: &CompiledKind, module: &InkwellModule) {
545 let mut path = self.debug_dir.clone();
546 path.push(format!("{}.preopt.ll", function_kind_to_filename(kind)));
547 module
548 .print_to_file(&path)
549 .expect("Error while dumping pre optimized LLVM IR");
550 }
551 fn postopt_ir(&self, kind: &CompiledKind, module: &InkwellModule) {
552 let mut path = self.debug_dir.clone();
553 path.push(format!("{}.postopt.ll", function_kind_to_filename(kind)));
554 module
555 .print_to_file(&path)
556 .expect("Error while dumping post optimized LLVM IR");
557 }
558 fn obj_memory_buffer(
559 &self,
560 kind: &CompiledKind,
561 memory_buffer: &InkwellMemoryBuffer,
562 ) {
563 let mut path = self.debug_dir.clone();
564 path.push(format!("{}.o", function_kind_to_filename(kind)));
565 let mem_buf_slice = memory_buffer.as_slice();
566 let mut file = File::create(path)
567 .expect("Error while creating debug object file from LLVM IR");
568 let mut pos = 0;
569 while pos < mem_buf_slice.len() {
570 pos += file.write(&mem_buf_slice[pos..]).unwrap();
571 }
572 }
573 fn asm_memory_buffer(
574 &self,
575 kind: &CompiledKind,
576 asm_memory_buffer: &InkwellMemoryBuffer,
577 ) {
578 let mut path = self.debug_dir.clone();
579 path.push(format!("{}.s", function_kind_to_filename(kind)));
580 let mem_buf_slice = asm_memory_buffer.as_slice();
581 let mut file = File::create(path)
582 .expect("Error while creating debug object file from LLVM IR");
583 let mut pos = 0;
584 while pos < mem_buf_slice.len() {
585 pos += file.write(&mem_buf_slice[pos..]).unwrap();
586 }
587 }
588 }
589
590 impl fmt::Debug for Callbacks {
591 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
592 write!(f, "LLVMCallbacks")
593 }
594 }
595
596 if let Some(ref llvm_debug_dir) = self.llvm_debug_dir {
597 config.callbacks(Some(Arc::new(Callbacks::new(llvm_debug_dir.clone())?)));
598 }
599 if self.enable_verifier {
600 config.enable_verifier();
601 }
602 if let Some(p) = &self.profiler {
603 match p {
604 Profiler::Perfmap => config.enable_perfmap(),
605 }
606 }
607
608 Box::new(config)
609 }
610 BackendType::V8 | BackendType::Wamr | BackendType::Wasmi => unreachable!(),
611 #[cfg(not(all(feature = "singlepass", feature = "cranelift", feature = "llvm")))]
612 compiler => {
613 bail!(
614 "The `{}` compiler is not included in this binary.",
615 compiler.to_string()
616 )
617 }
618 };
619
620 #[allow(unreachable_code)]
621 Ok(compiler_config)
622 }
623}
624
625#[derive(Debug, PartialEq, Eq, Clone, Copy)]
627#[allow(clippy::upper_case_acronyms, dead_code)]
628pub enum BackendType {
629 Singlepass,
631
632 Cranelift,
634
635 LLVM,
637
638 V8,
640
641 Wamr,
643
644 Wasmi,
646
647 #[allow(dead_code)]
649 Headless,
650}
651
652impl BackendType {
653 pub fn enabled() -> Vec<Self> {
655 vec![
656 #[cfg(feature = "cranelift")]
657 Self::Cranelift,
658 #[cfg(feature = "llvm")]
659 Self::LLVM,
660 #[cfg(feature = "singlepass")]
661 Self::Singlepass,
662 #[cfg(feature = "v8")]
663 Self::V8,
664 #[cfg(feature = "wamr")]
665 Self::Wamr,
666 #[cfg(feature = "wasmi")]
667 Self::Wasmi,
668 ]
669 }
670
671 pub fn get_engine(
673 &self,
674 target: &Target,
675 features: &Features,
676 runtime_opts: &RuntimeOptions,
677 ) -> Result<Engine> {
678 match self {
679 #[cfg(feature = "singlepass")]
680 Self::Singlepass => {
681 let mut config = wasmer_compiler_singlepass::Singlepass::new();
682 if runtime_opts.enable_verifier {
683 config.enable_verifier();
684 }
685 if let Some(p) = &runtime_opts.profiler {
686 match p {
687 Profiler::Perfmap => config.enable_perfmap(),
688 }
689 }
690 let engine = wasmer_compiler::EngineBuilder::new(config)
691 .set_features(Some(features.clone()))
692 .set_target(Some(target.clone()))
693 .engine()
694 .into();
695 Ok(engine)
696 }
697 #[cfg(feature = "cranelift")]
698 Self::Cranelift => {
699 let mut config = wasmer_compiler_cranelift::Cranelift::new();
700 if runtime_opts.enable_verifier {
701 config.enable_verifier();
702 }
703 if let Some(p) = &runtime_opts.profiler {
704 match p {
705 Profiler::Perfmap => config.enable_perfmap(),
706 }
707 }
708 let engine = wasmer_compiler::EngineBuilder::new(config)
709 .set_features(Some(features.clone()))
710 .set_target(Some(target.clone()))
711 .engine()
712 .into();
713 Ok(engine)
714 }
715 #[cfg(feature = "llvm")]
716 Self::LLVM => {
717 use std::{fmt, fs::File, io::Write};
718
719 use wasmer_compiler_llvm::{
720 CompiledKind, InkwellMemoryBuffer, InkwellModule, LLVM, LLVMCallbacks,
721 };
722 use wasmer_types::entity::EntityRef;
723
724 let mut config = wasmer_compiler_llvm::LLVM::new();
725
726 struct Callbacks {
727 debug_dir: PathBuf,
728 }
729 impl Callbacks {
730 fn new(debug_dir: PathBuf) -> Result<Self> {
731 std::fs::create_dir_all(&debug_dir)?;
733 Ok(Self { debug_dir })
734 }
735 }
736 fn types_to_signature(types: &[Type]) -> String {
739 types
740 .iter()
741 .map(|ty| match ty {
742 Type::I32 => "i".to_string(),
743 Type::I64 => "I".to_string(),
744 Type::F32 => "f".to_string(),
745 Type::F64 => "F".to_string(),
746 Type::V128 => "v".to_string(),
747 Type::ExternRef => "e".to_string(),
748 Type::FuncRef => "r".to_string(),
749 Type::ExceptionRef => "x".to_string(),
750 })
751 .collect::<Vec<_>>()
752 .join("")
753 }
754 fn function_kind_to_filename(kind: &CompiledKind) -> String {
757 match kind {
758 CompiledKind::Local(local_index) => {
759 format!("function_{}", local_index.index())
760 }
761 CompiledKind::FunctionCallTrampoline(func_type) => format!(
762 "trampoline_call_{}_{}",
763 types_to_signature(func_type.params()),
764 types_to_signature(func_type.results())
765 ),
766 CompiledKind::DynamicFunctionTrampoline(func_type) => format!(
767 "trampoline_dynamic_{}_{}",
768 types_to_signature(func_type.params()),
769 types_to_signature(func_type.results())
770 ),
771 CompiledKind::Module => "module".into(),
772 }
773 }
774 impl LLVMCallbacks for Callbacks {
775 fn preopt_ir(&self, kind: &CompiledKind, module: &InkwellModule) {
776 let mut path = self.debug_dir.clone();
777 path.push(format!("{}.preopt.ll", function_kind_to_filename(kind)));
778 module
779 .print_to_file(&path)
780 .expect("Error while dumping pre optimized LLVM IR");
781 }
782 fn postopt_ir(&self, kind: &CompiledKind, module: &InkwellModule) {
783 let mut path = self.debug_dir.clone();
784 path.push(format!("{}.postopt.ll", function_kind_to_filename(kind)));
785 module
786 .print_to_file(&path)
787 .expect("Error while dumping post optimized LLVM IR");
788 }
789 fn obj_memory_buffer(
790 &self,
791 kind: &CompiledKind,
792 memory_buffer: &InkwellMemoryBuffer,
793 ) {
794 let mut path = self.debug_dir.clone();
795 path.push(format!("{}.o", function_kind_to_filename(kind)));
796 let mem_buf_slice = memory_buffer.as_slice();
797 let mut file = File::create(path)
798 .expect("Error while creating debug object file from LLVM IR");
799 let mut pos = 0;
800 while pos < mem_buf_slice.len() {
801 pos += file.write(&mem_buf_slice[pos..]).unwrap();
802 }
803 }
804 fn asm_memory_buffer(
805 &self,
806 kind: &CompiledKind,
807 asm_memory_buffer: &InkwellMemoryBuffer,
808 ) {
809 let mut path = self.debug_dir.clone();
810 path.push(format!("{}.s", function_kind_to_filename(kind)));
811 let mem_buf_slice = asm_memory_buffer.as_slice();
812 let mut file = File::create(path)
813 .expect("Error while creating debug object file from LLVM IR");
814 let mut pos = 0;
815 while pos < mem_buf_slice.len() {
816 pos += file.write(&mem_buf_slice[pos..]).unwrap();
817 }
818 }
819 }
820
821 impl fmt::Debug for Callbacks {
822 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
823 write!(f, "LLVMCallbacks")
824 }
825 }
826
827 if let Some(ref llvm_debug_dir) = runtime_opts.llvm_debug_dir {
828 config.callbacks(Some(Arc::new(Callbacks::new(llvm_debug_dir.clone())?)));
829 }
830 if runtime_opts.enable_verifier {
831 config.enable_verifier();
832 }
833
834 if runtime_opts.enable_pass_params_opt {
835 config.enable_pass_params_opt();
836 }
837
838 if let Some(num_threads) = runtime_opts.llvm_num_threads {
839 config.num_threads(num_threads);
840 }
841
842 if let Some(p) = &runtime_opts.profiler {
843 match p {
844 Profiler::Perfmap => config.enable_perfmap(),
845 }
846 }
847
848 let engine = wasmer_compiler::EngineBuilder::new(config)
849 .set_features(Some(features.clone()))
850 .set_target(Some(target.clone()))
851 .engine()
852 .into();
853 Ok(engine)
854 }
855 #[cfg(feature = "v8")]
856 Self::V8 => Ok(wasmer::v8::V8::new().into()),
857 #[cfg(feature = "wamr")]
858 Self::Wamr => Ok(wasmer::wamr::Wamr::new().into()),
859 #[cfg(feature = "wasmi")]
860 Self::Wasmi => Ok(wasmer::wasmi::Wasmi::new().into()),
861 Self::Headless => bail!("Headless is not a valid runtime to instantiate directly"),
862 #[allow(unreachable_patterns)]
863 _ => bail!("Unsupported backend type"),
864 }
865 }
866
867 #[allow(unreachable_code)]
869 pub fn supports_features(&self, required_features: &Features, target: &Target) -> bool {
870 let backend_kind = match self {
872 #[cfg(feature = "singlepass")]
873 Self::Singlepass => wasmer::BackendKind::Singlepass,
874 #[cfg(feature = "cranelift")]
875 Self::Cranelift => wasmer::BackendKind::Cranelift,
876 #[cfg(feature = "llvm")]
877 Self::LLVM => wasmer::BackendKind::LLVM,
878 #[cfg(feature = "v8")]
879 Self::V8 => wasmer::BackendKind::V8,
880 #[cfg(feature = "wamr")]
881 Self::Wamr => wasmer::BackendKind::Wamr,
882 #[cfg(feature = "wasmi")]
883 Self::Wasmi => wasmer::BackendKind::Wasmi,
884 Self::Headless => return false, #[allow(unreachable_patterns)]
886 _ => return false,
887 };
888
889 let supported = wasmer::Engine::supported_features_for_backend(&backend_kind, target);
891
892 if !supported.contains_features(required_features) {
894 return false;
895 }
896
897 true
898 }
899}
900
901impl From<&BackendType> for wasmer::BackendKind {
902 fn from(backend_type: &BackendType) -> Self {
903 match backend_type {
904 #[cfg(feature = "singlepass")]
905 BackendType::Singlepass => wasmer::BackendKind::Singlepass,
906 #[cfg(feature = "cranelift")]
907 BackendType::Cranelift => wasmer::BackendKind::Cranelift,
908 #[cfg(feature = "llvm")]
909 BackendType::LLVM => wasmer::BackendKind::LLVM,
910 #[cfg(feature = "v8")]
911 BackendType::V8 => wasmer::BackendKind::V8,
912 #[cfg(feature = "wamr")]
913 BackendType::Wamr => wasmer::BackendKind::Wamr,
914 #[cfg(feature = "wasmi")]
915 BackendType::Wasmi => wasmer::BackendKind::Wasmi,
916 _ => {
917 #[cfg(feature = "sys")]
918 {
919 wasmer::BackendKind::Headless
920 }
921 #[cfg(not(feature = "sys"))]
922 {
923 unreachable!("No backend enabled!")
924 }
925 }
926 }
927 }
928}
929
930impl std::fmt::Display for BackendType {
931 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
932 write!(
933 f,
934 "{}",
935 match self {
936 Self::Singlepass => "singlepass",
937 Self::Cranelift => "cranelift",
938 Self::LLVM => "llvm",
939 Self::V8 => "v8",
940 Self::Wamr => "wamr",
941 Self::Wasmi => "wasmi",
942 Self::Headless => "headless",
943 }
944 )
945 }
946}