json-as 1.1.26 → 1.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (50) hide show
  1. package/.github/workflows/benchmark.yml +72 -0
  2. package/.prettierrc.json +1 -0
  3. package/CHANGELOG.md +4 -0
  4. package/README.md +44 -59
  5. package/assembly/__benches__/abc.bench.ts +5 -9
  6. package/assembly/__benches__/large.bench.ts +114 -120
  7. package/assembly/__benches__/lib/bench.ts +44 -1
  8. package/assembly/__benches__/medium.bench.ts +108 -29
  9. package/assembly/__benches__/small.bench.ts +28 -18
  10. package/assembly/__benches__/throughput.ts +172 -0
  11. package/assembly/__benches__/vec3.bench.ts +8 -3
  12. package/assembly/__tests__/string.spec.ts +4 -0
  13. package/assembly/deserialize/simple/arbitrary.ts +5 -2
  14. package/assembly/deserialize/simple/object.ts +3 -1
  15. package/assembly/deserialize/swar/string.ts +62 -62
  16. package/assembly/index.ts +6 -2
  17. package/assembly/serialize/simd/string.ts +1 -1
  18. package/assembly/serialize/swar/number.ts +0 -0
  19. package/assembly/serialize/swar/string.ts +25 -25
  20. package/assembly/test.tmp.ts +124 -2
  21. package/assembly/test.ts +0 -7
  22. package/bench/abc.bench.ts +6 -8
  23. package/bench/large.bench.ts +119 -118
  24. package/bench/lib/bench.d.ts +27 -0
  25. package/bench/lib/bench.js +53 -0
  26. package/bench/lib/chart.ts +217 -0
  27. package/bench/medium.bench.ts +55 -30
  28. package/bench/runners/assemblyscript.js +6 -1
  29. package/bench/small.bench.ts +7 -3
  30. package/bench/throughput.ts +87 -0
  31. package/bench/tsconfig.json +3 -2
  32. package/bench/vec3.bench.ts +7 -3
  33. package/ci/bench/runners/assemblyscript.js +29 -0
  34. package/ci/run-bench.as.sh +63 -0
  35. package/lib/as-bs.ts +13 -0
  36. package/package.json +3 -1
  37. package/run-bench.as.sh +21 -13
  38. package/run-bench.js.sh +9 -7
  39. package/run-tests.sh +34 -14
  40. package/scripts/build-chart01.ts +38 -0
  41. package/scripts/build-chart02.ts +38 -0
  42. package/scripts/build-chart03.ts +139 -0
  43. package/scripts/build-chart05.ts +47 -0
  44. package/scripts/generate-as-class.ts +50 -0
  45. package/scripts/lib/bench-utils.ts +308 -0
  46. package/transform/lib/index.js +2 -2
  47. package/transform/lib/index.js.map +1 -1
  48. package/transform/src/index.ts +2 -2
  49. package/assembly/__tests__/simd/string.spec.ts +0 -32
  50. /package/{bench → ci/bench}/lib/bench.ts +0 -0
@@ -1,43 +1,68 @@
1
- import { bench } from "./lib/bench.js";
2
-
3
- class MediumJSON {
4
- public id!: number;
5
- public name!: string;
6
- public age!: number;
7
- public email!: string;
8
- public street!: string;
9
- public city!: string;
10
- public state!: string;
11
- public zip!: string;
12
- public tags!: string[];
1
+ import { bench, blackbox, dumpToFile } from "./lib/bench.js";
2
+
3
+ class UserPreferences {
4
+ theme: string = "dark";
5
+ notifications: boolean = true;
6
+ language: string = "en-US";
7
+ timezone: string = "America/Los_Angeles";
8
+ privacy_level: string = "friends_only";
9
+ two_factor_enabled: boolean = false;
10
+ }
11
+
12
+ class RecentActivity {
13
+ action: string = "";
14
+ timestamp: string = "";
15
+ target: string = "";
16
+ }
17
+
18
+ class MediumAPIResponse {
19
+ id: number = 42;
20
+ username: string = "jairus";
21
+ full_name: string = "Jairus Tanaka";
22
+ email: string = "me@jairus.dev";
23
+ avatar_url: string = "https://avatars.githubusercontent.com/u/123456?v=4";
24
+ bio: string = "I like compilers, elegant algorithms, bare metal, simd, and wasm.";
25
+ website: string = "https://jairus.dev/";
26
+ location: string = "Seattle, WA";
27
+ joined_at: string = "2020-01-15T08:30:00Z";
28
+ is_verified: boolean = true;
29
+ is_premium: boolean = true;
30
+ follower_count: number = 61;
31
+ following_count: number = 39;
32
+
33
+ preferences: UserPreferences = new UserPreferences();
34
+
35
+ tags: string[] = ["typescript", "webassembly", "performance", "rust", "assemblyscript", "json"];
36
+
37
+ recent_activity: RecentActivity[] = [
38
+ { action: "starred", timestamp: "2025-12-22T10:15:00Z", target: "assemblyscript/json-as" },
39
+ { action: "commented", timestamp: "2025-12-22T09:42:00Z", target: "issue #142" },
40
+ { action: "pushed", timestamp: "2025-12-21T23:58:00Z", target: "main branch" },
41
+ { action: "forked", timestamp: "2025-12-21T18:20:00Z", target: "fast-json-wasm" },
42
+ { action: "created", timestamp: "2025-12-21T14:10:00Z", target: "new benchmark suite" },
43
+ ];
13
44
  }
14
45
 
15
- const v1: MediumJSON = {
16
- id: 2,
17
- name: "Medium Object",
18
- age: 18,
19
- email: "me@jairus.dev",
20
- street: "I don't want to say my street",
21
- city: "I don't want to say this either",
22
- state: "It really depends",
23
- zip: "I forget what it is",
24
- tags: ["me", "dogs", "mountains", "bar", "foo"],
25
- };
46
+ const v1 = new MediumAPIResponse();
26
47
 
27
- const v2 = `{"id":2,"name":"Medium Object","age":18,"email":"me@jairus.dev","street":"I don't want to say my street","city":"I don't want to say this either","state":"It really depends","zip":"I forget what it is","tags":["me","dogs","mountains","bar","foo"]}`;
48
+ const v2 = JSON.stringify(v1);
28
49
 
29
50
  bench(
30
- "Serialize Medium Object",
51
+ "Serialize Medium API Response",
31
52
  () => {
32
- JSON.stringify(v1);
53
+ blackbox(JSON.stringify(v1));
33
54
  },
34
- 8_000_00,
55
+ 500_000,
56
+ v2.length << 1
35
57
  );
58
+ dumpToFile("medium", "serialize")
36
59
 
37
60
  bench(
38
- "Deserialize Medium Object",
61
+ "Deserialize Medium API Response",
39
62
  () => {
40
- JSON.parse(v2);
63
+ blackbox(JSON.parse(v2));
41
64
  },
42
- 8_000_00,
65
+ 500_000,
66
+ v2.length << 1
43
67
  );
68
+ dumpToFile("medium", "deserialize")
@@ -11,6 +11,11 @@ const { exports } = new WebAssembly.Instance(module, {
11
11
  },
12
12
  "Date.now": () => Date.now(),
13
13
  "performance.now": () => performance.now(),
14
+ "writeFile": (fileName, data) => {
15
+ fileName = __liftString(fileName)
16
+ data = __liftString(data);
17
+ writeFile(fileName, data);
18
+ }
14
19
  },
15
20
  });
16
21
 
@@ -26,4 +31,4 @@ function __liftString(pointer) {
26
31
  return string + String.fromCharCode(...memoryU16.subarray(start, end));
27
32
  }
28
33
 
29
- exports.start();
34
+ exports.start();
@@ -1,4 +1,4 @@
1
- import { bench } from "./lib/bench.js";
1
+ import { bench, blackbox, dumpToFile } from "./lib/bench.js";
2
2
 
3
3
  class SmallJSON {
4
4
  public id!: number;
@@ -16,15 +16,19 @@ const v2 = '{"id":1,"name":"Small Object","active":true}';
16
16
  bench(
17
17
  "Serialize Small Object",
18
18
  () => {
19
- JSON.stringify(v1);
19
+ blackbox(JSON.stringify(v1));
20
20
  },
21
21
  16_000_00,
22
+ v2.length << 1
22
23
  );
24
+ dumpToFile("small", "serialize")
23
25
 
24
26
  bench(
25
27
  "Deserialize Small Object",
26
28
  () => {
27
- JSON.parse(v2);
29
+ blackbox(JSON.parse(v2));
28
30
  },
29
31
  16_000_00,
32
+ v2.length << 1
30
33
  );
34
+ dumpToFile("small", "deserialize")
@@ -0,0 +1,87 @@
1
+ import { bench, blackbox, dumpToFile } from "./lib/bench";
2
+
3
+ const objSmall = { a: 1 };
4
+ const objMedium = { a: 1, b: 2, c: 3, d: 4, e: 5, f: 6, g: 7, h: 8 };
5
+ const objLarge = Object.fromEntries(Array.from({ length: 100 }, (_, i) => [`key${i}`, i]));
6
+
7
+ const arrSmall = [1, 2, 3];
8
+ const arrMedium = Array.from({ length: 100 }, (_, i) => i);
9
+ const arrLarge = Array.from({ length: 1000 }, (_, i) => i);
10
+
11
+ const strSmall = 'abc';
12
+ const strMedium = 'abcdefghijklmnopqrstuvwxyz'.repeat(10);
13
+ const strLarge = 'abcdefghijklmnopqrstuvwxyz'.repeat(100);
14
+
15
+ const ITERATIONS = 1_000_000;
16
+
17
+ const objSmallStr = JSON.stringify(objSmall);
18
+ const objMediumStr = JSON.stringify(objMedium);
19
+ const objLargeStr = JSON.stringify(objLarge);
20
+
21
+ const arrSmallStr = JSON.stringify(arrSmall);
22
+ const arrMediumStr = JSON.stringify(arrMedium);
23
+ const arrLargeStr = JSON.stringify(arrLarge);
24
+
25
+ const strSmallStr = JSON.stringify(strSmall);
26
+ const strMediumStr = JSON.stringify(strMedium);
27
+ const strLargeStr = JSON.stringify(strLarge);
28
+
29
+ // Objects
30
+ bench('Serialize Small Object', () => blackbox(JSON.stringify(objSmall)), ITERATIONS, objSmallStr.length << 1);
31
+ dumpToFile('small-obj', 'serialize');
32
+
33
+ bench('Serialize Medium Object', () => blackbox(JSON.stringify(objMedium)), ITERATIONS, objMediumStr.length << 1);
34
+ dumpToFile('medium-obj', 'serialize');
35
+
36
+ bench('Serialize Large Object', () => blackbox(JSON.stringify(objLarge)), ITERATIONS, objLargeStr.length << 1);
37
+ dumpToFile('large-obj', 'serialize');
38
+
39
+ // Arrays
40
+ bench('Serialize Small Array', () => blackbox(JSON.stringify(arrSmall)), ITERATIONS, arrSmallStr.length << 1);
41
+ dumpToFile('small-arr', 'serialize');
42
+
43
+ bench('Serialize Medium Array', () => blackbox(JSON.stringify(arrMedium)), ITERATIONS, arrMediumStr.length << 1);
44
+ dumpToFile('medium-arr', 'serialize');
45
+
46
+ bench('Serialize Large Array', () => blackbox(JSON.stringify(arrLarge)), ITERATIONS, arrLargeStr.length << 1);
47
+ dumpToFile('large-arr', 'serialize');
48
+
49
+ // Strings
50
+ bench('Serialize Small String', () => blackbox(JSON.stringify(strSmall)), ITERATIONS, strSmallStr.length << 1);
51
+ dumpToFile('small-str', 'serialize');
52
+
53
+ bench('Serialize Medium String', () => blackbox(JSON.stringify(strMedium)), ITERATIONS, strMediumStr.length << 1);
54
+ dumpToFile('medium-str', 'serialize');
55
+
56
+ bench('Serialize Large String', () => blackbox(JSON.stringify(strLarge)), ITERATIONS, strLargeStr.length << 1);
57
+ dumpToFile('large-str', 'serialize');
58
+
59
+ // Objects
60
+ bench('Deserialize Small Object', () => blackbox(JSON.parse(objSmallStr)), ITERATIONS, objSmallStr.length << 1);
61
+ dumpToFile('small-obj', 'deserialize');
62
+
63
+ bench('Deserialize Medium Object', () => blackbox(JSON.parse(objMediumStr)), ITERATIONS, objMediumStr.length << 1);
64
+ dumpToFile('medium-obj', 'deserialize');
65
+
66
+ bench('Deserialize Large Object', () => blackbox(JSON.parse(objLargeStr)), ITERATIONS, objLargeStr.length << 1);
67
+ dumpToFile('large-obj', 'deserialize');
68
+
69
+ // Arrays
70
+ bench('Deserialize Small Array', () => blackbox(JSON.parse(arrSmallStr)), ITERATIONS, arrSmallStr.length << 1);
71
+ dumpToFile('small-arr', 'deserialize');
72
+
73
+ bench('Deserialize Medium Array', () => blackbox(JSON.parse(arrMediumStr)), ITERATIONS, arrMediumStr.length << 1);
74
+ dumpToFile('medium-arr', 'deserialize');
75
+
76
+ bench('Deserialize Large Array', () => blackbox(JSON.parse(arrLargeStr)), ITERATIONS, arrLargeStr.length << 1);
77
+ dumpToFile('large-arr', 'deserialize');
78
+
79
+ // Strings
80
+ bench('Deserialize Small String', () => blackbox(JSON.parse(strSmallStr)), ITERATIONS, strSmallStr.length << 1);
81
+ dumpToFile('small-str', 'deserialize');
82
+
83
+ bench('Deserialize Medium String', () => blackbox(JSON.parse(strMediumStr)), ITERATIONS, strMediumStr.length << 1);
84
+ dumpToFile('medium-str', 'deserialize');
85
+
86
+ bench('Deserialize Large String', () => blackbox(JSON.parse(strLargeStr)), ITERATIONS, strLargeStr.length << 1);
87
+ dumpToFile('large-str', 'deserialize');
@@ -6,7 +6,8 @@
6
6
  "removeComments": true,
7
7
  "types": ["node"],
8
8
  "outDir": "../build",
9
- "sourceMap": false
9
+ "sourceMap": false,
10
+ "allowJs": true
10
11
  },
11
- "include": ["./*.ts", "./lib/*.ts"]
12
+ "include": ["./*.ts", "./lib/*.ts", "lib/bench.js"]
12
13
  }
@@ -1,4 +1,4 @@
1
- import { bench } from "./lib/bench.js";
1
+ import { bench, blackbox, dumpToFile } from "./lib/bench.js";
2
2
 
3
3
  class Vec3 {
4
4
  public x!: number;
@@ -12,15 +12,19 @@ const v2 = '{"x":1,"y":2,"z":3}';
12
12
  bench(
13
13
  "Serialize Vec3",
14
14
  () => {
15
- JSON.stringify(v1);
15
+ blackbox(JSON.stringify(v1));
16
16
  },
17
17
  16_000_00,
18
+ v2.length << 1
18
19
  );
20
+ dumpToFile("vec3", "serialize")
19
21
 
20
22
  bench(
21
23
  "Deserialize Vec3",
22
24
  () => {
23
- JSON.parse(v2);
25
+ blackbox(JSON.parse(v2));
24
26
  },
25
27
  16_000_00,
28
+ v2.length << 1
26
29
  );
30
+ dumpToFile("vec3", "deserialize")
@@ -0,0 +1,29 @@
1
+ const bytes = readbuffer("./build/" + arguments[0]);
2
+ const module = new WebAssembly.Module(bytes);
3
+ let memory = null;
4
+ const { exports } = new WebAssembly.Instance(module, {
5
+ env: {
6
+ abort: (msg, file, line) => {
7
+ console.log("abort: " + __liftString(msg) + " in " + __liftString(file) + ":" + __liftString(line));
8
+ },
9
+ "console.log": (ptr) => {
10
+ console.log(__liftString(ptr));
11
+ },
12
+ "Date.now": () => Date.now(),
13
+ "performance.now": () => performance.now(),
14
+ },
15
+ });
16
+
17
+ memory = exports.memory;
18
+
19
+ function __liftString(pointer) {
20
+ if (!pointer) return null;
21
+ const end = (pointer + new Uint32Array(memory.buffer)[(pointer - 4) >>> 2]) >>> 1,
22
+ memoryU16 = new Uint16Array(memory.buffer);
23
+ let start = pointer >>> 1,
24
+ string = "";
25
+ while (end - start > 1024) string += String.fromCharCode(...memoryU16.subarray(start, (start += 1024)));
26
+ return string + String.fromCharCode(...memoryU16.subarray(start, end));
27
+ }
28
+
29
+ exports.start();
@@ -0,0 +1,63 @@
1
+ #!/bin/bash
2
+ RUNTIMES=${RUNTIMES:-"incremental"}
3
+ ENGINES=${ENGINES:-"turbofan"}
4
+ for file in ../assembly/__benches__/*.bench.ts; do
5
+ filename=$(basename -- "$file")
6
+ for runtime in $RUNTIMES; do
7
+ output="./build/${filename%.ts}.${runtime}"
8
+
9
+ npx asc "$file" --transform ../transform -o "${output}.1" -O3 --converge --noAssert --uncheckedBehavior always --runtime $runtime --enable bulk-memory --exportStart start || {
10
+ echo "Build failed"
11
+ exit 1
12
+ }
13
+
14
+ wasm-opt --enable-bulk-memory --enable-nontrapping-float-to-int --enable-tail-call -tnh -iit -ifwl -s 0 -O4 "${output}.1" -o "${output}.wasm"
15
+ rm "${output}.1"
16
+
17
+ npx asc "$file" --transform ../transform -o "${output}.1" -O3 --converge --noAssert --uncheckedBehavior always --runtime $runtime --enable bulk-memory --enable simd --exportStart start || {
18
+ echo "Build failed"
19
+ exit 1
20
+ }
21
+
22
+ wasm-opt --enable-bulk-memory --enable-simd --enable-nontrapping-float-to-int --enable-tail-call -tnh -iit -ifwl -s 0 -O4 "${output}.1" -o "${output}.simd.wasm"
23
+ rm "${output}.1"
24
+
25
+ for engine in $ENGINES; do
26
+ echo -e "$filename (asc/$runtime/$engine)\n"
27
+
28
+ arg="${filename%.ts}.${runtime}.wasm"
29
+ argSimd="${filename%.ts}.${runtime}.simd.wasm"
30
+ if [[ "$engine" == "ignition" ]]; then
31
+ v8 --no-opt --module ./bench/runners/assemblyscript.js -- $arg
32
+ echo -e "$filename (asc/$runtime/$engine/simd)\n"
33
+ v8 --no-opt --module ./bench/runners/assemblyscript.js -- $argSimd
34
+ fi
35
+
36
+ if [[ "$engine" == "liftoff" ]]; then
37
+ v8 --liftoff-only --no-opt --module ./bench/runners/assemblyscript.js -- $arg
38
+ echo -e "$filename (asc/$runtime/$engine/simd)\n"
39
+ v8 --liftoff-only --no-opt --module ./bench/runners/assemblyscript.js -- $argSimd
40
+ fi
41
+
42
+ if [[ "$engine" == "sparkplug" ]]; then
43
+ v8 --sparkplug --always-sparkplug --no-opt --module ./bench/runners/assemblyscript.js -- $arg
44
+ echo -e "$filename (asc/$runtime/$engine/simd)\n"
45
+ v8 --sparkplug --always-sparkplug --no-opt --module ./bench/runners/assemblyscript.js -- $argSimd
46
+ fi
47
+
48
+ if [[ "$engine" == "turbofan" ]]; then
49
+ v8 --no-liftoff --no-wasm-tier-up --module ./bench/runners/assemblyscript.js -- $arg
50
+ echo -e "$filename (asc/$runtime/$engine/simd)\n"
51
+ v8 --no-liftoff --no-wasm-tier-up --module ./bench/runners/assemblyscript.js -- $argSimd
52
+ fi
53
+
54
+ if [[ "$engine" == "llvm" ]]; then
55
+ wasmer run --cranelift --enable-simd --enable-bulk-memory "${output}.wasi.wasm"
56
+ echo -e "$filename (asc/$runtime/$engine/simd)\n"
57
+ wasmer run --cranelift --enable-simd --enable-bulk-memory "${output}.wasi.simd.wasm"
58
+ fi
59
+ done
60
+ done
61
+ done
62
+
63
+ echo "Finished benchmarks"
package/lib/as-bs.ts CHANGED
@@ -167,6 +167,19 @@ export namespace bs {
167
167
  return changetype<T>(_out);
168
168
  }
169
169
 
170
+ /**
171
+ * Copies the buffer's content to a new object of a specified type.
172
+ * @returns The new object containing the buffer's content.
173
+ */
174
+ // @ts-ignore: Decorator valid here
175
+ @inline export function view<T>(): T {
176
+ const len = offset - changetype<usize>(buffer);
177
+ // @ts-ignore: exists
178
+ const _out = __new(len, idof<T>());
179
+ memory.copy(_out, changetype<usize>(buffer), len);
180
+ return changetype<T>(_out);
181
+ }
182
+
170
183
  /**
171
184
  * Copies the buffer's content to a given destination pointer.
172
185
  * Optionally shrinks the buffer after copying.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "json-as",
3
- "version": "1.1.26",
3
+ "version": "1.2.0",
4
4
  "author": "Jairus Tanaka",
5
5
  "repository": {
6
6
  "type": "git",
@@ -12,6 +12,8 @@
12
12
  "@types/node": "^25.0.3",
13
13
  "assemblyscript": "^0.28.9",
14
14
  "assemblyscript-prettier": "^3.0.1",
15
+ "chartjs-node-canvas": "^5.0.0",
16
+ "chartjs-plugin-datalabels": "^2.2.0",
15
17
  "prettier": "^3.7.4",
16
18
  "tinybench": "^6.0.0",
17
19
  "typescript": "^5.9.3"
package/run-bench.as.sh CHANGED
@@ -1,49 +1,57 @@
1
1
  #!/bin/bash
2
- RUNTIMES=${RUNTIMES:-"minimal stub"}
3
- ENGINES=${ENGINES:-"liftoff ignition sparkplug turbofan llvm"}
4
- for file in ./assembly/__benches__/abc.bench.ts; do
2
+ RUNTIMES=${RUNTIMES:-"incremental"} # incremental minimal stub
3
+ ENGINES=${ENGINES:-"turbofan"} # liftoff ignition sparkplug turbofan
4
+ mkdir -p ./build/logs/as/simd
5
+ mkdir -p ./build/logs/as/swar
6
+ for file in ./assembly/__benches__/*.bench.ts; do
5
7
  filename=$(basename -- "$file")
6
8
  for runtime in $RUNTIMES; do
7
9
  output="./build/${filename%.ts}.${runtime}"
8
10
 
9
- npx asc "$file" --transform ./transform -o "${output}.1" -O3 --converge --noAssert --uncheckedBehavior always --runtime $runtime --enable simd --enable bulk-memory --exportStart start || {
11
+ npx asc "$file" --transform ./transform -o "${output}.1" -O3 --converge --noAssert --uncheckedBehavior always --runtime $runtime --enable bulk-memory --exportStart start || {
10
12
  echo "Build failed"
11
13
  exit 1
12
14
  }
13
15
 
14
- wasm-opt --enable-bulk-memory --enable-simd --enable-nontrapping-float-to-int --enable-tail-call -tnh -iit -ifwl -s 0 -O4 "${output}.1" -o "${output}.wasm"
16
+ wasm-opt --enable-bulk-memory --enable-nontrapping-float-to-int --enable-tail-call -tnh -iit -ifwl -s 0 -O4 "${output}.1" -o "${output}.wasm"
15
17
  rm "${output}.1"
16
18
 
17
- npx asc "$file" --transform ./transform -o "${output}.2" -O3 --converge --noAssert --uncheckedBehavior always --runtime $runtime --enable simd --enable bulk-memory --config ./node_modules/@assemblyscript/wasi-shim/asconfig.json || {
19
+ npx asc "$file" --transform ./transform -o "${output}.1" -O3 --converge --noAssert --uncheckedBehavior always --runtime $runtime --enable bulk-memory --enable simd --exportStart start || {
18
20
  echo "Build failed"
19
21
  exit 1
20
22
  }
21
23
 
22
- wasm-opt --enable-bulk-memory --enable-simd --enable-nontrapping-float-to-int --enable-tail-call -tnh -iit -ifwl -s 0 -O4 "${output}.2" -o "${output%.wasm}.wasi.wasm"
23
- rm "${output}.2"
24
+ wasm-opt --enable-bulk-memory --enable-simd --enable-nontrapping-float-to-int --enable-tail-call -tnh -iit -ifwl -s 0 -O4 "${output}.1" -o "${output}.simd.wasm"
25
+ rm "${output}.1"
24
26
 
25
27
  for engine in $ENGINES; do
26
- echo -e "$filename (asc/$runtime/$engine)\n"
28
+ echo -e "$filename (asc/$runtime/$engine/swar)\n"
27
29
 
28
30
  arg="${filename%.ts}.${runtime}.wasm"
31
+
32
+ argSimd="${filename%.ts}.${runtime}.simd.wasm"
29
33
  if [[ "$engine" == "ignition" ]]; then
30
34
  v8 --no-opt --module ./bench/runners/assemblyscript.js -- $arg
35
+ echo -e "$filename (asc/$runtime/$engine/simd)\n"
36
+ v8 --no-opt --module ./bench/runners/assemblyscript.js -- $argSimd
31
37
  fi
32
38
 
33
39
  if [[ "$engine" == "liftoff" ]]; then
34
40
  v8 --liftoff-only --no-opt --module ./bench/runners/assemblyscript.js -- $arg
41
+ echo -e "$filename (asc/$runtime/$engine/simd)\n"
42
+ v8 --liftoff-only --no-opt --module ./bench/runners/assemblyscript.js -- $argSimd
35
43
  fi
36
44
 
37
45
  if [[ "$engine" == "sparkplug" ]]; then
38
46
  v8 --sparkplug --always-sparkplug --no-opt --module ./bench/runners/assemblyscript.js -- $arg
47
+ echo -e "$filename (asc/$runtime/$engine/simd)\n"
48
+ v8 --sparkplug --always-sparkplug --no-opt --module ./bench/runners/assemblyscript.js -- $argSimd
39
49
  fi
40
50
 
41
51
  if [[ "$engine" == "turbofan" ]]; then
42
52
  v8 --no-liftoff --no-wasm-tier-up --module ./bench/runners/assemblyscript.js -- $arg
43
- fi
44
-
45
- if [[ "$engine" == "llvm" ]]; then
46
- wasmer run --cranelift --enable-simd --enable-bulk-memory "${output}.wasi.wasm"
53
+ echo -e "$filename (asc/$runtime/$engine/simd)\n"
54
+ v8 --no-liftoff --no-wasm-tier-up --module ./bench/runners/assemblyscript.js -- $argSimd
47
55
  fi
48
56
  done
49
57
  done
package/run-bench.js.sh CHANGED
@@ -1,7 +1,9 @@
1
1
  #!/bin/bash
2
- RUNTIMES=${RUNTIMES:-"liftoff ignition sparkplug turbofan"}
2
+ RUNTIMES=${RUNTIMES:-"turbofan"}
3
3
  npx tsc -p ./bench > /dev/null 2>&1
4
- for file in ./bench/vec3.bench.ts; do
4
+ cp ./bench/lib/bench.js ./build/lib/bench.js
5
+ mkdir -p ./build/logs/js
6
+ for file in ./bench/*.bench.ts; do
5
7
  filename=$(basename -- "$file")
6
8
  file_js="${filename%.ts}.js"
7
9
 
@@ -12,21 +14,21 @@ for file in ./bench/vec3.bench.ts; do
12
14
  engine=$(echo $rt | cut -d'-' -f2-)
13
15
  echo -e "$filename (js/$runtime/$engine)\n"
14
16
 
15
- arg="${filename%.ts}.${runtime}.wasm"
17
+ arg="${filename%.ts}.${runtime}.ts"
16
18
  if [[ "$engine" == "ignition" ]]; then
17
- v8 --no-opt --module ./build/$file_js
19
+ v8 --no-opt --allow-natives-syntax --module ./build/$file_js -- $arg
18
20
  fi
19
21
 
20
22
  if [[ "$engine" == "liftoff" ]]; then
21
- v8 --liftoff-only --no-opt --module ./build/$file_js
23
+ v8 --liftoff-only --no-opt --allow-natives-syntax --module ./build/$file_js -- $arg
22
24
  fi
23
25
 
24
26
  if [[ "$engine" == "sparkplug" ]]; then
25
- v8 --sparkplug --always-sparkplug --no-opt --module ./build/$file_js
27
+ v8 --sparkplug --always-sparkplug --allow-natives-syntax --no-opt --module ./build/$file_js -- $arg
26
28
  fi
27
29
 
28
30
  if [[ "$engine" == "turbofan" ]]; then
29
- v8 --no-liftoff --no-wasm-tier-up --module ./build/$file_js
31
+ v8 --no-liftoff --no-wasm-tier-up --allow-natives-syntax --module ./build/$file_js -- $arg
30
32
  fi
31
33
  done
32
34
  done
package/run-tests.sh CHANGED
@@ -5,24 +5,44 @@ mkdir -p ./build
5
5
  for file in ./assembly/__tests__/*.spec.ts; do
6
6
  filename=$(basename -- "$file")
7
7
  if [ -z "$1" ] || [ "$1" = "$filename" ]; then
8
- output="./build/${filename%.ts}.wasm"
8
+ for mode in swar simd; do
9
+ output="./build/${filename%.ts}.${mode}.wasm"
9
10
 
10
- start_time=$(date +%s%3N)
11
- npx asc "$file" --transform ./transform -o "$output" --runtime incremental --enable simd --config ./node_modules/@assemblyscript/wasi-shim/asconfig.json --debug --disableWarning 226 || { echo "Tests failed"; exit 1; }
12
- end_time=$(date +%s%3N)
11
+ start_time=$(date +%s%3N)
13
12
 
14
- build_time=$((end_time - start_time))
13
+ if [ "$mode" = "simd" ]; then
14
+ npx asc "$file" \
15
+ --transform ./transform \
16
+ -o "$output" \
17
+ --runtime incremental \
18
+ --enable simd \
19
+ --config ./node_modules/@assemblyscript/wasi-shim/asconfig.json \
20
+ --debug \
21
+ --disableWarning 226 || { echo "Tests failed ($mode)"; exit 1; }
22
+ else
23
+ npx asc "$file" \
24
+ --transform ./transform \
25
+ -o "$output" \
26
+ --runtime incremental \
27
+ --config ./node_modules/@assemblyscript/wasi-shim/asconfig.json \
28
+ --debug \
29
+ --disableWarning 226 || { echo "Tests failed ($mode)"; exit 1; }
30
+ fi
15
31
 
16
- if [ "$build_time" -ge 60000 ]; then
17
- formatted_time="$(bc <<< "scale=2; $build_time/60000")m"
18
- elif [ "$build_time" -ge 1000 ]; then
19
- formatted_time="$(bc <<< "scale=2; $build_time/1000")s"
20
- else
21
- formatted_time="${build_time}ms"
22
- fi
32
+ end_time=$(date +%s%3N)
33
+ build_time=$((end_time - start_time))
23
34
 
24
- echo " -> $filename (built in $formatted_time)"
25
- wasmtime "$output" || { echo "Tests failed"; exit 1; }
35
+ if [ "$build_time" -ge 60000 ]; then
36
+ formatted_time="$(bc <<< "scale=2; $build_time/60000")m"
37
+ elif [ "$build_time" -ge 1000 ]; then
38
+ formatted_time="$(bc <<< "scale=2; $build_time/1000")s"
39
+ else
40
+ formatted_time="${build_time}ms"
41
+ fi
42
+
43
+ echo " -> $filename ($mode build in $formatted_time)"
44
+ wasmtime "$output" || { echo "Tests failed ($mode)"; exit 1; }
45
+ done
26
46
  else
27
47
  echo " -> $filename (skipped)"
28
48
  fi
@@ -0,0 +1,38 @@
1
+ import {
2
+ getBenchResults,
3
+ createBarChart,
4
+ generateChart,
5
+ type BenchKind
6
+ } from "./lib/bench-utils";
7
+
8
+ const PAYLOADS: Record<string, string> = {
9
+ abc: "Alphabet (104b)",
10
+ vec3: "3D Vector (38b)",
11
+ small: "Small Payload (88b)",
12
+ medium: "Medium Payload (2.1kb)",
13
+ large: "Large Payload (10.5kb)"
14
+ };
15
+
16
+ const KIND: BenchKind = "serialize";
17
+ const OUTPUT_FILE = "./data/chart01.svg";
18
+
19
+ const allResults = getBenchResults(Object.keys(PAYLOADS));
20
+
21
+ const chartData: Record<string, any> = {};
22
+
23
+ for (const payload of Object.keys(PAYLOADS)) {
24
+ chartData[payload] = allResults[payload][KIND];
25
+ }
26
+
27
+ const config = createBarChart(chartData, PAYLOADS, {
28
+ title: "Serialization Throughput by Payload Size",
29
+ yLabel: "Throughput (MB/s)",
30
+ xLabel: "Payload",
31
+ datasetLabels: [
32
+ "Built-in JSON (JS)",
33
+ "JSON-AS (SWAR)",
34
+ "JSON-AS (SIMD)"
35
+ ]
36
+ });
37
+
38
+ generateChart(config, OUTPUT_FILE);
@@ -0,0 +1,38 @@
1
+ import {
2
+ getBenchResults,
3
+ createBarChart,
4
+ generateChart,
5
+ type BenchKind
6
+ } from "./lib/bench-utils";
7
+
8
+ const PAYLOADS: Record<string, string> = {
9
+ abc: "Alphabet (104b)",
10
+ vec3: "3D Vector (38b)",
11
+ small: "Small Payload (88b)",
12
+ medium: "Medium Payload (2.1kb)",
13
+ large: "Large Payload (10.5kb)"
14
+ };
15
+
16
+ const KIND: BenchKind = "deserialize";
17
+ const OUTPUT_FILE = "./data/chart02.svg";
18
+
19
+ const allResults = getBenchResults(Object.keys(PAYLOADS));
20
+
21
+ const chartData: Record<string, any> = {};
22
+
23
+ for (const payload of Object.keys(PAYLOADS)) {
24
+ chartData[payload] = allResults[payload][KIND];
25
+ }
26
+
27
+ const config = createBarChart(chartData, PAYLOADS, {
28
+ title: "Deserialization Throughput by Payload Size",
29
+ yLabel: "Throughput (MB/s)",
30
+ xLabel: "Payload",
31
+ datasetLabels: [
32
+ "Built-in JSON (JS)",
33
+ "JSON-AS (SWAR)",
34
+ "JSON-AS (SIMD)"
35
+ ]
36
+ });
37
+
38
+ generateChart(config, OUTPUT_FILE);