json-as 1.0.7 → 1.0.9

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 (42) hide show
  1. package/CHANGELOG.md +15 -0
  2. package/README.md +18 -2
  3. package/asconfig.json +1 -2
  4. package/assembly/__benches__/abc.bench.ts +5 -5
  5. package/assembly/__benches__/large.bench.ts +5 -51
  6. package/assembly/{custom → __benches__/lib}/bench.ts +4 -0
  7. package/assembly/__benches__/medium.bench.ts +3 -3
  8. package/assembly/__benches__/small.bench.ts +1 -1
  9. package/assembly/__benches__/vec3.bench.ts +3 -49
  10. package/assembly/__tests__/custom.spec.ts +4 -3
  11. package/assembly/__tests__/hierarchy.spec.ts +55 -0
  12. package/assembly/__tests__/lib/index.ts +1 -0
  13. package/assembly/custom/util.ts +0 -4
  14. package/assembly/deserialize/simple/array/box.ts +45 -0
  15. package/assembly/deserialize/simple/array/object.ts +28 -0
  16. package/assembly/deserialize/simple/array.ts +8 -0
  17. package/assembly/index.ts +39 -41
  18. package/assembly/serialize/simd/string.ts +12 -12
  19. package/assembly/test.ts +46 -133
  20. package/assembly/util/idofd.ts +6 -0
  21. package/bench/abc.bench.ts +1 -1
  22. package/bench/large.bench.ts +3 -3
  23. package/bench/lib/bench.ts +12 -0
  24. package/bench/medium.bench.ts +1 -1
  25. package/bench/runners/assemblyscript.js +28 -0
  26. package/bench/small.bench.ts +1 -1
  27. package/bench/tsconfig.json +12 -0
  28. package/bench/vec3.bench.ts +1 -1
  29. package/package.json +3 -4
  30. package/run-bench.as.sh +44 -18
  31. package/run-bench.js.sh +32 -6
  32. package/run-tests.sh +1 -1
  33. package/transform/lib/index.js +381 -122
  34. package/transform/lib/index.js.map +1 -1
  35. package/transform/lib/types.js +1 -0
  36. package/transform/lib/types.js.map +1 -1
  37. package/transform/src/index.ts +430 -117
  38. package/transform/src/types.ts +1 -0
  39. package/assembly/__benches__/lib/index.ts +0 -26
  40. package/assembly/custom/memory.ts +0 -25
  41. package/assembly/custom/sink.ts +0 -231
  42. package/assembly/custom/types.ts +0 -5
package/assembly/index.ts CHANGED
@@ -15,7 +15,6 @@ import { deserializeInteger } from "./deserialize/simple/integer";
15
15
  import { deserializeString } from "./deserialize/simple/string";
16
16
  import { serializeArbitrary } from "./serialize/simple/arbitrary";
17
17
 
18
- import { Sink } from "./custom/sink";
19
18
  import { NULL_WORD, QUOTE } from "./custom/chars";
20
19
  import { dtoa_buffered, itoa_buffered } from "util/number";
21
20
  import { serializeBool } from "./serialize/simple/bool";
@@ -29,8 +28,6 @@ import { serializeObject } from "./serialize/simple/object";
29
28
  import { deserializeObject } from "./deserialize/simple/object";
30
29
  import { serializeRaw } from "./serialize/simple/raw";
31
30
  import { deserializeRaw } from "./deserialize/simple/raw";
32
- import { isSpace } from "util/string";
33
- import { deserializeString_SIMD } from "./deserialize/simd/string";
34
31
 
35
32
  /**
36
33
  * Offset of the 'storage' property in the JSON.Value class.
@@ -116,12 +113,11 @@ export namespace JSON {
116
113
  // bs.setBuffer(oldBuf);
117
114
  // return changetype<string>(newBuf);
118
115
  // }
119
- serializeString(changetype<string>(data));
120
- return bs.out<string>();
121
- // @ts-ignore: Supplied by transform
122
- } else if (isDefined(data.__SERIALIZE_CUSTOM)) {
123
- // @ts-ignore
124
- inline.always(data.__SERIALIZE_CUSTOM());
116
+ // if (ASC_FEATURE_SIMD) {
117
+ // serializeString_SIMD(data as string);
118
+ // } else {
119
+ serializeString(data as string);
120
+ // }
125
121
  return bs.out<string>();
126
122
  // @ts-ignore: Supplied by transform
127
123
  } else if (isDefined(data.__SERIALIZE)) {
@@ -145,7 +141,7 @@ export namespace JSON {
145
141
  inline.always(serializeMap(changetype<nonnull<T>>(data)));
146
142
  return bs.out<string>();
147
143
  } else if (data instanceof JSON.Raw) {
148
- inline.always(serializeRaw(data));
144
+ serializeRaw(data);
149
145
  return bs.out<string>();
150
146
  } else if (data instanceof JSON.Value) {
151
147
  inline.always(serializeArbitrary(data));
@@ -196,19 +192,12 @@ export namespace JSON {
196
192
  } else {
197
193
  let type: nonnull<T> = changetype<nonnull<T>>(0);
198
194
  // @ts-ignore: Defined by transform
199
- if (isDefined(type.__DESERIALIZE_CUSTOM)) {
200
- const out = changetype<nonnull<T>>(0);
195
+ if (isDefined(type.__DESERIALIZE)) {
196
+ const out = changetype<nonnull<T>>(__new(offsetof<nonnull<T>>(), idof<nonnull<T>>()));
201
197
  // @ts-ignore: Defined by transform
202
198
  if (isDefined(type.__INITIALIZE)) out.__INITIALIZE();
203
199
  // @ts-ignore
204
- return out.__DESERIALIZE_CUSTOM(ptrToStr(dataPtr, dataPtr + dataSize));
205
- // @ts-ignore: Defined by transform
206
- } else if (isDefined(type.__DESERIALIZE)) {
207
- const out = __new(offsetof<nonnull<T>>(), idof<nonnull<T>>());
208
- // @ts-ignore: Defined by transform
209
- if (isDefined(type.__INITIALIZE)) changetype<nonnull<T>>(out).__INITIALIZE();
210
- // @ts-ignore
211
- return inline.always(deserializeStruct<nonnull<T>>(dataPtr, dataPtr + dataSize, out));
200
+ return out.__DESERIALIZE(dataPtr, dataPtr + dataSize, out);
212
201
  } else if (type instanceof Map) {
213
202
  // @ts-ignore
214
203
  return inline.always(deserializeMap<nonnull<T>>(dataPtr, dataPtr + dataSize, 0));
@@ -404,18 +393,16 @@ export namespace JSON {
404
393
  case JSON.Types.Array: {
405
394
  const arr = this.get<JSON.Value[]>();
406
395
  if (!arr.length) return "[]";
407
- const out = Sink.fromStringLiteral("[");
396
+ let out = "[";
408
397
  const end = arr.length - 1;
409
398
  for (let i = 0; i < end; i++) {
410
399
  const element = unchecked(arr[i]);
411
- out.write(element.toString());
412
- out.write(",");
400
+ out += element.toString() + ",";
413
401
  }
414
402
 
415
403
  const element = unchecked(arr[end]);
416
- out.write(element.toString());
404
+ out += element.toString() + "]";
417
405
 
418
- out.write("]");
419
406
  return out.toString();
420
407
  }
421
408
  case JSON.Types.Object: {
@@ -556,22 +543,22 @@ export namespace JSON {
556
543
  // @ts-ignore: Supplied by transform
557
544
  } else if (isDefined(src.__SERIALIZE)) {
558
545
  // @ts-ignore
559
- inline.always(serializeStruct(changetype<nonnull<T>>(src)));
546
+ serializeStruct(changetype<nonnull<T>>(src));
560
547
  } else if (src instanceof Date) {
561
548
  // @ts-ignore
562
549
  inline.always(serializeDate(changetype<nonnull<T>>(src)));
563
550
  } else if (src instanceof Array) {
564
551
  // @ts-ignore
565
- inline.always(serializeArray(changetype<nonnull<T>>(src)));
552
+ serializeArray(changetype<nonnull<T>>(src));
566
553
  } else if (src instanceof Map) {
567
554
  // @ts-ignore
568
- inline.always(serializeMap(changetype<nonnull<T>>(src)));
555
+ serializeMap(changetype<nonnull<T>>(src));
569
556
  } else if (src instanceof JSON.Raw) {
570
557
  serializeRaw(src);
571
558
  } else if (src instanceof JSON.Value) {
572
- inline.always(serializeArbitrary(src));
559
+ serializeArbitrary(src);
573
560
  } else if (src instanceof JSON.Obj) {
574
- inline.always(serializeObject(src));
561
+ serializeObject(src);
575
562
  } else if (src instanceof JSON.Box) {
576
563
  __serialize(src.value);
577
564
  } else {
@@ -596,22 +583,17 @@ export namespace JSON {
596
583
  return null;
597
584
  } else if (isArray<T>()) {
598
585
  // @ts-ignore: type
599
- return inline.always(deserializeArray<T>(srcStart, srcEnd, dst));
586
+ return deserializeArray<T>(srcStart, srcEnd, dst);
600
587
  } else {
601
588
  let type: nonnull<T> = changetype<nonnull<T>>(0);
602
589
  // @ts-ignore: Defined by transform
603
- if (isDefined(type.__DESERIALIZE_CUSTOM)) {
604
- const out = __new(offsetof<nonnull<T>>(), idof<nonnull<T>>());
590
+ if (isDefined(type.__DESERIALIZE)) {
591
+ const out = changetype<nonnull<T>>(dst || __new(offsetof<nonnull<T>>(), idof<nonnull<T>>()))
605
592
  // @ts-ignore: Defined by transform
606
- if (isDefined(type.__INITIALIZE)) changetype<nonnull<T>>(out).__INITIALIZE();
607
- // @ts-ignore
608
- return changetype<nonnull<T>>(out).__DESERIALIZE_CUSTOM(ptrToStr(srcStart, srcEnd));
609
- // @ts-ignore: Defined by transform
610
- } else if (isDefined(type.__DESERIALIZE)) {
611
- return inline.always(deserializeStruct<T>(srcStart, srcEnd, dst));
593
+ return out.__DESERIALIZE(srcStart, srcEnd, out);
612
594
  } else if (type instanceof Map) {
613
595
  // @ts-ignore: type
614
- return inline.always(deserializeMap<T>(srcStart, srcEnd, dst));
596
+ return deserializeMap<T>(srcStart, srcEnd, dst);
615
597
  } else if (type instanceof Date) {
616
598
  // @ts-ignore: type
617
599
  return deserializeDate(srcStart, srcEnd);
@@ -620,7 +602,10 @@ export namespace JSON {
620
602
  return deserializeRaw(srcStart, srcEnd);
621
603
  } else if (type instanceof JSON.Value) {
622
604
  // @ts-ignore: type
623
- return inline.always(deserializeArbitrary(srcStart, srcEnd, 0));
605
+ return deserializeArbitrary(srcStart, srcEnd, 0);
606
+ } else if (type instanceof JSON.Obj) {
607
+ // @ts-ignore: type
608
+ return deserializeObject(srcStart, srcEnd, 0);
624
609
  } else if (type instanceof JSON.Box) {
625
610
  // @ts-ignore: type
626
611
  return new JSON.Box(deserializeBox(srcStart, srcEnd, dst, changetype<nonnull<T>>(0).value));
@@ -628,6 +613,19 @@ export namespace JSON {
628
613
  }
629
614
  throw new Error(`Could not deserialize data '${ptrToStr(srcStart, srcEnd).slice(0, 100)}' to type. Make sure to add the correct decorators to classes.`);
630
615
  }
616
+ namespace Util {
617
+ // @ts-ignore: decorator
618
+ @inline export function isSpace(code: u16): boolean {
619
+ return code == 0x20 || code - 9 <= 4;
620
+ }
621
+ // @ts-ignore: decorator
622
+ @inline export function ptrToStr(start: usize, end: usize): string {
623
+ const size = end - start;
624
+ const out = __new(size, idof<string>());
625
+ memory.copy(out, start, size);
626
+ return changetype<string>(out);
627
+ }
628
+ }
631
629
  }
632
630
 
633
631
  // @ts-ignore: decorator
@@ -1,13 +1,7 @@
1
1
  import { bs } from "../../../lib/as-bs";
2
2
  import { BACK_SLASH } from "../../custom/chars";
3
3
  import { SERIALIZE_ESCAPE_TABLE } from "../../globals/tables";
4
- import { OBJECT, TOTAL_OVERHEAD } from "rt/common";
5
-
6
- const SPLAT_34 = i16x8.splat(34); /* " */
7
- const SPLAT_92 = i16x8.splat(92); /* \ */
8
-
9
- const SPLAT_32 = i16x8.splat(32); /* [ESC] */
10
- const SPLAT_0 = i16x8.splat(0); /* 0 */
4
+ import { bytes } from "../../util";
11
5
 
12
6
  /**
13
7
  * Serializes strings into their JSON counterparts using SIMD operations
@@ -15,16 +9,23 @@ const SPLAT_0 = i16x8.splat(0); /* 0 */
15
9
  * @param srcEnd pointer to end serialization at
16
10
  */
17
11
  export function serializeString_SIMD(src: string): void {
18
- const srcSize = changetype<OBJECT>(changetype<usize>(src) - TOTAL_OVERHEAD).rtSize;
12
+ const SPLAT_34 = i16x8.splat(34); /* " */
13
+ const SPLAT_92 = i16x8.splat(92); /* \ */
14
+
15
+ const SPLAT_32 = i16x8.splat(32); /* [ESC] */
16
+ const SPLAT_0 = i16x8.splat(0); /* 0 */
17
+
18
+ const srcSize = bytes(src);
19
19
  let srcStart = changetype<usize>(src);
20
20
  const srcEnd = srcStart + srcSize;
21
+ const srcEnd16 = srcEnd - 16;
22
+
21
23
  bs.proposeSize(srcSize + 4);
22
- const srcEnd16 = srcEnd - 15;
23
24
 
24
25
  store<u8>(changetype<usize>(bs.offset), 34); /* " */
25
26
  bs.offset += 2;
26
27
 
27
- while (srcStart < srcEnd16) {
28
+ while (srcStart <= srcEnd16) {
28
29
  const block = v128.load(srcStart);
29
30
  v128.store(bs.offset, block);
30
31
 
@@ -62,8 +63,7 @@ export function serializeString_SIMD(src: string): void {
62
63
  bs.offset += 16;
63
64
  }
64
65
 
65
- let rem = srcEnd - srcStart;
66
-
66
+ const rem = srcEnd - srcStart;
67
67
  if (rem & 8) {
68
68
  const block = v128.load64_zero(srcStart);
69
69
  v128.store64_lane(bs.offset, block, 0);
package/assembly/test.ts CHANGED
@@ -1,153 +1,66 @@
1
1
  import { JSON } from ".";
2
2
  import { bytes } from "./util";
3
-
4
-
5
3
  @json
6
- class Obj {
7
- public a: string = "hello";
8
- public b: string = "world";
9
- public c: string = '"\t\f\u0000\u0001';
10
- }
11
-
12
-
13
- @json
14
- class Vec3 {
15
- x: f32 = 0.0;
16
- y: f32 = 0.0;
17
- z: f32 = 0.0;
18
- }
4
+ class GenericEnum<T> {
5
+ private tag: string = ""
6
+ private value: T | null = null
19
7
 
8
+ constructor() {
9
+ this.tag = ""
10
+ this.value = null
11
+ }
20
12
 
21
- @json
22
- class Player {
23
- @alias("first name")
24
- firstName!: string;
25
- lastName!: string;
26
- lastActive!: i32[];
27
- // Drop in a code block, function, or expression that evaluates to a boolean
28
- @omitif((self: Player) => self.age < 18)
29
- age!: i32;
30
-
31
-
32
- @omitnull()
33
- pos!: Vec3 | null;
34
- isVerified!: boolean;
35
- }
36
-
13
+ static create<T>(tag: string, value: T): GenericEnum<T> {
14
+ const item = new GenericEnum<T>()
15
+ item.tag = tag
16
+ item.value = value
17
+ return item
18
+ }
37
19
 
38
- @json
39
- class Point {
40
- x: f64 = 0.0;
41
- y: f64 = 0.0;
42
- constructor(x: f64, y: f64) {
43
- this.x = x;
44
- this.y = y;
20
+ getTag(): string {
21
+ return this.tag
45
22
  }
46
23
 
24
+ getValue(): T | null {
25
+ return this.value
26
+ }
47
27
 
48
28
  @serializer
49
- serializer(self: Point): string {
50
- return `(${self.x},${self.y})`;
29
+ serialize(self: GenericEnum<T>): string {
30
+ const tagJson = JSON.stringify(self.tag)
31
+ const valueJson = JSON.stringify(self.value)
32
+ return `{"tag":${tagJson},"value":${valueJson}}`
51
33
  }
52
34
 
53
-
54
35
  @deserializer
55
- deserializer(data: string): Point | null {
56
- const dataSize = bytes(data);
57
- if (dataSize <= 2) return null;
58
-
59
- const c = data.indexOf(",");
60
- const x = data.slice(1, c);
61
- const y = data.slice(c + 1, data.length - 1);
36
+ deserialize(data: string): GenericEnum<T> {
37
+ const parsed = JSON.parse<Map<string, JSON.Raw>>(data);
38
+ const result = new GenericEnum<T>();
62
39
 
63
- return new Point(f64.parse(x), f64.parse(y));
64
- }
65
- }
40
+ if (parsed.has("tag")) {
41
+ result.tag = JSON.parse<string>(parsed.get("tag").data);
42
+ }
66
43
 
44
+ if (parsed.has("value")) {
45
+ result.value = JSON.parse<T>(parsed.get("value").data);
46
+ }
67
47
 
68
- @json
69
- class InnerObj<T> {
70
- obj: T = instantiate<T>();
48
+ return result;
49
+ }
71
50
  }
72
51
 
73
-
74
- @json
75
- class ObjWithBracketString {
76
- data: string = "";
52
+ export function test(): void {
53
+ const myEnum = GenericEnum.create<string>("test_tag", "test_value");
54
+ // Serialize it
55
+ const serialized = JSON.stringify<GenericEnum<string>>(myEnum);
56
+ console.log("=== Serialized ===");
57
+ console.log(serialized);
58
+ console.log("=== Attempting to deserialize (this will crash) ===");
59
+
60
+ // This line crashes
61
+ const parsed = JSON.parse<GenericEnum<string>>(serialized);
62
+ console.log("=== Deserialized ===");
63
+ console.log(JSON.stringify(parsed))
77
64
  }
78
65
 
79
- const player: Player = {
80
- firstName: "Jairus",
81
- lastName: "Tanaka",
82
- lastActive: [2, 7, 2025],
83
- age: 18,
84
- pos: {
85
- x: 3.4,
86
- y: 1.2,
87
- z: 8.3,
88
- },
89
- isVerified: true,
90
- };
91
-
92
- const a1 = JSON.stringify("\u0000\u0001\u0002\u0003\u0004\u0005\u0006\u0007\u0008\u0009\u000a\u000b\u000c\u000d\u000e\u000f\u000f\u0011\u0012\u0013\u0014\u0015\u0016\u0017\u0018\u0019\u001a\u001b\u001c\u001d\u001e\u001f");
93
- // console.log("Bytes " + bytes(a1).toString());
94
- console.log("a1: " + a1);
95
-
96
- const obj = new Obj();
97
- const a2 = JSON.stringify(obj);
98
- // console.log("Bytes " + bytes(a2).toString());
99
- console.log("a2: " + a2);
100
-
101
- const a3 = JSON.stringify(player);
102
- // console.log("Bytes " + bytes(a3).toString());
103
- console.log("a3: " + a3);
104
-
105
- const a4 = new JSON.Obj();
106
-
107
- a4.set("x", 1.5);
108
- a4.set("y", 5.4);
109
- a4.set("z", 9.8);
110
- a4.set("obj", obj);
111
- a4.set<boolean>("bool", false);
112
-
113
- console.log("a4: " + JSON.stringify(a4));
114
-
115
- const a5 = JSON.parse<JSON.Obj>('{"foo":"bar"}');
116
-
117
- console.log("a5: " + JSON.stringify(a5));
118
-
119
- const a6 = JSON.parse<JSON.Obj>('{"x":1.5,"y":5.4,"z":9.8,"obj":{"foo":"bar"}}');
120
-
121
- console.log("a6: " + JSON.stringify(a6));
122
-
123
- const a7 = JSON.parse<JSON.Value[]>('["string",true,3.14,{"x":1.0,"y":2.0,"z":3.0},[1,2,3,true]]');
124
-
125
- console.log("a7: " + JSON.stringify(a7));
126
-
127
- const a8 = JSON.stringify(["hello", JSON.stringify("world"), "working?"]);
128
-
129
- console.log("a8: " + a8);
130
-
131
- const a9 = JSON.stringify<JSON.Raw>(JSON.Raw.from('"hello world"'));
132
-
133
- console.log("a9: " + a9);
134
-
135
- const m10 = new Map<string, JSON.Raw>();
136
- m10.set("hello", new JSON.Raw('"world"'));
137
- m10.set("pos", new JSON.Raw('{"x":1.0,"y":2.0,"z":3.0}'));
138
-
139
- const a10 = JSON.stringify(m10);
140
-
141
- console.log("a10: " + a10);
142
-
143
- const a11 = JSON.parse<JSON.Obj>(' { "x" : 3.4 , "y" : 1.2 , "z" : 8.3 } ');
144
-
145
- console.log("a11: " + JSON.stringify(a11));
146
-
147
- const a12 = JSON.parse<InnerObj<ObjWithBracketString>>('{"obj":{"data":"hello} world"}}');
148
-
149
- console.log("a12: " + JSON.stringify(a12));
150
-
151
- const a13 = JSON.stringify<JSON.Obj>(new JSON.Obj());
152
-
153
- console.log("a13: " + a13);
66
+ test();
@@ -0,0 +1,6 @@
1
+ import { OBJECT, TOTAL_OVERHEAD } from "rt/common";
2
+
3
+ // @ts-ignore: decorator
4
+ @inline export function idofD<T>(value: T): usize {
5
+ return changetype<OBJECT>(changetype<usize>(value) - TOTAL_OVERHEAD).rtId;
6
+ }
@@ -1,4 +1,4 @@
1
- import { bench } from "./lib/bench";
1
+ import { bench } from "./lib/bench.js";
2
2
 
3
3
  const v1 = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
4
4
  const v2 = '"abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"';
@@ -1,4 +1,4 @@
1
- import { bench } from "./lib/bench";
1
+ import { bench } from "./lib/bench.js";
2
2
 
3
3
  class Vec3 {
4
4
  public x!: number;
@@ -110,7 +110,7 @@ const v1: LargeJSON = {
110
110
  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"],"theme":"Hyper Term Black","notifications":true,"language":"en-US","movement":[{"x":1,"y":2,"z":3},{"x":1,"y":2,"z":3},{"x":1,"y":2,"z":3},{"x":1,"y":2,"z":3},{"x":1,"y":2,"z":3},{"x":1,"y":2,"z":3},{"x":1,"y":2,"z":3},{"x":1,"y":2,"z":3},{"x":1,"y":2,"z":3},{"x":1,"y":2,"z":3},{"x":1,"y":2,"z":3},{"x":1,"y":2,"z":3},{"x":1,"y":2,"z":3},{"x":1,"y":2,"z":3},{"x":1,"y":2,"z":3},{"x":1,"y":2,"z":3},{"x":1,"y":2,"z":3},{"x":1,"y":2,"z":3},{"x":1,"y":2,"z":3},{"x":1,"y":2,"z":3},{"x":1,"y":2,"z":3},{"x":1,"y":2,"z":3},{"x":1,"y":2,"z":3},{"x":1,"y":2,"z":3},{"x":1,"y":2,"z":3},{"x":1,"y":2,"z":3},{"x":1,"y":2,"z":3},{"x":1,"y":2,"z":3},{"x":1,"y":2,"z":3},{"x":1,"y":2,"z":3},{"x":1,"y":2,"z":3},{"x":1,"y":2,"z":3},{"x":1,"y":2,"z":3},{"x":1,"y":2,"z":3},{"x":1,"y":2,"z":3},{"x":1,"y":2,"z":3},{"x":1,"y":2,"z":3},{"x":1,"y":2,"z":3},{"x":1,"y":2,"z":3},{"x":1,"y":2,"z":3},{"x":1,"y":2,"z":3},{"x":1,"y":2,"z":3},{"x":1,"y":2,"z":3},{"x":1,"y":2,"z":3},{"x":1,"y":2,"z":3},{"x":1,"y":2,"z":3},{"x":1,"y":2,"z":3},{"x":1,"y":2,"z":3},{"x":1,"y":2,"z":3},{"x":1,"y":2,"z":3},{"x":1,"y":2,"z":3},{"x":1,"y":2,"z":3},{"x":1,"y":2,"z":3},{"x":1,"y":2,"z":3},{"x":1,"y":2,"z":3},{"x":1,"y":2,"z":3},{"x":1,"y":2,"z":3},{"x":1,"y":2,"z":3},{"x":1,"y":2,"z":3},{"x":1,"y":2,"z":3},{"x":1,"y":2,"z":3},{"x":1,"y":2,"z":3},{"x":1,"y":2,"z":3},{"x":1,"y":2,"z":3},{"x":1,"y":2,"z":3},{"x":1,"y":2,"z":3},{"x":1,"y":2,"z":3},{"x":1,"y":2,"z":3}]}`;
111
111
 
112
112
  bench(
113
- "Serialize Medium Object",
113
+ "Serialize Large Object",
114
114
  () => {
115
115
  JSON.stringify(v1);
116
116
  },
@@ -118,7 +118,7 @@ bench(
118
118
  );
119
119
 
120
120
  bench(
121
- "Deserialize Medium Object",
121
+ "Deserialize Large Object",
122
122
  () => {
123
123
  JSON.parse(v2);
124
124
  },
@@ -1,5 +1,17 @@
1
+ if (typeof console === "undefined") {
2
+ console = {
3
+ log: print,
4
+ error: print,
5
+ warn: print,
6
+ };
7
+ }
8
+
1
9
  export function bench(description: string, routine: () => void, ops: number = 1_000_000): void {
2
10
  console.log(" - Benchmarking " + description);
11
+ let warmup = ops / 10;
12
+ while (--warmup) {
13
+ routine();
14
+ }
3
15
  const start = Date.now();
4
16
  let count = ops;
5
17
  while (count !== 0) {
@@ -1,4 +1,4 @@
1
- import { bench } from "./lib/bench";
1
+ import { bench } from "./lib/bench.js";
2
2
 
3
3
  class MediumJSON {
4
4
  public id!: number;
@@ -0,0 +1,28 @@
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
+ },
14
+ });
15
+
16
+ memory = exports.memory;
17
+
18
+ function __liftString(pointer) {
19
+ if (!pointer) return null;
20
+ const end = (pointer + new Uint32Array(memory.buffer)[(pointer - 4) >>> 2]) >>> 1,
21
+ memoryU16 = new Uint16Array(memory.buffer);
22
+ let start = pointer >>> 1,
23
+ string = "";
24
+ while (end - start > 1024) string += String.fromCharCode(...memoryU16.subarray(start, (start += 1024)));
25
+ return string + String.fromCharCode(...memoryU16.subarray(start, end));
26
+ }
27
+
28
+ exports.start();
@@ -1,4 +1,4 @@
1
- import { bench } from "./lib/bench";
1
+ import { bench } from "./lib/bench.js";
2
2
 
3
3
  class SmallJSON {
4
4
  public id!: number;
@@ -0,0 +1,12 @@
1
+ {
2
+ "compilerOptions": {
3
+ "target": "ES2022",
4
+ "module": "ES2020",
5
+ "moduleResolution": "Node",
6
+ "removeComments": true,
7
+ "types": ["node"],
8
+ "outDir": "../build",
9
+ "sourceMap": false
10
+ },
11
+ "include": ["./*.ts", "./lib/*.ts"]
12
+ }
@@ -1,4 +1,4 @@
1
- import { bench } from "./lib/bench";
1
+ import { bench } from "./lib/bench.js";
2
2
 
3
3
  class Vec3 {
4
4
  public x!: number;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "json-as",
3
- "version": "1.0.7",
3
+ "version": "1.0.9",
4
4
  "author": "Jairus Tanaka",
5
5
  "description": "The only JSON library you'll need for AssemblyScript. SIMD enabled",
6
6
  "types": "assembly/index.ts",
@@ -18,9 +18,8 @@
18
18
  "test": "bash ./run-tests.sh",
19
19
  "bench:as": "bash ./run-bench.as.sh",
20
20
  "bench:js": "bash ./run-bench.js.sh",
21
- "build:time": "time npx asc ./assembly/__benches__/abc.bench.ts --transform ./transform -o ./build/abc.bench.wasm --optimizeLevel 3 --shrinkLevel 0 --converge --noAssert --uncheckedBehavior always --runtime stub --enable simd --enable bulk-memory",
22
- "build:test": "rm -rf ./build/ && JSON_DEBUG=true asc assembly/test.ts --transform ./transform -o ./build/test.wasm --textFile ./build/test.wat --optimizeLevel 3 --shrinkLevel 0",
23
- "build:test:simd": "rm -rf ./build/ && JSON_DEBUG=true asc assembly/test.ts --transform ./transform -o ./build/test.wasm --textFile ./build/test.wat --optimizeLevel 3 --shrinkLevel 0 --enable simd",
21
+ "build:test": "rm -rf ./build/ && JSON_DEBUG=true asc assembly/test.ts --transform ./transform -o ./build/test.wasm --textFile ./build/test.wat --debug --config ./node_modules/@assemblyscript/wasi-shim/asconfig.json",
22
+ "build:test:simd": "rm -rf ./build/ && JSON_DEBUG=true asc assembly/test.ts --transform ./transform -o ./build/test.wasm --textFile ./build/test.wat --optimizeLevel 3 --shrinkLevel 0 --enable simd --config ./node_modules/@assemblyscript/wasi-shim/asconfig.json",
24
23
  "test:wasmtime": "wasmtime ./build/test.wasm",
25
24
  "test:wasmer": "wasmer ./build/test.wasm",
26
25
  "build:transform": "tsc -p ./transform",
package/run-bench.as.sh CHANGED
@@ -1,27 +1,53 @@
1
1
  #!/bin/bash
2
+ RUNTIMES=${RUNTIMES:-"minimal stub"}
3
+ ENGINES=${ENGINES:-"liftoff ignition sparkplug turbofan llvm"}
4
+ for file in ./assembly/__benches__/vec3.bench.ts; do
5
+ filename=$(basename -- "$file")
6
+ output_wasi=
7
+ for runtime in $RUNTIMES; do
8
+ output="./build/${filename%.ts}.${runtime}.wasm"
2
9
 
3
- mkdir -p ./build
10
+ npx asc "$file" --transform ./transform -o "${output}.1" -O3 --converge --noAssert --uncheckedBehavior always --runtime $runtime --enable simd --enable bulk-memory --exportStart start || {
11
+ echo "Build failed"
12
+ exit 1
13
+ }
4
14
 
5
- for file in ./assembly/__benches__/*.bench.ts; do
6
- filename=$(basename -- "$file")
7
- output="./build/${filename%.ts}.wasm"
15
+ wasm-opt -all -O4 "${output}.1" -o "$output"
16
+ rm "${output}.1"
8
17
 
9
- start_time=$(date +%s%3N)
10
- npx asc "$file" --transform ./transform -o "$output" --optimizeLevel 3 --shrinkLevel 0 --converge --noAssert --uncheckedBehavior always --runtime stub --enable simd --enable bulk-memory || { echo "Build failed"; exit 1; }
11
- end_time=$(date +%s%3N)
18
+ 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
+ echo "Build failed"
20
+ exit 1
21
+ }
12
22
 
13
- build_time=$((end_time - start_time))
23
+ wasm-opt -all -O4 "${output}.2" -o "${output%.wasm}.wasi.wasm"
24
+ rm "${output}.2"
14
25
 
15
- if [ "$build_time" -ge 60000 ]; then
16
- formatted_time="$(bc <<< "scale=2; $build_time/60000")m"
17
- elif [ "$build_time" -ge 1000 ]; then
18
- formatted_time="$(bc <<< "scale=2; $build_time/1000")s"
19
- else
20
- formatted_time="${build_time}ms"
21
- fi
26
+ for engine in $ENGINES; do
27
+ echo -e "$filename (asc/$runtime/$engine)\n"
22
28
 
23
- echo -e "$filename (built in $formatted_time)\n"
24
- wasmer "$output" --llvm || { echo "Benchmarked failed."; exit 1; }
29
+ arg="${filename%.ts}.${runtime}.wasm"
30
+ if [[ "$engine" == "ignition" ]]; then
31
+ v8 --no-opt --module ./bench/runners/assemblyscript.js -- $arg
32
+ fi
33
+
34
+ if [[ "$engine" == "liftoff" ]]; then
35
+ v8 --liftoff-only --no-opt --module ./bench/runners/assemblyscript.js -- $arg
36
+ fi
37
+
38
+ if [[ "$engine" == "sparkplug" ]]; then
39
+ v8 --sparkplug --always-sparkplug --no-opt --module ./bench/runners/assemblyscript.js -- $arg
40
+ fi
41
+
42
+ if [[ "$engine" == "turbofan" ]]; then
43
+ v8 --no-liftoff --no-wasm-tier-up --module ./bench/runners/assemblyscript.js -- $arg
44
+ fi
45
+
46
+ if [[ "$engine" == "llvm" ]]; then
47
+ wasmer run "${output%.wasm}.wasi.wasm" --llvm --enable-simd --enable-bulk-memory --enable-relaxed-simd --enable-pass-params-opt
48
+ fi
49
+ done
50
+ done
25
51
  done
26
52
 
27
- echo "Finished benchmarks."
53
+ echo "Finished benchmarks"