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
This commit is contained in:
Alex Crichton 2018-11-13 08:10:05 -08:00
parent 8520a54f63
commit c915870526
3 changed files with 22 additions and 9 deletions

View File

@ -155,7 +155,7 @@ impl<'a, 'b> Js2Rust<'a, 'b> {
format!("{}({})", func, name) format!("{}({})", func, name)
}; };
self.prelude(&format!( self.prelude(&format!(
"const [ptr{i}, len{i}] = {val};", "const ptr{i} = {val};\nconst len{i} = WASM_VECTOR_LEN;",
i = i, i = i,
val = val, val = val,
)); ));

View File

@ -319,8 +319,8 @@ impl<'a> Context<'a> {
function(i, len_ptr) { function(i, len_ptr) {
let obj = getObject(i); let obj = getObject(i);
if (typeof(obj) !== 'string') return 0; if (typeof(obj) !== 'string') return 0;
const [ptr, len] = passStringToWasm(obj); const ptr = passStringToWasm(obj);
getUint32Memory()[len_ptr / 4] = len; getUint32Memory()[len_ptr / 4] = WASM_VECTOR_LEN;
return ptr; return ptr;
} }
", ",
@ -368,9 +368,9 @@ impl<'a> Context<'a> {
Ok(String::from( Ok(String::from(
" "
function(idx, ptrptr) { function(idx, ptrptr) {
const [ptr, len] = passStringToWasm(JSON.stringify(getObject(idx))); const ptr = passStringToWasm(JSON.stringify(getObject(idx)));
getUint32Memory()[ptrptr / 4] = ptr; 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> { fn expose_pass_string_to_wasm(&mut self) -> Result<(), Error> {
if !self.exposed_globals.insert("pass_string_to_wasm") { if !self.exposed_globals.insert("pass_string_to_wasm") {
return Ok(()); return Ok(());
@ -1001,6 +1008,7 @@ impl<'a> Context<'a> {
self.require_internal_export("__wbindgen_malloc")?; self.require_internal_export("__wbindgen_malloc")?;
self.expose_text_encoder(); self.expose_text_encoder();
self.expose_uint8_memory(); self.expose_uint8_memory();
self.expose_wasm_vector_len();
let debug = if self.config.debug { let debug = if self.config.debug {
" "
if (typeof(arg) !== 'string') throw new Error('expected a string argument'); 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 buf = cachedTextEncoder.encode(arg);
const ptr = wasm.__wbindgen_malloc(buf.length); const ptr = wasm.__wbindgen_malloc(buf.length);
getUint8Memory().set(buf, ptr); getUint8Memory().set(buf, ptr);
return [ptr, buf.length]; WASM_VECTOR_LEN = buf.length;
return ptr;
}} }}
", ",
debug debug
@ -1068,7 +1077,8 @@ impl<'a> Context<'a> {
for (let i = 0; i < array.length; i++) { for (let i = 0; i < array.length; i++) {
mem[ptr / 4 + i] = addHeapObject(array[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(()); return Ok(());
} }
self.require_internal_export("__wbindgen_malloc")?; self.require_internal_export("__wbindgen_malloc")?;
self.expose_wasm_vector_len();
self.global(&format!( self.global(&format!(
" "
function {}(arg) {{ function {}(arg) {{
const ptr = wasm.__wbindgen_malloc(arg.length * {size}); const ptr = wasm.__wbindgen_malloc(arg.length * {size});
{}().set(arg, ptr / {size}); {}().set(arg, ptr / {size});
return [ptr, arg.length]; WASM_VECTOR_LEN = arg.length;
return ptr;
}} }}
", ",
name, name,

View File

@ -328,7 +328,8 @@ impl<'a, 'b> Rust2Js<'a, 'b> {
self.ret_expr = format!( self.ret_expr = format!(
"\ "\
{} {}
const [retptr, retlen] = {}; const retptr = {};
const retlen = WASM_VECTOR_LEN;
const mem = getUint32Memory(); const mem = getUint32Memory();
mem[ret / 4] = retptr; mem[ret / 4] = retptr;
mem[ret / 4 + 1] = retlen; mem[ret / 4 + 1] = retlen;