Skip to content

Commit 58cc466

Browse files
fix(transpile): preserve Unicode core export names in asm.js
1 parent 2926dff commit 58cc466

2 files changed

Lines changed: 49 additions & 0 deletions

File tree

‎packages/jco-transpile/src/asm.ts‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -226,6 +226,9 @@ ${autoInstantiate}`;
226226
* See https://github.com/WebAssembly/binaryen/blob/main/src/asmjs/asmangle.cpp
227227
*/
228228
function asmMangle(name: string) {
229+
// Binaryen mangles the UTF-8 bytes of a name, rather than UTF-16 code units.
230+
name = Buffer.from(name, 'utf8').toString('latin1');
231+
229232
if (name === '') {
230233
return '$';
231234
}

‎packages/jco-transpile/test/asm.ts‎

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
import { rm, writeFile } from 'node:fs/promises';
2+
import { join } from 'node:path';
3+
import { pathToFileURL } from 'node:url';
4+
5+
import { assert, describe, test } from 'vitest';
6+
7+
import { transpileBytes, writeFiles } from '../src/index.js';
8+
import { parse } from '../src/wasm-tools.js';
9+
import { getTmpDir } from './helpers.js';
10+
11+
describe.each([false, true])('asm.js core exports (minify: %s)', (minify) => {
12+
test.concurrent.each([
13+
'$value',
14+
'0',
15+
'return',
16+
'quoted"slash\\line\n',
17+
'\u00e9',
18+
'caf\u00e9',
19+
'\u6f22\u5b57',
20+
'\ud83d\ude00run',
21+
'run\ud83d\ude00',
22+
'line\u2028\u2029',
23+
])('preserves the core export name %j', async (name) => {
24+
const outDir = await getTmpDir();
25+
try {
26+
// WAT byte escapes preserve the exact UTF-8 name, including quotes and controls.
27+
const quoted = `"${Array.from(Buffer.from(name), (byte) => `\\${byte.toString(16).padStart(2, '0')}`).join('')}"`;
28+
const component = await parse(`(component
29+
(core module $m (func (export ${quoted}) (result i32) i32.const 42))
30+
(core instance $i (instantiate $m))
31+
(func (export "run") (result u32) (canon lift (core func $i ${quoted}))))`);
32+
const { files } = await transpileBytes(component, {
33+
name: 'asm-export-name',
34+
js: true,
35+
instantiation: 'sync',
36+
minify,
37+
});
38+
await writeFiles(files, { baseDir: outDir });
39+
await writeFile(join(outDir, 'package.json'), JSON.stringify({ type: 'module' }));
40+
const { instantiate } = await import(pathToFileURL(join(outDir, 'asm-export-name.js')).href);
41+
assert.strictEqual(instantiate({}).run(), 42);
42+
} finally {
43+
await rm(outDir, { recursive: true, force: true });
44+
}
45+
});
46+
});

0 commit comments

Comments
 (0)