From c0d86e65e68971d0855ece2c8ffdf68ece0899d9 Mon Sep 17 00:00:00 2001 From: dcode Date: Tue, 25 Apr 2023 19:28:14 +0200 Subject: [PATCH] fix: Handle exportRuntime in generated bindings (#2694) --- src/bindings/js.ts | 29 +++++++++++++++++++----- src/bindings/tsd.ts | 14 ++++++++++++ src/compiler.ts | 4 ++-- tests/compiler/bindings/esm.debug.d.ts | 6 +++++ tests/compiler/bindings/esm.debug.js | 13 +++++++---- tests/compiler/bindings/esm.json | 3 ++- tests/compiler/bindings/esm.release.d.ts | 6 +++++ tests/compiler/bindings/esm.release.js | 15 ++++++++---- 8 files changed, 72 insertions(+), 18 deletions(-) diff --git a/src/bindings/js.ts b/src/bindings/js.ts index e5ba8f9487..a86f77dec4 100644 --- a/src/bindings/js.ts +++ b/src/bindings/js.ts @@ -13,6 +13,11 @@ import { CommonFlags } from "../common"; +import { + runtimeFunctions, + runtimeGlobals +} from "../compiler"; + import { ElementKind, Element, @@ -945,19 +950,31 @@ export class JSBuilder extends ExportsWalker { assert(this.indentLevel == 0); if (this.esm) { - sb.push("export const {\n "); + sb.push("export const {\n"); if (this.program.options.exportMemory) { - sb.push("memory,\n "); + sb.push(" memory,\n"); } if (this.program.options.exportTable) { - sb.push("table,\n "); + sb.push(" table,\n"); + } + if (this.program.options.exportRuntime) { + for (let i = 0, k = runtimeFunctions.length; i < k; ++i) { + sb.push(" "); + sb.push(runtimeFunctions[i]); + sb.push(",\n"); + } + for (let i = 0, k = runtimeGlobals.length; i < k; ++i) { + sb.push(" "); + sb.push(runtimeGlobals[i]); + sb.push(",\n"); + } } for (let i = 0, k = exports.length; i < k; ++i) { - if (i > 0) sb.push(",\n "); + sb.push(" "); sb.push(exports[i]); + sb.push(",\n"); } - sb.push(` -} = await (async url => instantiate( + sb.push(`} = await (async url => instantiate( await (async () => { try { return await globalThis.WebAssembly.compileStreaming(globalThis.fetch(url)); } catch { return globalThis.WebAssembly.compile(await (await import("node:fs/promises")).readFile(url)); } diff --git a/src/bindings/tsd.ts b/src/bindings/tsd.ts index a7f65bfd9d..23374fb553 100644 --- a/src/bindings/tsd.ts +++ b/src/bindings/tsd.ts @@ -198,6 +198,20 @@ export class TSDBuilder extends ExportsWalker { indent(sb, this.indentLevel); sb.push(`export ${this.esm ? "declare " : ""}const table: WebAssembly.Table;\n`); } + if (this.program.options.exportRuntime) { + indent(sb, this.indentLevel); + sb.push("// Exported runtime interface\n"); + indent(sb, this.indentLevel); + sb.push(`export ${this.esm ? "declare " : ""}function __new(size: number, id: number): number;\n`); + indent(sb, this.indentLevel); + sb.push(`export ${this.esm ? "declare " : ""}function __pin(ptr: number): number;\n`); + indent(sb, this.indentLevel); + sb.push(`export ${this.esm ? "declare " : ""}function __unpin(ptr: number): void;\n`); + indent(sb, this.indentLevel); + sb.push(`export ${this.esm ? "declare " : ""}function __collect(): void;\n`); + indent(sb, this.indentLevel); + sb.push(`export ${this.esm ? "declare " : ""}const __rtti_base: number;\n`); + } this.walk(); if (!this.esm) { --this.indentLevel; diff --git a/src/compiler.ts b/src/compiler.ts index 7703f5de18..a2b313603b 100644 --- a/src/compiler.ts +++ b/src/compiler.ts @@ -418,9 +418,9 @@ export namespace ExportNames { } /** Functions to export if `--exportRuntime` is set. */ -const runtimeFunctions = [ "__new", "__pin", "__unpin", "__collect" ]; +export const runtimeFunctions = [ "__new", "__pin", "__unpin", "__collect" ]; /** Globals to export if `--exportRuntime` is set. */ -const runtimeGlobals = [ "__rtti_base" ]; +export const runtimeGlobals = [ "__rtti_base" ]; /** Compiler interface. */ export class Compiler extends DiagnosticEmitter { diff --git a/tests/compiler/bindings/esm.debug.d.ts b/tests/compiler/bindings/esm.debug.d.ts index 981be67804..b533213227 100644 --- a/tests/compiler/bindings/esm.debug.d.ts +++ b/tests/compiler/bindings/esm.debug.d.ts @@ -1,5 +1,11 @@ /** Exported memory */ export declare const memory: WebAssembly.Memory; +// Exported runtime interface +export declare function __new(size: number, id: number): number; +export declare function __pin(ptr: number): number; +export declare function __unpin(ptr: number): void; +export declare function __collect(): void; +export declare const __rtti_base: number; /** bindings/esm/plainGlobal */ export declare const plainGlobal: { /** @type `i32` */ diff --git a/tests/compiler/bindings/esm.debug.js b/tests/compiler/bindings/esm.debug.js index 9503ad5efb..15804abe90 100644 --- a/tests/compiler/bindings/esm.debug.js +++ b/tests/compiler/bindings/esm.debug.js @@ -18,10 +18,10 @@ async function instantiate(module, imports = {}) { // ~lib/bindings/dom/Math.E: f64 Math.E ), - "Math.log": ( + "Math.log"(x) { // ~lib/bindings/dom/Math.log(f64) => f64 - Math.log - ), + return Math.log(x); + }, "globalThis.globalThis": ( // bindings/esm/immutableGlobalNested: ref_extern | null} globalThis.globalThis @@ -522,6 +522,11 @@ async function instantiate(module, imports = {}) { } export const { memory, + __new, + __pin, + __unpin, + __collect, + __rtti_base, plainGlobal, plainMutableGlobal, stringGlobal, @@ -545,7 +550,7 @@ export const { newInternref, internrefFunction, functionFunction, - fn + fn, } = await (async url => instantiate( await (async () => { try { return await globalThis.WebAssembly.compileStreaming(globalThis.fetch(url)); } diff --git a/tests/compiler/bindings/esm.json b/tests/compiler/bindings/esm.json index badd390ae5..eb18631afc 100644 --- a/tests/compiler/bindings/esm.json +++ b/tests/compiler/bindings/esm.json @@ -1,7 +1,8 @@ { "asc_flags": [ "--exportStart _start", - "--bindings esm" + "--bindings esm", + "--exportRuntime" ], "features": [ "reference-types" diff --git a/tests/compiler/bindings/esm.release.d.ts b/tests/compiler/bindings/esm.release.d.ts index 981be67804..b533213227 100644 --- a/tests/compiler/bindings/esm.release.d.ts +++ b/tests/compiler/bindings/esm.release.d.ts @@ -1,5 +1,11 @@ /** Exported memory */ export declare const memory: WebAssembly.Memory; +// Exported runtime interface +export declare function __new(size: number, id: number): number; +export declare function __pin(ptr: number): number; +export declare function __unpin(ptr: number): void; +export declare function __collect(): void; +export declare const __rtti_base: number; /** bindings/esm/plainGlobal */ export declare const plainGlobal: { /** @type `i32` */ diff --git a/tests/compiler/bindings/esm.release.js b/tests/compiler/bindings/esm.release.js index e929b4a60f..6df7b0c319 100644 --- a/tests/compiler/bindings/esm.release.js +++ b/tests/compiler/bindings/esm.release.js @@ -18,12 +18,12 @@ async function instantiate(module, imports = {}) { // ~lib/bindings/dom/Math.E: f64 Math.E ), - "Math.log": ( + "Math.log"(x) { // ~lib/bindings/dom/Math.log(f64) => f64 - Math.log - ), + return Math.log(x); + }, "globalThis.globalThis": ( - // bindings/esm/immutableGlobalNested: externref + // bindings/esm/immutableGlobalNested: ref_extern | null} globalThis.globalThis ), "Date.getTimezoneOffset"() { @@ -522,6 +522,11 @@ async function instantiate(module, imports = {}) { } export const { memory, + __new, + __pin, + __unpin, + __collect, + __rtti_base, plainGlobal, plainMutableGlobal, stringGlobal, @@ -545,7 +550,7 @@ export const { newInternref, internrefFunction, functionFunction, - fn + fn, } = await (async url => instantiate( await (async () => { try { return await globalThis.WebAssembly.compileStreaming(globalThis.fetch(url)); }