Skip to content

Commit 9cdac6f

Browse files
committed
re-structured wasm modules
1 parent dfe06c3 commit 9cdac6f

File tree

6 files changed

+94
-39
lines changed

6 files changed

+94
-39
lines changed

package-lock.json

Lines changed: 7 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
"types": "./dist/index.d.ts",
88
"scripts": {
99
"build": "npm publish --dry-run",
10-
"prepare": "rm -rf dist dist.* ; tsc -p tsconfig.dist.json && webpack",
10+
"prepare": "rm -rf dist dist.* ; tsc -p tsconfig.dist.json && webpack && npm run asbuild",
1111
"prepublishOnly": "TEST_DIST=true npm run test",
1212
"clean": "rm -rf build dist dist.*",
1313
"test": "mocha 'test/**/*.test.ts'",
@@ -24,9 +24,9 @@
2424
"profile:encode": "rm -f isolate-*.log ; node --prof --require ts-node/register -e 'require(\"./benchmark/profile-encode\")' && node --prof-process --preprocess -j isolate-*.log | npx flamebearer",
2525
"profile:decode": "rm -f isolate-*.log ; node --prof --require ts-node/register -e 'require(\"./benchmark/profile-decode\")' && node --prof-process --preprocess -j isolate-*.log | npx flamebearer",
2626
"benchmark": "ts-node benchmark/benchmark-from-msgpack-lite.ts",
27-
"asbuild:untouched": "asc assembly/index.ts -b build/wasm/untouched.wasm -t build/wasm/untouched.wat --sourceMap --validate --debug",
28-
"asbuild:optimized": "asc assembly/index.ts -b build/wasm/optimized.wasm -t build/wasm/optimized.wat --sourceMap --validate -O3",
29-
"asbuild": "npm run asbuild:untouched && npm run asbuild:optimized"
27+
"asbuild:untouched": "asc assembly/index.ts -b build/wasm/untouched.wasm -t build/wasm/untouched.wat --sourceMap --validate --debug --measure",
28+
"asbuild:optimized": "asc assembly/index.ts -b build/wasm/optimized.wasm -t build/wasm/optimized.wat --sourceMap --validate -O3 --measure",
29+
"asbuild": "rm -rf build/wasm && npm run asbuild:untouched && npm run asbuild:optimized && ts-node tools/pack-wasm.ts"
3030
},
3131
"repository": {
3232
"type": "git",
@@ -45,6 +45,7 @@
4545
"homepage": "https://msgpack.org/",
4646
"devDependencies": {
4747
"@bitjourney/check-es-version-webpack-plugin": "^1.0.2",
48+
"@types/base64-js": "^1.2.5",
4849
"@types/mocha": "^5.2.6",
4950
"@types/node": "^11.13.10",
5051
"@typescript-eslint/eslint-plugin": "^1.9.0",
@@ -75,7 +76,9 @@
7576
"webpack": "^4.30.0",
7677
"webpack-cli": "^3.3.1"
7778
},
78-
"dependencies": {},
79+
"dependencies": {
80+
"base64-js": "^1.3.0"
81+
},
7982
"files": [
8083
"src/**/*.*",
8184
"dist/**/*.*",

src/Decoder.ts

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { prettyByte } from "./utils/prettyByte";
22
import { ExtensionCodec } from "./ExtensionCodec";
33
import { getInt64, getUint64 } from "./utils/int";
44
import { utf8Decode } from "./utils/utf8";
5-
import { utf8Decode2 } from "../wasmModule";
5+
import { utf8DecodeWasm, WASM_AVAILABLE } from "./wasmFunctions";
66
import { createDataView, ensureUint8Array } from "./utils/typedArrays";
77

88
enum State {
@@ -47,8 +47,6 @@ export const DataViewIndexOutOfBoundsError: typeof Error = (() => {
4747

4848
const MORE_DATA = new DataViewIndexOutOfBoundsError("Insufficient data");
4949

50-
const USE_WASM = process.env.USE_WASM === "true";
51-
5250
export class Decoder {
5351
totalPos = 0;
5452
pos = 0;
@@ -382,8 +380,8 @@ export class Decoder {
382380
}
383381

384382
let object: string;
385-
if (USE_WASM) {
386-
object = utf8Decode2(this.bytes, this.pos + headOffset, byteLength);
383+
if (WASM_AVAILABLE) {
384+
object = utf8DecodeWasm(this.bytes, this.pos + headOffset, byteLength);
387385
} else {
388386
object = utf8Decode(this.bytes, this.pos + headOffset, byteLength);
389387
}

src/wasmFunctions.ts

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
let wasmModule: any;
2+
try {
3+
wasmModule = require("../build/wasm/optimized.wasm.js").wasmModule;
4+
} catch {
5+
// WebAssembly is not supported.
6+
}
7+
8+
declare var WebAssembly: any;
9+
const WASM_MEMORY_PAGE_SIZE = 0x10000; // 64KiB
10+
11+
const defaultWasmInstance = wasmModule && new WebAssembly.Instance(wasmModule);
12+
13+
export const WASM_AVAILABLE = !!wasmModule && process.env.NO_WASM !== "true";
14+
15+
function copyArrayBuffer(dest: ArrayBuffer, src: Uint8Array) {
16+
const destView = new Uint8Array(dest);
17+
destView.set(src);
18+
}
19+
20+
export function utf8DecodeWasm(
21+
bytes: Uint8Array,
22+
offset: number,
23+
byteLength: number,
24+
wasmInstance = defaultWasmInstance,
25+
): string {
26+
if (!wasmInstance) {
27+
throw new Error("No WebAssembly available");
28+
}
29+
30+
const currentMemorySize: number = wasmInstance.exports.memory.buffer.byteLength;
31+
const requiredMemorySize = bytes.length * 3; // input(utf8) + output(utf16)
32+
if (currentMemorySize < requiredMemorySize) {
33+
const page = Math.ceil((requiredMemorySize - currentMemorySize) / WASM_MEMORY_PAGE_SIZE);
34+
wasmInstance.exports.memory.grow(page);
35+
}
36+
37+
copyArrayBuffer(wasmInstance.exports.memory.buffer, bytes.subarray(offset, offset + byteLength));
38+
// console.log(instanceMemory.subarray(0, 10));
39+
40+
const outputStart = Math.ceil(byteLength / Uint16Array.BYTES_PER_ELEMENT) * Uint16Array.BYTES_PER_ELEMENT;
41+
const outputEnd = wasmInstance.exports.utf8ToUtf16(byteLength, outputStart);
42+
const codepoints = new Uint16Array(
43+
wasmInstance.exports.memory.buffer,
44+
outputStart,
45+
(outputEnd - outputStart) / Uint16Array.BYTES_PER_ELEMENT,
46+
);
47+
// console.log([byteLength, outputStart, outputEnd]);
48+
// console.log(instanceMemory.subarray(0, 10));
49+
// console.log(utf16array);
50+
return String.fromCharCode.apply(String, codepoints as any);
51+
}

tools/pack-wasm.ts

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
// pack build/wasm/*.wasm
2+
3+
import fs from "fs";
4+
import { resolve } from "path";
5+
import base64 from "base64-js";
6+
7+
const artifactDir = resolve(__dirname, "../build/wasm");
8+
for (const basename of fs.readdirSync(artifactDir)) {
9+
const file = resolve(artifactDir, basename);
10+
if (!file.endsWith(".wasm")) {
11+
continue;
12+
}
13+
14+
const blob = fs.readFileSync(file);
15+
fs.writeFileSync(
16+
`${file}.js`,
17+
`// generated from ${basename}
18+
var base64 = require("base64-js");
19+
module.exports.wasmModule = new WebAssembly.Module(
20+
base64.toByteArray(
21+
${JSON.stringify(base64.fromByteArray(blob))}
22+
));
23+
`,
24+
);
25+
}

wasmModule.ts

Lines changed: 0 additions & 27 deletions
This file was deleted.

0 commit comments

Comments
 (0)