From c915870526c3466d5bd880a4688d06b22718b092 Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Tue, 13 Nov 2018 08:10:05 -0800 Subject: [PATCH] Remove temporary object allocation When returning a ptr/length for allocations and such wasm-bindgen's generated JS would previously return an array with two elements. It turns out this doesn't optimize well in all engines! (See #1031). It looks like we can optimize the array destructuring a bit more, but this is all generated code which doesn't need to be too readable so we can also remove the temporary allocation entirely and just pass the second element of this array through a global instead of the return value. Closes #1031 --- crates/cli-support/src/js/js2rust.rs | 2 +- crates/cli-support/src/js/mod.rs | 26 +++++++++++++++++++------- crates/cli-support/src/js/rust2js.rs | 3 ++- 3 files changed, 22 insertions(+), 9 deletions(-) diff --git a/crates/cli-support/src/js/js2rust.rs b/crates/cli-support/src/js/js2rust.rs index 07c4e327f54..0243d605b4f 100644 --- a/crates/cli-support/src/js/js2rust.rs +++ b/crates/cli-support/src/js/js2rust.rs @@ -155,7 +155,7 @@ impl<'a, 'b> Js2Rust<'a, 'b> { format!("{}({})", func, name) }; self.prelude(&format!( - "const [ptr{i}, len{i}] = {val};", + "const ptr{i} = {val};\nconst len{i} = WASM_VECTOR_LEN;", i = i, val = val, )); diff --git a/crates/cli-support/src/js/mod.rs b/crates/cli-support/src/js/mod.rs index e2392bdbe80..ef3806ea852 100644 --- a/crates/cli-support/src/js/mod.rs +++ b/crates/cli-support/src/js/mod.rs @@ -319,8 +319,8 @@ impl<'a> Context<'a> { function(i, len_ptr) { let obj = getObject(i); if (typeof(obj) !== 'string') return 0; - const [ptr, len] = passStringToWasm(obj); - getUint32Memory()[len_ptr / 4] = len; + const ptr = passStringToWasm(obj); + getUint32Memory()[len_ptr / 4] = WASM_VECTOR_LEN; return ptr; } ", @@ -368,9 +368,9 @@ impl<'a> Context<'a> { Ok(String::from( " function(idx, ptrptr) { - const [ptr, len] = passStringToWasm(JSON.stringify(getObject(idx))); + const ptr = passStringToWasm(JSON.stringify(getObject(idx))); getUint32Memory()[ptrptr / 4] = ptr; - return len; + return WASM_VECTOR_LEN; } ", )) @@ -994,6 +994,13 @@ impl<'a> Context<'a> { )); } + fn expose_wasm_vector_len(&mut self) { + if !self.exposed_globals.insert("wasm_vector_len") { + return; + } + self.global("let WASM_VECTOR_LEN = 0;"); + } + fn expose_pass_string_to_wasm(&mut self) -> Result<(), Error> { if !self.exposed_globals.insert("pass_string_to_wasm") { return Ok(()); @@ -1001,6 +1008,7 @@ impl<'a> Context<'a> { self.require_internal_export("__wbindgen_malloc")?; self.expose_text_encoder(); self.expose_uint8_memory(); + self.expose_wasm_vector_len(); let debug = if self.config.debug { " if (typeof(arg) !== 'string') throw new Error('expected a string argument'); @@ -1015,7 +1023,8 @@ impl<'a> Context<'a> { const buf = cachedTextEncoder.encode(arg); const ptr = wasm.__wbindgen_malloc(buf.length); getUint8Memory().set(buf, ptr); - return [ptr, buf.length]; + WASM_VECTOR_LEN = buf.length; + return ptr; }} ", debug @@ -1068,7 +1077,8 @@ impl<'a> Context<'a> { for (let i = 0; i < array.length; i++) { mem[ptr / 4 + i] = addHeapObject(array[i]); } - return [ptr, array.length]; + WASM_VECTOR_LEN = array.length; + return ptr; } ", @@ -1086,12 +1096,14 @@ impl<'a> Context<'a> { return Ok(()); } self.require_internal_export("__wbindgen_malloc")?; + self.expose_wasm_vector_len(); self.global(&format!( " function {}(arg) {{ const ptr = wasm.__wbindgen_malloc(arg.length * {size}); {}().set(arg, ptr / {size}); - return [ptr, arg.length]; + WASM_VECTOR_LEN = arg.length; + return ptr; }} ", name, diff --git a/crates/cli-support/src/js/rust2js.rs b/crates/cli-support/src/js/rust2js.rs index 6e6cc246af9..a6aba6c2445 100644 --- a/crates/cli-support/src/js/rust2js.rs +++ b/crates/cli-support/src/js/rust2js.rs @@ -328,7 +328,8 @@ impl<'a, 'b> Rust2Js<'a, 'b> { self.ret_expr = format!( "\ {} - const [retptr, retlen] = {}; + const retptr = {}; + const retlen = WASM_VECTOR_LEN; const mem = getUint32Memory(); mem[ret / 4] = retptr; mem[ret / 4 + 1] = retlen;