Skip to content

Commit 549b77d

Browse files
axicpepyakin
authored andcommitted
Make crate thread-safe (by removing set_global_codegen_config) (#43)
* Add thread-safe BinaryenModuleOptimizeWithSettings * Derive Default trait on CodegenConfig (which sets -O0) * Change optimize() to take CodegenConfig * Add thread-safe BinaryenModuleRunPassesWithSettings * Change run_optimization_passes() to take CodegenConfig * Remove set_global_codegen_config
1 parent 5c2576d commit 549b77d

File tree

4 files changed

+68
-48
lines changed

4 files changed

+68
-48
lines changed

binaryen-sys/Shim.cpp

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
using namespace wasm;
1818
using namespace std;
1919

20-
// NOTE: this is a copy from binaryen-c.cpp
20+
// NOTE: this is based on BinaryenModuleRead from binaryen-c.cpp
2121
extern "C" BinaryenModuleRef BinaryenModuleSafeRead(const char* input, size_t inputSize) {
2222
auto* wasm = new Module;
2323
vector<char> buffer(input, input + inputSize);
@@ -56,3 +56,36 @@ extern "C" void BinaryenShimDisposeBinaryenModuleAllocateAndWriteResult(
5656
free(result.sourceMap);
5757
}
5858
}
59+
60+
// NOTE: this is based on BinaryenModuleOptimizer from binaryen-c.cpp
61+
// Main benefit is being thread safe.
62+
extern "C" void BinaryenModuleOptimizeWithSettings(
63+
BinaryenModuleRef module, int shrinkLevel, int optimizeLevel, int debugInfo
64+
) {
65+
Module* wasm = (Module*)module;
66+
PassRunner passRunner(wasm);
67+
passRunner.options = PassOptions::getWithDefaultOptimizationOptions();
68+
passRunner.options.shrinkLevel = shrinkLevel;
69+
passRunner.options.optimizeLevel = optimizeLevel;
70+
passRunner.options.debugInfo = debugInfo != 0;
71+
passRunner.addDefaultOptimizationPasses();
72+
passRunner.run();
73+
}
74+
75+
// NOTE: this is based on BinaryenModuleRunPasses from binaryen-c.cpp
76+
// Main benefit is being thread safe.
77+
extern "C" void BinaryenModuleRunPassesWithSettings(
78+
BinaryenModuleRef module, const char** passes, BinaryenIndex numPasses,
79+
int shrinkLevel, int optimizeLevel, int debugInfo
80+
) {
81+
Module* wasm = (Module*)module;
82+
PassRunner passRunner(wasm);
83+
passRunner.options = PassOptions::getWithDefaultOptimizationOptions();
84+
passRunner.options.shrinkLevel = shrinkLevel;
85+
passRunner.options.optimizeLevel = optimizeLevel;
86+
passRunner.options.debugInfo = debugInfo != 0;
87+
for (BinaryenIndex i = 0; i < numPasses; i++) {
88+
passRunner.add(passes[i]);
89+
}
90+
passRunner.run();
91+
}

binaryen-sys/wrapper.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,15 @@ void BinaryenShimDisposeBinaryenModuleAllocateAndWriteResult(
1414
BinaryenModuleAllocateAndWriteResult result
1515
);
1616

17+
void BinaryenModuleOptimizeWithSettings(
18+
BinaryenModuleRef module, int shrinkLevel, int optimizeLevel, int debugInfo
19+
);
20+
21+
void BinaryenModuleRunPassesWithSettings(
22+
BinaryenModuleRef module, const char** passes, BinaryenIndex numPasses,
23+
int shrinkLevel, int optimizeLevel, int debugInfo
24+
);
25+
1726
#ifdef __cplusplus
1827
}
1928
#endif

examples/wasm_opt.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -97,8 +97,7 @@ fn main() {
9797
}
9898
};
9999
let mut module = read_module(&args.input_path);
100-
binaryen::set_global_codegen_config(&args.codegen_config);
101-
module.optimize();
100+
module.optimize(&args.codegen_config);
102101

103102
let optimized_wasm = module.write();
104103
write_module(&args.output_path, &optimized_wasm);

src/lib.rs

Lines changed: 24 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -11,15 +11,13 @@ pub use binaryen_sys as ffi;
1111
use std::rc::Rc;
1212
use std::os::raw::c_char;
1313
use std::{ptr, slice};
14-
use std::sync::{Once, Mutex};
1514
use std::ffi::CString;
1615
use std::str::FromStr;
1716

1817
pub mod tools;
1918

2019
/// Codegen configuration.
21-
///
22-
/// Use `set_global_codegen_config`.
20+
#[derive(Default)]
2321
pub struct CodegenConfig {
2422
/// 0, 1, 2 correspond to -O0, -Os, -Oz
2523
pub shrink_level: u32,
@@ -29,38 +27,6 @@ pub struct CodegenConfig {
2927
pub debug_info: bool,
3028
}
3129

32-
/// Set the global code generation configuration.
33-
///
34-
/// This can be used to set parameters before running `optimize` function.
35-
/// However, this can influence behavior of running binaryen passes in general (for example,
36-
/// `auto_drop` is implemented via a pass).
37-
pub fn set_global_codegen_config(codegen_config: &CodegenConfig) {
38-
static mut MUTEX: Option<Mutex<()>> = None;
39-
static INIT: Once = Once::new();
40-
41-
// Initialize the mutex only once.
42-
INIT.call_once(|| {
43-
unsafe {
44-
// This is safe since we are in `call_once`, and it will execute this closure only once.
45-
// If the second invocation happens before the closure returned then the invocation will be blocked until
46-
// the closure returns.
47-
MUTEX = Some(Mutex::new(()));
48-
}
49-
});
50-
51-
unsafe {
52-
let _guard = MUTEX
53-
.as_ref()
54-
.expect("should be initialized in call_once block above")
55-
.lock()
56-
.unwrap();
57-
58-
ffi::BinaryenSetOptimizeLevel(codegen_config.optimization_level as i32);
59-
ffi::BinaryenSetShrinkLevel(codegen_config.shrink_level as i32);
60-
ffi::BinaryenSetDebugInfo(codegen_config.debug_info as i32);
61-
}
62-
}
63-
6430
fn is_valid_pass(pass: &str) -> bool {
6531
ffi::passes::OptimizationPass::from_str(pass).is_ok()
6632
}
@@ -112,18 +78,22 @@ impl Module {
11278
}
11379

11480
/// Run the standard optimization passes on the module.
115-
///
116-
/// It will take into account code generation configuration set by `set_global_codegen_config`.
117-
pub fn optimize(&mut self) {
118-
unsafe { ffi::BinaryenModuleOptimize(self.inner.raw) }
81+
pub fn optimize(&mut self, codegen_config: &CodegenConfig) {
82+
unsafe {
83+
ffi::BinaryenModuleOptimizeWithSettings(
84+
self.inner.raw,
85+
codegen_config.shrink_level as i32,
86+
codegen_config.optimization_level as i32,
87+
codegen_config.debug_info as i32
88+
)
89+
}
11990
}
12091

12192
/// Run a specified set of optimization passes on the module.
122-
///
123-
/// This WILL NOT take into account code generation configuration set by `set_global_codegen_config`.
12493
pub fn run_optimization_passes<B: AsRef<str>, I: IntoIterator<Item = B>>(
12594
&mut self,
12695
passes: I,
96+
codegen_config: &CodegenConfig
12797
) -> Result<(), ()> {
12898
let mut cstr_vec: Vec<_> = vec![];
12999

@@ -141,7 +111,16 @@ impl Module {
141111
.map(|pass| pass.as_ptr())
142112
.collect();
143113

144-
unsafe { ffi::BinaryenModuleRunPasses(self.inner.raw, ptr_vec.as_mut_ptr(), ptr_vec.len() as u32) };
114+
unsafe {
115+
ffi::BinaryenModuleRunPassesWithSettings(
116+
self.inner.raw,
117+
ptr_vec.as_mut_ptr(),
118+
ptr_vec.len() as u32,
119+
codegen_config.shrink_level as i32,
120+
codegen_config.optimization_level as i32,
121+
codegen_config.debug_info as i32
122+
)
123+
};
145124
Ok(())
146125
}
147126

@@ -217,15 +196,15 @@ mod tests {
217196

218197
assert!(module.is_valid());
219198

220-
module.run_optimization_passes(&["vacuum", "untee"]).expect("passes succeeded");
199+
module.run_optimization_passes(&["vacuum", "untee"], &CodegenConfig::default()).expect("passes succeeded");
221200

222201
assert!(module.is_valid());
223202
}
224203

225204
#[test]
226205
fn test_invalid_optimization_passes() {
227206
let mut module = Module::new();
228-
assert!(module.run_optimization_passes(&["invalid"]).is_err());
207+
assert!(module.run_optimization_passes(&["invalid"], &CodegenConfig::default()).is_err());
229208
}
230209

231210
#[test]
@@ -243,7 +222,7 @@ mod tests {
243222

244223
let mut module = Module::read(&input).unwrap();
245224
assert!(module.is_valid());
246-
module.optimize();
225+
module.optimize(&CodegenConfig::default());
247226
assert!(module.is_valid());
248227
assert_eq!(module.write(), expected);
249228
}

0 commit comments

Comments
 (0)