From 5372294b6449d1e57b183ae674337895db86b331 Mon Sep 17 00:00:00 2001 From: Christopher Serr Date: Mon, 16 Sep 2024 23:57:05 +0200 Subject: [PATCH] Support the Tail Call Proposal (#4111) --- CHANGELOG.md | 5 ++++- crates/cli-support/Cargo.toml | 2 +- crates/cli-support/src/descriptors.rs | 12 ++++++++++++ crates/cli/Cargo.toml | 2 +- crates/externref-xform/Cargo.toml | 2 +- crates/externref-xform/src/lib.rs | 15 ++++++++------- crates/multi-value-xform/Cargo.toml | 2 +- crates/threads-xform/Cargo.toml | 2 +- crates/wasm-conventions/Cargo.toml | 2 +- crates/wasm-interpreter/Cargo.toml | 2 +- crates/wasm-interpreter/src/lib.rs | 18 ++++++++++++------ 11 files changed, 43 insertions(+), 21 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 20fb6ba7308..7ae724f8cbc 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,9 @@ ### Added +* Added support for the WebAssembly `Tail Call` proposal. + [#4111](https://github.com/rustwasm/wasm-bindgen/pull/4111) + * Add bindings for `RTCPeerConnection.setConfiguration(RTCConfiguration)` method. [#4105](https://github.com/rustwasm/wasm-bindgen/pull/4105) @@ -204,7 +207,7 @@ Released 2024-08-13 * Fix MDN links to static interface methods. [#4010](https://github.com/rustwasm/wasm-bindgen/pull/4010) - + * Fixed Deno support. [#3990](https://github.com/rustwasm/wasm-bindgen/pull/3990) diff --git a/crates/cli-support/Cargo.toml b/crates/cli-support/Cargo.toml index 9513c5adbdf..1486027f9d4 100644 --- a/crates/cli-support/Cargo.toml +++ b/crates/cli-support/Cargo.toml @@ -22,7 +22,7 @@ serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" tempfile = "3.0" unicode-ident = "1.0.5" -walrus = "0.21" +walrus = "0.21.2" wasm-bindgen-externref-xform = { path = '../externref-xform', version = '=0.2.93' } wasm-bindgen-multi-value-xform = { path = '../multi-value-xform', version = '=0.2.93' } wasm-bindgen-shared = { path = "../shared", version = '=0.2.93' } diff --git a/crates/cli-support/src/descriptors.rs b/crates/cli-support/src/descriptors.rs index 83617900532..30cd06db029 100644 --- a/crates/cli-support/src/descriptors.rs +++ b/crates/cli-support/src/descriptors.rs @@ -199,6 +199,12 @@ impl WasmBindgenDescriptorsSection { self.found = true; } } + + fn visit_return_call(&mut self, instr: &walrus::ir::ReturnCall) { + if instr.func == self.wbindgen_describe_closure { + self.found = true; + } + } } struct UpdateDescribeClosure { @@ -212,6 +218,12 @@ impl WasmBindgenDescriptorsSection { call.func = self.replacement; } } + + fn visit_return_call_mut(&mut self, instr: &mut walrus::ir::ReturnCall) { + if instr.func == self.wbindgen_describe_closure { + instr.func = self.replacement; + } + } } } } diff --git a/crates/cli/Cargo.toml b/crates/cli/Cargo.toml index 66e39de960e..f6fb21aebb6 100644 --- a/crates/cli/Cargo.toml +++ b/crates/cli/Cargo.toml @@ -31,7 +31,7 @@ serde = { version = "1.0", features = ['derive'] } serde_derive = "1.0" serde_json = "1.0" ureq = { version = "2.7", default-features = false, features = ["brotli", "gzip"] } -walrus = { version = "0.21", features = ['parallel'] } +walrus = { version = "0.21.2", features = ['parallel'] } wasm-bindgen-cli-support = { path = "../cli-support", version = "=0.2.93" } wasm-bindgen-shared = { path = "../shared", version = "=0.2.93" } diff --git a/crates/externref-xform/Cargo.toml b/crates/externref-xform/Cargo.toml index 27feed12b5d..3131625ec6e 100644 --- a/crates/externref-xform/Cargo.toml +++ b/crates/externref-xform/Cargo.toml @@ -15,7 +15,7 @@ version = "0.2.93" [dependencies] anyhow = "1.0" -walrus = "0.21" +walrus = "0.21.2" wasm-bindgen-wasm-conventions = { path = "../wasm-conventions", version = "=0.2.93" } [dev-dependencies] diff --git a/crates/externref-xform/src/lib.rs b/crates/externref-xform/src/lib.rs index 7ddf593b2cf..dae449264c0 100644 --- a/crates/externref-xform/src/lib.rs +++ b/crates/externref-xform/src/lib.rs @@ -722,18 +722,19 @@ impl Transform<'_> { impl VisitorMut for Rewrite<'_, '_> { fn start_instr_seq_mut(&mut self, seq: &mut InstrSeq) { for i in (0..seq.instrs.len()).rev() { - let call = match &mut seq.instrs[i].0 { - Instr::Call(call) => call, + let func = match &mut seq.instrs[i].0 { + Instr::Call(Call { func }) => func, + Instr::ReturnCall(ReturnCall { func }) => func, _ => continue, }; - let intrinsic = match self.xform.intrinsic_map.get(&call.func) { + let intrinsic = match self.xform.intrinsic_map.get(func) { Some(f) => f, None => { // If this wasn't a call of an intrinsic, but it was a // call of one of our old import functions then we // switch the functions we're calling here. - if let Some(f) = self.xform.import_map.get(&call.func) { - call.func = *f; + if let Some(f) = self.xform.import_map.get(func) { + *func = *f; } continue; } @@ -776,8 +777,8 @@ impl Transform<'_> { seq.instrs .insert(i, (RefNull { ty }.into(), InstrLocId::default())); } - Intrinsic::DropRef => call.func = self.heap_dealloc, - Intrinsic::CloneRef => call.func = self.clone_ref, + Intrinsic::DropRef => *func = self.heap_dealloc, + Intrinsic::CloneRef => *func = self.clone_ref, } } } diff --git a/crates/multi-value-xform/Cargo.toml b/crates/multi-value-xform/Cargo.toml index 8361b0b4d10..af64348884c 100644 --- a/crates/multi-value-xform/Cargo.toml +++ b/crates/multi-value-xform/Cargo.toml @@ -15,7 +15,7 @@ version = "0.2.93" [dependencies] anyhow = "1.0" -walrus = "0.21" +walrus = "0.21.2" wasm-bindgen-wasm-conventions = { path = "../wasm-conventions", version = "=0.2.93" } [dev-dependencies] diff --git a/crates/threads-xform/Cargo.toml b/crates/threads-xform/Cargo.toml index df6ca461e9f..d702fc6169e 100644 --- a/crates/threads-xform/Cargo.toml +++ b/crates/threads-xform/Cargo.toml @@ -15,7 +15,7 @@ version = "0.2.93" [dependencies] anyhow = "1.0" -walrus = "0.21" +walrus = "0.21.2" wasm-bindgen-wasm-conventions = { path = "../wasm-conventions", version = "=0.2.93" } [dev-dependencies] diff --git a/crates/wasm-conventions/Cargo.toml b/crates/wasm-conventions/Cargo.toml index c840850a07f..9ff8a9ffeb2 100644 --- a/crates/wasm-conventions/Cargo.toml +++ b/crates/wasm-conventions/Cargo.toml @@ -13,7 +13,7 @@ version = "0.2.93" [dependencies] leb128 = "0.2" -walrus = "0.21" +walrus = "0.21.2" # Matching the version `walrus` depends on. anyhow = "1.0" log = "0.4" diff --git a/crates/wasm-interpreter/Cargo.toml b/crates/wasm-interpreter/Cargo.toml index 899025b7a09..ce62ffd1091 100644 --- a/crates/wasm-interpreter/Cargo.toml +++ b/crates/wasm-interpreter/Cargo.toml @@ -16,7 +16,7 @@ version = "0.2.93" [dependencies] anyhow = "1.0" log = "0.4" -walrus = "0.21" +walrus = "0.21.2" wasm-bindgen-wasm-conventions = { path = "../wasm-conventions", version = "0.2.93" } [dev-dependencies] diff --git a/crates/wasm-interpreter/src/lib.rs b/crates/wasm-interpreter/src/lib.rs index 23729a17e14..a45772ad5a0 100644 --- a/crates/wasm-interpreter/src/lib.rs +++ b/crates/wasm-interpreter/src/lib.rs @@ -338,13 +338,14 @@ impl Frame<'_> { stack.pop().unwrap(); } - Instr::Call(e) => { + Instr::Call(Call { func }) | Instr::ReturnCall(ReturnCall { func }) => { + let func = *func; // If this function is calling the `__wbindgen_describe` // function, which we've precomputed the id for, then // it's telling us about the next `u32` element in the // descriptor to return. We "call" the imported function // here by directly inlining it. - if Some(e.func) == self.interp.describe_id { + if Some(func) == self.interp.describe_id { let val = stack.pop().unwrap(); log::debug!("__wbindgen_describe({})", val); self.interp.descriptor.push(val as u32); @@ -354,7 +355,7 @@ impl Frame<'_> { // slightly different signature. Note that we don't eval the // previous arguments because they shouldn't have any side // effects we're interested in. - } else if Some(e.func) == self.interp.describe_closure_id { + } else if Some(func) == self.interp.describe_closure_id { let val = stack.pop().unwrap(); stack.pop(); stack.pop(); @@ -368,7 +369,7 @@ impl Frame<'_> { if self .module .funcs - .get(e.func) + .get(func) .name .as_ref() .is_some_and(|name| { @@ -380,12 +381,17 @@ impl Frame<'_> { return Ok(()); } - let ty = self.module.types.get(self.module.funcs.get(e.func).ty()); + let ty = self.module.types.get(self.module.funcs.get(func).ty()); let args = (0..ty.params().len()) .map(|_| stack.pop().unwrap()) .collect::>(); - self.interp.call(e.func, self.module, &args); + self.interp.call(func, self.module, &args); + } + + if let Instr::ReturnCall(_) = instr { + log::debug!("return_call"); + self.done = true; } }