contract_build/
wasm_opt.rs1use anyhow::Result;
18use wasm_opt::{
19 Feature,
20 OptimizationOptions,
21 Pass,
22};
23
24use std::{
25 fmt,
26 path::PathBuf,
27 str,
28};
29
30pub struct WasmOptHandler {
32 optimization_level: OptimizationPasses,
34 keep_debug_symbols: bool,
36}
37
38impl WasmOptHandler {
39 pub fn new(
44 optimization_level: OptimizationPasses,
45 keep_debug_symbols: bool,
46 ) -> Result<Self> {
47 Ok(Self {
48 optimization_level,
49 keep_debug_symbols,
50 })
51 }
52
53 pub fn optimize(&self, original_wasm: &PathBuf, dest_wasm: &PathBuf) -> Result<()> {
57 tracing::debug!(
58 "Optimization level passed to wasm-opt: {}",
59 self.optimization_level
60 );
61
62 OptimizationOptions::from(self.optimization_level)
63 .mvp_features_only()
64 .enable_feature(Feature::SignExt)
67 .add_pass(Pass::SignextLowering)
71 .zero_filled_memory(true)
75 .debug_info(self.keep_debug_symbols)
76 .run(original_wasm, dest_wasm)?;
77
78 if !dest_wasm.exists() {
79 return Err(anyhow::anyhow!(
80 "Optimization failed, optimized wasm output file `{}` not found.",
81 dest_wasm.display()
82 ))
83 }
84
85 Ok(())
86 }
87}
88
89#[derive(
90 Clone, Copy, Debug, Default, Eq, PartialEq, serde::Serialize, serde::Deserialize,
91)]
92pub enum OptimizationPasses {
93 Zero,
94 One,
95 Two,
96 Three,
97 Four,
98 S,
99 #[default]
100 Z,
101}
102
103impl fmt::Display for OptimizationPasses {
104 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
105 let out = match self {
106 OptimizationPasses::Zero => "0",
107 OptimizationPasses::One => "1",
108 OptimizationPasses::Two => "2",
109 OptimizationPasses::Three => "3",
110 OptimizationPasses::Four => "4",
111 OptimizationPasses::S => "s",
112 OptimizationPasses::Z => "z",
113 };
114 write!(f, "{out}")
115 }
116}
117
118impl str::FromStr for OptimizationPasses {
119 type Err = anyhow::Error;
120
121 fn from_str(input: &str) -> std::result::Result<Self, Self::Err> {
122 let normalized_input = input.replace('"', "").to_lowercase();
126 match normalized_input.as_str() {
127 "0" => Ok(OptimizationPasses::Zero),
128 "1" => Ok(OptimizationPasses::One),
129 "2" => Ok(OptimizationPasses::Two),
130 "3" => Ok(OptimizationPasses::Three),
131 "4" => Ok(OptimizationPasses::Four),
132 "s" => Ok(OptimizationPasses::S),
133 "z" => Ok(OptimizationPasses::Z),
134 _ => anyhow::bail!("Unknown optimization passes for option {}", input),
135 }
136 }
137}
138
139impl From<String> for OptimizationPasses {
140 fn from(str: String) -> Self {
141 <OptimizationPasses as str::FromStr>::from_str(&str).expect("conversion failed")
142 }
143}
144
145impl From<OptimizationPasses> for OptimizationOptions {
146 fn from(passes: OptimizationPasses) -> OptimizationOptions {
147 match passes {
148 OptimizationPasses::Zero => OptimizationOptions::new_opt_level_0(),
149 OptimizationPasses::One => OptimizationOptions::new_opt_level_1(),
150 OptimizationPasses::Two => OptimizationOptions::new_opt_level_2(),
151 OptimizationPasses::Three => OptimizationOptions::new_opt_level_3(),
152 OptimizationPasses::Four => OptimizationOptions::new_opt_level_4(),
153 OptimizationPasses::S => OptimizationOptions::new_optimize_for_size(),
154 OptimizationPasses::Z => {
155 OptimizationOptions::new_optimize_for_size_aggressively()
156 }
157 }
158 }
159}
160
161#[derive(serde::Serialize, serde::Deserialize)]
163pub struct OptimizationResult {
164 pub original_size: f64,
166 pub optimized_size: f64,
168}