Skip to content

Commit 60f3b1d

Browse files
authored
Pass actual stack pointers around instead of address 8 (#2249)
* Pass actual stack pointers around instead of address 8 This commit updates the implementation of passing return pointers from JS to wasm to actually modify the wasm's shadow stack pointer instead of manufacturing the arbitrary address of 8. The purpose of this is to correctly handle threaded scenarios where each thread will write to its own area instead of everyone trying to compete at address 8. The implementation here will lazily, if necessary, export the stack pointer we find the module and modify it as necessary. Closes #2218 * Fix benchmarks build
1 parent d70ae96 commit 60f3b1d

File tree

7 files changed

+44
-18
lines changed

7 files changed

+44
-18
lines changed

azure-pipelines.yml

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -211,11 +211,12 @@ jobs:
211211
displayName: "Build benchmarks"
212212
steps:
213213
- template: ci/azure-install-rust.yml
214-
- template: ci/azure-install-wasm-pack.yml
215-
- script: wasm-pack build --target web benchmarks
214+
- script: rustup target add wasm32-unknown-unknown
215+
displayName: "add target"
216+
- script: cargo build --manifest-path benchmarks/Cargo.toml --release --target wasm32-unknown-unknown
216217
displayName: "build benchmarks"
217-
- script: rm -f benchmarks/pkg/.gitignore
218-
displayName: "remove stray gitignore"
218+
- script: cargo run -p wasm-bindgen-cli target/wasm32-unknown-unknown/release/wasm_bindgen_benchmark.wasm --out-dir benchmarks/pkg --target web
219+
displayName: "run wasm-bindgen"
219220
- task: PublishPipelineArtifact@0
220221
inputs:
221222
artifactName: benchmarks

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

Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -463,13 +463,6 @@ impl<'a, 'b> JsBuilder<'a, 'b> {
463463
}
464464

465465
fn instruction(js: &mut JsBuilder, instr: &Instruction, log_error: &mut bool) -> Result<(), Error> {
466-
// Here first properly aligned nonzero address is chosen to be the
467-
// out-pointer. We use the address for a BigInt64Array sometimes which
468-
// means it needs to be 8-byte aligned. Otherwise valid code is
469-
// unlikely to ever be working around address 8, so this should be a
470-
// safe address to use for returning data through.
471-
let retptr_val = 8;
472-
473466
match instr {
474467
Instruction::Standard(wit_walrus::Instruction::ArgGet(n)) => {
475468
let arg = js.arg(*n).to_string();
@@ -566,7 +559,20 @@ fn instruction(js: &mut JsBuilder, instr: &Instruction, log_error: &mut bool) ->
566559
js.string_to_memory(*mem, *malloc, *realloc)?;
567560
}
568561

569-
Instruction::Retptr => js.stack.push(retptr_val.to_string()),
562+
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));
574+
js.stack.push("retptr".to_string());
575+
}
570576

571577
Instruction::StoreRetptr { ty, offset, mem } => {
572578
let (mem, size) = match ty {
@@ -599,7 +605,7 @@ fn instruction(js: &mut JsBuilder, instr: &Instruction, log_error: &mut bool) ->
599605
// If we're loading from the return pointer then we must have pushed
600606
// it earlier, and we always push the same value, so load that value
601607
// here
602-
let expr = format!("{}()[{} / {} + {}]", mem, retptr_val, size, offset);
608+
let expr = format!("{}()[retptr / {} + {}]", mem, size, offset);
603609
js.prelude(&format!("var r{} = {};", offset, expr));
604610
js.push(format!("r{}", offset));
605611
}

crates/cli-support/src/multivalue.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ fn extract_xform<'a>(
6464
// If the first instruction is a `Retptr`, then this must be an exported
6565
// adapter which calls a wasm-defined function. Something we'd like to
6666
// adapt to multi-value!
67-
if let Some(Instruction::Retptr) = instructions.first().map(|e| &e.instr) {
67+
if let Some(Instruction::Retptr { .. }) = instructions.first().map(|e| &e.instr) {
6868
instructions.remove(0);
6969
let mut types = Vec::new();
7070
instructions.retain(|instruction| match &instruction.instr {

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

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1292,8 +1292,23 @@ impl<'a> Context<'a> {
12921292
// everything into the outgoing arguments.
12931293
let mut instructions = Vec::new();
12941294
if uses_retptr {
1295+
let size = ret.input.iter().fold(0, |sum, ty| {
1296+
let size = match ty {
1297+
AdapterType::I32 => 4,
1298+
AdapterType::I64 => 8,
1299+
AdapterType::F32 => 4,
1300+
AdapterType::F64 => 8,
1301+
_ => panic!("unsupported type in retptr {:?}", ty),
1302+
};
1303+
let sum_rounded_up = (sum + (size - 1)) & (!(size - 1));
1304+
sum_rounded_up + size
1305+
});
1306+
// Round the number of bytes up to a 16-byte alignment to ensure the
1307+
// stack pointer is always 16-byte aligned (which LLVM currently
1308+
// requires).
1309+
let size = (size + 15) & (!15);
12951310
instructions.push(InstructionData {
1296-
instr: Instruction::Retptr,
1311+
instr: Instruction::Retptr { size },
12971312
stack_change: StackChange::Modified {
12981313
pushed: 1,
12991314
popped: 0,

crates/cli-support/src/wit/section.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -234,7 +234,7 @@ fn translate_instruction(
234234
mem: *mem,
235235
malloc: *malloc,
236236
}),
237-
StoreRetptr { .. } | LoadRetptr { .. } | Retptr => {
237+
StoreRetptr { .. } | LoadRetptr { .. } | Retptr { .. } => {
238238
bail!("return pointers aren't supported in wasm interface types");
239239
}
240240
I32FromBool | BoolFromI32 => {

crates/cli-support/src/wit/standard.rs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -113,8 +113,11 @@ pub enum Instruction {
113113
offset: usize,
114114
mem: walrus::MemoryId,
115115
},
116-
/// An instruction which pushes the return pointer onto the stack.
117-
Retptr,
116+
/// An instruction which pushes the return pointer onto the stack, reserving
117+
/// `size` bytes of space.
118+
Retptr {
119+
size: u32,
120+
},
118121

119122
/// Pops a `bool` from the stack and pushes an `i32` equivalent
120123
I32FromBool,

crates/cli/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ Command line interface of the `#[wasm_bindgen]` attribute and project. For more
1212
information see https://github.com/rustwasm/wasm-bindgen.
1313
"""
1414
edition = '2018'
15+
default-run = 'wasm-bindgen'
1516

1617
[dependencies]
1718
curl = "0.4.13"

0 commit comments

Comments
 (0)