xref: /wasmtime-44.0.1/src/lib.rs (revision dff789c7)
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, vtune: bool) -> Result<ProfilingStrategy> {
47     Ok(match (jitdump, vtune) {
48         (true, false) => ProfilingStrategy::JitDump,
49         (false, true) => ProfilingStrategy::VTune,
50         (true, true) => {
51             println!("Can't enable --jitdump and --vtune at the same time. Profiling not enabled.");
52             ProfilingStrategy::None
53         }
54         _ => ProfilingStrategy::None,
55     })
56 }
57 
58 fn init_file_per_thread_logger(prefix: &'static str) {
59     file_per_thread_logger::initialize(prefix);
60 
61     // Extending behavior of default spawner:
62     // https://docs.rs/rayon/1.1.0/rayon/struct.ThreadPoolBuilder.html#method.spawn_handler
63     // Source code says DefaultSpawner is implementation detail and
64     // shouldn't be used directly.
65     rayon::ThreadPoolBuilder::new()
66         .spawn_handler(move |thread| {
67             let mut b = std::thread::Builder::new();
68             if let Some(name) = thread.name() {
69                 b = b.name(name.to_owned());
70             }
71             if let Some(stack_size) = thread.stack_size() {
72                 b = b.stack_size(stack_size);
73             }
74             b.spawn(move || {
75                 file_per_thread_logger::initialize(prefix);
76                 thread.run()
77             })?;
78             Ok(())
79         })
80         .build_global()
81         .unwrap();
82 }
83 
84 /// Common options for commands that translate WebAssembly modules
85 #[derive(StructOpt)]
86 struct CommonOptions {
87     /// Use specified configuration file
88     #[structopt(long, parse(from_os_str), value_name = "CONFIG_PATH")]
89     config: Option<PathBuf>,
90 
91     /// Use Cranelift for all compilation
92     #[structopt(long, conflicts_with = "lightbeam")]
93     cranelift: bool,
94 
95     /// Log to per-thread log files instead of stderr.
96     #[structopt(long)]
97     log_to_files: bool,
98 
99     /// Generate debug information
100     #[structopt(short = "g")]
101     debug_info: bool,
102 
103     /// Disable cache system
104     #[structopt(long)]
105     disable_cache: bool,
106 
107     /// Enable support for proposed SIMD instructions
108     #[structopt(long)]
109     enable_simd: bool,
110 
111     /// Enable support for reference types
112     #[structopt(long)]
113     enable_reference_types: bool,
114 
115     /// Enable support for multi-value functions
116     #[structopt(long)]
117     enable_multi_value: bool,
118 
119     /// Enable support for Wasm threads
120     #[structopt(long)]
121     enable_threads: bool,
122 
123     /// Enable support for bulk memory instructions
124     #[structopt(long)]
125     enable_bulk_memory: bool,
126 
127     /// Enable all experimental Wasm features
128     #[structopt(long)]
129     enable_all: bool,
130 
131     /// Use Lightbeam for all compilation
132     #[structopt(long, conflicts_with = "cranelift")]
133     lightbeam: bool,
134 
135     /// Generate jitdump file (supported on --features=profiling build)
136     #[structopt(long, conflicts_with = "vtune")]
137     jitdump: bool,
138 
139     /// Generate vtune (supported on --features=vtune build)
140     #[structopt(long, conflicts_with = "jitdump")]
141     vtune: bool,
142 
143     /// Run optimization passes on translated functions, on by default
144     #[structopt(short = "O", long)]
145     optimize: bool,
146 
147     /// Optimization level for generated functions (0 (none), 1, 2 (most), or s
148     /// (size))
149     #[structopt(
150         long,
151         parse(try_from_str = parse_opt_level),
152         default_value = "2",
153     )]
154     opt_level: wasmtime::OptLevel,
155 }
156 
157 impl CommonOptions {
158     fn config(&self) -> Result<Config> {
159         let mut config = Config::new();
160         config
161             .cranelift_debug_verifier(cfg!(debug_assertions))
162             .debug_info(self.debug_info)
163             .wasm_bulk_memory(self.enable_bulk_memory || self.enable_all)
164             .wasm_simd(self.enable_simd || self.enable_all)
165             .wasm_reference_types(self.enable_reference_types || self.enable_all)
166             .wasm_multi_value(self.enable_multi_value || self.enable_all)
167             .wasm_threads(self.enable_threads || self.enable_all)
168             .cranelift_opt_level(self.opt_level())
169             .strategy(pick_compilation_strategy(self.cranelift, self.lightbeam)?)?
170             .profiler(pick_profiling_strategy(self.jitdump, self.vtune)?)?;
171         if !self.disable_cache {
172             match &self.config {
173                 Some(path) => {
174                     config.cache_config_load(path)?;
175                 }
176                 None => {
177                     config.cache_config_load_default()?;
178                 }
179             }
180         }
181         Ok(config)
182     }
183 
184     fn opt_level(&self) -> wasmtime::OptLevel {
185         match (self.optimize, self.opt_level.clone()) {
186             (true, _) => wasmtime::OptLevel::Speed,
187             (false, other) => other,
188         }
189     }
190 }
191 
192 fn parse_opt_level(opt_level: &str) -> Result<wasmtime::OptLevel> {
193     match opt_level {
194         "s" => Ok(wasmtime::OptLevel::SpeedAndSize),
195         "0" => Ok(wasmtime::OptLevel::None),
196         "1" => Ok(wasmtime::OptLevel::Speed),
197         "2" => Ok(wasmtime::OptLevel::Speed),
198         other => bail!(
199             "unknown optimization level `{}`, only 0,1,2,s accepted",
200             other
201         ),
202     }
203 }
204