Skip to main content

wasmtime_test_util/
wast.rs

1use serde::de::DeserializeOwned;
2use serde_derive::Deserialize;
3use std::fmt;
4use std::fs;
5use std::path::Path;
6use std::path::PathBuf;
7use 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.
18pub 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.
33pub 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
74enum FindConfig {
75    InTest,
76    Infer(fn(&Path) -> TestConfig),
77}
78
79fn 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
112fn 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
177fn 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/// `;;!`.
215pub fn parse_test_config<T>(wat: &str, comment: &'static str) -> Result<T>
216where
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)]
233pub struct WastTest {
234    pub path: PathBuf,
235    pub contents: String,
236    pub config: TestConfig,
237}
238
239impl fmt::Debug for WastTest {
240    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
249macro_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
286macro_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
306foreach_config_option!(define_test_config);
307
308impl TestConfig {
309    /// Returns an iterator over each option.
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)]
324pub 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)]
335pub 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
359impl 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`.
370    pub fn should_fail(&self, config: &TestConfig) -> bool {
371        match self {
372            Compiler::CraneliftNative => {
373                if config.legacy_exceptions() {
374                    return true;
375                }
376
377                // Stack-switching is only implemented on x86_64 for unix
378                // platforms right now.
379                if config.stack_switching() && !(cfg!(target_arch = "x86_64") && cfg!(unix)) {
380                    return true;
381                }
382
383                false
384            }
385
386            Compiler::Winch => {
387                if config.gc()
388                    || config.tail_call()
389                    || config.function_references()
390                    || config.gc()
391                    || config.relaxed_simd()
392                    || config.gc_types()
393                    || config.exceptions()
394                    || config.legacy_exceptions()
395                    || config.stack_switching()
396                    || config.legacy_exceptions()
397                    || config.component_model_async()
398                {
399                    return true;
400                }
401
402                if cfg!(target_arch = "aarch64") {
403                    return config.wide_arithmetic()
404                        || (config.simd() && !config.spec_test())
405                        || config.threads();
406                }
407
408                !cfg!(target_arch = "x86_64")
409            }
410
411            Compiler::CraneliftPulley => {
412                config.threads() || config.legacy_exceptions() || config.stack_switching()
413            }
414        }
415    }
416
417    /// Returns whether this compiler configuration supports the current host
418    /// architecture.
419    pub fn supports_host(&self) -> bool {
420        match self {
421            Compiler::CraneliftNative => {
422                cfg!(target_arch = "x86_64")
423                    || cfg!(target_arch = "aarch64")
424                    || cfg!(target_arch = "riscv64")
425                    || cfg!(target_arch = "s390x")
426            }
427            Compiler::Winch => cfg!(target_arch = "x86_64") || cfg!(target_arch = "aarch64"),
428            Compiler::CraneliftPulley => true,
429        }
430    }
431}
432
433#[derive(PartialEq, Debug, Copy, Clone)]
434pub enum Collector {
435    Auto,
436    Null,
437    DeferredReferenceCounting,
438}
439
440impl WastTest {
441    /// Returns whether this test exercises the GC types and might want to use
442    /// multiple different garbage collectors.
443    pub fn test_uses_gc_types(&self) -> bool {
444        self.config.gc() || self.config.function_references()
445    }
446
447    /// Returns the optional spec proposal that this test is associated with.
448    pub fn spec_proposal(&self) -> Option<&str> {
449        spec_proposal_from_path(&self.path)
450    }
451
452    /// Returns whether this test should fail under the specified extra
453    /// configuration.
454    pub fn should_fail(&self, config: &WastConfig) -> bool {
455        if !config.compiler.supports_host() {
456            return true;
457        }
458
459        // These tests in the `component-model` submodule have not yet been
460        // updated to account for the recent threading-related intrinsic
461        // changes
462        let unsupported = [
463            "test/async/same-component-stream-future.wast",
464            "test/async/trap-if-block-and-sync.wast",
465        ];
466        if unsupported.iter().any(|part| self.path.ends_with(part)) {
467            return true;
468        }
469
470        // Some tests are known to fail with the pooling allocator
471        if config.pooling {
472            // allocates too much memory for the pooling configuration here
473            if self.config.hogs_memory() {
474                return true;
475            }
476            let unsupported = [
477                // shared memories + pooling allocator aren't supported yet
478                "misc_testsuite/memory-combos.wast",
479                "misc_testsuite/threads/atomics-end-of-memory.wast",
480                "misc_testsuite/threads/LB.wast",
481                "misc_testsuite/threads/LB_atomic.wast",
482                "misc_testsuite/threads/MP.wast",
483                "misc_testsuite/threads/MP_atomic.wast",
484                "misc_testsuite/threads/MP_wait.wast",
485                "misc_testsuite/threads/SB.wast",
486                "misc_testsuite/threads/SB_atomic.wast",
487                "misc_testsuite/threads/atomics_notify.wast",
488                "misc_testsuite/threads/atomics_wait_address.wast",
489                "misc_testsuite/threads/wait_notify.wast",
490                "spec_testsuite/proposals/threads/atomic.wast",
491                "spec_testsuite/proposals/threads/exports.wast",
492                "spec_testsuite/proposals/threads/memory.wast",
493                "misc_testsuite/memory64/threads.wast",
494            ];
495
496            if unsupported.iter().any(|part| self.path.ends_with(part)) {
497                return true;
498            }
499        }
500
501        if config.compiler.should_fail(&self.config) {
502            return true;
503        }
504
505        // Disable spec tests per target for proposals that Winch does not implement yet.
506        if config.compiler == Compiler::Winch {
507            // Common list for tests that fail in all targets supported by Winch.
508            let unsupported = [
509                "extended-const/elem.wast",
510                "extended-const/global.wast",
511                "misc_testsuite/component-model/modules.wast",
512                "misc_testsuite/externref-id-function.wast",
513                "misc_testsuite/externref-segment.wast",
514                "misc_testsuite/externref-segments.wast",
515                "misc_testsuite/externref-table-dropped-segment-issue-8281.wast",
516                "misc_testsuite/linking-errors.wast",
517                "misc_testsuite/many_table_gets_lead_to_gc.wast",
518                "misc_testsuite/mutable_externref_globals.wast",
519                "misc_testsuite/no-mixup-stack-maps.wast",
520                "misc_testsuite/no-panic.wast",
521                "misc_testsuite/simple_ref_is_null.wast",
522            ];
523
524            if unsupported.iter().any(|part| self.path.ends_with(part)) {
525                return true;
526            }
527
528            #[cfg(target_arch = "aarch64")]
529            {
530                let unsupported = [
531                    "misc_testsuite/int-to-float-splat.wast",
532                    "misc_testsuite/issue6562.wast",
533                    "misc_testsuite/memory64/simd.wast",
534                    "misc_testsuite/simd/almost-extmul.wast",
535                    "misc_testsuite/simd/canonicalize-nan.wast",
536                    "misc_testsuite/simd/cvt-from-uint.wast",
537                    "misc_testsuite/simd/edge-of-memory.wast",
538                    "misc_testsuite/simd/interesting-float-splat.wast",
539                    "misc_testsuite/simd/issue4807.wast",
540                    "misc_testsuite/simd/issue6725-no-egraph-panic.wast",
541                    "misc_testsuite/simd/issue_3173_select_v128.wast",
542                    "misc_testsuite/simd/issue_3327_bnot_lowering.wast",
543                    "misc_testsuite/simd/load_splat_out_of_bounds.wast",
544                    "misc_testsuite/simd/replace-lane-preserve.wast",
545                    "misc_testsuite/simd/spillslot-size-fuzzbug.wast",
546                    "misc_testsuite/simd/sse-cannot-fold-unaligned-loads.wast",
547                    "misc_testsuite/simd/unaligned-load.wast",
548                    "misc_testsuite/simd/v128-select.wast",
549                    "misc_testsuite/winch/issue-10331.wast",
550                    "misc_testsuite/winch/issue-10357.wast",
551                    "misc_testsuite/winch/issue-10460.wast",
552                    "misc_testsuite/winch/replace_lane.wast",
553                    "misc_testsuite/winch/simd_multivalue.wast",
554                    "misc_testsuite/winch/v128_load_lane_invalid_address.wast",
555                    "spec_testsuite/proposals/annotations/simd_lane.wast",
556                    "spec_testsuite/proposals/multi-memory/simd_memory-multi.wast",
557                    "spec_testsuite/simd_address.wast",
558                    "spec_testsuite/simd_align.wast",
559                    "spec_testsuite/simd_bit_shift.wast",
560                    "spec_testsuite/simd_bitwise.wast",
561                    "spec_testsuite/simd_boolean.wast",
562                    "spec_testsuite/simd_const.wast",
563                    "spec_testsuite/simd_conversions.wast",
564                    "spec_testsuite/simd_f32x4.wast",
565                    "spec_testsuite/simd_f32x4_arith.wast",
566                    "spec_testsuite/simd_f32x4_cmp.wast",
567                    "spec_testsuite/simd_f32x4_pmin_pmax.wast",
568                    "spec_testsuite/simd_f32x4_rounding.wast",
569                    "spec_testsuite/simd_f64x2.wast",
570                    "spec_testsuite/simd_f64x2_arith.wast",
571                    "spec_testsuite/simd_f64x2_cmp.wast",
572                    "spec_testsuite/simd_f64x2_pmin_pmax.wast",
573                    "spec_testsuite/simd_f64x2_rounding.wast",
574                    "spec_testsuite/simd_i16x8_arith.wast",
575                    "spec_testsuite/simd_i16x8_arith2.wast",
576                    "spec_testsuite/simd_i16x8_cmp.wast",
577                    "spec_testsuite/simd_i16x8_extadd_pairwise_i8x16.wast",
578                    "spec_testsuite/simd_i16x8_extmul_i8x16.wast",
579                    "spec_testsuite/simd_i16x8_q15mulr_sat_s.wast",
580                    "spec_testsuite/simd_i16x8_sat_arith.wast",
581                    "spec_testsuite/simd_i32x4_arith.wast",
582                    "spec_testsuite/simd_i32x4_arith2.wast",
583                    "spec_testsuite/simd_i32x4_cmp.wast",
584                    "spec_testsuite/simd_i32x4_dot_i16x8.wast",
585                    "spec_testsuite/simd_i32x4_extadd_pairwise_i16x8.wast",
586                    "spec_testsuite/simd_i32x4_extmul_i16x8.wast",
587                    "spec_testsuite/simd_i32x4_trunc_sat_f32x4.wast",
588                    "spec_testsuite/simd_i32x4_trunc_sat_f64x2.wast",
589                    "spec_testsuite/simd_i64x2_arith.wast",
590                    "spec_testsuite/simd_i64x2_arith2.wast",
591                    "spec_testsuite/simd_i64x2_cmp.wast",
592                    "spec_testsuite/simd_i64x2_extmul_i32x4.wast",
593                    "spec_testsuite/simd_i8x16_arith.wast",
594                    "spec_testsuite/simd_i8x16_arith2.wast",
595                    "spec_testsuite/simd_i8x16_cmp.wast",
596                    "spec_testsuite/simd_i8x16_sat_arith.wast",
597                    "spec_testsuite/simd_int_to_int_extend.wast",
598                    "spec_testsuite/simd_lane.wast",
599                    "spec_testsuite/simd_load.wast",
600                    "spec_testsuite/simd_load16_lane.wast",
601                    "spec_testsuite/simd_load32_lane.wast",
602                    "spec_testsuite/simd_load64_lane.wast",
603                    "spec_testsuite/simd_load8_lane.wast",
604                    "spec_testsuite/simd_load_extend.wast",
605                    "spec_testsuite/simd_load_splat.wast",
606                    "spec_testsuite/simd_load_zero.wast",
607                    "spec_testsuite/simd_select.wast",
608                    "spec_testsuite/simd_splat.wast",
609                    "spec_testsuite/simd_store.wast",
610                    "spec_testsuite/simd_store16_lane.wast",
611                    "spec_testsuite/simd_store32_lane.wast",
612                    "spec_testsuite/simd_store64_lane.wast",
613                    "spec_testsuite/simd_store8_lane.wast",
614                ];
615
616                if unsupported.iter().any(|part| self.path.ends_with(part)) {
617                    return true;
618                }
619            }
620
621            #[cfg(target_arch = "x86_64")]
622            {
623                // SIMD on Winch requires AVX instructions.
624                #[cfg(target_arch = "x86_64")]
625                if !(std::is_x86_feature_detected!("avx") && std::is_x86_feature_detected!("avx2"))
626                {
627                    let unsupported = [
628                        "annotations/simd_lane.wast",
629                        "memory64/simd.wast",
630                        "misc_testsuite/int-to-float-splat.wast",
631                        "misc_testsuite/issue6562.wast",
632                        "misc_testsuite/simd/almost-extmul.wast",
633                        "misc_testsuite/simd/canonicalize-nan.wast",
634                        "misc_testsuite/simd/cvt-from-uint.wast",
635                        "misc_testsuite/simd/edge-of-memory.wast",
636                        "misc_testsuite/simd/issue_3327_bnot_lowering.wast",
637                        "misc_testsuite/simd/issue6725-no-egraph-panic.wast",
638                        "misc_testsuite/simd/replace-lane-preserve.wast",
639                        "misc_testsuite/simd/spillslot-size-fuzzbug.wast",
640                        "misc_testsuite/simd/sse-cannot-fold-unaligned-loads.wast",
641                        "misc_testsuite/winch/issue-10331.wast",
642                        "misc_testsuite/winch/replace_lane.wast",
643                        "misc_testsuite/simd/riscv64-replicated-imm5-works.wast",
644                        "spec_testsuite/simd_align.wast",
645                        "spec_testsuite/simd_boolean.wast",
646                        "spec_testsuite/simd_conversions.wast",
647                        "spec_testsuite/simd_f32x4.wast",
648                        "spec_testsuite/simd_f32x4_arith.wast",
649                        "spec_testsuite/simd_f32x4_cmp.wast",
650                        "spec_testsuite/simd_f32x4_pmin_pmax.wast",
651                        "spec_testsuite/simd_f32x4_rounding.wast",
652                        "spec_testsuite/simd_f64x2.wast",
653                        "spec_testsuite/simd_f64x2_arith.wast",
654                        "spec_testsuite/simd_f64x2_cmp.wast",
655                        "spec_testsuite/simd_f64x2_pmin_pmax.wast",
656                        "spec_testsuite/simd_f64x2_rounding.wast",
657                        "spec_testsuite/simd_i16x8_cmp.wast",
658                        "spec_testsuite/simd_i32x4_cmp.wast",
659                        "spec_testsuite/simd_i64x2_arith2.wast",
660                        "spec_testsuite/simd_i64x2_cmp.wast",
661                        "spec_testsuite/simd_i8x16_arith2.wast",
662                        "spec_testsuite/simd_i8x16_cmp.wast",
663                        "spec_testsuite/simd_int_to_int_extend.wast",
664                        "spec_testsuite/simd_load.wast",
665                        "spec_testsuite/simd_load_extend.wast",
666                        "spec_testsuite/simd_load_splat.wast",
667                        "spec_testsuite/simd_load_zero.wast",
668                        "spec_testsuite/simd_splat.wast",
669                        "spec_testsuite/simd_store16_lane.wast",
670                        "spec_testsuite/simd_store32_lane.wast",
671                        "spec_testsuite/simd_store64_lane.wast",
672                        "spec_testsuite/simd_store8_lane.wast",
673                        "spec_testsuite/simd_load16_lane.wast",
674                        "spec_testsuite/simd_load32_lane.wast",
675                        "spec_testsuite/simd_load64_lane.wast",
676                        "spec_testsuite/simd_load8_lane.wast",
677                        "spec_testsuite/simd_bitwise.wast",
678                        "misc_testsuite/simd/load_splat_out_of_bounds.wast",
679                        "misc_testsuite/simd/unaligned-load.wast",
680                        "multi-memory/simd_memory-multi.wast",
681                        "misc_testsuite/simd/issue4807.wast",
682                        "spec_testsuite/simd_const.wast",
683                        "spec_testsuite/simd_i8x16_sat_arith.wast",
684                        "spec_testsuite/simd_i64x2_arith.wast",
685                        "spec_testsuite/simd_i16x8_arith.wast",
686                        "spec_testsuite/simd_i16x8_arith2.wast",
687                        "spec_testsuite/simd_i16x8_q15mulr_sat_s.wast",
688                        "spec_testsuite/simd_i16x8_sat_arith.wast",
689                        "spec_testsuite/simd_i32x4_arith.wast",
690                        "spec_testsuite/simd_i32x4_dot_i16x8.wast",
691                        "spec_testsuite/simd_i32x4_trunc_sat_f32x4.wast",
692                        "spec_testsuite/simd_i32x4_trunc_sat_f64x2.wast",
693                        "spec_testsuite/simd_i8x16_arith.wast",
694                        "spec_testsuite/simd_bit_shift.wast",
695                        "spec_testsuite/simd_lane.wast",
696                        "spec_testsuite/simd_i16x8_extmul_i8x16.wast",
697                        "spec_testsuite/simd_i32x4_extmul_i16x8.wast",
698                        "spec_testsuite/simd_i64x2_extmul_i32x4.wast",
699                        "spec_testsuite/simd_i16x8_extadd_pairwise_i8x16.wast",
700                        "spec_testsuite/simd_i32x4_extadd_pairwise_i16x8.wast",
701                        "spec_testsuite/simd_i32x4_arith2.wast",
702                    ];
703
704                    if unsupported.iter().any(|part| self.path.ends_with(part)) {
705                        return true;
706                    }
707                }
708            }
709        }
710
711        // Not implemented in Wasmtime anywhere yet.
712        if self.config.custom_descriptors() {
713            let happens_to_work =
714                ["spec_testsuite/proposals/custom-descriptors/binary-leb128.wast"];
715
716            if happens_to_work.iter().any(|part| self.path.ends_with(part)) {
717                return false;
718            }
719            return true;
720        }
721
722        false
723    }
724}
725
726fn spec_proposal_from_path(path: &Path) -> Option<&str> {
727    let mut iter = path.iter();
728    loop {
729        match iter.next()?.to_str()? {
730            "proposals" => break,
731            _ => {}
732        }
733    }
734    Some(iter.next()?.to_str()?)
735}