#![allow(dead_code, reason = "")]
use component::WasiOpts;
use std::path::PathBuf;
use structopt::StructOpt;
use wasmparser::{Encoding, Parser, Payload};
mod cache;
mod component;
mod constant_offsets;
mod dce;
mod directive;
mod escape;
mod eval;
mod filter;
mod image;
mod intrinsics;
mod liveness;
mod module;
mod state;
mod stats;
mod value;
#[derive(Clone, Debug, StructOpt)]
pub enum Command {
Weval {
#[structopt(short = "i")]
input_module: PathBuf,
#[structopt(short = "o")]
output_module: PathBuf,
#[structopt(short = "w")]
wizen: bool,
#[structopt(long = "dir")]
preopens: Vec<PathBuf>,
#[structopt(long = "init-func", default_value = "wizer-initialize")]
init_func: String,
#[structopt(long = "keep-init-func")]
keep_init_func: bool,
#[structopt(long = "allow-wasip2")]
allow_wasip2: bool,
#[structopt(long = "allow-wasip3")]
allow_wasip3: bool,
#[structopt(long = "allow-wasi-http")]
allow_wasi_http: bool,
#[structopt(long = "cache")]
cache: Option<PathBuf>,
#[structopt(long = "cache-ro")]
cache_ro: Option<PathBuf>,
#[structopt(long = "show-stats")]
show_stats: bool,
#[structopt(long = "output-ir")]
output_ir: Option<PathBuf>,
#[structopt(short = "v", long = "verbose")]
verbose: bool,
},
}
fn main() -> anyhow::Result<()> {
let _ = env_logger::try_init();
let cmd = Command::from_args();
match cmd {
Command::Weval {
input_module,
output_module,
wizen,
preopens,
init_func,
keep_init_func,
allow_wasip2,
allow_wasip3,
allow_wasi_http,
cache,
cache_ro,
show_stats,
output_ir,
verbose,
} => weval(
input_module,
output_module,
wizen,
preopens,
init_func,
keep_init_func,
cache,
cache_ro,
show_stats,
output_ir,
verbose,
WasiOpts {
p2: allow_wasip2,
p3: allow_wasip3,
http: allow_wasi_http,
},
),
}
}
fn wasm_encoding(wasm: &[u8]) -> anyhow::Result<Encoding> {
for payload in Parser::new(0).parse_all(wasm) {
if let Payload::Version { encoding, .. } = payload? {
return Ok(encoding);
}
}
anyhow::bail!("input is not a wasm module or component")
}
pub(crate) fn configure_wasi(
wasi_ctx: &mut wasmtime_wasi::WasiCtxBuilder,
preopens: &[PathBuf],
) -> anyhow::Result<()> {
wasi_ctx.inherit_stdio();
wasi_ctx.inherit_env();
for preopen in preopens {
wasi_ctx.preopened_dir(
preopen,
preopen.to_str().unwrap_or("."),
wasmtime_wasi::DirPerms::all(),
wasmtime_wasi::FilePerms::all(),
)?;
}
Ok(())
}
fn wizen(
wasm_bytes: Vec<u8>,
preopens: Vec<PathBuf>,
init_func: String,
keep_init_func: bool,
wasi: WasiOpts,
encoding: Encoding,
) -> anyhow::Result<Vec<u8>> {
let runtime = tokio::runtime::Builder::new_current_thread()
.enable_all()
.build()?;
runtime.block_on(async {
match encoding {
Encoding::Module => {
module::wizen(wasm_bytes, preopens, init_func, keep_init_func).await
}
Encoding::Component => {
component::wizen(wasm_bytes, preopens, init_func, keep_init_func, wasi).await
}
}
})
}
fn weval(
input_module: PathBuf,
output_module: PathBuf,
do_wizen: bool,
preopens: Vec<PathBuf>,
init_func: String,
keep_init_func: bool,
cache: Option<PathBuf>,
cache_ro: Option<PathBuf>,
show_stats: bool,
output_ir: Option<PathBuf>,
verbose: bool,
wasi: WasiOpts,
) -> anyhow::Result<()> {
if verbose {
eprintln!("Reading raw module bytes...");
}
let raw_bytes = std::fs::read(&input_module)?;
let input_hash = cache::compute_hash(&raw_bytes[..]);
let input_encoding = wasm_encoding(&raw_bytes)?;
let wasm_bytes = if do_wizen {
if verbose {
let encoding = match input_encoding {
Encoding::Module => "module",
Encoding::Component => "component",
};
eprintln!("Wizening the {encoding} with its input...");
}
wizen(
raw_bytes,
preopens,
init_func,
keep_init_func,
wasi,
input_encoding,
)?
} else {
raw_bytes
};
let bytes = match input_encoding {
Encoding::Module => module::weval(
&wasm_bytes,
module::Opts {
cache,
cache_ro,
module_hash: input_hash,
show_stats,
output_ir,
verbose,
},
)?,
Encoding::Component => component::weval(
&wasm_bytes,
component::Opts {
cache,
cache_ro,
show_stats,
output_ir,
verbose,
},
)?,
};
if verbose {
eprintln!("Writing output file...");
}
std::fs::write(&output_module, &bytes[..])?;
if verbose {
eprintln!("Done.");
}
Ok(())
}