1use super::{
4 AsyncConfig, CodegenSettings, InstanceAllocationStrategy, MemoryConfig, ModuleConfig,
5 NormalMemoryConfig, UnalignedMemoryCreator,
6};
7use crate::oracles::{StoreLimits, Timeout};
8use anyhow::Result;
9use arbitrary::{Arbitrary, Unstructured};
10use std::sync::Arc;
11use std::time::Duration;
12use wasmtime::{Engine, Module, MpkEnabled, Store};
13use wasmtime_wast_util::{limits, WastConfig, WastTest};
14
15#[derive(Debug, Clone)]
22pub struct Config {
23 pub wasmtime: WasmtimeConfig,
25 pub module_config: ModuleConfig,
27}
28
29impl Config {
30 pub fn set_differential_config(&mut self) {
38 let config = &mut self.module_config.config;
39
40 config.min_types = config.min_types.max(1);
43 config.max_types = config.max_types.max(1);
44
45 config.min_funcs = config.min_funcs.max(1);
47 config.max_funcs = config.max_funcs.max(1);
48
49 config.max_memory32_bytes = 10 << 16;
53 config.max_memory64_bytes = 10 << 16;
54 config.memory_max_size_required = true;
55
56 config.max_table_elements = 1_000;
64 config.table_max_size_required = true;
65
66 config.max_imports = 0;
68
69 config.export_everything = true;
71
72 config.canonicalize_nans = true;
75
76 if let InstanceAllocationStrategy::Pooling(pooling) = &mut self.wasmtime.strategy {
78 pooling.total_memories = config.max_memories as u32;
80 pooling.max_memory_size = 10 << 16;
81 pooling.max_memories_per_module = config.max_memories as u32;
82 if pooling.memory_protection_keys == MpkEnabled::Auto
83 && pooling.max_memory_protection_keys > 1
84 {
85 pooling.total_memories =
86 pooling.total_memories * (pooling.max_memory_protection_keys as u32);
87 }
88
89 pooling.total_tables = config.max_tables as u32;
90 pooling.table_elements = 1_000;
91 pooling.max_tables_per_module = config.max_tables as u32;
92
93 pooling.core_instance_size = 1_000_000;
94
95 if let MemoryConfig::Normal(cfg) = &mut self.wasmtime.memory_config {
96 match &mut cfg.memory_reservation {
97 Some(size) => *size = (*size).max(pooling.max_memory_size as u64),
98 other @ None => *other = Some(pooling.max_memory_size as u64),
99 }
100 }
101 }
102
103 config.relaxed_simd_enabled = false;
106 }
107
108 pub fn generate(
115 &self,
116 input: &mut Unstructured<'_>,
117 default_fuel: Option<u32>,
118 ) -> arbitrary::Result<wasm_smith::Module> {
119 self.module_config.generate(input, default_fuel)
120 }
121
122 pub fn make_wast_test_compliant(&mut self, test: &WastTest) -> WastConfig {
129 let wasmtime_wast_util::TestConfig {
130 memory64,
131 custom_page_sizes,
132 multi_memory,
133 threads,
134 gc,
135 function_references,
136 relaxed_simd,
137 reference_types,
138 tail_call,
139 extended_const,
140 wide_arithmetic,
141 component_model_async,
142 simd,
143
144 hogs_memory: _,
145 nan_canonicalization: _,
146 gc_types: _,
147 } = test.config;
148
149 self.module_config.function_references_enabled =
152 function_references.or(gc).unwrap_or(false);
153 self.module_config.component_model_async = component_model_async.unwrap_or(false);
154
155 let config = &mut self.module_config.config;
158 config.bulk_memory_enabled = true;
159 config.multi_value_enabled = true;
160 config.wide_arithmetic_enabled = wide_arithmetic.unwrap_or(false);
161 config.memory64_enabled = memory64.unwrap_or(false);
162 config.relaxed_simd_enabled = relaxed_simd.unwrap_or(false);
163 config.simd_enabled = config.relaxed_simd_enabled || simd.unwrap_or(false);
164 config.tail_call_enabled = tail_call.unwrap_or(false);
165 config.custom_page_sizes_enabled = custom_page_sizes.unwrap_or(false);
166 config.threads_enabled = threads.unwrap_or(false);
167 config.gc_enabled = gc.unwrap_or(false);
168 config.reference_types_enabled = config.gc_enabled
169 || self.module_config.function_references_enabled
170 || reference_types.unwrap_or(false);
171 config.extended_const_enabled = extended_const.unwrap_or(false);
172 if multi_memory.unwrap_or(false) {
173 config.max_memories = limits::MEMORIES_PER_MODULE as usize;
174 } else {
175 config.max_memories = 1;
176 }
177
178 match &mut self.wasmtime.memory_config {
179 MemoryConfig::Normal(config) => {
180 if let Some(n) = &mut config.memory_reservation {
181 *n = (*n).max(limits::MEMORY_SIZE as u64);
182 }
183 }
184 MemoryConfig::CustomUnaligned => {}
185 }
186
187 if let InstanceAllocationStrategy::Pooling(pooling) = &mut self.wasmtime.strategy {
194 pooling.max_memory_protection_keys = pooling.max_memory_protection_keys.max(1).min(2);
198 pooling.total_memories = pooling
199 .total_memories
200 .max(limits::MEMORIES * (pooling.max_memory_protection_keys as u32));
201
202 pooling.total_component_instances = pooling
205 .total_component_instances
206 .max(limits::COMPONENT_INSTANCES);
207 pooling.total_tables = pooling.total_tables.max(limits::TABLES);
208 pooling.max_tables_per_module =
209 pooling.max_tables_per_module.max(limits::TABLES_PER_MODULE);
210 pooling.max_memories_per_module = pooling
211 .max_memories_per_module
212 .max(limits::MEMORIES_PER_MODULE);
213 pooling.max_memories_per_component = pooling
214 .max_memories_per_component
215 .max(limits::MEMORIES_PER_MODULE);
216 pooling.total_core_instances = pooling.total_core_instances.max(limits::CORE_INSTANCES);
217 pooling.max_memory_size = pooling.max_memory_size.max(limits::MEMORY_SIZE);
218 pooling.table_elements = pooling.table_elements.max(limits::TABLE_ELEMENTS);
219 pooling.core_instance_size = pooling.core_instance_size.max(limits::CORE_INSTANCE_SIZE);
220 pooling.component_instance_size = pooling
221 .component_instance_size
222 .max(limits::CORE_INSTANCE_SIZE);
223 }
224
225 WastConfig {
229 collector: match self.wasmtime.collector {
230 Collector::Null => wasmtime_wast_util::Collector::Null,
231 Collector::DeferredReferenceCounting => {
232 wasmtime_wast_util::Collector::DeferredReferenceCounting
233 }
234 },
235 pooling: matches!(
236 self.wasmtime.strategy,
237 InstanceAllocationStrategy::Pooling(_)
238 ),
239 compiler: match self.wasmtime.compiler_strategy {
240 CompilerStrategy::CraneliftNative => wasmtime_wast_util::Compiler::CraneliftNative,
241 CompilerStrategy::CraneliftPulley => wasmtime_wast_util::Compiler::CraneliftPulley,
242 CompilerStrategy::Winch => wasmtime_wast_util::Compiler::Winch,
243 },
244 }
245 }
246
247 pub fn to_wasmtime(&self) -> wasmtime::Config {
249 crate::init_fuzzing();
250
251 let mut cfg = wasmtime_cli_flags::CommonOptions::default();
252 cfg.codegen.native_unwind_info =
253 Some(cfg!(target_os = "windows") || self.wasmtime.native_unwind_info);
254 cfg.codegen.parallel_compilation = Some(false);
255 cfg.debug.address_map = Some(self.wasmtime.generate_address_map);
256 cfg.opts.opt_level = Some(self.wasmtime.opt_level.to_wasmtime());
257 cfg.opts.regalloc_algorithm = Some(self.wasmtime.regalloc_algorithm.to_wasmtime());
258 cfg.opts.signals_based_traps = Some(self.wasmtime.signals_based_traps);
259 cfg.opts.memory_guaranteed_dense_image_size = Some(std::cmp::min(
260 16 << 20,
263 self.wasmtime.memory_guaranteed_dense_image_size,
264 ));
265 cfg.wasm.async_stack_zeroing = Some(self.wasmtime.async_stack_zeroing);
266 cfg.wasm.bulk_memory = Some(true);
267 cfg.wasm.component_model_async = Some(self.module_config.component_model_async);
268 cfg.wasm.custom_page_sizes = Some(self.module_config.config.custom_page_sizes_enabled);
269 cfg.wasm.epoch_interruption = Some(self.wasmtime.epoch_interruption);
270 cfg.wasm.extended_const = Some(self.module_config.config.extended_const_enabled);
271 cfg.wasm.fuel = self.wasmtime.consume_fuel.then(|| u64::MAX);
272 cfg.wasm.function_references = Some(self.module_config.function_references_enabled);
273 cfg.wasm.gc = Some(self.module_config.config.gc_enabled);
274 cfg.wasm.memory64 = Some(self.module_config.config.memory64_enabled);
275 cfg.wasm.multi_memory = Some(self.module_config.config.max_memories > 1);
276 cfg.wasm.multi_value = Some(self.module_config.config.multi_value_enabled);
277 cfg.wasm.nan_canonicalization = Some(self.wasmtime.canonicalize_nans);
278 cfg.wasm.reference_types = Some(self.module_config.config.reference_types_enabled);
279 cfg.wasm.simd = Some(self.module_config.config.simd_enabled);
280 cfg.wasm.tail_call = Some(self.module_config.config.tail_call_enabled);
281 cfg.wasm.threads = Some(self.module_config.config.threads_enabled);
282 cfg.wasm.wide_arithmetic = Some(self.module_config.config.wide_arithmetic_enabled);
283 if !self.module_config.config.simd_enabled {
284 cfg.wasm.relaxed_simd = Some(false);
285 }
286 cfg.codegen.collector = Some(self.wasmtime.collector.to_wasmtime());
287
288 let compiler_strategy = &self.wasmtime.compiler_strategy;
289 let cranelift_strategy = match compiler_strategy {
290 CompilerStrategy::CraneliftNative | CompilerStrategy::CraneliftPulley => true,
291 CompilerStrategy::Winch => false,
292 };
293 self.wasmtime.compiler_strategy.configure(&mut cfg);
294
295 self.wasmtime.codegen.configure(&mut cfg);
296
297 let pcc = cfg!(feature = "fuzz-pcc")
301 && self.wasmtime.pcc
302 && !self.module_config.config.memory64_enabled;
303
304 if cranelift_strategy {
307 cfg.wasm.nan_canonicalization = Some(!self.module_config.config.canonicalize_nans);
311
312 if self.module_config.config.max_funcs > 10 {
318 cfg.codegen.cranelift_debug_verifier = Some(false);
319 }
320
321 if self.wasmtime.force_jump_veneers {
322 cfg.codegen.cranelift.push((
323 "wasmtime_linkopt_force_jump_veneer".to_string(),
324 Some("true".to_string()),
325 ));
326 }
327
328 if let Some(pad) = self.wasmtime.padding_between_functions {
329 cfg.codegen.cranelift.push((
330 "wasmtime_linkopt_padding_between_functions".to_string(),
331 Some(pad.to_string()),
332 ));
333 }
334
335 cfg.codegen.pcc = Some(pcc);
336
337 cfg.opts.table_lazy_init = Some(self.wasmtime.table_lazy_init);
339 }
340
341 self.wasmtime.strategy.configure(&mut cfg);
342
343 let host_memory = if !self.module_config.config.threads_enabled {
354 let memory_config = if pcc {
357 MemoryConfig::Normal(NormalMemoryConfig {
358 memory_reservation: Some(4 << 30), memory_guard_size: Some(2 << 30), memory_reservation_for_growth: Some(0),
361 guard_before_linear_memory: false,
362 memory_init_cow: true,
363 cranelift_enable_heap_access_spectre_mitigations: None,
365 })
366 } else {
367 self.wasmtime.memory_config.clone()
368 };
369
370 match &memory_config {
371 MemoryConfig::Normal(memory_config) => {
372 memory_config.configure(&mut cfg);
373 None
374 }
375 MemoryConfig::CustomUnaligned => {
376 cfg.opts.memory_reservation = Some(0);
377 cfg.opts.memory_guard_size = Some(0);
378 cfg.opts.memory_reservation_for_growth = Some(0);
379 cfg.opts.guard_before_linear_memory = Some(false);
380 cfg.opts.memory_init_cow = Some(false);
381 log::debug!("a custom unaligned host memory will be in use");
382 Some(Arc::new(UnalignedMemoryCreator))
383 }
384 }
385 } else {
386 None
387 };
388
389 if ((cfg.opts.signals_based_traps == Some(true) && cfg.opts.memory_guard_size == Some(0))
396 || self.wasmtime.compiler_strategy == CompilerStrategy::CraneliftPulley)
397 && cfg.opts.memory_reservation == Some(0)
398 && cfg.opts.memory_init_cow == Some(false)
399 {
400 let growth = &mut cfg.opts.memory_reservation_for_growth;
401 let max = 1 << 20;
402 *growth = match *growth {
403 Some(n) => Some(n.min(max)),
404 None => Some(max),
405 };
406 }
407
408 log::debug!("creating wasmtime config with CLI options:\n{cfg}");
409 let mut cfg = cfg.config(None).expect("failed to create wasmtime::Config");
410
411 if let Some(host_memory) = host_memory {
412 cfg.with_host_memory(host_memory);
413 }
414
415 if self.wasmtime.async_config != AsyncConfig::Disabled {
416 log::debug!("async config in use {:?}", self.wasmtime.async_config);
417 self.wasmtime.async_config.configure(&mut cfg);
418 }
419
420 return cfg;
421 }
422
423 pub fn to_store(&self) -> Store<StoreLimits> {
426 let engine = Engine::new(&self.to_wasmtime()).unwrap();
427 let mut store = Store::new(&engine, StoreLimits::new());
428 self.configure_store(&mut store);
429 store
430 }
431
432 pub fn configure_store(&self, store: &mut Store<StoreLimits>) {
434 store.limiter(|s| s as &mut dyn wasmtime::ResourceLimiter);
435
436 if self.wasmtime.consume_fuel {
443 store.set_fuel(u64::MAX).unwrap();
444 }
445 if self.wasmtime.epoch_interruption {
446 store.epoch_deadline_trap();
447 store.set_epoch_deadline(1);
448 }
449 match self.wasmtime.async_config {
450 AsyncConfig::Disabled => {}
451 AsyncConfig::YieldWithFuel(amt) => {
452 assert!(self.wasmtime.consume_fuel);
453 store.fuel_async_yield_interval(Some(amt)).unwrap();
454 }
455 AsyncConfig::YieldWithEpochs { ticks, .. } => {
456 assert!(self.wasmtime.epoch_interruption);
457 store.set_epoch_deadline(ticks);
458 store.epoch_deadline_async_yield_and_update(ticks);
459 }
460 }
461 }
462
463 pub fn generate_timeout(&mut self, u: &mut Unstructured<'_>) -> arbitrary::Result<Timeout> {
466 let time_duration = Duration::from_millis(100);
467 let timeout = u
468 .choose(&[Timeout::Fuel(100_000), Timeout::Epoch(time_duration)])?
469 .clone();
470 match &timeout {
471 Timeout::Fuel(..) => {
472 self.wasmtime.consume_fuel = true;
473 }
474 Timeout::Epoch(..) => {
475 self.wasmtime.epoch_interruption = true;
476 }
477 Timeout::None => unreachable!("Not an option given to choose()"),
478 }
479 Ok(timeout)
480 }
481
482 pub fn compile(&self, engine: &Engine, wasm: &[u8]) -> Result<Module> {
487 let module = Module::new(engine, wasm)?;
490 if !self.wasmtime.use_precompiled_cwasm {
491 return Ok(module);
492 }
493
494 let dir = tempfile::TempDir::new().unwrap();
498 let file = dir.path().join("module.wasm");
499 std::fs::write(&file, module.serialize().unwrap()).unwrap();
500 unsafe { Ok(Module::deserialize_file(engine, &file).unwrap()) }
501 }
502
503 pub fn enable_async(&mut self, u: &mut Unstructured<'_>) -> arbitrary::Result<()> {
506 if self.wasmtime.consume_fuel || u.arbitrary()? {
507 self.wasmtime.async_config =
508 AsyncConfig::YieldWithFuel(u.int_in_range(1000..=100_000)?);
509 self.wasmtime.consume_fuel = true;
510 } else {
511 self.wasmtime.async_config = AsyncConfig::YieldWithEpochs {
512 dur: Duration::from_millis(u.int_in_range(1..=10)?),
513 ticks: u.int_in_range(1..=10)?,
514 };
515 self.wasmtime.epoch_interruption = true;
516 }
517 Ok(())
518 }
519}
520
521impl<'a> Arbitrary<'a> for Config {
522 fn arbitrary(u: &mut Unstructured<'a>) -> arbitrary::Result<Self> {
523 let mut config = Self {
524 wasmtime: u.arbitrary()?,
525 module_config: u.arbitrary()?,
526 };
527
528 config
529 .wasmtime
530 .update_module_config(&mut config.module_config, u)?;
531
532 Ok(config)
533 }
534}
535
536#[derive(Arbitrary, Clone, Debug, Eq, Hash, PartialEq)]
539pub struct WasmtimeConfig {
540 opt_level: OptLevel,
541 regalloc_algorithm: RegallocAlgorithm,
542 debug_info: bool,
543 canonicalize_nans: bool,
544 interruptable: bool,
545 pub(crate) consume_fuel: bool,
546 pub(crate) epoch_interruption: bool,
547 pub memory_config: MemoryConfig,
549 force_jump_veneers: bool,
550 memory_init_cow: bool,
551 memory_guaranteed_dense_image_size: u64,
552 use_precompiled_cwasm: bool,
553 async_stack_zeroing: bool,
554 pub strategy: InstanceAllocationStrategy,
556 codegen: CodegenSettings,
557 padding_between_functions: Option<u16>,
558 generate_address_map: bool,
559 native_unwind_info: bool,
560 pub compiler_strategy: CompilerStrategy,
562 collector: Collector,
563 table_lazy_init: bool,
564
565 pcc: bool,
567
568 pub async_config: AsyncConfig,
571
572 signals_based_traps: bool,
575}
576
577impl WasmtimeConfig {
578 pub fn make_compatible_with(&mut self, other: &Self) {
582 self.strategy = other.strategy.clone();
594 if let InstanceAllocationStrategy::Pooling { .. } = &other.strategy {
595 self.memory_config = other.memory_config.clone();
598 }
599
600 self.make_internally_consistent();
601 }
602
603 pub fn update_module_config(
606 &mut self,
607 config: &mut ModuleConfig,
608 u: &mut Unstructured<'_>,
609 ) -> arbitrary::Result<()> {
610 match self.compiler_strategy {
611 CompilerStrategy::CraneliftNative => {}
612
613 CompilerStrategy::Winch => {
614 if cfg!(not(target_arch = "x86_64")) {
620 log::warn!(
621 "want to compile with Winch but host architecture does not support it"
622 );
623 return Err(arbitrary::Error::IncorrectFormat);
624 }
625
626 config.config.relaxed_simd_enabled = false;
631 config.config.gc_enabled = false;
632 config.config.tail_call_enabled = false;
633 config.config.reference_types_enabled = false;
634 config.function_references_enabled = false;
635
636 if self
638 .codegen_flag("has_avx")
639 .is_some_and(|value| value == "false")
640 || self
641 .codegen_flag("has_avx2")
642 .is_some_and(|value| value == "false")
643 {
644 config.config.simd_enabled = false;
645 }
646
647 self.signals_based_traps = true;
650 self.table_lazy_init = true;
651 self.debug_info = false;
652 }
653
654 CompilerStrategy::CraneliftPulley => {
655 config.config.threads_enabled = false;
656 }
657 }
658
659 if config.config.threads_enabled
666 || matches!(self.strategy, InstanceAllocationStrategy::Pooling(_))
667 {
668 self.avoid_custom_unaligned_memory(u)?;
669 }
670
671 if let InstanceAllocationStrategy::Pooling(pooling) = &mut self.strategy {
674 config.config.threads_enabled = false;
678
679 let min_bytes = config
682 .config
683 .max_memory32_bytes
684 .min(
687 config
688 .config
689 .max_memory64_bytes
690 .try_into()
691 .unwrap_or(u64::MAX),
692 );
693 let mut min = min_bytes.min(pooling.max_memory_size as u64);
694 if let MemoryConfig::Normal(cfg) = &self.memory_config {
695 min = min.min(cfg.memory_reservation.unwrap_or(0));
696 }
697 pooling.max_memory_size = min as usize;
698 config.config.max_memory32_bytes = min;
699 config.config.max_memory64_bytes = min as u128;
700
701 if config.config.disallow_traps {
705 if pooling.max_memory_size < (1 << 16) {
706 pooling.max_memory_size = 1 << 16;
707 config.config.max_memory32_bytes = 1 << 16;
708 config.config.max_memory64_bytes = 1 << 16;
709 if let MemoryConfig::Normal(cfg) = &mut self.memory_config {
710 match &mut cfg.memory_reservation {
711 Some(size) => *size = (*size).max(pooling.max_memory_size as u64),
712 size @ None => *size = Some(pooling.max_memory_size as u64),
713 }
714 }
715 }
716 if pooling.table_elements == 0 {
718 pooling.table_elements = 1;
719 }
720 }
721
722 config.config.min_memories = config.config.min_memories.min(10);
725 config.config.max_memories = config.config.max_memories.min(10);
726
727 pooling.total_memories = config.config.max_memories as u32;
730 pooling.total_tables = config.config.max_tables as u32;
731 }
732
733 if !self.signals_based_traps {
734 config.config.threads_enabled = false;
741
742 if let MemoryConfig::Normal(cfg) = &mut self.memory_config {
745 cfg.cranelift_enable_heap_access_spectre_mitigations = None;
746 }
747 }
748
749 self.make_internally_consistent();
750
751 Ok(())
752 }
753
754 pub(crate) fn codegen_flag(&self, name: &str) -> Option<&str> {
756 self.codegen.flags().iter().find_map(|(n, value)| {
757 if n == name {
758 Some(value.as_str())
759 } else {
760 None
761 }
762 })
763 }
764
765 fn avoid_custom_unaligned_memory(&mut self, u: &mut Unstructured<'_>) -> arbitrary::Result<()> {
768 if let MemoryConfig::CustomUnaligned = self.memory_config {
769 self.memory_config = MemoryConfig::Normal(u.arbitrary()?);
770 }
771 Ok(())
772 }
773
774 fn make_internally_consistent(&mut self) {
783 if !self.signals_based_traps {
784 if let MemoryConfig::Normal(cfg) = &mut self.memory_config {
785 cfg.cranelift_enable_heap_access_spectre_mitigations = None;
789
790 if !cfg.memory_init_cow
794 && cfg.memory_guard_size == Some(0)
795 && cfg.memory_reservation == Some(0)
796 {
797 let min = 10 << 20; if let Some(val) = &mut cfg.memory_reservation_for_growth {
799 *val = (*val).min(min);
800 } else {
801 cfg.memory_reservation_for_growth = Some(min);
802 }
803 }
804 }
805 }
806 }
807}
808
809#[derive(Arbitrary, Clone, Debug, PartialEq, Eq, Hash)]
810enum OptLevel {
811 None,
812 Speed,
813 SpeedAndSize,
814}
815
816impl OptLevel {
817 fn to_wasmtime(&self) -> wasmtime::OptLevel {
818 match self {
819 OptLevel::None => wasmtime::OptLevel::None,
820 OptLevel::Speed => wasmtime::OptLevel::Speed,
821 OptLevel::SpeedAndSize => wasmtime::OptLevel::SpeedAndSize,
822 }
823 }
824}
825
826#[derive(Arbitrary, Clone, Debug, PartialEq, Eq, Hash)]
827enum RegallocAlgorithm {
828 Backtracking,
829 SinglePass,
830}
831
832impl RegallocAlgorithm {
833 fn to_wasmtime(&self) -> wasmtime::RegallocAlgorithm {
834 match self {
835 RegallocAlgorithm::Backtracking => wasmtime::RegallocAlgorithm::Backtracking,
836 RegallocAlgorithm::SinglePass => wasmtime::RegallocAlgorithm::SinglePass,
837 }
838 }
839}
840
841#[derive(Clone, Debug, PartialEq, Eq, Hash)]
842pub enum CompilerStrategy {
844 CraneliftNative,
846 Winch,
848 CraneliftPulley,
850}
851
852impl CompilerStrategy {
853 pub fn configure(&self, config: &mut wasmtime_cli_flags::CommonOptions) {
855 match self {
856 CompilerStrategy::CraneliftNative => {
857 config.codegen.compiler = Some(wasmtime::Strategy::Cranelift);
858 }
859 CompilerStrategy::Winch => {
860 config.codegen.compiler = Some(wasmtime::Strategy::Winch);
861 }
862 CompilerStrategy::CraneliftPulley => {
863 config.codegen.compiler = Some(wasmtime::Strategy::Cranelift);
864 config.target = Some("pulley64".to_string());
865 }
866 }
867 }
868}
869
870impl Arbitrary<'_> for CompilerStrategy {
871 fn arbitrary(u: &mut Unstructured<'_>) -> arbitrary::Result<Self> {
872 match u.int_in_range(0..=19)? {
875 1 => Ok(Self::CraneliftPulley),
876 2 => Ok(Self::Winch),
877 _ => Ok(Self::CraneliftNative),
878 }
879 }
880}
881
882#[derive(Arbitrary, Clone, Debug, PartialEq, Eq, Hash)]
883pub enum Collector {
884 DeferredReferenceCounting,
885 Null,
886}
887
888impl Collector {
889 fn to_wasmtime(&self) -> wasmtime::Collector {
890 match self {
891 Collector::DeferredReferenceCounting => wasmtime::Collector::DeferredReferenceCounting,
892 Collector::Null => wasmtime::Collector::Null,
893 }
894 }
895}