Cache more objects in generated JS bindings

Cache the `Uint8Array` and `Uint32Array` views into wasm memory as well as the
instances of `TextEncoder` and `TextDecoder`. Should hopefully help cut down on
gc traffic and otherwise convince the engine to keep these as long-lived
objects.
This commit is contained in:
Alex Crichton 2018-02-06 15:32:45 -08:00
parent ec5f0a29f7
commit 2c7c2e7ae1

View File

@ -85,12 +85,13 @@ impl<'a> Js<'a> {
bind("__wbindgen_number_get", &|me| { bind("__wbindgen_number_get", &|me| {
me.expose_get_object(); me.expose_get_object();
me.expose_uint8_memory();
format!(" format!("
function(n, invalid) {{ function(n, invalid) {{
let obj = getObject(n); let obj = getObject(n);
if (typeof(obj) === 'number') if (typeof(obj) === 'number')
return obj; return obj;
(new Uint8Array(wasm.memory.buffer))[invalid] = 1; getUint8Memory()[invalid] = 1;
return 0; return 0;
}} }}
") ")
@ -165,12 +166,13 @@ impl<'a> Js<'a> {
bind("__wbindgen_string_get", &|me| { bind("__wbindgen_string_get", &|me| {
me.expose_pass_string_to_wasm(); me.expose_pass_string_to_wasm();
me.expose_get_object(); me.expose_get_object();
me.expose_uint32_memory();
String::from("(i, len_ptr) => { String::from("(i, len_ptr) => {
let obj = getObject(i); let obj = getObject(i);
if (typeof(obj) !== 'string') if (typeof(obj) !== 'string')
return 0; return 0;
const [ptr, len] = passStringToWasm(obj); const [ptr, len] = passStringToWasm(obj);
(new Uint32Array(wasm.memory.buffer))[len_ptr / 4] = len; getUint32Memory()[len_ptr / 4] = len;
return ptr; return ptr;
}") }")
}); });
@ -599,13 +601,14 @@ impl<'a> Js<'a> {
} }
Some(shared::TYPE_STRING) => { Some(shared::TYPE_STRING) => {
self.expose_pass_string_to_wasm(); self.expose_pass_string_to_wasm();
self.expose_uint32_memory();
if import.arguments.len() > 0 || is_method { if import.arguments.len() > 0 || is_method {
dst.push_str(", "); dst.push_str(", ");
} }
dst.push_str("wasmretptr"); dst.push_str("wasmretptr");
format!(" format!("
const [retptr, retlen] = passStringToWasm({}); const [retptr, retlen] = passStringToWasm({});
(new Uint32Array(wasm.memory.buffer))[wasmretptr / 4] = retlen; getUint32Memory()[wasmretptr / 4] = retlen;
return retptr; return retptr;
", invoc) ", invoc)
} }
@ -839,21 +842,52 @@ impl<'a> Js<'a> {
}} }}
")); "));
} else { } else {
self.expose_text_encoder();
self.expose_uint8_memory();
self.globals.push_str(&format!(" self.globals.push_str(&format!("
function passStringToWasm(arg) {{ function passStringToWasm(arg) {{
if (typeof(arg) !== 'string') if (typeof(arg) !== 'string')
throw new Error('expected a string argument'); throw new Error('expected a string argument');
const buf = new TextEncoder('utf-8').encode(arg); const buf = textEncoder().encode(arg);
const len = buf.length; const len = buf.length;
const ptr = wasm.__wbindgen_malloc(len); const ptr = wasm.__wbindgen_malloc(len);
let array = new Uint8Array(wasm.memory.buffer); getUint8Memory().set(buf, ptr);
array.set(buf, ptr);
return [ptr, len]; return [ptr, len];
}} }}
")); "));
} }
} }
fn expose_text_encoder(&mut self) {
if !self.exposed_globals.insert("text_encoder") {
return
}
self.globals.push_str(&format!("
let cachedEncoder = null;
function textEncoder() {{
if (cachedEncoder)
return cachedEncoder;
cachedEncoder = new TextEncoder('utf-8');
return cachedEncoder;
}}
"));
}
fn expose_text_decoder(&mut self) {
if !self.exposed_globals.insert("text_decoder") {
return
}
self.globals.push_str(&format!("
let cachedDecoder = null;
function textDecoder() {{
if (cachedDecoder)
return cachedDecoder;
cachedDecoder = new TextDecoder('utf-8');
return cachedDecoder;
}}
"));
}
fn expose_get_string_from_wasm(&mut self) { fn expose_get_string_from_wasm(&mut self) {
if !self.exposed_globals.insert("get_string_from_wasm") { if !self.exposed_globals.insert("get_string_from_wasm") {
return return
@ -867,17 +901,49 @@ impl<'a> Js<'a> {
}} }}
")); "));
} else { } else {
self.expose_text_decoder();
self.expose_uint8_memory();
self.globals.push_str(&format!(" self.globals.push_str(&format!("
function getStringFromWasm(ptr, len) {{ function getStringFromWasm(ptr, len) {{
const mem = new Uint8Array(wasm.memory.buffer); const mem = getUint8Memory();
const slice = mem.slice(ptr, ptr + len); const slice = mem.slice(ptr, ptr + len);
const ret = new TextDecoder('utf-8').decode(slice); const ret = textDecoder().decode(slice);
return ret; return ret;
}} }}
")); "));
} }
} }
fn expose_uint8_memory(&mut self) {
if !self.exposed_globals.insert("uint8_memory") {
return
}
self.globals.push_str(&format!("
let cachedUint8Memory = null;
function getUint8Memory() {{
if (cachedUint8Memory === null ||
cachedUint8Memory.buffer !== wasm.memory.buffer)
cachedUint8Memory = new Uint8Array(wasm.memory.buffer);
return cachedUint8Memory;
}}
"));
}
fn expose_uint32_memory(&mut self) {
if !self.exposed_globals.insert("uint32_memory") {
return
}
self.globals.push_str(&format!("
let cachedUint32Memory = null;
function getUint32Memory() {{
if (cachedUint32Memory === null ||
cachedUint32Memory.buffer !== wasm.memory.buffer)
cachedUint32Memory = new Uint32Array(wasm.memory.buffer);
return cachedUint32Memory;
}}
"));
}
fn expose_assert_class(&mut self) { fn expose_assert_class(&mut self) {
if !self.exposed_globals.insert("assert_class") { if !self.exposed_globals.insert("assert_class") {
return return