diff --git a/src/lexer.js b/src/lexer.js index 30bca50..6655280 100755 --- a/src/lexer.js +++ b/src/lexer.js @@ -1,6 +1,7 @@ let wasm; const isLE = new Uint8Array(new Uint16Array([1]).buffer)[0] === 1; +const hasBuffer = typeof Buffer !== 'undefined'; export function parse (source, name = '@') { if (!wasm) @@ -14,7 +15,11 @@ export function parse (source, name = '@') { wasm.memory.grow(Math.ceil(extraMem / 65536)); const addr = wasm.sa(len); - (isLE ? copyLE : copyBE)(source, new Uint16Array(wasm.memory.buffer, addr, len)); + // Buffer setup is slower than the loop for short sources. + if (source.length >= 64 && hasBuffer) + Buffer.from(wasm.memory.buffer, addr, (len - 1) * 2).write(source, 'utf16le'); + else + (isLE ? copyLE : copyBE)(source, new Uint16Array(wasm.memory.buffer, addr, len)); const err_code = wasm.parseCJS(addr, source.length, 0, 0, 0); diff --git a/test/_unit.js b/test/_unit.js index 0458f17..4f989a4 100755 --- a/test/_unit.js +++ b/test/_unit.js @@ -758,6 +758,51 @@ suite('Lexer', () => { }); }); + test('browser UTF-16 source copy', async () => { + const originalBuffer = global.Buffer; + global.Buffer = undefined; + let browserLexer; + try { + browserLexer = await import('../dist/lexer.mjs?browser-utf16-copy'); + } + finally { + global.Buffer = originalBuffer; + } + browserLexer.initSync(); + const source = `const value = '${'ð“€€'.repeat(40000)}'; exports.value = value`; + const { exports, reexports } = browserLexer.parse(source); + assert.deepStrictEqual(exports, ['value']); + assert.deepStrictEqual(reexports, []); + }); + + test('Node.js UTF-16 source copy cutoff', async function testNodeUtf16CopyCutoff () { + const nodeLexer = await import('../dist/lexer.mjs?node-utf16-copy-cutoff'); + nodeLexer.initSync(); + + const originalBuffer = global.Buffer; + let copies = 0; + global.Buffer = { + /** + * @param {ArrayBuffer} arrayBuffer + * @param {number} byteOffset + * @param {number} length + */ + from (arrayBuffer, byteOffset, length) { + copies++; + return originalBuffer.from(arrayBuffer, byteOffset, length); + } + }; + try { + nodeLexer.parse(' '.repeat(63)); + assert.strictEqual(copies, 0); + nodeLexer.parse(' '.repeat(64)); + assert.strictEqual(copies, 1); + } + finally { + global.Buffer = originalBuffer; + } + }); + test('Simple import', () => { const source = ` import test from "test";