wasm_opt.rs 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293
  1. use crate::config::WasmOptLevel;
  2. use crate::{Result, WasmOptConfig};
  3. use std::path::Path;
  4. /// Write these wasm bytes with a particular set of optimizations
  5. pub async fn write_wasm(bytes: &[u8], output_path: &Path, cfg: &WasmOptConfig) -> Result<()> {
  6. tokio::fs::write(output_path, bytes).await?;
  7. optimize(output_path, output_path, cfg).await?;
  8. Ok(())
  9. }
  10. #[allow(unreachable_code)]
  11. pub async fn optimize(input_path: &Path, output_path: &Path, cfg: &WasmOptConfig) -> Result<()> {
  12. #[cfg(feature = "optimizations")]
  13. return run_from_lib(input_path, output_path, cfg).await;
  14. // It's okay not to run wasm-opt but we should *really* try it
  15. if which::which("wasm-opt").is_err() {
  16. tracing::warn!("wasm-opt not found and CLI is compiled without optimizations. Skipping optimization for {}", input_path.display());
  17. return Ok(());
  18. }
  19. run_locally(input_path, output_path, cfg).await?;
  20. Ok(())
  21. }
  22. async fn run_locally(input_path: &Path, output_path: &Path, cfg: &WasmOptConfig) -> Result<()> {
  23. let mut args = vec![
  24. // needed by wasm-bindgen
  25. "--enable-reference-types",
  26. ];
  27. if cfg.memory_packing {
  28. // needed for our current approach to bundle splitting to work properly
  29. // todo(jon): emit the main module's data section in chunks instead of all at once
  30. args.push("--memory-packing");
  31. }
  32. if !cfg.debug {
  33. args.push("--strip-debug");
  34. } else {
  35. args.push("--debuginfo");
  36. }
  37. let level = match cfg.level {
  38. WasmOptLevel::Z => "-Oz",
  39. WasmOptLevel::S => "-Os",
  40. WasmOptLevel::Zero => "-O0",
  41. WasmOptLevel::One => "-O1",
  42. WasmOptLevel::Two => "-O2",
  43. WasmOptLevel::Three => "-O3",
  44. WasmOptLevel::Four => "-O4",
  45. };
  46. tokio::process::Command::new("wasm-opt")
  47. .arg(input_path)
  48. .arg(level)
  49. .arg("-o")
  50. .arg(output_path)
  51. .args(args)
  52. .output()
  53. .await?;
  54. Ok(())
  55. }
  56. /// Use the `wasm_opt` crate
  57. #[cfg(feature = "optimizations")]
  58. async fn run_from_lib(
  59. input_path: &Path,
  60. output_path: &Path,
  61. options: &WasmOptConfig,
  62. ) -> Result<()> {
  63. let mut level = match options.level {
  64. WasmOptLevel::Z => wasm_opt::OptimizationOptions::new_optimize_for_size_aggressively(),
  65. WasmOptLevel::S => wasm_opt::OptimizationOptions::new_optimize_for_size(),
  66. WasmOptLevel::Zero => wasm_opt::OptimizationOptions::new_opt_level_0(),
  67. WasmOptLevel::One => wasm_opt::OptimizationOptions::new_opt_level_1(),
  68. WasmOptLevel::Two => wasm_opt::OptimizationOptions::new_opt_level_2(),
  69. WasmOptLevel::Three => wasm_opt::OptimizationOptions::new_opt_level_3(),
  70. WasmOptLevel::Four => wasm_opt::OptimizationOptions::new_opt_level_4(),
  71. };
  72. level
  73. .enable_feature(wasm_opt::Feature::ReferenceTypes)
  74. .add_pass(wasm_opt::Pass::MemoryPacking)
  75. .debug_info(options.debug)
  76. .run(input_path, output_path)
  77. .map_err(|err| crate::Error::Other(anyhow::anyhow!(err)))?;
  78. Ok(())
  79. }