xref: /wasmtime-44.0.1/src/lib.rs (revision 3b7cb6ee)
1 //! The Wasmtime command line interface (CLI) crate.
2 //!
3 //! This crate implements the Wasmtime command line tools.
4 
5 #![deny(
6     missing_docs,
7     trivial_numeric_casts,
8     unused_extern_crates,
9     unstable_features
10 )]
11 #![warn(unused_import_braces)]
12 #![cfg_attr(feature = "clippy", plugin(clippy(conf_file = "../clippy.toml")))]
13 #![cfg_attr(feature = "cargo-clippy", allow(clippy::new_without_default))]
14 #![cfg_attr(
15     feature = "cargo-clippy",
16     warn(
17         clippy::float_arithmetic,
18         clippy::mut_mut,
19         clippy::nonminimal_bool,
20         clippy::option_map_unwrap_or,
21         clippy::option_map_unwrap_or_else,
22         clippy::unicode_not_nfc,
23         clippy::use_self
24     )
25 )]
26 
27 pub mod commands;
28 mod obj;
29 
30 use anyhow::{bail, Result};
31 use std::path::PathBuf;
32 use structopt::StructOpt;
33 use wasmtime::{Config, ProfilingStrategy, Strategy};
34 
35 pub use obj::compile_to_obj;
36 
37 fn pick_compilation_strategy(cranelift: bool, lightbeam: bool) -> Result<Strategy> {
38     Ok(match (lightbeam, cranelift) {
39         (true, false) => Strategy::Lightbeam,
40         (false, true) => Strategy::Cranelift,
41         (false, false) => Strategy::Auto,
42         (true, true) => bail!("Can't enable --cranelift and --lightbeam at the same time"),
43     })
44 }
45 
46 fn pick_profiling_strategy(jitdump: bool) -> Result<ProfilingStrategy> {
47     Ok(match jitdump {
48         true => ProfilingStrategy::JitDump,
49         false => ProfilingStrategy::None,
50     })
51 }
52 
53 fn init_file_per_thread_logger(prefix: &'static str) {
54     file_per_thread_logger::initialize(prefix);
55 
56     // Extending behavior of default spawner:
57     // https://docs.rs/rayon/1.1.0/rayon/struct.ThreadPoolBuilder.html#method.spawn_handler
58     // Source code says DefaultSpawner is implementation detail and
59     // shouldn't be used directly.
60     rayon::ThreadPoolBuilder::new()
61         .spawn_handler(move |thread| {
62             let mut b = std::thread::Builder::new();
63             if let Some(name) = thread.name() {
64                 b = b.name(name.to_owned());
65             }
66             if let Some(stack_size) = thread.stack_size() {
67                 b = b.stack_size(stack_size);
68             }
69             b.spawn(move || {
70                 file_per_thread_logger::initialize(prefix);
71                 thread.run()
72             })?;
73             Ok(())
74         })
75         .build_global()
76         .unwrap();
77 }
78 
79 /// Common options for commands that translate WebAssembly modules
80 #[derive(StructOpt)]
81 struct CommonOptions {
82     /// Use specified configuration file
83     #[structopt(long, parse(from_os_str), value_name = "CONFIG_PATH")]
84     config: Option<PathBuf>,
85 
86     /// Use Cranelift for all compilation
87     #[structopt(long, conflicts_with = "lightbeam")]
88     cranelift: bool,
89 
90     /// Log to per-thread log files instead of stderr.
91     #[structopt(long)]
92     log_to_files: bool,
93 
94     /// Generate debug information
95     #[structopt(short = "g")]
96     debug_info: bool,
97 
98     /// Disable cache system
99     #[structopt(long)]
100     disable_cache: bool,
101 
102     /// Enable support for proposed SIMD instructions
103     #[structopt(long)]
104     enable_simd: bool,
105 
106     /// Enable support for reference types
107     #[structopt(long)]
108     enable_reference_types: bool,
109 
110     /// Enable support for multi-value functions
111     #[structopt(long)]
112     enable_multi_value: bool,
113 
114     /// Enable support for Wasm threads
115     #[structopt(long)]
116     enable_threads: bool,
117 
118     /// Enable support for bulk memory instructions
119     #[structopt(long)]
120     enable_bulk_memory: bool,
121 
122     /// Enable all experimental Wasm features
123     #[structopt(long)]
124     enable_all: bool,
125 
126     /// Use Lightbeam for all compilation
127     #[structopt(long, conflicts_with = "cranelift")]
128     lightbeam: bool,
129 
130     /// Generate jitdump file (supported on --features=profiling build)
131     #[structopt(long)]
132     jitdump: bool,
133 
134     /// Run optimization passes on translated functions, on by default
135     #[structopt(short = "O", long)]
136     optimize: bool,
137 
138     /// Optimization level for generated functions (0 (none), 1, 2 (most), or s
139     /// (size))
140     #[structopt(
141         long,
142         parse(try_from_str = parse_opt_level),
143         default_value = "2",
144     )]
145     opt_level: wasmtime::OptLevel,
146 }
147 
148 impl CommonOptions {
149     fn config(&self) -> Result<Config> {
150         let mut config = Config::new();
151         config
152             .cranelift_debug_verifier(cfg!(debug_assertions))
153             .debug_info(self.debug_info)
154             .wasm_bulk_memory(self.enable_bulk_memory || self.enable_all)
155             .wasm_simd(self.enable_simd || self.enable_all)
156             .wasm_reference_types(self.enable_reference_types || self.enable_all)
157             .wasm_multi_value(self.enable_multi_value || self.enable_all)
158             .wasm_threads(self.enable_threads || self.enable_all)
159             .cranelift_opt_level(self.opt_level())
160             .strategy(pick_compilation_strategy(self.cranelift, self.lightbeam)?)?
161             .profiler(pick_profiling_strategy(self.jitdump)?)?;
162         if !self.disable_cache {
163             match &self.config {
164                 Some(path) => {
165                     config.cache_config_load(path)?;
166                 }
167                 None => {
168                     config.cache_config_load_default()?;
169                 }
170             }
171         }
172         Ok(config)
173     }
174 
175     fn opt_level(&self) -> wasmtime::OptLevel {
176         match (self.optimize, self.opt_level.clone()) {
177             (true, _) => wasmtime::OptLevel::Speed,
178             (false, other) => other,
179         }
180     }
181 }
182 
183 fn parse_opt_level(opt_level: &str) -> Result<wasmtime::OptLevel> {
184     match opt_level {
185         "s" => Ok(wasmtime::OptLevel::SpeedAndSize),
186         "0" => Ok(wasmtime::OptLevel::None),
187         "1" => Ok(wasmtime::OptLevel::Speed),
188         "2" => Ok(wasmtime::OptLevel::Speed),
189         other => bail!(
190             "unknown optimization level `{}`, only 0,1,2,s accepted",
191             other
192         ),
193     }
194 }
195