json-as 1.1.25 → 1.1.27

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 (52) hide show
  1. package/.github/workflows/benchmark.yml +64 -0
  2. package/.prettierrc.json +1 -0
  3. package/CHANGELOG.md +4 -0
  4. package/README.md +40 -63
  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 +128 -0
  16. package/assembly/index.ts +6 -2
  17. package/assembly/serialize/swar/number.ts +0 -0
  18. package/assembly/serialize/swar/string.ts +72 -70
  19. package/assembly/test.tmp.ts +5 -9
  20. package/assembly/test.ts +3 -6
  21. package/bench/abc.bench.ts +6 -8
  22. package/bench/large.bench.ts +119 -118
  23. package/bench/lib/bench.d.ts +27 -0
  24. package/bench/lib/bench.js +53 -0
  25. package/bench/lib/chart.ts +217 -0
  26. package/bench/medium.bench.ts +55 -30
  27. package/bench/runners/assemblyscript.js +6 -1
  28. package/bench/small.bench.ts +7 -3
  29. package/bench/throughput.ts +87 -0
  30. package/bench/tsconfig.json +3 -2
  31. package/bench/vec3.bench.ts +7 -3
  32. package/ci/bench/runners/assemblyscript.js +29 -0
  33. package/ci/run-bench.as.sh +63 -0
  34. package/data/chart01.svg +258 -0
  35. package/data/chart02.svg +246 -0
  36. package/data/chart03.svg +193 -0
  37. package/data/chart05.svg +142 -0
  38. package/dump.txt +41590 -0
  39. package/package.json +4 -2
  40. package/run-bench.as.sh +21 -13
  41. package/run-bench.js.sh +9 -7
  42. package/run-tests.sh +34 -14
  43. package/scripts/build-chart01.ts +38 -0
  44. package/scripts/build-chart02.ts +38 -0
  45. package/scripts/build-chart03.ts +139 -0
  46. package/scripts/build-chart05.ts +47 -0
  47. package/scripts/generate-as-class.ts +50 -0
  48. package/scripts/lib/bench-utils.ts +308 -0
  49. package/transform/lib/index.js +2 -2
  50. package/transform/lib/index.js.map +1 -1
  51. package/transform/src/index.ts +2 -2
  52. /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"