diff --git a/src/bindings/js.ts b/src/bindings/js.ts index 735d5a1e2a..59f9685c43 100644 --- a/src/bindings/js.ts +++ b/src/bindings/js.ts @@ -119,6 +119,7 @@ export class JSBuilder extends ExportsWalker { private needsRetain: bool = false; private needsRelease: bool = false; private needsNotNull: bool = false; + private needsStoreRef: bool = false; private deferredLifts: Set = new Set(); private deferredLowers: Set = new Set(); @@ -851,6 +852,12 @@ export class JSBuilder extends ExportsWalker { } `); } + if (this.needsStoreRef) { + sb.push(` function __store_ref(pointer, value) { + new Uint32Array(memory.buffer)[pointer >>> 2] = value; + } +`); + } let exportStart = options.exportStart; if (exportStart) { @@ -1177,36 +1184,44 @@ export class JSBuilder extends ExportsWalker { skipTail = false; } if (valueType.isInternalReference) { + // The RHS is typically another lowering to memory, which may trigger + // memory growth. Use a helper closure to delay evaluation of `memory`. + this.needsStoreRef = true; + sb.push("__store_ref("); + sb.push(targetName); + sb.push(", "); + this.makeLowerToValue(valueName, valueType, sb); + sb.push(")"); + if (!skipTail) sb.push("; }"); + return; + } + if (valueType == Type.i8) { + sb.push("new Int8Array(memory.buffer)["); + } else if (valueType == Type.u8 || valueType == Type.bool) { + sb.push("new Uint8Array(memory.buffer)["); + } else if (valueType == Type.i16) { + sb.push("new Int16Array(memory.buffer)["); + } else if (valueType == Type.u16) { + sb.push("new Uint16Array(memory.buffer)["); + } else if (valueType == Type.i32 || valueType == Type.isize32) { + sb.push("new Int32Array(memory.buffer)["); + } else if (valueType == Type.u32 || valueType == Type.usize32) { sb.push("new Uint32Array(memory.buffer)["); + } else if (valueType == Type.i64 || valueType == Type.isize64) { + sb.push("new BigInt64Array(memory.buffer)["); + } else if (valueType == Type.u64 || valueType == Type.usize64) { + sb.push("new BigUint64Array(memory.buffer)["); + } else if (valueType == Type.f32) { + sb.push("new Float32Array(memory.buffer)["); + } else if (valueType == Type.f64) { + sb.push("new Float64Array(memory.buffer)["); } else { - if (valueType == Type.i8) { - sb.push("new Int8Array(memory.buffer)["); - } else if (valueType == Type.u8 || valueType == Type.bool) { - sb.push("new Uint8Array(memory.buffer)["); - } else if (valueType == Type.i16) { - sb.push("new Int16Array(memory.buffer)["); - } else if (valueType == Type.u16) { - sb.push("new Uint16Array(memory.buffer)["); - } else if (valueType == Type.i32 || valueType == Type.isize32) { - sb.push("new Int32Array(memory.buffer)["); - } else if (valueType == Type.u32 || valueType == Type.usize32) { - sb.push("new Uint32Array(memory.buffer)["); - } else if (valueType == Type.i64 || valueType == Type.isize64) { - sb.push("new BigInt64Array(memory.buffer)["); - } else if (valueType == Type.u64 || valueType == Type.usize64) { - sb.push("new BigUint64Array(memory.buffer)["); - } else if (valueType == Type.f32) { - sb.push("new Float32Array(memory.buffer)["); - } else if (valueType == Type.f64) { - sb.push("new Float64Array(memory.buffer)["); + if (skipTail) { + sb.push("(() => { throw Error(\"unsupported type\") })()"); } else { - if (skipTail) { - sb.push("(() => { throw Error(\"unsupported type\") })()"); - } else { - sb.push("throw Error(\"unsupported type\"); }"); - } - return; + sb.push("throw Error(\"unsupported type\"); }"); } + return; } sb.push(targetName); sb.push(" >>> "); diff --git a/tests/compiler/bindings/esm.debug.js b/tests/compiler/bindings/esm.debug.js index 59423a594f..4f88bbba17 100644 --- a/tests/compiler/bindings/esm.debug.js +++ b/tests/compiler/bindings/esm.debug.js @@ -220,9 +220,9 @@ async function instantiate(module, imports = {}) { new Uint8Array(memory.buffer)[pointer + 40 >>> 0] = value.k ? 1 : 0; new Float32Array(memory.buffer)[pointer + 44 >>> 2] = value.l; new Float64Array(memory.buffer)[pointer + 48 >>> 3] = value.m; - new Uint32Array(memory.buffer)[pointer + 56 >>> 2] = __lowerString(value.n); - new Uint32Array(memory.buffer)[pointer + 60 >>> 2] = __lowerTypedArray(Uint8Array, 13, 0, value.o); - new Uint32Array(memory.buffer)[pointer + 64 >>> 2] = __lowerArray((pointer, value) => { new Uint32Array(memory.buffer)[pointer >>> 2] = __lowerString(value) || __notnull(); }, 14, 2, value.p); + __store_ref(pointer + 56, __lowerString(value.n)); + __store_ref(pointer + 60, __lowerTypedArray(Uint8Array, 13, 0, value.o)); + __store_ref(pointer + 64, __lowerArray((pointer, value) => { __store_ref(pointer, __lowerString(value) || __notnull()); }, 14, 2, value.p)); exports.__unpin(pointer); return pointer; } @@ -382,6 +382,9 @@ async function instantiate(module, imports = {}) { function __notnull() { throw TypeError("value must not be null"); } + function __store_ref(pointer, value) { + new Uint32Array(memory.buffer)[pointer >>> 2] = value; + } exports._start(); return adaptedExports; } diff --git a/tests/compiler/bindings/esm.release.js b/tests/compiler/bindings/esm.release.js index 6c2a8096ed..bb01c74f5c 100644 --- a/tests/compiler/bindings/esm.release.js +++ b/tests/compiler/bindings/esm.release.js @@ -220,9 +220,9 @@ async function instantiate(module, imports = {}) { new Uint8Array(memory.buffer)[pointer + 40 >>> 0] = value.k ? 1 : 0; new Float32Array(memory.buffer)[pointer + 44 >>> 2] = value.l; new Float64Array(memory.buffer)[pointer + 48 >>> 3] = value.m; - new Uint32Array(memory.buffer)[pointer + 56 >>> 2] = __lowerString(value.n); - new Uint32Array(memory.buffer)[pointer + 60 >>> 2] = __lowerTypedArray(Uint8Array, 13, 0, value.o); - new Uint32Array(memory.buffer)[pointer + 64 >>> 2] = __lowerArray((pointer, value) => { new Uint32Array(memory.buffer)[pointer >>> 2] = __lowerString(value) || __notnull(); }, 14, 2, value.p); + __store_ref(pointer + 56, __lowerString(value.n)); + __store_ref(pointer + 60, __lowerTypedArray(Uint8Array, 13, 0, value.o)); + __store_ref(pointer + 64, __lowerArray((pointer, value) => { __store_ref(pointer, __lowerString(value) || __notnull()); }, 14, 2, value.p)); exports.__unpin(pointer); return pointer; } @@ -382,6 +382,9 @@ async function instantiate(module, imports = {}) { function __notnull() { throw TypeError("value must not be null"); } + function __store_ref(pointer, value) { + new Uint32Array(memory.buffer)[pointer >>> 2] = value; + } exports._start(); return adaptedExports; } diff --git a/tests/compiler/bindings/raw.debug.js b/tests/compiler/bindings/raw.debug.js index 57a055392a..6f8505848e 100644 --- a/tests/compiler/bindings/raw.debug.js +++ b/tests/compiler/bindings/raw.debug.js @@ -220,9 +220,9 @@ export async function instantiate(module, imports = {}) { new Uint8Array(memory.buffer)[pointer + 40 >>> 0] = value.k ? 1 : 0; new Float32Array(memory.buffer)[pointer + 44 >>> 2] = value.l; new Float64Array(memory.buffer)[pointer + 48 >>> 3] = value.m; - new Uint32Array(memory.buffer)[pointer + 56 >>> 2] = __lowerString(value.n); - new Uint32Array(memory.buffer)[pointer + 60 >>> 2] = __lowerTypedArray(Uint8Array, 13, 0, value.o); - new Uint32Array(memory.buffer)[pointer + 64 >>> 2] = __lowerArray((pointer, value) => { new Uint32Array(memory.buffer)[pointer >>> 2] = __lowerString(value) || __notnull(); }, 14, 2, value.p); + __store_ref(pointer + 56, __lowerString(value.n)); + __store_ref(pointer + 60, __lowerTypedArray(Uint8Array, 13, 0, value.o)); + __store_ref(pointer + 64, __lowerArray((pointer, value) => { __store_ref(pointer, __lowerString(value) || __notnull()); }, 14, 2, value.p)); exports.__unpin(pointer); return pointer; } @@ -382,6 +382,9 @@ export async function instantiate(module, imports = {}) { function __notnull() { throw TypeError("value must not be null"); } + function __store_ref(pointer, value) { + new Uint32Array(memory.buffer)[pointer >>> 2] = value; + } exports._start(); return adaptedExports; } diff --git a/tests/compiler/bindings/raw.release.js b/tests/compiler/bindings/raw.release.js index 57a055392a..6f8505848e 100644 --- a/tests/compiler/bindings/raw.release.js +++ b/tests/compiler/bindings/raw.release.js @@ -220,9 +220,9 @@ export async function instantiate(module, imports = {}) { new Uint8Array(memory.buffer)[pointer + 40 >>> 0] = value.k ? 1 : 0; new Float32Array(memory.buffer)[pointer + 44 >>> 2] = value.l; new Float64Array(memory.buffer)[pointer + 48 >>> 3] = value.m; - new Uint32Array(memory.buffer)[pointer + 56 >>> 2] = __lowerString(value.n); - new Uint32Array(memory.buffer)[pointer + 60 >>> 2] = __lowerTypedArray(Uint8Array, 13, 0, value.o); - new Uint32Array(memory.buffer)[pointer + 64 >>> 2] = __lowerArray((pointer, value) => { new Uint32Array(memory.buffer)[pointer >>> 2] = __lowerString(value) || __notnull(); }, 14, 2, value.p); + __store_ref(pointer + 56, __lowerString(value.n)); + __store_ref(pointer + 60, __lowerTypedArray(Uint8Array, 13, 0, value.o)); + __store_ref(pointer + 64, __lowerArray((pointer, value) => { __store_ref(pointer, __lowerString(value) || __notnull()); }, 14, 2, value.p)); exports.__unpin(pointer); return pointer; } @@ -382,6 +382,9 @@ export async function instantiate(module, imports = {}) { function __notnull() { throw TypeError("value must not be null"); } + function __store_ref(pointer, value) { + new Uint32Array(memory.buffer)[pointer >>> 2] = value; + } exports._start(); return adaptedExports; }