1use super::{AsyncConfig, CodegenSettings, InstanceAllocationStrategy, MemoryConfig, ModuleConfig};
4use crate::oracles::{StoreLimits, Timeout};
5use anyhow::Result;
6use arbitrary::{Arbitrary, Unstructured};
7use std::time::Duration;
8use wasmtime::{Enabled, Engine, Module, Store};
9use wasmtime_test_util::wast::{WastConfig, WastTest, limits};
10
11#[derive(Debug, Clone)]
18pub struct Config {
19 pub wasmtime: WasmtimeConfig,
21 pub module_config: ModuleConfig,
23}
24
25impl Config {
26 pub fn set_differential_config(&mut self) {
34 let config = &mut self.module_config.config;
35
36 config.min_types = config.min_types.max(1);
39 config.max_types = config.max_types.max(1);
40
41 config.min_funcs = config.min_funcs.max(1);
43 config.max_funcs = config.max_funcs.max(1);
44
45 config.max_memory32_bytes = 10 << 16;
49 config.max_memory64_bytes = 10 << 16;
50 config.memory_max_size_required = true;
51
52 config.max_table_elements = 1_000;
60 config.table_max_size_required = true;
61
62 config.max_imports = 0;
64
65 config.export_everything = true;
67
68 config.canonicalize_nans = true;
71
72 if let InstanceAllocationStrategy::Pooling(pooling) = &mut self.wasmtime.strategy {
74 pooling.total_memories = config.max_memories as u32;
76 pooling.max_memory_size = 10 << 16;
77 pooling.max_memories_per_module = config.max_memories as u32;
78 if pooling.memory_protection_keys == Enabled::Auto
79 && pooling.max_memory_protection_keys > 1
80 {
81 pooling.total_memories =
82 pooling.total_memories * (pooling.max_memory_protection_keys as u32);
83 }
84
85 pooling.total_tables = config.max_tables as u32;
86 pooling.table_elements = 1_000;
87 pooling.max_tables_per_module = config.max_tables as u32;
88
89 pooling.core_instance_size = 1_000_000;
90
91 let cfg = &mut self.wasmtime.memory_config;
92 match &mut cfg.memory_reservation {
93 Some(size) => *size = (*size).max(pooling.max_memory_size as u64),
94 other @ None => *other = Some(pooling.max_memory_size as u64),
95 }
96 }
97
98 config.relaxed_simd_enabled = false;
101 }
102
103 pub fn generate(
110 &self,
111 input: &mut Unstructured<'_>,
112 default_fuel: Option<u32>,
113 ) -> arbitrary::Result<wasm_smith::Module> {
114 self.module_config.generate(input, default_fuel)
115 }
116
117 pub fn make_wast_test_compliant(&mut self, test: &WastTest) -> WastConfig {
124 let wasmtime_test_util::wast::TestConfig {
125 memory64,
126 custom_page_sizes,
127 multi_memory,
128 threads,
129 shared_everything_threads,
130 gc,
131 function_references,
132 relaxed_simd,
133 reference_types,
134 tail_call,
135 extended_const,
136 wide_arithmetic,
137 component_model_async,
138 component_model_async_builtins,
139 component_model_async_stackful,
140 component_model_error_context,
141 component_model_gc,
142 simd,
143 exceptions,
144 legacy_exceptions: _,
145
146 hogs_memory: _,
147 nan_canonicalization: _,
148 gc_types: _,
149 stack_switching: _,
150 spec_test: _,
151 } = test.config;
152
153 self.module_config.function_references_enabled =
156 function_references.or(gc).unwrap_or(false);
157 self.module_config.component_model_async = component_model_async.unwrap_or(false);
158 self.module_config.component_model_async_builtins =
159 component_model_async_builtins.unwrap_or(false);
160 self.module_config.component_model_async_stackful =
161 component_model_async_stackful.unwrap_or(false);
162 self.module_config.component_model_error_context =
163 component_model_error_context.unwrap_or(false);
164 self.module_config.component_model_gc = component_model_gc.unwrap_or(false);
165
166 let config = &mut self.module_config.config;
169 config.bulk_memory_enabled = true;
170 config.multi_value_enabled = true;
171 config.wide_arithmetic_enabled = wide_arithmetic.unwrap_or(false);
172 config.memory64_enabled = memory64.unwrap_or(false);
173 config.relaxed_simd_enabled = relaxed_simd.unwrap_or(false);
174 config.simd_enabled = config.relaxed_simd_enabled || simd.unwrap_or(false);
175 config.tail_call_enabled = tail_call.unwrap_or(false);
176 config.custom_page_sizes_enabled = custom_page_sizes.unwrap_or(false);
177 config.threads_enabled = threads.unwrap_or(false);
178 config.shared_everything_threads_enabled = shared_everything_threads.unwrap_or(false);
179 config.gc_enabled = gc.unwrap_or(false);
180 config.reference_types_enabled = config.gc_enabled
181 || self.module_config.function_references_enabled
182 || reference_types.unwrap_or(false);
183 config.extended_const_enabled = extended_const.unwrap_or(false);
184 config.exceptions_enabled = exceptions.unwrap_or(false);
185 if multi_memory.unwrap_or(false) {
186 config.max_memories = limits::MEMORIES_PER_MODULE as usize;
187 } else {
188 config.max_memories = 1;
189 }
190
191 if let Some(n) = &mut self.wasmtime.memory_config.memory_reservation {
192 *n = (*n).max(limits::MEMORY_SIZE as u64);
193 }
194
195 if let InstanceAllocationStrategy::Pooling(pooling) = &mut self.wasmtime.strategy {
202 pooling.max_memory_protection_keys = pooling.max_memory_protection_keys.max(1).min(2);
206 pooling.total_memories = pooling
207 .total_memories
208 .max(limits::MEMORIES * (pooling.max_memory_protection_keys as u32));
209
210 pooling.total_component_instances = pooling
213 .total_component_instances
214 .max(limits::COMPONENT_INSTANCES);
215 pooling.total_tables = pooling.total_tables.max(limits::TABLES);
216 pooling.max_tables_per_module =
217 pooling.max_tables_per_module.max(limits::TABLES_PER_MODULE);
218 pooling.max_memories_per_module = pooling
219 .max_memories_per_module
220 .max(limits::MEMORIES_PER_MODULE);
221 pooling.max_memories_per_component = pooling
222 .max_memories_per_component
223 .max(limits::MEMORIES_PER_MODULE);
224 pooling.total_core_instances = pooling.total_core_instances.max(limits::CORE_INSTANCES);
225 pooling.max_memory_size = pooling.max_memory_size.max(limits::MEMORY_SIZE);
226 pooling.table_elements = pooling.table_elements.max(limits::TABLE_ELEMENTS);
227 pooling.core_instance_size = pooling.core_instance_size.max(limits::CORE_INSTANCE_SIZE);
228 pooling.component_instance_size = pooling
229 .component_instance_size
230 .max(limits::CORE_INSTANCE_SIZE);
231 pooling.total_stacks = pooling.total_stacks.max(limits::TOTAL_STACKS);
232 }
233
234 WastConfig {
238 collector: match self.wasmtime.collector {
239 Collector::Null => wasmtime_test_util::wast::Collector::Null,
240 Collector::DeferredReferenceCounting => {
241 wasmtime_test_util::wast::Collector::DeferredReferenceCounting
242 }
243 },
244 pooling: matches!(
245 self.wasmtime.strategy,
246 InstanceAllocationStrategy::Pooling(_)
247 ),
248 compiler: match self.wasmtime.compiler_strategy {
249 CompilerStrategy::CraneliftNative => {
250 wasmtime_test_util::wast::Compiler::CraneliftNative
251 }
252 CompilerStrategy::CraneliftPulley => {
253 wasmtime_test_util::wast::Compiler::CraneliftPulley
254 }
255 CompilerStrategy::Winch => wasmtime_test_util::wast::Compiler::Winch,
256 },
257 }
258 }
259
260 pub fn to_wasmtime(&self) -> wasmtime::Config {
262 crate::init_fuzzing();
263
264 let mut cfg = wasmtime_cli_flags::CommonOptions::default();
265 cfg.codegen.native_unwind_info =
266 Some(cfg!(target_os = "windows") || self.wasmtime.native_unwind_info);
267 cfg.codegen.parallel_compilation = Some(false);
268
269 cfg.debug.address_map = Some(self.wasmtime.generate_address_map);
270 cfg.opts.opt_level = Some(self.wasmtime.opt_level.to_wasmtime());
271 cfg.opts.regalloc_algorithm = Some(self.wasmtime.regalloc_algorithm.to_wasmtime());
272 cfg.opts.signals_based_traps = Some(self.wasmtime.signals_based_traps);
273 cfg.opts.memory_guaranteed_dense_image_size = Some(std::cmp::min(
274 16 << 20,
277 self.wasmtime.memory_guaranteed_dense_image_size,
278 ));
279 cfg.wasm.async_stack_zeroing = Some(self.wasmtime.async_stack_zeroing);
280 cfg.wasm.bulk_memory = Some(true);
281 cfg.wasm.component_model_async = Some(self.module_config.component_model_async);
282 cfg.wasm.component_model_async_builtins =
283 Some(self.module_config.component_model_async_builtins);
284 cfg.wasm.component_model_async_stackful =
285 Some(self.module_config.component_model_async_stackful);
286 cfg.wasm.component_model_error_context =
287 Some(self.module_config.component_model_error_context);
288 cfg.wasm.component_model_gc = Some(self.module_config.component_model_gc);
289 cfg.wasm.custom_page_sizes = Some(self.module_config.config.custom_page_sizes_enabled);
290 cfg.wasm.epoch_interruption = Some(self.wasmtime.epoch_interruption);
291 cfg.wasm.extended_const = Some(self.module_config.config.extended_const_enabled);
292 cfg.wasm.fuel = self.wasmtime.consume_fuel.then(|| u64::MAX);
293 cfg.wasm.function_references = Some(self.module_config.function_references_enabled);
294 cfg.wasm.gc = Some(self.module_config.config.gc_enabled);
295 cfg.wasm.memory64 = Some(self.module_config.config.memory64_enabled);
296 cfg.wasm.multi_memory = Some(self.module_config.config.max_memories > 1);
297 cfg.wasm.multi_value = Some(self.module_config.config.multi_value_enabled);
298 cfg.wasm.nan_canonicalization = Some(self.wasmtime.canonicalize_nans);
299 cfg.wasm.reference_types = Some(self.module_config.config.reference_types_enabled);
300 cfg.wasm.simd = Some(self.module_config.config.simd_enabled);
301 cfg.wasm.tail_call = Some(self.module_config.config.tail_call_enabled);
302 cfg.wasm.threads = Some(self.module_config.config.threads_enabled);
303 cfg.wasm.shared_everything_threads =
304 Some(self.module_config.config.shared_everything_threads_enabled);
305 cfg.wasm.wide_arithmetic = Some(self.module_config.config.wide_arithmetic_enabled);
306 cfg.wasm.exceptions = Some(self.module_config.config.exceptions_enabled);
307 if !self.module_config.config.simd_enabled {
308 cfg.wasm.relaxed_simd = Some(false);
309 }
310 cfg.codegen.collector = Some(self.wasmtime.collector.to_wasmtime());
311
312 let compiler_strategy = &self.wasmtime.compiler_strategy;
313 let cranelift_strategy = match compiler_strategy {
314 CompilerStrategy::CraneliftNative | CompilerStrategy::CraneliftPulley => true,
315 CompilerStrategy::Winch => false,
316 };
317 self.wasmtime.compiler_strategy.configure(&mut cfg);
318
319 self.wasmtime.codegen.configure(&mut cfg);
320
321 let pcc = cfg!(feature = "fuzz-pcc")
325 && self.wasmtime.pcc
326 && !self.module_config.config.memory64_enabled;
327
328 cfg.codegen.inlining = self.wasmtime.inlining;
329
330 if cranelift_strategy {
333 if let Some(option) = self.wasmtime.inlining_intra_module {
334 cfg.codegen.cranelift.push((
335 "wasmtime_inlining_intra_module".to_string(),
336 Some(option.to_string()),
337 ));
338 }
339 if let Some(size) = self.wasmtime.inlining_small_callee_size {
340 cfg.codegen.cranelift.push((
341 "wasmtime_inlining_small_callee_size".to_string(),
342 Some(std::cmp::min(1000, size).to_string()),
344 ));
345 }
346 if let Some(size) = self.wasmtime.inlining_sum_size_threshold {
347 cfg.codegen.cranelift.push((
348 "wasmtime_inlining_sum_size_threshold".to_string(),
349 Some(std::cmp::min(1000, size).to_string()),
351 ));
352 }
353
354 cfg.wasm.nan_canonicalization = Some(!self.module_config.config.canonicalize_nans);
358
359 if self.module_config.config.max_funcs > 10 {
365 cfg.codegen.cranelift_debug_verifier = Some(false);
366 }
367
368 if self.wasmtime.force_jump_veneers {
369 cfg.codegen.cranelift.push((
370 "wasmtime_linkopt_force_jump_veneer".to_string(),
371 Some("true".to_string()),
372 ));
373 }
374
375 if let Some(pad) = self.wasmtime.padding_between_functions {
376 cfg.codegen.cranelift.push((
377 "wasmtime_linkopt_padding_between_functions".to_string(),
378 Some(pad.to_string()),
379 ));
380 }
381
382 cfg.codegen.pcc = Some(pcc);
383
384 cfg.opts.table_lazy_init = Some(self.wasmtime.table_lazy_init);
386 }
387
388 self.wasmtime.strategy.configure(&mut cfg);
389
390 if !self.module_config.config.threads_enabled {
401 let memory_config = if pcc {
404 MemoryConfig {
405 memory_reservation: Some(4 << 30), memory_guard_size: Some(2 << 30), memory_reservation_for_growth: Some(0),
408 guard_before_linear_memory: false,
409 memory_init_cow: true,
410 cranelift_enable_heap_access_spectre_mitigations: None,
412 }
413 } else {
414 self.wasmtime.memory_config.clone()
415 };
416
417 memory_config.configure(&mut cfg);
418 };
419
420 if ((cfg.opts.signals_based_traps == Some(true) && cfg.opts.memory_guard_size == Some(0))
427 || self.wasmtime.compiler_strategy == CompilerStrategy::CraneliftPulley)
428 && cfg.opts.memory_reservation == Some(0)
429 && cfg.opts.memory_init_cow == Some(false)
430 {
431 let growth = &mut cfg.opts.memory_reservation_for_growth;
432 let max = 1 << 20;
433 *growth = match *growth {
434 Some(n) => Some(n.min(max)),
435 None => Some(max),
436 };
437 }
438
439 log::debug!("creating wasmtime config with CLI options:\n{cfg}");
440 let mut cfg = cfg.config(None).expect("failed to create wasmtime::Config");
441
442 if self.wasmtime.async_config != AsyncConfig::Disabled {
443 log::debug!("async config in use {:?}", self.wasmtime.async_config);
444 self.wasmtime.async_config.configure(&mut cfg);
445 }
446
447 return cfg;
448 }
449
450 pub fn to_store(&self) -> Store<StoreLimits> {
453 let engine = Engine::new(&self.to_wasmtime()).unwrap();
454 let mut store = Store::new(&engine, StoreLimits::new());
455 self.configure_store(&mut store);
456 store
457 }
458
459 pub fn configure_store(&self, store: &mut Store<StoreLimits>) {
461 store.limiter(|s| s as &mut dyn wasmtime::ResourceLimiter);
462 self.configure_store_epoch_and_fuel(store);
463 }
464
465 pub fn configure_store_epoch_and_fuel<T>(&self, store: &mut Store<T>) {
468 if self.wasmtime.consume_fuel {
475 store.set_fuel(u64::MAX).unwrap();
476 }
477 if self.wasmtime.epoch_interruption {
478 store.epoch_deadline_trap();
479 store.set_epoch_deadline(1);
480 }
481 match self.wasmtime.async_config {
482 AsyncConfig::Disabled => {}
483 AsyncConfig::YieldWithFuel(amt) => {
484 assert!(self.wasmtime.consume_fuel);
485 store.fuel_async_yield_interval(Some(amt)).unwrap();
486 }
487 AsyncConfig::YieldWithEpochs { ticks, .. } => {
488 assert!(self.wasmtime.epoch_interruption);
489 store.set_epoch_deadline(ticks);
490 store.epoch_deadline_async_yield_and_update(ticks);
491 }
492 }
493 }
494
495 pub fn generate_timeout(&mut self, u: &mut Unstructured<'_>) -> arbitrary::Result<Timeout> {
498 let time_duration = Duration::from_millis(100);
499 let timeout = u
500 .choose(&[Timeout::Fuel(100_000), Timeout::Epoch(time_duration)])?
501 .clone();
502 match &timeout {
503 Timeout::Fuel(..) => {
504 self.wasmtime.consume_fuel = true;
505 }
506 Timeout::Epoch(..) => {
507 self.wasmtime.epoch_interruption = true;
508 }
509 Timeout::None => unreachable!("Not an option given to choose()"),
510 }
511 Ok(timeout)
512 }
513
514 pub fn compile(&self, engine: &Engine, wasm: &[u8]) -> Result<Module> {
519 let module = Module::new(engine, wasm)?;
522 if !self.wasmtime.use_precompiled_cwasm {
523 return Ok(module);
524 }
525
526 let dir = tempfile::TempDir::new().unwrap();
530 let file = dir.path().join("module.wasm");
531 std::fs::write(&file, module.serialize().unwrap()).unwrap();
532 unsafe { Ok(Module::deserialize_file(engine, &file).unwrap()) }
533 }
534
535 pub fn enable_async(&mut self, u: &mut Unstructured<'_>) -> arbitrary::Result<()> {
538 if self.wasmtime.consume_fuel || u.arbitrary()? {
539 self.wasmtime.async_config =
540 AsyncConfig::YieldWithFuel(u.int_in_range(1000..=100_000)?);
541 self.wasmtime.consume_fuel = true;
542 } else {
543 self.wasmtime.async_config = AsyncConfig::YieldWithEpochs {
544 dur: Duration::from_millis(u.int_in_range(1..=10)?),
545 ticks: u.int_in_range(1..=10)?,
546 };
547 self.wasmtime.epoch_interruption = true;
548 }
549 Ok(())
550 }
551}
552
553impl<'a> Arbitrary<'a> for Config {
554 fn arbitrary(u: &mut Unstructured<'a>) -> arbitrary::Result<Self> {
555 let mut config = Self {
556 wasmtime: u.arbitrary()?,
557 module_config: u.arbitrary()?,
558 };
559
560 config
561 .wasmtime
562 .update_module_config(&mut config.module_config, u)?;
563
564 Ok(config)
565 }
566}
567
568#[derive(Arbitrary, Clone, Debug, Eq, Hash, PartialEq)]
571pub struct WasmtimeConfig {
572 opt_level: OptLevel,
573 regalloc_algorithm: RegallocAlgorithm,
574 debug_info: bool,
575 canonicalize_nans: bool,
576 interruptable: bool,
577 pub(crate) consume_fuel: bool,
578 pub(crate) epoch_interruption: bool,
579 pub memory_config: MemoryConfig,
581 force_jump_veneers: bool,
582 memory_init_cow: bool,
583 memory_guaranteed_dense_image_size: u64,
584 inlining: Option<bool>,
585 inlining_intra_module: Option<IntraModuleInlining>,
586 inlining_small_callee_size: Option<u32>,
587 inlining_sum_size_threshold: Option<u32>,
588 use_precompiled_cwasm: bool,
589 async_stack_zeroing: bool,
590 pub strategy: InstanceAllocationStrategy,
592 codegen: CodegenSettings,
593 padding_between_functions: Option<u16>,
594 generate_address_map: bool,
595 native_unwind_info: bool,
596 pub compiler_strategy: CompilerStrategy,
598 collector: Collector,
599 table_lazy_init: bool,
600
601 pcc: bool,
603
604 pub async_config: AsyncConfig,
607
608 signals_based_traps: bool,
611}
612
613impl WasmtimeConfig {
614 pub fn make_compatible_with(&mut self, other: &Self) {
618 self.strategy = other.strategy.clone();
630 if let InstanceAllocationStrategy::Pooling { .. } = &other.strategy {
631 self.memory_config = other.memory_config.clone();
634 }
635
636 self.make_internally_consistent();
637 }
638
639 pub fn update_module_config(
642 &mut self,
643 config: &mut ModuleConfig,
644 _u: &mut Unstructured<'_>,
645 ) -> arbitrary::Result<()> {
646 match self.compiler_strategy {
647 CompilerStrategy::CraneliftNative => {}
648
649 CompilerStrategy::Winch => {
650 if cfg!(not(target_arch = "x86_64")) {
656 log::warn!(
657 "want to compile with Winch but host architecture does not support it"
658 );
659 return Err(arbitrary::Error::IncorrectFormat);
660 }
661
662 config.config.relaxed_simd_enabled = false;
667 config.config.gc_enabled = false;
668 config.config.tail_call_enabled = false;
669 config.config.reference_types_enabled = false;
670 config.config.exceptions_enabled = false;
671 config.function_references_enabled = false;
672
673 if self
675 .codegen_flag("has_avx")
676 .is_some_and(|value| value == "false")
677 || self
678 .codegen_flag("has_avx2")
679 .is_some_and(|value| value == "false")
680 {
681 config.config.simd_enabled = false;
682 }
683
684 self.signals_based_traps = true;
687 self.table_lazy_init = true;
688 self.debug_info = false;
689 }
690
691 CompilerStrategy::CraneliftPulley => {
692 config.config.threads_enabled = false;
693 }
694 }
695
696 if let InstanceAllocationStrategy::Pooling(pooling) = &mut self.strategy {
699 config.config.threads_enabled = false;
703
704 let min_bytes = config
707 .config
708 .max_memory32_bytes
709 .min(
712 config
713 .config
714 .max_memory64_bytes
715 .try_into()
716 .unwrap_or(u64::MAX),
717 );
718 let min = min_bytes
719 .min(pooling.max_memory_size as u64)
720 .min(self.memory_config.memory_reservation.unwrap_or(0));
721 pooling.max_memory_size = min as usize;
722 config.config.max_memory32_bytes = min;
723 config.config.max_memory64_bytes = min as u128;
724
725 if config.config.disallow_traps {
729 if pooling.max_memory_size < (1 << 16) {
730 pooling.max_memory_size = 1 << 16;
731 config.config.max_memory32_bytes = 1 << 16;
732 config.config.max_memory64_bytes = 1 << 16;
733 let cfg = &mut self.memory_config;
734 match &mut cfg.memory_reservation {
735 Some(size) => *size = (*size).max(pooling.max_memory_size as u64),
736 size @ None => *size = Some(pooling.max_memory_size as u64),
737 }
738 }
739 if pooling.table_elements == 0 {
741 pooling.table_elements = 1;
742 }
743 }
744
745 config.config.min_memories = config.config.min_memories.min(10);
748 config.config.max_memories = config.config.max_memories.min(10);
749
750 pooling.total_memories = config.config.max_memories as u32;
753 pooling.total_tables = config.config.max_tables as u32;
754 }
755
756 if !self.signals_based_traps {
757 config.config.threads_enabled = false;
764
765 self.memory_config
768 .cranelift_enable_heap_access_spectre_mitigations = None;
769 }
770
771 self.make_internally_consistent();
772
773 Ok(())
774 }
775
776 pub(crate) fn codegen_flag(&self, name: &str) -> Option<&str> {
778 self.codegen.flags().iter().find_map(|(n, value)| {
779 if n == name {
780 Some(value.as_str())
781 } else {
782 None
783 }
784 })
785 }
786
787 fn make_internally_consistent(&mut self) {
796 if !self.signals_based_traps {
797 let cfg = &mut self.memory_config;
798 cfg.cranelift_enable_heap_access_spectre_mitigations = None;
802
803 if !cfg.memory_init_cow
807 && cfg.memory_guard_size == Some(0)
808 && cfg.memory_reservation == Some(0)
809 {
810 let min = 10 << 20; if let Some(val) = &mut cfg.memory_reservation_for_growth {
812 *val = (*val).min(min);
813 } else {
814 cfg.memory_reservation_for_growth = Some(min);
815 }
816 }
817 }
818 }
819}
820
821#[derive(Arbitrary, Clone, Debug, PartialEq, Eq, Hash)]
822enum OptLevel {
823 None,
824 Speed,
825 SpeedAndSize,
826}
827
828impl OptLevel {
829 fn to_wasmtime(&self) -> wasmtime::OptLevel {
830 match self {
831 OptLevel::None => wasmtime::OptLevel::None,
832 OptLevel::Speed => wasmtime::OptLevel::Speed,
833 OptLevel::SpeedAndSize => wasmtime::OptLevel::SpeedAndSize,
834 }
835 }
836}
837
838#[derive(Arbitrary, Clone, Debug, PartialEq, Eq, Hash)]
839enum RegallocAlgorithm {
840 Backtracking,
841 TemporarilyDisabledSinglePass,
844}
845
846impl RegallocAlgorithm {
847 fn to_wasmtime(&self) -> wasmtime::RegallocAlgorithm {
848 match self {
849 RegallocAlgorithm::Backtracking => wasmtime::RegallocAlgorithm::Backtracking,
850 RegallocAlgorithm::TemporarilyDisabledSinglePass => {
851 wasmtime::RegallocAlgorithm::Backtracking
852 }
853 }
854 }
855}
856
857#[derive(Arbitrary, Clone, Copy, Debug, PartialEq, Eq, Hash)]
858enum IntraModuleInlining {
859 Yes,
860 No,
861 WhenUsingGc,
862}
863
864impl std::fmt::Display for IntraModuleInlining {
865 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
866 match self {
867 IntraModuleInlining::Yes => write!(f, "yes"),
868 IntraModuleInlining::No => write!(f, "no"),
869 IntraModuleInlining::WhenUsingGc => write!(f, "gc"),
870 }
871 }
872}
873
874#[derive(Clone, Debug, PartialEq, Eq, Hash)]
875pub enum CompilerStrategy {
877 CraneliftNative,
879 Winch,
881 CraneliftPulley,
883}
884
885impl CompilerStrategy {
886 pub fn configure(&self, config: &mut wasmtime_cli_flags::CommonOptions) {
888 match self {
889 CompilerStrategy::CraneliftNative => {
890 config.codegen.compiler = Some(wasmtime::Strategy::Cranelift);
891 }
892 CompilerStrategy::Winch => {
893 config.codegen.compiler = Some(wasmtime::Strategy::Winch);
894 }
895 CompilerStrategy::CraneliftPulley => {
896 config.codegen.compiler = Some(wasmtime::Strategy::Cranelift);
897 config.target = Some("pulley64".to_string());
898 }
899 }
900 }
901}
902
903impl Arbitrary<'_> for CompilerStrategy {
904 fn arbitrary(u: &mut Unstructured<'_>) -> arbitrary::Result<Self> {
905 match u.int_in_range(0..=19)? {
908 1 => Ok(Self::CraneliftPulley),
909 2 => Ok(Self::Winch),
910 _ => Ok(Self::CraneliftNative),
911 }
912 }
913}
914
915#[derive(Arbitrary, Clone, Debug, PartialEq, Eq, Hash)]
916pub enum Collector {
917 DeferredReferenceCounting,
918 Null,
919}
920
921impl Collector {
922 fn to_wasmtime(&self) -> wasmtime::Collector {
923 match self {
924 Collector::DeferredReferenceCounting => wasmtime::Collector::DeferredReferenceCounting,
925 Collector::Null => wasmtime::Collector::Null,
926 }
927 }
928}