Skip to content

Slightly optimize interop with binaryen #2108

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 16 commits into from
Nov 1, 2021
5 changes: 5 additions & 0 deletions src/glue/binaryen.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -643,6 +643,11 @@ export declare function _BinaryenSetAllowInliningFunctionsWithLoops(enabled: boo

// Helpers

// Binaryen.js only (ASC_TARGET = 0)
export declare const HEAPU8: Uint8Array;
export declare const HEAPU32: Uint32Array;
export declare const HEAP32: Int32Array;

export declare function _malloc(size: usize): usize;
export declare function _free(ptr: usize): void;
export declare function __i32_store8(ptr: usize, value: number): void;
Expand Down
137 changes: 86 additions & 51 deletions src/module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2501,7 +2501,7 @@ export class Module {
// avoid quite a bit of unnecessary garbage.
if (ptr == 0) return null;
var cached = this.cachedPointersToStrings;
if (cached.has(ptr)) return changetype<string>(this.cachedPointersToStrings.get(ptr));
if (cached.has(ptr)) return changetype<string>(cached.get(ptr));
var str = readString(ptr);
cached.set(ptr, str);
return str;
Expand Down Expand Up @@ -3029,8 +3029,12 @@ function allocU8Array(u8s: Uint8Array | null): usize {
if (!u8s) return 0;
var len = u8s.length;
var ptr = binaryen._malloc(len);
for (let i = 0; i < len; ++i) {
binaryen.__i32_store8(ptr + i, u8s[i]);
if (!ASC_TARGET) {
binaryen.HEAPU8.set(u8s, ptr);
} else {
for (let i = 0; i < len; ++i) {
binaryen.__i32_store8(ptr + i, u8s[i]);
}
}
return ptr;
}
Expand All @@ -3039,11 +3043,15 @@ function allocI32Array(i32s: i32[] | null): usize {
if (!i32s) return 0;
var len = i32s.length;
var ptr = binaryen._malloc(len << 2);
var idx = ptr;
for (let i = 0; i < len; ++i) {
let val = i32s[i];
binaryen.__i32_store(idx, val);
idx += 4;
if (!ASC_TARGET) {
binaryen.HEAP32.set(i32s, ptr >>> 2);
} else {
var idx = ptr;
for (let i = 0; i < len; ++i) {
let val = i32s[i];
binaryen.__i32_store(idx, val);
idx += 4;
}
}
return ptr;
}
Expand All @@ -3052,11 +3060,15 @@ function allocU32Array(u32s: u32[] | null): usize {
if (!u32s) return 0;
var len = u32s.length;
var ptr = binaryen._malloc(len << 2);
var idx = ptr;
for (let i = 0; i < len; ++i) {
let val = u32s[i];
binaryen.__i32_store(idx, val);
idx += 4;
if (!ASC_TARGET) {
binaryen.HEAPU32.set(u32s, ptr >>> 2);
} else {
var idx = ptr;
for (let i = 0; i < len; ++i) {
let val = u32s[i];
binaryen.__i32_store(idx, val);
idx += 4;
}
}
return ptr;
}
Expand All @@ -3067,72 +3079,95 @@ export function allocPtrArray(ptrs: usize[] | null): usize {
assert(ASC_TARGET != Target.WASM64);
var len = ptrs.length;
var ptr = binaryen._malloc(len << 2);
var idx = ptr;
for (let i = 0, k = len; i < k; ++i) {
let val = ptrs[i];
binaryen.__i32_store(idx, <i32>val);
idx += 4;
if (!ASC_TARGET) {
binaryen.HEAPU32.set(ptrs, ptr >>> 2);
} else {
var idx = ptr;
for (let i = 0, k = len; i < k; ++i) {
let val = ptrs[i];
binaryen.__i32_store(idx, <i32>val);
idx += 4;
}
}
return ptr;
}

function stringLengthUTF8(str: string): usize {
var len = 0;
for (let i = 0, k = str.length; i < k; ++i) {
let u = str.charCodeAt(i);
if (u >= 0xD800 && u <= 0xDFFF && i + 1 < k) {
u = 0x10000 + ((u & 0x3FF) << 10) | (str.charCodeAt(++i) & 0x3FF);
}
let u = str.charCodeAt(i) >>> 0;
if (u <= 0x7F) {
len += 1;
} else if (u <= 0x7FF) {
len += 2;
} else if (u <= 0xFFFF) {
len += 3;
} else {
} else if (u >= 0xD800 && u <= 0xDFFF && i + 1 < k) {
u = 0x10000 + ((u & 0x3FF) << 10) | (str.charCodeAt(++i) & 0x3FF);
len += 4;
} else {
len += 3;
}
}
return len;
}

function allocString(str: string | null): usize {
if (str === null) return 0;
var ptr = binaryen._malloc(stringLengthUTF8(str) + 1) >>> 0;
// the following is based on Emscripten's stringToUTF8Array
var len = stringLengthUTF8(str);
var ptr = binaryen._malloc(len + 1) >>> 0;
var idx = ptr;
for (let i = 0, k = str.length; i < k; ++i) {
let u = str.charCodeAt(i);
if (u >= 0xD800 && u <= 0xDFFF && i + 1 < k) {
u = 0x10000 + ((u & 0x3FF) << 10) | (str.charCodeAt(++i) & 0x3FF);
}
if (u <= 0x7F) {
binaryen.__i32_store8(idx++, u as u8);
} else if (u <= 0x7FF) {
binaryen.__i32_store8(idx++, (0xC0 | (u >>> 6) ) as u8);
binaryen.__i32_store8(idx++, (0x80 | ( u & 63)) as u8);
} else if (u <= 0xFFFF) {
binaryen.__i32_store8(idx++, (0xE0 | (u >>> 12) ) as u8);
binaryen.__i32_store8(idx++, (0x80 | ((u >>> 6) & 63)) as u8);
binaryen.__i32_store8(idx++, (0x80 | ( u & 63)) as u8);
if (len === str.length) {
// fast path when all chars are ascii
if (!ASC_TARGET) {
for (let i = 0, k = str.length; i < k; ++i) {
binaryen.HEAPU8[idx++] = str.charCodeAt(i);
}
} else {
assert(u < 0x200000, "Invalid Unicode code point during allocString");
binaryen.__i32_store8(idx++, (0xF0 | (u >>> 18) ) as u8);
binaryen.__i32_store8(idx++, (0x80 | ((u >>> 12) & 63)) as u8);
binaryen.__i32_store8(idx++, (0x80 | ((u >>> 6) & 63)) as u8);
binaryen.__i32_store8(idx++, (0x80 | ( u & 63)) as u8);
for (let i = 0, k = str.length; i < k; ++i) {
let u = str.charCodeAt(i) >>> 0;
binaryen.__i32_store8(idx++, u as u8);
}
}
} else {
// the following is based on Emscripten's stringToUTF8Array
for (let i = 0, k = str.length; i < k; ++i) {
let u = str.charCodeAt(i) >>> 0;
if (u <= 0x7F) {
binaryen.__i32_store8(idx++, u as u8);
} else if (u <= 0x7FF) {
binaryen.__i32_store8(idx++, (0xC0 | (u >>> 6) ) as u8);
binaryen.__i32_store8(idx++, (0x80 | ( u & 63)) as u8);
} else if (u >= 0xD800 && u <= 0xDFFF) {
if (i + 1 < k) {
u = 0x10000 + ((u & 0x3FF) << 10) | (str.charCodeAt(++i) & 0x3FF);
}
if (u <= 0xFFFF) {
binaryen.__i32_store8(idx++, (0xE0 | (u >>> 12) ) as u8);
binaryen.__i32_store8(idx++, (0x80 | ((u >>> 6) & 63)) as u8);
binaryen.__i32_store8(idx++, (0x80 | ( u & 63)) as u8);
} else {
assert(u <= 0x10FFFF, "Invalid Unicode code point during allocString");
binaryen.__i32_store8(idx++, (0xF0 | (u >>> 18) ) as u8);
binaryen.__i32_store8(idx++, (0x80 | ((u >>> 12) & 63)) as u8);
binaryen.__i32_store8(idx++, (0x80 | ((u >>> 6) & 63)) as u8);
binaryen.__i32_store8(idx++, (0x80 | ( u & 63)) as u8);
}
}
}
}
binaryen.__i32_store8(idx, 0);
binaryen.__i32_store8(idx, 0); // \0
return ptr;
}

function readBuffer(ptr: usize, len: i32): Uint8Array {
var ret = new Uint8Array(len);
for (let i = 0; i < len; ++i) {
ret[i] = binaryen.__i32_load8_u(ptr + <usize>i);
if (!ASC_TARGET) {
return binaryen.HEAPU8.slice(ptr, ptr + len);
} else {
var ret = new Uint8Array(len);
for (let i = 0; i < len; ++i) {
ret[i] = binaryen.__i32_load8_u(ptr + <usize>i);
}
return ret;
}
return ret;
}

export function readString(ptr: usize): string | null {
Expand Down