1 use serde::de::DeserializeOwned;
2 use serde_derive::Deserialize;
3 use std::fmt;
4 use std::fs;
5 use std::path::Path;
6 use std::path::PathBuf;
7 use wasmtime_environ::prelude::*;
8 
9 /// Limits for running wast tests.
10 ///
11 /// This is useful for sharing between `tests/wast.rs` and fuzzing, for
12 /// example, and is used as the minimum threshold for configuration when
13 /// fuzzing.
14 ///
15 /// Note that it's ok to increase these numbers if a test comes along and needs
16 /// it, they're just here as empirically found minimum thresholds so far and
17 /// they're not too scientific.
18 pub mod limits {
19     pub const MEMORY_SIZE: usize = 805 << 16;
20     pub const MEMORIES: u32 = 450;
21     pub const TABLES: u32 = 200;
22     pub const MEMORIES_PER_MODULE: u32 = 9;
23     pub const TABLES_PER_MODULE: u32 = 5;
24     pub const COMPONENT_INSTANCES: u32 = 50;
25     pub const CORE_INSTANCES: u32 = 900;
26     pub const TABLE_ELEMENTS: usize = 1000;
27     pub const CORE_INSTANCE_SIZE: usize = 64 * 1024;
28     pub const TOTAL_STACKS: u32 = 10;
29 }
30 
31 /// Local all `*.wast` tests under `root` which should be the path to the root
32 /// of the wasmtime repository.
find_tests(root: &Path) -> Result<Vec<WastTest>>33 pub fn find_tests(root: &Path) -> Result<Vec<WastTest>> {
34     let mut tests = Vec::new();
35 
36     let spec_tests = root.join("tests/spec_testsuite");
37     add_tests(
38         &mut tests,
39         &spec_tests,
40         &FindConfig::Infer(spec_test_config),
41     )
42     .with_context(|| format!("failed to add tests from `{}`", spec_tests.display()))?;
43 
44     let misc_tests = root.join("tests/misc_testsuite");
45     add_tests(&mut tests, &misc_tests, &FindConfig::InTest)
46         .with_context(|| format!("failed to add tests from `{}`", misc_tests.display()))?;
47 
48     let cm_tests = root.join("tests/component-model/test");
49     add_tests(
50         &mut tests,
51         &cm_tests,
52         &FindConfig::Infer(component_test_config),
53     )
54     .with_context(|| format!("failed to add tests from `{}`", cm_tests.display()))?;
55 
56     // Temporarily work around upstream tests that fail in unexpected ways (e.g.
57     // panics, loops, etc).
58     {
59         let skip_list = &[
60             // .. empty currently ..
61         ];
62         tests.retain(|test| {
63             test.path
64                 .file_name()
65                 .and_then(|name| name.to_str())
66                 .map(|name| !skip_list.contains(&name))
67                 .unwrap_or(true)
68         });
69     }
70 
71     Ok(tests)
72 }
73 
74 enum FindConfig {
75     InTest,
76     Infer(fn(&Path) -> TestConfig),
77 }
78 
add_tests(tests: &mut Vec<WastTest>, path: &Path, config: &FindConfig) -> Result<()>79 fn add_tests(tests: &mut Vec<WastTest>, path: &Path, config: &FindConfig) -> Result<()> {
80     for entry in path.read_dir().context("failed to read directory")? {
81         let entry = entry.context("failed to read directory entry")?;
82         let path = entry.path();
83         if entry
84             .file_type()
85             .context("failed to get file type")?
86             .is_dir()
87         {
88             add_tests(tests, &path, config).context("failed to read sub-directory")?;
89             continue;
90         }
91 
92         if path.extension().and_then(|s| s.to_str()) != Some("wast") {
93             continue;
94         }
95 
96         let contents =
97             fs::read_to_string(&path).with_context(|| format!("failed to read test: {path:?}"))?;
98         let config = match config {
99             FindConfig::InTest => parse_test_config(&contents, ";;!")
100                 .with_context(|| format!("failed to parse test configuration: {path:?}"))?,
101             FindConfig::Infer(f) => f(&path),
102         };
103         tests.push(WastTest {
104             path,
105             contents,
106             config,
107         })
108     }
109     Ok(())
110 }
111 
spec_test_config(test: &Path) -> TestConfig112 fn spec_test_config(test: &Path) -> TestConfig {
113     let mut ret = TestConfig::default();
114     ret.spec_test = Some(true);
115     ret.bulk_memory = Some(true);
116     match spec_proposal_from_path(test) {
117         Some("wide-arithmetic") => {
118             ret.wide_arithmetic = Some(true);
119         }
120         Some("threads") => {
121             ret.threads = Some(true);
122             ret.reference_types = Some(false);
123         }
124         Some("custom-page-sizes") => {
125             ret.custom_page_sizes = Some(true);
126             ret.multi_memory = Some(true);
127             ret.memory64 = Some(true);
128 
129             // See commentary below in `wasm-3.0` case for why these "hog
130             // memory"
131             if test.ends_with("memory_max.wast") || test.ends_with("memory_max_i64.wast") {
132                 ret.hogs_memory = Some(true);
133             }
134         }
135         Some("custom-descriptors") => {
136             ret.custom_descriptors = Some(true);
137         }
138         Some(proposal) => panic!("unsupported proposal {proposal:?}"),
139         None => {
140             ret.reference_types = Some(true);
141             ret.simd = Some(true);
142             ret.simd = Some(true);
143             ret.relaxed_simd = Some(true);
144             ret.multi_memory = Some(true);
145             ret.gc = Some(true);
146             ret.reference_types = Some(true);
147             ret.memory64 = Some(true);
148             ret.tail_call = Some(true);
149             ret.extended_const = Some(true);
150             ret.exceptions = Some(true);
151 
152             if test.parent().unwrap().ends_with("legacy") {
153                 ret.legacy_exceptions = Some(true);
154             }
155 
156             // These tests technically don't actually hog any memory but they
157             // do have a module definition with a table/memory that is the
158             // maximum size. These modules fail to compile in the pooling
159             // allocator which has limits on the minimum size of
160             // memories/tables by default.
161             //
162             // Pretend that these hog memory to avoid running the tests in the
163             // pooling allocator.
164             if test.ends_with("memory.wast")
165                 || test.ends_with("table.wast")
166                 || test.ends_with("memory64.wast")
167                 || test.ends_with("table64.wast")
168             {
169                 ret.hogs_memory = Some(true);
170             }
171         }
172     }
173 
174     ret
175 }
176 
component_test_config(test: &Path) -> TestConfig177 fn component_test_config(test: &Path) -> TestConfig {
178     let mut ret = TestConfig::default();
179     ret.spec_test = Some(true);
180     ret.reference_types = Some(true);
181     ret.multi_memory = Some(true);
182 
183     if let Some(parent) = test.parent() {
184         if parent.ends_with("async")
185             || [
186                 "trap-in-post-return.wast",
187                 "resources.wast",
188                 "multiple-resources.wast",
189             ]
190             .into_iter()
191             .any(|name| Some(name) == test.file_name().and_then(|s| s.to_str()))
192         {
193             ret.component_model_async = Some(true);
194             ret.component_model_async_stackful = Some(true);
195             ret.component_model_async_builtins = Some(true);
196             ret.component_model_threading = Some(true);
197         }
198         if parent.ends_with("wasm-tools") {
199             ret.memory64 = Some(true);
200             ret.threads = Some(true);
201             ret.exceptions = Some(true);
202             ret.gc = Some(true);
203         }
204         if parent.ends_with("wasmtime") {
205             ret.exceptions = Some(true);
206             ret.gc = Some(true);
207         }
208     }
209 
210     ret
211 }
212 
213 /// Parse test configuration from the specified test, comments starting with
214 /// `;;!`.
parse_test_config<T>(wat: &str, comment: &'static str) -> Result<T> where T: DeserializeOwned,215 pub fn parse_test_config<T>(wat: &str, comment: &'static str) -> Result<T>
216 where
217     T: DeserializeOwned,
218 {
219     // The test config source is the leading lines of the WAT file that are
220     // prefixed with `;;!`.
221     let config_lines: Vec<_> = wat
222         .lines()
223         .take_while(|l| l.starts_with(comment))
224         .map(|l| &l[comment.len()..])
225         .collect();
226     let config_text = config_lines.join("\n");
227 
228     toml::from_str(&config_text).context("failed to parse the test configuration")
229 }
230 
231 /// A `*.wast` test with its path, contents, and configuration.
232 #[derive(Clone)]
233 pub struct WastTest {
234     pub path: PathBuf,
235     pub contents: String,
236     pub config: TestConfig,
237 }
238 
239 impl fmt::Debug for WastTest {
fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result240     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
241         f.debug_struct("WastTest")
242             .field("path", &self.path)
243             .field("contents", &"...")
244             .field("config", &self.config)
245             .finish()
246     }
247 }
248 
249 macro_rules! foreach_config_option {
250     ($m:ident) => {
251         $m! {
252             bulk_memory
253             memory64
254             custom_page_sizes
255             multi_memory
256             threads
257             shared_everything_threads
258             gc
259             function_references
260             relaxed_simd
261             reference_types
262             tail_call
263             extended_const
264             wide_arithmetic
265             hogs_memory
266             nan_canonicalization
267             component_model_async
268             component_model_async_builtins
269             component_model_async_stackful
270             component_model_threading
271             component_model_error_context
272             component_model_gc
273             component_model_map
274             component_model_fixed_length_lists
275             simd
276             gc_types
277             exceptions
278             legacy_exceptions
279             stack_switching
280             spec_test
281             custom_descriptors
282         }
283     };
284 }
285 
286 macro_rules! define_test_config {
287     ($($option:ident)*) => {
288         /// Per-test configuration which is written down in the test file itself for
289         /// `misc_testsuite/**/*.wast` or in `spec_test_config` above for spec tests.
290         #[derive(Debug, PartialEq, Default, Deserialize, Clone)]
291         #[serde(deny_unknown_fields)]
292         pub struct TestConfig {
293             $(pub $option: Option<bool>,)*
294         }
295 
296         impl TestConfig {
297             $(
298                 pub fn $option(&self) -> bool {
299                     self.$option.unwrap_or(false)
300                 }
301             )*
302         }
303     }
304 }
305 
306 foreach_config_option!(define_test_config);
307 
308 impl TestConfig {
309     /// Returns an iterator over each option.
options_mut(&mut self) -> impl Iterator<Item = (&'static str, &mut Option<bool>)>310     pub fn options_mut(&mut self) -> impl Iterator<Item = (&'static str, &mut Option<bool>)> {
311         macro_rules! mk {
312             ($($option:ident)*) => {
313                 [
314                     $((stringify!($option), &mut self.$option),)*
315                 ].into_iter()
316             }
317         }
318         foreach_config_option!(mk)
319     }
320 }
321 
322 /// Configuration that spec tests can run under.
323 #[derive(Debug)]
324 pub struct WastConfig {
325     /// Compiler chosen to run this test.
326     pub compiler: Compiler,
327     /// Whether or not the pooling allocator is enabled.
328     pub pooling: bool,
329     /// What garbage collector is being used.
330     pub collector: Collector,
331 }
332 
333 /// Different compilers that can be tested in Wasmtime.
334 #[derive(PartialEq, Debug, Copy, Clone)]
335 pub enum Compiler {
336     /// Cranelift backend.
337     ///
338     /// This tests the Cranelift code generator for native platforms. This
339     /// notably excludes Pulley since that's listed separately below even though
340     /// Pulley is a backend of Cranelift. This is only used for native code
341     /// generation such as x86_64.
342     CraneliftNative,
343 
344     /// Winch backend.
345     ///
346     /// This tests the Winch backend for native platforms. Currently Winch
347     /// primarily supports x86_64.
348     Winch,
349 
350     /// Pulley interpreter.
351     ///
352     /// This tests the Cranelift pulley backend plus the pulley execution
353     /// environment of the output bytecode. Note that this is separate from
354     /// `Cranelift` above to be able to test both on platforms where Cranelift
355     /// has native codegen support.
356     CraneliftPulley,
357 }
358 
359 impl Compiler {
360     /// Returns whether this compiler is known to fail for the provided
361     /// `TestConfig`.
362     ///
363     /// This function will determine if the configuration of the test provided
364     /// is known to guarantee fail. This effectively tracks the proposal support
365     /// for each compiler backend/runtime and tests whether `config` enables or
366     /// disables features that aren't supported.
367     ///
368     /// Note that this is closely aligned with
369     /// `Config::compiler_panicking_wasm_features`.
should_fail(&self, config: &TestConfig) -> bool370     pub fn should_fail(&self, config: &TestConfig) -> bool {
371         match self {
372             Compiler::CraneliftNative => config.legacy_exceptions(),
373 
374             Compiler::Winch => {
375                 if config.gc()
376                     || config.tail_call()
377                     || config.function_references()
378                     || config.gc()
379                     || config.relaxed_simd()
380                     || config.gc_types()
381                     || config.exceptions()
382                     || config.legacy_exceptions()
383                     || config.stack_switching()
384                     || config.legacy_exceptions()
385                     || config.component_model_async()
386                 {
387                     return true;
388                 }
389 
390                 if cfg!(target_arch = "aarch64") {
391                     return config.wide_arithmetic()
392                         || (config.simd() && !config.spec_test())
393                         || config.threads();
394                 }
395 
396                 !cfg!(target_arch = "x86_64")
397             }
398 
399             Compiler::CraneliftPulley => {
400                 config.threads() || config.legacy_exceptions() || config.stack_switching()
401             }
402         }
403     }
404 
405     /// Returns whether this compiler configuration supports the current host
406     /// architecture.
supports_host(&self) -> bool407     pub fn supports_host(&self) -> bool {
408         match self {
409             Compiler::CraneliftNative => {
410                 cfg!(target_arch = "x86_64")
411                     || cfg!(target_arch = "aarch64")
412                     || cfg!(target_arch = "riscv64")
413                     || cfg!(target_arch = "s390x")
414             }
415             Compiler::Winch => cfg!(target_arch = "x86_64") || cfg!(target_arch = "aarch64"),
416             Compiler::CraneliftPulley => true,
417         }
418     }
419 }
420 
421 #[derive(PartialEq, Debug, Copy, Clone)]
422 pub enum Collector {
423     Auto,
424     Null,
425     DeferredReferenceCounting,
426 }
427 
428 impl WastTest {
429     /// Returns whether this test exercises the GC types and might want to use
430     /// multiple different garbage collectors.
test_uses_gc_types(&self) -> bool431     pub fn test_uses_gc_types(&self) -> bool {
432         self.config.gc() || self.config.function_references()
433     }
434 
435     /// Returns the optional spec proposal that this test is associated with.
spec_proposal(&self) -> Option<&str>436     pub fn spec_proposal(&self) -> Option<&str> {
437         spec_proposal_from_path(&self.path)
438     }
439 
440     /// Returns whether this test should fail under the specified extra
441     /// configuration.
should_fail(&self, config: &WastConfig) -> bool442     pub fn should_fail(&self, config: &WastConfig) -> bool {
443         if !config.compiler.supports_host() {
444             return true;
445         }
446 
447         // These tests in the `component-model` submodule have not yet been
448         // updated to account for the recent threading-related intrinsic
449         // changes
450         let unsupported = [
451             "test/async/same-component-stream-future.wast",
452             "test/async/trap-if-block-and-sync.wast",
453         ];
454         if unsupported.iter().any(|part| self.path.ends_with(part)) {
455             return true;
456         }
457 
458         // Some tests are known to fail with the pooling allocator
459         if config.pooling {
460             // allocates too much memory for the pooling configuration here
461             if self.config.hogs_memory() {
462                 return true;
463             }
464             let unsupported = [
465                 // shared memories + pooling allocator aren't supported yet
466                 "misc_testsuite/memory-combos.wast",
467                 "misc_testsuite/threads/atomics-end-of-memory.wast",
468                 "misc_testsuite/threads/LB.wast",
469                 "misc_testsuite/threads/LB_atomic.wast",
470                 "misc_testsuite/threads/MP.wast",
471                 "misc_testsuite/threads/MP_atomic.wast",
472                 "misc_testsuite/threads/MP_wait.wast",
473                 "misc_testsuite/threads/SB.wast",
474                 "misc_testsuite/threads/SB_atomic.wast",
475                 "misc_testsuite/threads/atomics_notify.wast",
476                 "misc_testsuite/threads/atomics_wait_address.wast",
477                 "misc_testsuite/threads/wait_notify.wast",
478                 "spec_testsuite/proposals/threads/atomic.wast",
479                 "spec_testsuite/proposals/threads/exports.wast",
480                 "spec_testsuite/proposals/threads/memory.wast",
481                 "misc_testsuite/memory64/threads.wast",
482             ];
483 
484             if unsupported.iter().any(|part| self.path.ends_with(part)) {
485                 return true;
486             }
487         }
488 
489         if config.compiler.should_fail(&self.config) {
490             return true;
491         }
492 
493         // Disable spec tests per target for proposals that Winch does not implement yet.
494         if config.compiler == Compiler::Winch {
495             // Common list for tests that fail in all targets supported by Winch.
496             let unsupported = [
497                 "extended-const/elem.wast",
498                 "extended-const/global.wast",
499                 "misc_testsuite/component-model/modules.wast",
500                 "misc_testsuite/externref-id-function.wast",
501                 "misc_testsuite/externref-segment.wast",
502                 "misc_testsuite/externref-segments.wast",
503                 "misc_testsuite/externref-table-dropped-segment-issue-8281.wast",
504                 "misc_testsuite/linking-errors.wast",
505                 "misc_testsuite/many_table_gets_lead_to_gc.wast",
506                 "misc_testsuite/mutable_externref_globals.wast",
507                 "misc_testsuite/no-mixup-stack-maps.wast",
508                 "misc_testsuite/no-panic.wast",
509                 "misc_testsuite/simple_ref_is_null.wast",
510             ];
511 
512             if unsupported.iter().any(|part| self.path.ends_with(part)) {
513                 return true;
514             }
515 
516             #[cfg(target_arch = "aarch64")]
517             {
518                 let unsupported = [
519                     "misc_testsuite/int-to-float-splat.wast",
520                     "misc_testsuite/issue6562.wast",
521                     "misc_testsuite/memory64/simd.wast",
522                     "misc_testsuite/simd/almost-extmul.wast",
523                     "misc_testsuite/simd/canonicalize-nan.wast",
524                     "misc_testsuite/simd/cvt-from-uint.wast",
525                     "misc_testsuite/simd/edge-of-memory.wast",
526                     "misc_testsuite/simd/interesting-float-splat.wast",
527                     "misc_testsuite/simd/issue4807.wast",
528                     "misc_testsuite/simd/issue6725-no-egraph-panic.wast",
529                     "misc_testsuite/simd/issue_3173_select_v128.wast",
530                     "misc_testsuite/simd/issue_3327_bnot_lowering.wast",
531                     "misc_testsuite/simd/load_splat_out_of_bounds.wast",
532                     "misc_testsuite/simd/replace-lane-preserve.wast",
533                     "misc_testsuite/simd/spillslot-size-fuzzbug.wast",
534                     "misc_testsuite/simd/sse-cannot-fold-unaligned-loads.wast",
535                     "misc_testsuite/simd/unaligned-load.wast",
536                     "misc_testsuite/simd/v128-select.wast",
537                     "misc_testsuite/winch/issue-10331.wast",
538                     "misc_testsuite/winch/issue-10357.wast",
539                     "misc_testsuite/winch/issue-10460.wast",
540                     "misc_testsuite/winch/replace_lane.wast",
541                     "misc_testsuite/winch/simd_multivalue.wast",
542                     "misc_testsuite/winch/v128_load_lane_invalid_address.wast",
543                     "spec_testsuite/proposals/annotations/simd_lane.wast",
544                     "spec_testsuite/proposals/multi-memory/simd_memory-multi.wast",
545                     "spec_testsuite/simd_address.wast",
546                     "spec_testsuite/simd_align.wast",
547                     "spec_testsuite/simd_bit_shift.wast",
548                     "spec_testsuite/simd_bitwise.wast",
549                     "spec_testsuite/simd_boolean.wast",
550                     "spec_testsuite/simd_const.wast",
551                     "spec_testsuite/simd_conversions.wast",
552                     "spec_testsuite/simd_f32x4.wast",
553                     "spec_testsuite/simd_f32x4_arith.wast",
554                     "spec_testsuite/simd_f32x4_cmp.wast",
555                     "spec_testsuite/simd_f32x4_pmin_pmax.wast",
556                     "spec_testsuite/simd_f32x4_rounding.wast",
557                     "spec_testsuite/simd_f64x2.wast",
558                     "spec_testsuite/simd_f64x2_arith.wast",
559                     "spec_testsuite/simd_f64x2_cmp.wast",
560                     "spec_testsuite/simd_f64x2_pmin_pmax.wast",
561                     "spec_testsuite/simd_f64x2_rounding.wast",
562                     "spec_testsuite/simd_i16x8_arith.wast",
563                     "spec_testsuite/simd_i16x8_arith2.wast",
564                     "spec_testsuite/simd_i16x8_cmp.wast",
565                     "spec_testsuite/simd_i16x8_extadd_pairwise_i8x16.wast",
566                     "spec_testsuite/simd_i16x8_extmul_i8x16.wast",
567                     "spec_testsuite/simd_i16x8_q15mulr_sat_s.wast",
568                     "spec_testsuite/simd_i16x8_sat_arith.wast",
569                     "spec_testsuite/simd_i32x4_arith.wast",
570                     "spec_testsuite/simd_i32x4_arith2.wast",
571                     "spec_testsuite/simd_i32x4_cmp.wast",
572                     "spec_testsuite/simd_i32x4_dot_i16x8.wast",
573                     "spec_testsuite/simd_i32x4_extadd_pairwise_i16x8.wast",
574                     "spec_testsuite/simd_i32x4_extmul_i16x8.wast",
575                     "spec_testsuite/simd_i32x4_trunc_sat_f32x4.wast",
576                     "spec_testsuite/simd_i32x4_trunc_sat_f64x2.wast",
577                     "spec_testsuite/simd_i64x2_arith.wast",
578                     "spec_testsuite/simd_i64x2_arith2.wast",
579                     "spec_testsuite/simd_i64x2_cmp.wast",
580                     "spec_testsuite/simd_i64x2_extmul_i32x4.wast",
581                     "spec_testsuite/simd_i8x16_arith.wast",
582                     "spec_testsuite/simd_i8x16_arith2.wast",
583                     "spec_testsuite/simd_i8x16_cmp.wast",
584                     "spec_testsuite/simd_i8x16_sat_arith.wast",
585                     "spec_testsuite/simd_int_to_int_extend.wast",
586                     "spec_testsuite/simd_lane.wast",
587                     "spec_testsuite/simd_load.wast",
588                     "spec_testsuite/simd_load16_lane.wast",
589                     "spec_testsuite/simd_load32_lane.wast",
590                     "spec_testsuite/simd_load64_lane.wast",
591                     "spec_testsuite/simd_load8_lane.wast",
592                     "spec_testsuite/simd_load_extend.wast",
593                     "spec_testsuite/simd_load_splat.wast",
594                     "spec_testsuite/simd_load_zero.wast",
595                     "spec_testsuite/simd_select.wast",
596                     "spec_testsuite/simd_splat.wast",
597                     "spec_testsuite/simd_store.wast",
598                     "spec_testsuite/simd_store16_lane.wast",
599                     "spec_testsuite/simd_store32_lane.wast",
600                     "spec_testsuite/simd_store64_lane.wast",
601                     "spec_testsuite/simd_store8_lane.wast",
602                 ];
603 
604                 if unsupported.iter().any(|part| self.path.ends_with(part)) {
605                     return true;
606                 }
607             }
608 
609             #[cfg(target_arch = "x86_64")]
610             {
611                 let unsupported = [
612                     // externref/reference-types related
613                     // simd-related failures
614                     "misc_testsuite/simd/canonicalize-nan.wast",
615                 ];
616 
617                 if unsupported.iter().any(|part| self.path.ends_with(part)) {
618                     return true;
619                 }
620 
621                 // SIMD on Winch requires AVX instructions.
622                 #[cfg(target_arch = "x86_64")]
623                 if !(std::is_x86_feature_detected!("avx") && std::is_x86_feature_detected!("avx2"))
624                 {
625                     let unsupported = [
626                         "annotations/simd_lane.wast",
627                         "memory64/simd.wast",
628                         "misc_testsuite/int-to-float-splat.wast",
629                         "misc_testsuite/issue6562.wast",
630                         "misc_testsuite/simd/almost-extmul.wast",
631                         "misc_testsuite/simd/cvt-from-uint.wast",
632                         "misc_testsuite/simd/edge-of-memory.wast",
633                         "misc_testsuite/simd/issue_3327_bnot_lowering.wast",
634                         "misc_testsuite/simd/issue6725-no-egraph-panic.wast",
635                         "misc_testsuite/simd/replace-lane-preserve.wast",
636                         "misc_testsuite/simd/spillslot-size-fuzzbug.wast",
637                         "misc_testsuite/simd/sse-cannot-fold-unaligned-loads.wast",
638                         "misc_testsuite/winch/issue-10331.wast",
639                         "misc_testsuite/winch/replace_lane.wast",
640                         "spec_testsuite/simd_align.wast",
641                         "spec_testsuite/simd_boolean.wast",
642                         "spec_testsuite/simd_conversions.wast",
643                         "spec_testsuite/simd_f32x4.wast",
644                         "spec_testsuite/simd_f32x4_arith.wast",
645                         "spec_testsuite/simd_f32x4_cmp.wast",
646                         "spec_testsuite/simd_f32x4_pmin_pmax.wast",
647                         "spec_testsuite/simd_f32x4_rounding.wast",
648                         "spec_testsuite/simd_f64x2.wast",
649                         "spec_testsuite/simd_f64x2_arith.wast",
650                         "spec_testsuite/simd_f64x2_cmp.wast",
651                         "spec_testsuite/simd_f64x2_pmin_pmax.wast",
652                         "spec_testsuite/simd_f64x2_rounding.wast",
653                         "spec_testsuite/simd_i16x8_cmp.wast",
654                         "spec_testsuite/simd_i32x4_cmp.wast",
655                         "spec_testsuite/simd_i64x2_arith2.wast",
656                         "spec_testsuite/simd_i64x2_cmp.wast",
657                         "spec_testsuite/simd_i8x16_arith2.wast",
658                         "spec_testsuite/simd_i8x16_cmp.wast",
659                         "spec_testsuite/simd_int_to_int_extend.wast",
660                         "spec_testsuite/simd_load.wast",
661                         "spec_testsuite/simd_load_extend.wast",
662                         "spec_testsuite/simd_load_splat.wast",
663                         "spec_testsuite/simd_load_zero.wast",
664                         "spec_testsuite/simd_splat.wast",
665                         "spec_testsuite/simd_store16_lane.wast",
666                         "spec_testsuite/simd_store32_lane.wast",
667                         "spec_testsuite/simd_store64_lane.wast",
668                         "spec_testsuite/simd_store8_lane.wast",
669                         "spec_testsuite/simd_load16_lane.wast",
670                         "spec_testsuite/simd_load32_lane.wast",
671                         "spec_testsuite/simd_load64_lane.wast",
672                         "spec_testsuite/simd_load8_lane.wast",
673                         "spec_testsuite/simd_bitwise.wast",
674                         "misc_testsuite/simd/load_splat_out_of_bounds.wast",
675                         "misc_testsuite/simd/unaligned-load.wast",
676                         "multi-memory/simd_memory-multi.wast",
677                         "misc_testsuite/simd/issue4807.wast",
678                         "spec_testsuite/simd_const.wast",
679                         "spec_testsuite/simd_i8x16_sat_arith.wast",
680                         "spec_testsuite/simd_i64x2_arith.wast",
681                         "spec_testsuite/simd_i16x8_arith.wast",
682                         "spec_testsuite/simd_i16x8_arith2.wast",
683                         "spec_testsuite/simd_i16x8_q15mulr_sat_s.wast",
684                         "spec_testsuite/simd_i16x8_sat_arith.wast",
685                         "spec_testsuite/simd_i32x4_arith.wast",
686                         "spec_testsuite/simd_i32x4_dot_i16x8.wast",
687                         "spec_testsuite/simd_i32x4_trunc_sat_f32x4.wast",
688                         "spec_testsuite/simd_i32x4_trunc_sat_f64x2.wast",
689                         "spec_testsuite/simd_i8x16_arith.wast",
690                         "spec_testsuite/simd_bit_shift.wast",
691                         "spec_testsuite/simd_lane.wast",
692                         "spec_testsuite/simd_i16x8_extmul_i8x16.wast",
693                         "spec_testsuite/simd_i32x4_extmul_i16x8.wast",
694                         "spec_testsuite/simd_i64x2_extmul_i32x4.wast",
695                         "spec_testsuite/simd_i16x8_extadd_pairwise_i8x16.wast",
696                         "spec_testsuite/simd_i32x4_extadd_pairwise_i16x8.wast",
697                         "spec_testsuite/simd_i32x4_arith2.wast",
698                     ];
699 
700                     if unsupported.iter().any(|part| self.path.ends_with(part)) {
701                         return true;
702                     }
703                 }
704             }
705         }
706 
707         // Not implemented in Wasmtime anywhere yet.
708         if self.config.custom_descriptors() {
709             let happens_to_work =
710                 ["spec_testsuite/proposals/custom-descriptors/binary-leb128.wast"];
711 
712             if happens_to_work.iter().any(|part| self.path.ends_with(part)) {
713                 return false;
714             }
715             return true;
716         }
717 
718         false
719     }
720 }
721 
spec_proposal_from_path(path: &Path) -> Option<&str>722 fn spec_proposal_from_path(path: &Path) -> Option<&str> {
723     let mut iter = path.iter();
724     loop {
725         match iter.next()?.to_str()? {
726             "proposals" => break,
727             _ => {}
728         }
729     }
730     Some(iter.next()?.to_str()?)
731 }
732