Skip to main content

wasmtime_cli/commands/
wast.rs

1//! The module that implements the `wasmtime wast` command.
2
3use clap::Parser;
4use std::path::PathBuf;
5use wasmtime::{Engine, Result, error::Context as _};
6use wasmtime_cli_flags::CommonOptions;
7use wasmtime_wast::{SpectestConfig, WastContext};
8
9/// Runs a WebAssembly test script file
10#[derive(Parser)]
11pub struct WastCommand {
12    #[command(flatten)]
13    common: CommonOptions,
14
15    /// The path of the WebAssembly test script to run
16    #[arg(required = true, value_name = "SCRIPT_FILE")]
17    scripts: Vec<PathBuf>,
18
19    /// Whether or not to generate DWARF debugging information in text-to-binary
20    /// transformations to show line numbers in backtraces.
21    #[arg(long, require_equals = true, value_name = "true|false")]
22    generate_dwarf: Option<Option<bool>>,
23
24    /// Saves precompiled versions of modules to this path instead of running
25    /// tests.
26    #[arg(long)]
27    precompile_save: Option<PathBuf>,
28
29    /// Load precompiled modules from the specified directory instead of
30    /// compiling natively.
31    #[arg(long)]
32    precompile_load: Option<PathBuf>,
33
34    /// Whether or not to run wasm in async mode.
35    ///
36    /// This is enabled by default but disabling it may be useful when testing
37    /// Wasmtime itself.
38    #[arg(long = "async", require_equals = true, value_name = "true|false")]
39    async_: Option<Option<bool>>,
40
41    /// Whether or not to enable wasmtime's builtin functions for the `*.wast`
42    /// to import.
43    #[arg(long = "wasmtime-builtins")]
44    wasmtime_builtins: bool,
45
46    /// Whether or not to ignore error messages in directives like
47    /// `assert_invalid`.
48    #[arg(long)]
49    ignore_error_messages: bool,
50}
51
52impl WastCommand {
53    /// Executes the command.
54    pub fn execute(mut self) -> Result<()> {
55        self.common.init_logging()?;
56
57        let async_ = optional_flag_with_default(self.async_, true);
58        let mut config = self.common.config(None)?;
59        config.shared_memory(true);
60
61        let generate_dwarf = optional_flag_with_default(self.generate_dwarf, true);
62        // When DWARF is being generated go ahead and enable backtrace details
63        // unconditionally as that's generally what's intended.
64        if generate_dwarf {
65            config.wasm_backtrace_details(wasmtime::WasmBacktraceDetails::Enable);
66        }
67        let engine = Engine::new(&config)?;
68        let mut wast_context = WastContext::new(
69            &engine,
70            if async_ {
71                wasmtime_wast::Async::Yes
72            } else {
73                wasmtime_wast::Async::No
74            },
75            move |store| {
76                if let Some(fuel) = self.common.wasm.fuel {
77                    store.set_fuel(fuel).unwrap();
78                }
79                if let Some(true) = self.common.wasm.epoch_interruption {
80                    store.epoch_deadline_trap();
81                    store.set_epoch_deadline(1);
82                }
83            },
84        );
85
86        wast_context.generate_dwarf(generate_dwarf);
87        wast_context
88            .register_spectest(&SpectestConfig {
89                use_shared_memory: true,
90                suppress_prints: false,
91            })
92            .expect("error instantiating \"spectest\"");
93        wast_context.ignore_error_messages(self.ignore_error_messages);
94
95        if let Some(path) = &self.precompile_save {
96            wast_context.precompile_save(path);
97        }
98        if let Some(path) = &self.precompile_load {
99            wast_context.precompile_load(path);
100        }
101
102        if self.wasmtime_builtins {
103            wast_context.register_wasmtime()?;
104        }
105
106        for script in self.scripts.iter() {
107            wast_context
108                .run_file(script)
109                .with_context(|| format!("failed to run script file '{}'", script.display()))?;
110        }
111
112        Ok(())
113    }
114}
115
116fn optional_flag_with_default(flag: Option<Option<bool>>, default: bool) -> bool {
117    match flag {
118        None => default,
119        Some(None) => true,
120        Some(Some(val)) => val,
121    }
122}