Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
bytecodealliance
GitHub Repository: bytecodealliance/wasmtime
Path: blob/main/src/commands/wizer.rs
2450 views
1
use crate::commands::run::{CliInstance, Preloads, RunCommand};
2
use crate::common::{RunCommon, RunTarget};
3
use anyhow::{Context, Result};
4
use std::fs;
5
use std::io::{self, Read, Write};
6
use std::path::PathBuf;
7
use wasmtime::Module;
8
use wasmtime_wizer::Wizer;
9
10
#[derive(clap::Parser)]
11
#[expect(missing_docs, reason = "inheriting wizer's docs")]
12
pub struct WizerCommand {
13
#[command(flatten)]
14
run: RunCommon,
15
16
#[command(flatten)]
17
wizer: Wizer,
18
19
/// The input Wasm module's file path.
20
input: PathBuf,
21
22
#[command(flatten)]
23
preloads: Preloads,
24
25
/// The file path to write the output Wasm module to.
26
///
27
/// If not specified, then `stdout` is used.
28
#[arg(short = 'o', long)]
29
output: Option<PathBuf>,
30
}
31
32
enum WizerInfo<'a> {
33
Core(wasmtime_wizer::ModuleContext<'a>),
34
#[cfg(feature = "component-model")]
35
Component(wasmtime_wizer::ComponentContext<'a>),
36
}
37
38
impl WizerCommand {
39
/// Runs the command.
40
pub fn execute(mut self) -> Result<()> {
41
self.run.common.init_logging()?;
42
let runtime = tokio::runtime::Builder::new_multi_thread()
43
.enable_time()
44
.enable_io()
45
.build()?;
46
runtime.block_on(self.execute_async())
47
}
48
49
async fn execute_async(mut self) -> Result<()> {
50
// By default use deterministic relaxed simd operations to guarantee
51
// that if relaxed simd operations are used in a module that they always
52
// produce the same result.
53
if self.run.common.wasm.relaxed_simd_deterministic.is_none() {
54
self.run.common.wasm.relaxed_simd_deterministic = Some(true);
55
}
56
57
// Don't provide any WASI imports by default to wizened components. The
58
// `run` command provides the "cli" world as a default so turn that off
59
// here if the command line flags don't otherwise say what to do.
60
if self.run.common.wasi.cli.is_none() {
61
self.run.common.wasi.cli = Some(false);
62
}
63
64
// Read the input wasm, possibly from stdin.
65
let mut wasm = Vec::new();
66
if self.input.to_str() == Some("-") {
67
io::stdin()
68
.read_to_end(&mut wasm)
69
.context("failed to read input Wasm module from stdin")?;
70
} else {
71
wasm = fs::read(&self.input).context("failed to read input Wasm module")?;
72
}
73
74
#[cfg(feature = "wat")]
75
let wasm = wat::parse_bytes(&wasm)?;
76
let is_component = wasmparser::Parser::is_component(&wasm);
77
78
let mut run = RunCommand {
79
run: self.run,
80
argv0: None,
81
invoke: Some(if is_component {
82
format!("{}()", self.wizer.get_init_func())
83
} else {
84
self.wizer.get_init_func().to_string()
85
}),
86
module_and_args: vec![self.input.clone().into()],
87
preloads: self.preloads.clone(),
88
};
89
let engine = run.new_engine()?;
90
91
// Instrument the input wasm with wizer.
92
let (cx, main) = if is_component {
93
#[cfg(feature = "component-model")]
94
{
95
let (cx, wasm) = self.wizer.instrument_component(&wasm)?;
96
(
97
WizerInfo::Component(cx),
98
RunTarget::Component(wasmtime::component::Component::new(&engine, &wasm)?),
99
)
100
}
101
#[cfg(not(feature = "component-model"))]
102
unreachable!();
103
} else {
104
let (cx, wasm) = self.wizer.instrument(&wasm)?;
105
(
106
WizerInfo::Core(cx),
107
RunTarget::Core(Module::new(&engine, &wasm)?),
108
)
109
};
110
111
// Execute a rough equivalent of
112
// `wasmtime run --invoke <..> <instrumented-wasm>`
113
let (mut store, mut linker) = run.new_store_and_linker(&engine, &main)?;
114
let instance = run
115
.instantiate_and_run(&engine, &mut linker, &main, &mut store)
116
.await?;
117
118
// Use our state to capture a snapshot with Wizer and then serialize
119
// that.
120
let final_wasm = match (cx, instance) {
121
(WizerInfo::Core(cx), CliInstance::Core(instance)) => {
122
self.wizer
123
.snapshot(
124
cx,
125
&mut wasmtime_wizer::WasmtimeWizer {
126
store: &mut store,
127
instance,
128
},
129
)
130
.await?
131
}
132
133
#[cfg(feature = "component-model")]
134
(WizerInfo::Component(cx), CliInstance::Component(instance)) => {
135
self.wizer
136
.snapshot_component(
137
cx,
138
&mut wasmtime_wizer::WasmtimeWizerComponent {
139
store: &mut store,
140
instance,
141
},
142
)
143
.await?
144
}
145
146
#[cfg(feature = "component-model")]
147
(WizerInfo::Core(_) | WizerInfo::Component(_), _) => unreachable!(),
148
};
149
150
match &self.output {
151
Some(file) => fs::write(file, &final_wasm).context("failed to write output file")?,
152
None => std::io::stdout()
153
.write_all(&final_wasm)
154
.context("failed to write output to stdout")?,
155
}
156
Ok(())
157
}
158
}
159
160