Skip to content

Commit b584407

Browse files
authored
Don't emit mutable globals (#2391)
We emit a shim function that sets the stack pointer, so we can avoid emitting mutable globals. Mutable globals aren't supported everywhere Wasm is.
1 parent d6d222c commit b584407

File tree

2 files changed

+52
-12
lines changed

2 files changed

+52
-12
lines changed

crates/cli-support/src/js/binding.rs

Lines changed: 6 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -560,17 +560,12 @@ fn instruction(js: &mut JsBuilder, instr: &Instruction, log_error: &mut bool) ->
560560
}
561561

562562
Instruction::Retptr { size } => {
563-
let sp = match js.cx.aux.shadow_stack_pointer {
564-
Some(s) => js.cx.export_name_of(s),
565-
// In theory this shouldn't happen since malloc is included in
566-
// most wasm binaries (and may be gc'd out) and that almost
567-
// always pulls in a stack pointer. We can try to synthesize
568-
// something here later if necessary.
569-
None => bail!("failed to find shadow stack pointer"),
570-
};
571-
js.prelude(&format!("const retptr = wasm.{}.value - {};", sp, size));
572-
js.prelude(&format!("wasm.{}.value = retptr;", sp));
573-
js.finally(&format!("wasm.{}.value += {};", sp, size));
563+
js.cx.inject_stack_pointer_shim()?;
564+
js.prelude(&format!(
565+
"const retptr = wasm.__wbindgen_add_to_stack_pointer(-{});",
566+
size
567+
));
568+
js.finally(&format!("wasm.__wbindgen_add_to_stack_pointer({});", size));
574569
js.stack.push("retptr".to_string());
575570
}
576571

crates/cli-support/src/js/mod.rs

Lines changed: 46 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ use std::collections::{BTreeMap, BTreeSet, HashMap, HashSet};
1111
use std::fmt;
1212
use std::fs;
1313
use std::path::{Path, PathBuf};
14-
use walrus::{FunctionId, ImportId, MemoryId, Module, TableId};
14+
use walrus::{FunctionId, ImportId, MemoryId, Module, TableId, ValType};
1515

1616
mod binding;
1717

@@ -53,6 +53,9 @@ pub struct Context<'a> {
5353
/// names.
5454
memory_indices: HashMap<MemoryId, usize>,
5555
table_indices: HashMap<TableId, usize>,
56+
57+
/// A flag to track if the stack pointer setter shim has been injected.
58+
stack_pointer_shim_injected: bool,
5659
}
5760

5861
#[derive(Default)]
@@ -100,6 +103,7 @@ impl<'a> Context<'a> {
100103
aux,
101104
memory_indices: Default::default(),
102105
table_indices: Default::default(),
106+
stack_pointer_shim_injected: false,
103107
})
104108
}
105109

@@ -3305,6 +3309,47 @@ impl<'a> Context<'a> {
33053309
format!("{}{}", name, cnt)
33063310
}
33073311
}
3312+
3313+
fn inject_stack_pointer_shim(&mut self) -> Result<(), Error> {
3314+
if self.stack_pointer_shim_injected {
3315+
return Ok(());
3316+
}
3317+
let stack_pointer = match self.aux.shadow_stack_pointer {
3318+
Some(s) => s,
3319+
// In theory this shouldn't happen since malloc is included in
3320+
// most wasm binaries (and may be gc'd out) and that almost
3321+
// always pulls in a stack pointer. We can try to synthesize
3322+
// something here later if necessary.
3323+
None => bail!("failed to find shadow stack pointer"),
3324+
};
3325+
3326+
use walrus::ir::*;
3327+
3328+
let mut builder =
3329+
walrus::FunctionBuilder::new(&mut self.module.types, &[ValType::I32], &[ValType::I32]);
3330+
builder.name("__wbindgen_add_to_stack_pointer".to_string());
3331+
3332+
let mut body = builder.func_body();
3333+
let arg = self.module.locals.add(ValType::I32);
3334+
3335+
// Create a shim function that mutate the stack pointer
3336+
// to avoid exporting a mutable global.
3337+
body.local_get(arg)
3338+
.global_get(stack_pointer)
3339+
.binop(BinaryOp::I32Add)
3340+
.global_set(stack_pointer)
3341+
.global_get(stack_pointer);
3342+
3343+
let add_to_stack_pointer_func = builder.finish(vec![arg], &mut self.module.funcs);
3344+
3345+
self.module
3346+
.exports
3347+
.add("__wbindgen_add_to_stack_pointer", add_to_stack_pointer_func);
3348+
3349+
self.stack_pointer_shim_injected = true;
3350+
3351+
Ok(())
3352+
}
33083353
}
33093354

33103355
fn check_duplicated_getter_and_setter_names(

0 commit comments

Comments
 (0)