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::{Engine, Module, MpkEnabled, 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 == MpkEnabled::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.legacy_exceptions = legacy_exceptions.unwrap_or(false);
165 self.module_config.component_model_gc = component_model_gc.unwrap_or(false);
166
167 let config = &mut self.module_config.config;
170 config.bulk_memory_enabled = true;
171 config.multi_value_enabled = true;
172 config.wide_arithmetic_enabled = wide_arithmetic.unwrap_or(false);
173 config.memory64_enabled = memory64.unwrap_or(false);
174 config.relaxed_simd_enabled = relaxed_simd.unwrap_or(false);
175 config.simd_enabled = config.relaxed_simd_enabled || simd.unwrap_or(false);
176 config.tail_call_enabled = tail_call.unwrap_or(false);
177 config.custom_page_sizes_enabled = custom_page_sizes.unwrap_or(false);
178 config.threads_enabled = threads.unwrap_or(false);
179 config.shared_everything_threads_enabled = shared_everything_threads.unwrap_or(false);
180 config.gc_enabled = gc.unwrap_or(false);
181 config.reference_types_enabled = config.gc_enabled
182 || self.module_config.function_references_enabled
183 || reference_types.unwrap_or(false);
184 config.extended_const_enabled = extended_const.unwrap_or(false);
185 config.exceptions_enabled = exceptions.unwrap_or(false);
186 if multi_memory.unwrap_or(false) {
187 config.max_memories = limits::MEMORIES_PER_MODULE as usize;
188 } else {
189 config.max_memories = 1;
190 }
191
192 if let Some(n) = &mut self.wasmtime.memory_config.memory_reservation {
193 *n = (*n).max(limits::MEMORY_SIZE as u64);
194 }
195
196 if let InstanceAllocationStrategy::Pooling(pooling) = &mut self.wasmtime.strategy {
203 pooling.max_memory_protection_keys = pooling.max_memory_protection_keys.max(1).min(2);
207 pooling.total_memories = pooling
208 .total_memories
209 .max(limits::MEMORIES * (pooling.max_memory_protection_keys as u32));
210
211 pooling.total_component_instances = pooling
214 .total_component_instances
215 .max(limits::COMPONENT_INSTANCES);
216 pooling.total_tables = pooling.total_tables.max(limits::TABLES);
217 pooling.max_tables_per_module =
218 pooling.max_tables_per_module.max(limits::TABLES_PER_MODULE);
219 pooling.max_memories_per_module = pooling
220 .max_memories_per_module
221 .max(limits::MEMORIES_PER_MODULE);
222 pooling.max_memories_per_component = pooling
223 .max_memories_per_component
224 .max(limits::MEMORIES_PER_MODULE);
225 pooling.total_core_instances = pooling.total_core_instances.max(limits::CORE_INSTANCES);
226 pooling.max_memory_size = pooling.max_memory_size.max(limits::MEMORY_SIZE);
227 pooling.table_elements = pooling.table_elements.max(limits::TABLE_ELEMENTS);
228 pooling.core_instance_size = pooling.core_instance_size.max(limits::CORE_INSTANCE_SIZE);
229 pooling.component_instance_size = pooling
230 .component_instance_size
231 .max(limits::CORE_INSTANCE_SIZE);
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 cfg.debug.address_map = Some(self.wasmtime.generate_address_map);
269 cfg.opts.opt_level = Some(self.wasmtime.opt_level.to_wasmtime());
270 cfg.opts.regalloc_algorithm = Some(self.wasmtime.regalloc_algorithm.to_wasmtime());
271 cfg.opts.signals_based_traps = Some(self.wasmtime.signals_based_traps);
272 cfg.opts.memory_guaranteed_dense_image_size = Some(std::cmp::min(
273 16 << 20,
276 self.wasmtime.memory_guaranteed_dense_image_size,
277 ));
278 cfg.wasm.async_stack_zeroing = Some(self.wasmtime.async_stack_zeroing);
279 cfg.wasm.bulk_memory = Some(true);
280 cfg.wasm.component_model_async = Some(self.module_config.component_model_async);
281 cfg.wasm.component_model_async_builtins =
282 Some(self.module_config.component_model_async_builtins);
283 cfg.wasm.component_model_async_stackful =
284 Some(self.module_config.component_model_async_stackful);
285 cfg.wasm.component_model_error_context =
286 Some(self.module_config.component_model_error_context);
287 cfg.wasm.component_model_gc = Some(self.module_config.component_model_gc);
288 cfg.wasm.custom_page_sizes = Some(self.module_config.config.custom_page_sizes_enabled);
289 cfg.wasm.epoch_interruption = Some(self.wasmtime.epoch_interruption);
290 cfg.wasm.extended_const = Some(self.module_config.config.extended_const_enabled);
291 cfg.wasm.fuel = self.wasmtime.consume_fuel.then(|| u64::MAX);
292 cfg.wasm.function_references = Some(self.module_config.function_references_enabled);
293 cfg.wasm.gc = Some(self.module_config.config.gc_enabled);
294 cfg.wasm.memory64 = Some(self.module_config.config.memory64_enabled);
295 cfg.wasm.multi_memory = Some(self.module_config.config.max_memories > 1);
296 cfg.wasm.multi_value = Some(self.module_config.config.multi_value_enabled);
297 cfg.wasm.nan_canonicalization = Some(self.wasmtime.canonicalize_nans);
298 cfg.wasm.reference_types = Some(self.module_config.config.reference_types_enabled);
299 cfg.wasm.simd = Some(self.module_config.config.simd_enabled);
300 cfg.wasm.tail_call = Some(self.module_config.config.tail_call_enabled);
301 cfg.wasm.threads = Some(self.module_config.config.threads_enabled);
302 cfg.wasm.shared_everything_threads =
303 Some(self.module_config.config.shared_everything_threads_enabled);
304 cfg.wasm.wide_arithmetic = Some(self.module_config.config.wide_arithmetic_enabled);
305 cfg.wasm.exceptions = Some(self.module_config.config.exceptions_enabled);
306 cfg.wasm.legacy_exceptions = Some(self.module_config.legacy_exceptions);
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 if cranelift_strategy {
331 cfg.wasm.nan_canonicalization = Some(!self.module_config.config.canonicalize_nans);
335
336 if self.module_config.config.max_funcs > 10 {
342 cfg.codegen.cranelift_debug_verifier = Some(false);
343 }
344
345 if self.wasmtime.force_jump_veneers {
346 cfg.codegen.cranelift.push((
347 "wasmtime_linkopt_force_jump_veneer".to_string(),
348 Some("true".to_string()),
349 ));
350 }
351
352 if let Some(pad) = self.wasmtime.padding_between_functions {
353 cfg.codegen.cranelift.push((
354 "wasmtime_linkopt_padding_between_functions".to_string(),
355 Some(pad.to_string()),
356 ));
357 }
358
359 cfg.codegen.pcc = Some(pcc);
360
361 cfg.opts.table_lazy_init = Some(self.wasmtime.table_lazy_init);
363 }
364
365 self.wasmtime.strategy.configure(&mut cfg);
366
367 if !self.module_config.config.threads_enabled {
378 let memory_config = if pcc {
381 MemoryConfig {
382 memory_reservation: Some(4 << 30), memory_guard_size: Some(2 << 30), memory_reservation_for_growth: Some(0),
385 guard_before_linear_memory: false,
386 memory_init_cow: true,
387 cranelift_enable_heap_access_spectre_mitigations: None,
389 }
390 } else {
391 self.wasmtime.memory_config.clone()
392 };
393
394 memory_config.configure(&mut cfg);
395 };
396
397 if ((cfg.opts.signals_based_traps == Some(true) && cfg.opts.memory_guard_size == Some(0))
404 || self.wasmtime.compiler_strategy == CompilerStrategy::CraneliftPulley)
405 && cfg.opts.memory_reservation == Some(0)
406 && cfg.opts.memory_init_cow == Some(false)
407 {
408 let growth = &mut cfg.opts.memory_reservation_for_growth;
409 let max = 1 << 20;
410 *growth = match *growth {
411 Some(n) => Some(n.min(max)),
412 None => Some(max),
413 };
414 }
415
416 log::debug!("creating wasmtime config with CLI options:\n{cfg}");
417 let mut cfg = cfg.config(None).expect("failed to create wasmtime::Config");
418
419 if self.wasmtime.async_config != AsyncConfig::Disabled {
420 log::debug!("async config in use {:?}", self.wasmtime.async_config);
421 self.wasmtime.async_config.configure(&mut cfg);
422 }
423
424 return cfg;
425 }
426
427 pub fn to_store(&self) -> Store<StoreLimits> {
430 let engine = Engine::new(&self.to_wasmtime()).unwrap();
431 let mut store = Store::new(&engine, StoreLimits::new());
432 self.configure_store(&mut store);
433 store
434 }
435
436 pub fn configure_store(&self, store: &mut Store<StoreLimits>) {
438 store.limiter(|s| s as &mut dyn wasmtime::ResourceLimiter);
439
440 if self.wasmtime.consume_fuel {
447 store.set_fuel(u64::MAX).unwrap();
448 }
449 if self.wasmtime.epoch_interruption {
450 store.epoch_deadline_trap();
451 store.set_epoch_deadline(1);
452 }
453 match self.wasmtime.async_config {
454 AsyncConfig::Disabled => {}
455 AsyncConfig::YieldWithFuel(amt) => {
456 assert!(self.wasmtime.consume_fuel);
457 store.fuel_async_yield_interval(Some(amt)).unwrap();
458 }
459 AsyncConfig::YieldWithEpochs { ticks, .. } => {
460 assert!(self.wasmtime.epoch_interruption);
461 store.set_epoch_deadline(ticks);
462 store.epoch_deadline_async_yield_and_update(ticks);
463 }
464 }
465 }
466
467 pub fn generate_timeout(&mut self, u: &mut Unstructured<'_>) -> arbitrary::Result<Timeout> {
470 let time_duration = Duration::from_millis(100);
471 let timeout = u
472 .choose(&[Timeout::Fuel(100_000), Timeout::Epoch(time_duration)])?
473 .clone();
474 match &timeout {
475 Timeout::Fuel(..) => {
476 self.wasmtime.consume_fuel = true;
477 }
478 Timeout::Epoch(..) => {
479 self.wasmtime.epoch_interruption = true;
480 }
481 Timeout::None => unreachable!("Not an option given to choose()"),
482 }
483 Ok(timeout)
484 }
485
486 pub fn compile(&self, engine: &Engine, wasm: &[u8]) -> Result<Module> {
491 let module = Module::new(engine, wasm)?;
494 if !self.wasmtime.use_precompiled_cwasm {
495 return Ok(module);
496 }
497
498 let dir = tempfile::TempDir::new().unwrap();
502 let file = dir.path().join("module.wasm");
503 std::fs::write(&file, module.serialize().unwrap()).unwrap();
504 unsafe { Ok(Module::deserialize_file(engine, &file).unwrap()) }
505 }
506
507 pub fn enable_async(&mut self, u: &mut Unstructured<'_>) -> arbitrary::Result<()> {
510 if self.wasmtime.consume_fuel || u.arbitrary()? {
511 self.wasmtime.async_config =
512 AsyncConfig::YieldWithFuel(u.int_in_range(1000..=100_000)?);
513 self.wasmtime.consume_fuel = true;
514 } else {
515 self.wasmtime.async_config = AsyncConfig::YieldWithEpochs {
516 dur: Duration::from_millis(u.int_in_range(1..=10)?),
517 ticks: u.int_in_range(1..=10)?,
518 };
519 self.wasmtime.epoch_interruption = true;
520 }
521 Ok(())
522 }
523}
524
525impl<'a> Arbitrary<'a> for Config {
526 fn arbitrary(u: &mut Unstructured<'a>) -> arbitrary::Result<Self> {
527 let mut config = Self {
528 wasmtime: u.arbitrary()?,
529 module_config: u.arbitrary()?,
530 };
531
532 config
533 .wasmtime
534 .update_module_config(&mut config.module_config, u)?;
535
536 Ok(config)
537 }
538}
539
540#[derive(Arbitrary, Clone, Debug, Eq, Hash, PartialEq)]
543pub struct WasmtimeConfig {
544 opt_level: OptLevel,
545 regalloc_algorithm: RegallocAlgorithm,
546 debug_info: bool,
547 canonicalize_nans: bool,
548 interruptable: bool,
549 pub(crate) consume_fuel: bool,
550 pub(crate) epoch_interruption: bool,
551 pub memory_config: MemoryConfig,
553 force_jump_veneers: bool,
554 memory_init_cow: bool,
555 memory_guaranteed_dense_image_size: u64,
556 use_precompiled_cwasm: bool,
557 async_stack_zeroing: bool,
558 pub strategy: InstanceAllocationStrategy,
560 codegen: CodegenSettings,
561 padding_between_functions: Option<u16>,
562 generate_address_map: bool,
563 native_unwind_info: bool,
564 pub compiler_strategy: CompilerStrategy,
566 collector: Collector,
567 table_lazy_init: bool,
568
569 pcc: bool,
571
572 pub async_config: AsyncConfig,
575
576 signals_based_traps: bool,
579}
580
581impl WasmtimeConfig {
582 pub fn make_compatible_with(&mut self, other: &Self) {
586 self.strategy = other.strategy.clone();
598 if let InstanceAllocationStrategy::Pooling { .. } = &other.strategy {
599 self.memory_config = other.memory_config.clone();
602 }
603
604 self.make_internally_consistent();
605 }
606
607 pub fn update_module_config(
610 &mut self,
611 config: &mut ModuleConfig,
612 _u: &mut Unstructured<'_>,
613 ) -> arbitrary::Result<()> {
614 match self.compiler_strategy {
615 CompilerStrategy::CraneliftNative => {}
616
617 CompilerStrategy::Winch => {
618 if cfg!(not(target_arch = "x86_64")) {
624 log::warn!(
625 "want to compile with Winch but host architecture does not support it"
626 );
627 return Err(arbitrary::Error::IncorrectFormat);
628 }
629
630 config.config.relaxed_simd_enabled = false;
635 config.config.gc_enabled = false;
636 config.config.tail_call_enabled = false;
637 config.config.reference_types_enabled = false;
638 config.function_references_enabled = false;
639
640 if self
642 .codegen_flag("has_avx")
643 .is_some_and(|value| value == "false")
644 || self
645 .codegen_flag("has_avx2")
646 .is_some_and(|value| value == "false")
647 {
648 config.config.simd_enabled = false;
649 }
650
651 self.signals_based_traps = true;
654 self.table_lazy_init = true;
655 self.debug_info = false;
656 }
657
658 CompilerStrategy::CraneliftPulley => {
659 config.config.threads_enabled = false;
660 }
661 }
662
663 if let InstanceAllocationStrategy::Pooling(pooling) = &mut self.strategy {
666 config.config.threads_enabled = false;
670
671 let min_bytes = config
674 .config
675 .max_memory32_bytes
676 .min(
679 config
680 .config
681 .max_memory64_bytes
682 .try_into()
683 .unwrap_or(u64::MAX),
684 );
685 let min = min_bytes
686 .min(pooling.max_memory_size as u64)
687 .min(self.memory_config.memory_reservation.unwrap_or(0));
688 pooling.max_memory_size = min as usize;
689 config.config.max_memory32_bytes = min;
690 config.config.max_memory64_bytes = min as u128;
691
692 if config.config.disallow_traps {
696 if pooling.max_memory_size < (1 << 16) {
697 pooling.max_memory_size = 1 << 16;
698 config.config.max_memory32_bytes = 1 << 16;
699 config.config.max_memory64_bytes = 1 << 16;
700 let cfg = &mut self.memory_config;
701 match &mut cfg.memory_reservation {
702 Some(size) => *size = (*size).max(pooling.max_memory_size as u64),
703 size @ None => *size = Some(pooling.max_memory_size as u64),
704 }
705 }
706 if pooling.table_elements == 0 {
708 pooling.table_elements = 1;
709 }
710 }
711
712 config.config.min_memories = config.config.min_memories.min(10);
715 config.config.max_memories = config.config.max_memories.min(10);
716
717 pooling.total_memories = config.config.max_memories as u32;
720 pooling.total_tables = config.config.max_tables as u32;
721 }
722
723 if !self.signals_based_traps {
724 config.config.threads_enabled = false;
731
732 self.memory_config
735 .cranelift_enable_heap_access_spectre_mitigations = None;
736 }
737
738 self.make_internally_consistent();
739
740 Ok(())
741 }
742
743 pub(crate) fn codegen_flag(&self, name: &str) -> Option<&str> {
745 self.codegen.flags().iter().find_map(|(n, value)| {
746 if n == name {
747 Some(value.as_str())
748 } else {
749 None
750 }
751 })
752 }
753
754 fn make_internally_consistent(&mut self) {
763 if !self.signals_based_traps {
764 let cfg = &mut self.memory_config;
765 cfg.cranelift_enable_heap_access_spectre_mitigations = None;
769
770 if !cfg.memory_init_cow
774 && cfg.memory_guard_size == Some(0)
775 && cfg.memory_reservation == Some(0)
776 {
777 let min = 10 << 20; if let Some(val) = &mut cfg.memory_reservation_for_growth {
779 *val = (*val).min(min);
780 } else {
781 cfg.memory_reservation_for_growth = Some(min);
782 }
783 }
784 }
785 }
786}
787
788#[derive(Arbitrary, Clone, Debug, PartialEq, Eq, Hash)]
789enum OptLevel {
790 None,
791 Speed,
792 SpeedAndSize,
793}
794
795impl OptLevel {
796 fn to_wasmtime(&self) -> wasmtime::OptLevel {
797 match self {
798 OptLevel::None => wasmtime::OptLevel::None,
799 OptLevel::Speed => wasmtime::OptLevel::Speed,
800 OptLevel::SpeedAndSize => wasmtime::OptLevel::SpeedAndSize,
801 }
802 }
803}
804
805#[derive(Arbitrary, Clone, Debug, PartialEq, Eq, Hash)]
806enum RegallocAlgorithm {
807 Backtracking,
808 SinglePass,
809}
810
811impl RegallocAlgorithm {
812 fn to_wasmtime(&self) -> wasmtime::RegallocAlgorithm {
813 match self {
814 RegallocAlgorithm::Backtracking => wasmtime::RegallocAlgorithm::Backtracking,
815 RegallocAlgorithm::SinglePass => wasmtime::RegallocAlgorithm::Backtracking,
822 }
823 }
824}
825
826#[derive(Clone, Debug, PartialEq, Eq, Hash)]
827pub enum CompilerStrategy {
829 CraneliftNative,
831 Winch,
833 CraneliftPulley,
835}
836
837impl CompilerStrategy {
838 pub fn configure(&self, config: &mut wasmtime_cli_flags::CommonOptions) {
840 match self {
841 CompilerStrategy::CraneliftNative => {
842 config.codegen.compiler = Some(wasmtime::Strategy::Cranelift);
843 }
844 CompilerStrategy::Winch => {
845 config.codegen.compiler = Some(wasmtime::Strategy::Winch);
846 }
847 CompilerStrategy::CraneliftPulley => {
848 config.codegen.compiler = Some(wasmtime::Strategy::Cranelift);
849 config.target = Some("pulley64".to_string());
850 }
851 }
852 }
853}
854
855impl Arbitrary<'_> for CompilerStrategy {
856 fn arbitrary(u: &mut Unstructured<'_>) -> arbitrary::Result<Self> {
857 match u.int_in_range(0..=19)? {
860 1 => Ok(Self::CraneliftPulley),
861 2 => Ok(Self::Winch),
862 _ => Ok(Self::CraneliftNative),
863 }
864 }
865}
866
867#[derive(Arbitrary, Clone, Debug, PartialEq, Eq, Hash)]
868pub enum Collector {
869 DeferredReferenceCounting,
870 Null,
871}
872
873impl Collector {
874 fn to_wasmtime(&self) -> wasmtime::Collector {
875 match self {
876 Collector::DeferredReferenceCounting => wasmtime::Collector::DeferredReferenceCounting,
877 Collector::Null => wasmtime::Collector::Null,
878 }
879 }
880}