json-as 1.3.9 → 1.5.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 (122) hide show
  1. package/CHANGELOG.md +60 -19
  2. package/README.md +120 -21
  3. package/assembly/custom/chars.ts +39 -78
  4. package/assembly/deserialize/index/arbitrary.ts +28 -10
  5. package/assembly/deserialize/index/float.ts +2 -4
  6. package/assembly/deserialize/index/integer.ts +2 -4
  7. package/assembly/deserialize/index/object.ts +6 -1
  8. package/assembly/deserialize/index/string.ts +2 -7
  9. package/assembly/deserialize/index/unsigned.ts +2 -4
  10. package/assembly/deserialize/naive/array/arbitrary.ts +3 -136
  11. package/assembly/deserialize/naive/array/array.ts +30 -1
  12. package/assembly/deserialize/naive/array/integer.ts +2 -7
  13. package/assembly/deserialize/naive/array/map.ts +10 -14
  14. package/assembly/deserialize/naive/array/object.ts +10 -14
  15. package/assembly/deserialize/naive/array/struct.ts +19 -1
  16. package/assembly/deserialize/naive/bool.ts +1 -5
  17. package/assembly/deserialize/naive/date.ts +1 -2
  18. package/assembly/deserialize/naive/float.ts +4 -11
  19. package/assembly/deserialize/naive/integer.ts +2 -4
  20. package/assembly/deserialize/naive/map.ts +42 -205
  21. package/assembly/deserialize/naive/object.ts +291 -174
  22. package/assembly/deserialize/naive/raw.ts +1 -5
  23. package/assembly/deserialize/naive/set.ts +3 -6
  24. package/assembly/deserialize/naive/staticarray.ts +2 -4
  25. package/assembly/deserialize/naive/string.ts +68 -24
  26. package/assembly/deserialize/naive/typedarray.ts +1 -2
  27. package/assembly/deserialize/naive/unsigned.ts +2 -4
  28. package/assembly/deserialize/simd/array/integer.ts +5 -13
  29. package/assembly/deserialize/simd/float.ts +5 -12
  30. package/assembly/deserialize/simd/integer.ts +6 -15
  31. package/assembly/deserialize/simd/string.ts +21 -43
  32. package/assembly/deserialize/swar/array/arbitrary.ts +1 -2
  33. package/assembly/deserialize/swar/array/array.ts +2 -4
  34. package/assembly/deserialize/swar/array/bool.ts +2 -4
  35. package/assembly/deserialize/swar/array/box.ts +1 -2
  36. package/assembly/deserialize/swar/array/float.ts +8 -21
  37. package/assembly/deserialize/swar/array/generic.ts +2 -4
  38. package/assembly/deserialize/swar/array/integer.ts +13 -27
  39. package/assembly/deserialize/swar/array/map.ts +1 -2
  40. package/assembly/deserialize/swar/array/object.ts +2 -4
  41. package/assembly/deserialize/swar/array/raw.ts +1 -2
  42. package/assembly/deserialize/swar/array/shared.ts +9 -21
  43. package/assembly/deserialize/swar/array/string.ts +4 -10
  44. package/assembly/deserialize/swar/array/struct.ts +3 -9
  45. package/assembly/deserialize/swar/array.ts +1 -3
  46. package/assembly/deserialize/swar/float.ts +7 -17
  47. package/assembly/deserialize/swar/integer.ts +6 -15
  48. package/assembly/deserialize/swar/string.ts +40 -54
  49. package/assembly/deserialize/swar/typedarray.ts +4 -4
  50. package/assembly/index.d.ts +259 -21
  51. package/assembly/index.ts +1704 -266
  52. package/assembly/serialize/index/arbitrary.ts +70 -4
  53. package/assembly/serialize/index/jsonarray.ts +51 -0
  54. package/assembly/serialize/index/object.ts +39 -14
  55. package/assembly/serialize/index/string.ts +1 -2
  56. package/assembly/serialize/index/typedarray.ts +1 -2
  57. package/assembly/serialize/index.ts +1 -0
  58. package/assembly/serialize/naive/array.ts +23 -34
  59. package/assembly/serialize/naive/bool.ts +0 -1
  60. package/assembly/serialize/naive/float.ts +16 -25
  61. package/assembly/serialize/naive/integer.ts +1 -5
  62. package/assembly/serialize/naive/raw.ts +1 -2
  63. package/assembly/serialize/naive/set.ts +0 -4
  64. package/assembly/serialize/naive/staticarray.ts +0 -5
  65. package/assembly/serialize/naive/string.ts +11 -7
  66. package/assembly/serialize/naive/typedarray.ts +0 -6
  67. package/assembly/serialize/simd/string.ts +1 -3
  68. package/assembly/serialize/swar/string.ts +2 -4
  69. package/assembly/util/atoi-fast.ts +4 -14
  70. package/assembly/util/atoi.ts +1 -2
  71. package/assembly/util/bytes.ts +1 -2
  72. package/assembly/util/idofd.ts +1 -2
  73. package/assembly/util/isSpace.ts +1 -2
  74. package/assembly/util/itoa-fast.ts +9 -15
  75. package/assembly/util/nextPowerOf2.ts +1 -2
  76. package/assembly/util/parsefloat-fast.ts +4 -7
  77. package/assembly/util/ptrToStr.ts +1 -2
  78. package/assembly/util/scanValueEnd.ts +1 -2
  79. package/assembly/util/scanValueEndSimd.ts +198 -0
  80. package/assembly/util/scanValueEndSwar.ts +184 -0
  81. package/assembly/util/scientific.ts +8 -14
  82. package/assembly/util/simd-int.ts +4 -8
  83. package/assembly/util/snp.ts +2 -7
  84. package/assembly/util/stringScan.ts +2 -4
  85. package/assembly/util/swar-int.ts +8 -16
  86. package/assembly/util/swar.ts +2 -4
  87. package/lib/as-bs.ts +57 -42
  88. package/package.json +27 -10
  89. package/transform/lib/builder.d.ts +0 -1
  90. package/transform/lib/builder.js +0 -1
  91. package/transform/lib/index.d.ts +0 -1
  92. package/transform/lib/index.js +617 -326
  93. package/transform/lib/linkers/alias.d.ts +0 -1
  94. package/transform/lib/linkers/alias.js +0 -1
  95. package/transform/lib/linkers/custom.d.ts +0 -1
  96. package/transform/lib/linkers/custom.js +0 -1
  97. package/transform/lib/linkers/imports.d.ts +0 -1
  98. package/transform/lib/linkers/imports.js +0 -1
  99. package/transform/lib/types.d.ts +4 -2
  100. package/transform/lib/types.js +5 -1
  101. package/transform/lib/util.d.ts +0 -1
  102. package/transform/lib/util.js +0 -1
  103. package/transform/lib/visitor.d.ts +0 -1
  104. package/transform/lib/visitor.js +0 -1
  105. package/assembly/util/dragonbox-cache.ts +0 -445
  106. package/assembly/util/dragonbox.ts +0 -660
  107. package/transform/lib/builder.d.ts.map +0 -1
  108. package/transform/lib/builder.js.map +0 -1
  109. package/transform/lib/index.d.ts.map +0 -1
  110. package/transform/lib/index.js.map +0 -1
  111. package/transform/lib/linkers/alias.d.ts.map +0 -1
  112. package/transform/lib/linkers/alias.js.map +0 -1
  113. package/transform/lib/linkers/custom.d.ts.map +0 -1
  114. package/transform/lib/linkers/custom.js.map +0 -1
  115. package/transform/lib/linkers/imports.d.ts.map +0 -1
  116. package/transform/lib/linkers/imports.js.map +0 -1
  117. package/transform/lib/types.d.ts.map +0 -1
  118. package/transform/lib/types.js.map +0 -1
  119. package/transform/lib/util.d.ts.map +0 -1
  120. package/transform/lib/util.js.map +0 -1
  121. package/transform/lib/visitor.d.ts.map +0 -1
  122. package/transform/lib/visitor.js.map +0 -1
@@ -4,15 +4,13 @@ import { __heap_base } from "memory";
4
4
  import { BACK_SLASH, QUOTE } from "../../custom/chars";
5
5
  import { DESERIALIZE_ESCAPE_TABLE } from "../../globals/tables";
6
6
 
7
- // @ts-ignore: inline
8
- @inline function hexDigit(c: u16): u32 {
7
+ function hexDigit(c: u16): u32 {
9
8
  if (c <= 0x39) return c - 0x30; // '0'-'9'
10
9
  if (c <= 0x46) return c - 0x37; // 'A'-'F'
11
10
  return c - 0x57; // 'a'-'f'
12
11
  }
13
12
 
14
- // @ts-ignore: inline
15
- @inline function hex4ToU16(srcStart: usize): u16 {
13
+ function hex4ToU16(srcStart: usize): u16 {
16
14
  return <u16>(
17
15
  ((hexDigit(load<u16>(srcStart)) << 12) |
18
16
  (hexDigit(load<u16>(srcStart, 2)) << 8) |
@@ -21,8 +19,7 @@ import { DESERIALIZE_ESCAPE_TABLE } from "../../globals/tables";
21
19
  );
22
20
  }
23
21
 
24
- // @ts-ignore: inline
25
- @inline function isHexDigit(c: u16): bool {
22
+ function isHexDigit(c: u16): bool {
26
23
  return (
27
24
  (c >= 0x30 && c <= 0x39) ||
28
25
  (c >= 0x41 && c <= 0x46) ||
@@ -33,8 +30,7 @@ import { DESERIALIZE_ESCAPE_TABLE } from "../../globals/tables";
33
30
  // Strict RFC 8259 check for the char following a backslash, at [escPtr, srcEnd).
34
31
  // Legal escapes: " \ / b f n r t and \uXXXX (4 hex digits). Throws otherwise:
35
32
  // unknown escape letter, a trailing backslash, or a short / non-hex \u.
36
- // @ts-ignore: inline
37
- @inline function validateEscape(escPtr: usize, srcEnd: usize): void {
33
+ function validateEscape(escPtr: usize, srcEnd: usize): void {
38
34
  if (escPtr >= srcEnd)
39
35
  throw new Error("Invalid JSON string: incomplete escape");
40
36
  const code = load<u16>(escPtr);
@@ -65,8 +61,7 @@ import { DESERIALIZE_ESCAPE_TABLE } from "../../globals/tables";
65
61
  throw new Error("Invalid JSON string: illegal escape");
66
62
  }
67
63
 
68
- // @ts-ignore: inline
69
- @inline export function deserializeString_NAIVE(
64
+ export function deserializeString_NAIVE(
70
65
  srcStart: usize,
71
66
  srcEnd: usize,
72
67
  ): string {
@@ -121,8 +116,7 @@ import { DESERIALIZE_ESCAPE_TABLE } from "../../globals/tables";
121
116
 
122
117
  // Writes into the destination field, reusing or resizing the backing string.
123
118
  // Mirrors `writeStringToField` in ../swar/string.ts.
124
- // @ts-ignore: inline
125
- @inline function writeStringToField(
119
+ function writeStringToField(
126
120
  dstFieldPtr: usize,
127
121
  srcStart: usize,
128
122
  byteLength: u32,
@@ -148,23 +142,26 @@ import { DESERIALIZE_ESCAPE_TABLE } from "../../globals/tables";
148
142
  memory.copy(stringPtr, srcStart, byteLength);
149
143
  }
150
144
 
151
- // @ts-ignore: inline
152
- @inline export function deserializeStringField_NAIVE<T extends string | null>(
153
- srcStart: usize,
145
+ // Escape-bearing tail of the field parse: the clean prefix [payloadStart,
146
+ // escPos) is bulk-copied into the scratch buffer, then escapes are decoded into
147
+ // it, and the result is written to the field. Only reached when a backslash is
148
+ // actually present - the common escape-free case never touches `bs`.
149
+ function deserializeEscapedStringField_NAIVE(
150
+ payloadStart: usize,
151
+ escPos: usize,
154
152
  srcEnd: usize,
155
- dstObj: usize,
156
- dstOffset: usize = 0,
153
+ dstFieldPtr: usize,
157
154
  ): usize {
158
- const dstFieldPtr = dstObj + dstOffset;
159
- if (srcStart + 2 > srcEnd || load<u16>(srcStart) != QUOTE)
160
- abort("Expected leading quote");
161
-
162
- const payloadStart = srcStart + 2;
163
- srcStart = payloadStart;
164
-
165
155
  bs.offset = bs.buffer;
166
156
  bs.ensureSize(<u32>(srcEnd - payloadStart));
167
157
 
158
+ const prefixLen = escPos - payloadStart;
159
+ if (prefixLen) {
160
+ memory.copy(bs.offset, payloadStart, prefixLen);
161
+ bs.offset += prefixLen;
162
+ }
163
+
164
+ let srcStart = escPos;
168
165
  while (srcStart < srcEnd) {
169
166
  const block = load<u16>(srcStart);
170
167
 
@@ -197,3 +194,50 @@ import { DESERIALIZE_ESCAPE_TABLE } from "../../globals/tables";
197
194
  abort("Expected closing quote");
198
195
  return 0;
199
196
  }
197
+
198
+ // NOT @inline: this is a loop-bearing scanner called per string field. As an
199
+ // always-inline entry it gets inlined into every field call site inside the
200
+ // @inline __DESERIALIZE_FAST, exploding binaryen's optimize phase on large
201
+ // schemas (~118s on the `large` bench). Kept as a single shared function - one
202
+ // call per field - matching the non-inline SWAR/SIMD field deserializers.
203
+ export function deserializeStringField_NAIVE<T extends string | null>(
204
+ srcStart: usize,
205
+ srcEnd: usize,
206
+ dstObj: usize,
207
+ dstOffset: usize = 0,
208
+ ): usize {
209
+ const dstFieldPtr = dstObj + dstOffset;
210
+ if (srcStart + 2 > srcEnd || load<u16>(srcStart) != QUOTE)
211
+ abort("Expected leading quote");
212
+
213
+ const payloadStart = srcStart + 2;
214
+ srcStart = payloadStart;
215
+
216
+ // Scan for the closing quote without touching the scratch buffer. For the
217
+ // common escape-free case the bytes are a verbatim slice of the source, so we
218
+ // copy source -> field directly (mirrors the SWAR/SIMD field paths). Only a
219
+ // backslash diverts to the escape-decoding tail above.
220
+ while (srcStart < srcEnd) {
221
+ const block = load<u16>(srcStart);
222
+ if (block == QUOTE) {
223
+ writeStringToField(
224
+ dstFieldPtr,
225
+ payloadStart,
226
+ <u32>(srcStart - payloadStart),
227
+ );
228
+ return srcStart + 2;
229
+ }
230
+ if (block == BACK_SLASH) {
231
+ return deserializeEscapedStringField_NAIVE(
232
+ payloadStart,
233
+ srcStart,
234
+ srcEnd,
235
+ dstFieldPtr,
236
+ );
237
+ }
238
+ srcStart += 2;
239
+ }
240
+
241
+ abort("Expected closing quote");
242
+ return 0;
243
+ }
@@ -2,8 +2,7 @@ import { COMMA, BRACKET_RIGHT } from "../../custom/chars";
2
2
  import { deserializeFloat_NAIVE } from "./float";
3
3
  import { atoi, isSpace } from "../../util";
4
4
 
5
-
6
- @inline function countTypedArrayElements(srcStart: usize, srcEnd: usize): i32 {
5
+ function countTypedArrayElements(srcStart: usize, srcEnd: usize): i32 {
7
6
  let count = 0;
8
7
 
9
8
  while (srcStart < srcEnd) {
@@ -1,15 +1,13 @@
1
1
  import { atoi } from "../../util/atoi";
2
2
 
3
- // @ts-ignore: inline
4
- @inline export function deserializeUnsigned_NAIVE<T extends number>(
3
+ export function deserializeUnsigned_NAIVE<T extends number>(
5
4
  srcStart: usize,
6
5
  srcEnd: usize,
7
6
  ): T {
8
7
  return atoi<T>(srcStart, srcEnd);
9
8
  }
10
9
 
11
- // @ts-ignore: inline
12
- @inline export function deserializeUnsignedField_NAIVE<T extends number>(
10
+ export function deserializeUnsignedField_NAIVE<T extends number>(
13
11
  srcStart: usize,
14
12
  srcEnd: usize,
15
13
  dstObj: usize,
@@ -40,11 +40,7 @@ const ASCII_ZERO_4: u64 = 0x0030003000300030;
40
40
  // @ts-expect-error: decorators valid here
41
41
  @lazy const PAIR_WEIGHTS_100_1 = i16x8(100, 1, 100, 1, 0, 0, 0, 0);
42
42
 
43
- // @ts-expect-error: decorators valid here
44
- @inline function storeSignedInteger<T extends number[]>(
45
- slot: usize,
46
- value: i64,
47
- ): void {
43
+ function storeSignedInteger<T extends number[]>(slot: usize, value: i64): void {
48
44
  if (sizeof<valueof<T>>() == sizeof<i8>()) {
49
45
  store<i8>(slot, <i8>value);
50
46
  } else if (sizeof<valueof<T>>() == sizeof<i16>()) {
@@ -58,8 +54,7 @@ const ASCII_ZERO_4: u64 = 0x0030003000300030;
58
54
  }
59
55
  }
60
56
 
61
- // @ts-expect-error: decorators valid here
62
- @inline function storeUnsignedInteger<T extends number[]>(
57
+ function storeUnsignedInteger<T extends number[]>(
63
58
  slot: usize,
64
59
  value: u64,
65
60
  ): void {
@@ -76,8 +71,7 @@ const ASCII_ZERO_4: u64 = 0x0030003000300030;
76
71
  }
77
72
  }
78
73
 
79
- // @ts-expect-error: decorators valid here
80
- @inline function tryParseEightDigitsSIMD(srcStart: usize, value: u64): u64 {
74
+ function tryParseEightDigitsSIMD(srcStart: usize, value: u64): u64 {
81
75
  const block = load<v128>(srcStart);
82
76
  const digits = i16x8.sub(block, SPLAT_30);
83
77
  if (v128.any_true(i16x8.gt_u(digits, SPLAT_09))) return 0;
@@ -96,8 +90,7 @@ const ASCII_ZERO_4: u64 = 0x0030003000300030;
96
90
  // As in the SWAR variant: the parse helpers take a `slot` (`writePtr`) and
97
91
  // store directly. The dispatcher owns `out.length = maxElements` and the
98
92
  // per-element `writePtr` advance so `Array.push` is removed for every
99
- // @ts-expect-error: decorators valid here
100
- @inline function parseSignedIntegerSIMD<T extends number[]>(
93
+ function parseSignedIntegerSIMD<T extends number[]>(
101
94
  srcStart: usize,
102
95
  srcEnd: usize,
103
96
  slot: usize,
@@ -135,8 +128,7 @@ const ASCII_ZERO_4: u64 = 0x0030003000300030;
135
128
  return srcStart;
136
129
  }
137
130
 
138
- // @ts-expect-error: decorators valid here
139
- @inline function parseUnsignedIntegerSIMD<T extends number[]>(
131
+ function parseUnsignedIntegerSIMD<T extends number[]>(
140
132
  srcStart: usize,
141
133
  srcEnd: usize,
142
134
  slot: usize,
@@ -3,7 +3,7 @@
3
3
  // `parse8Digits_SIMD` (16 bytes / 8 digits) before falling through to
4
4
  // `parse4Digits_PairMul` (8 bytes / 4 digits) and finally the scalar tail.
5
5
  //
6
- // Output is bit-identical to `f64.parse` / `f32.parse` for every input the
6
+ // Output is bit-identical to `f64.parse` / `f32.parse` for every input - the
7
7
  // SIMD strides only change how the u64 mantissa is accumulated, not what it
8
8
  // becomes.
9
9
  //
@@ -23,8 +23,7 @@ const ASCII_ZERO: u16 = 48;
23
23
  const ASCII_E_UP: u16 = 69;
24
24
  const ASCII_E_LO: u16 = 101;
25
25
 
26
- // @ts-ignore: inline
27
- @inline function fallback<T>(srcStart: usize, srcEnd: usize): T {
26
+ function fallback<T>(srcStart: usize, srcEnd: usize): T {
28
27
  const s = ptrToStr(srcStart, srcEnd);
29
28
  // @ts-ignore
30
29
  const type: T = 0;
@@ -34,8 +33,7 @@ const ASCII_E_LO: u16 = 101;
34
33
  return <T>(<f32>f32.parse(s));
35
34
  }
36
35
 
37
- // @ts-ignore: inline
38
- @inline function fallbackField<T extends number>(
36
+ function fallbackField<T extends number>(
39
37
  origStart: usize,
40
38
  end: usize,
41
39
  fieldPtr: usize,
@@ -48,11 +46,7 @@ const ASCII_E_LO: u16 = 101;
48
46
  }
49
47
  }
50
48
 
51
- // @ts-ignore: inline
52
- @inline export function deserializeFloat_SIMD<T>(
53
- srcStart: usize,
54
- srcEnd: usize,
55
- ): T {
49
+ export function deserializeFloat_SIMD<T>(srcStart: usize, srcEnd: usize): T {
56
50
  const origStart = srcStart;
57
51
  let p = srcStart;
58
52
  let negative = false;
@@ -168,8 +162,7 @@ const ASCII_E_LO: u16 = 101;
168
162
  return <T>(<f32>result);
169
163
  }
170
164
 
171
- // @ts-ignore: inline
172
- @inline export function deserializeFloatField_SIMD<T extends number>(
165
+ export function deserializeFloatField_SIMD<T extends number>(
173
166
  srcStart: usize,
174
167
  srcEnd: usize,
175
168
  dstObj: usize,
@@ -38,11 +38,7 @@ const ASCII_ZERO: u16 = 48;
38
38
  * @param value The `u64` accumulator, interpreted as a two's-complement
39
39
  * signed integer for narrower types.
40
40
  */
41
- // @ts-expect-error: @inline is a valid decorator
42
- @inline function storeSignedToField<T extends number>(
43
- dstPtr: usize,
44
- value: u64,
45
- ): void {
41
+ function storeSignedToField<T extends number>(dstPtr: usize, value: u64): void {
46
42
  if (sizeof<T>() == 1) {
47
43
  store<i8>(dstPtr, <i8>value);
48
44
  } else if (sizeof<T>() == 2) {
@@ -61,8 +57,7 @@ const ASCII_ZERO: u16 = 48;
61
57
  * @param dstPtr Destination pointer (already includes any field offset).
62
58
  * @param value The `u64` accumulator.
63
59
  */
64
- // @ts-expect-error: decorator valid here
65
- @inline function storeUnsignedToField<T extends number>(
60
+ function storeUnsignedToField<T extends number>(
66
61
  dstPtr: usize,
67
62
  value: u64,
68
63
  ): void {
@@ -88,8 +83,7 @@ const ASCII_ZERO: u16 = 48;
88
83
  * @param srcEnd Pointer just past the last code unit.
89
84
  * @returns The parsed value, two's-complement truncated to `T`.
90
85
  */
91
- // @ts-expect-error: decorator valid here
92
- @inline export function deserializeInteger_SIMD<T extends number>(
86
+ export function deserializeInteger_SIMD<T extends number>(
93
87
  srcStart: usize,
94
88
  srcEnd: usize,
95
89
  ): T {
@@ -130,8 +124,7 @@ const ASCII_ZERO: u16 = 48;
130
124
  * @param dstOffset Byte offset of the field within `dstObj`.
131
125
  * @returns The source position immediately after the last digit consumed.
132
126
  */
133
- // @ts-expect-error: @inline is a valid decorator
134
- @inline export function deserializeIntegerField_SIMD<T extends number>(
127
+ export function deserializeIntegerField_SIMD<T extends number>(
135
128
  srcStart: usize,
136
129
  srcEnd: usize,
137
130
  dstObj: usize,
@@ -170,8 +163,7 @@ const ASCII_ZERO: u16 = 48;
170
163
  * @param srcEnd Pointer just past the last code unit.
171
164
  * @returns The parsed value, truncated to `T`.
172
165
  */
173
- // @ts-expect-error: @inline is a valid decorator
174
- @inline export function deserializeUnsigned_SIMD<T extends number>(
166
+ export function deserializeUnsigned_SIMD<T extends number>(
175
167
  srcStart: usize,
176
168
  srcEnd: usize,
177
169
  ): T {
@@ -207,8 +199,7 @@ const ASCII_ZERO: u16 = 48;
207
199
  * @param dstOffset Byte offset of the field within `dstObj`.
208
200
  * @returns The source position immediately after the last digit consumed.
209
201
  */
210
- // @ts-expect-error: @inline is a valid decorator
211
- @inline export function deserializeUnsignedField_SIMD<T extends number>(
202
+ export function deserializeUnsignedField_SIMD<T extends number>(
212
203
  srcStart: usize,
213
204
  srcEnd: usize,
214
205
  dstObj: usize,
@@ -63,20 +63,14 @@ import { hex4_to_u16_swar } from "../../util/swar";
63
63
  * @param dst buffer to write to
64
64
  * @returns number of bytes written
65
65
  */
66
- // @ts-expect-error: @inline is a valid decorator
67
- @inline function copyStringFromSource_SIMD(
68
- srcStart: usize,
69
- byteLength: usize,
70
- ): string {
66
+ function copyStringFromSource_SIMD(srcStart: usize, byteLength: usize): string {
71
67
  if (byteLength == 0) return changetype<string>("");
72
- // @ts-expect-error: __new is a runtime builtin
73
68
  const out = __new(byteLength, idof<string>());
74
69
  memory.copy(out, srcStart, byteLength);
75
70
  return changetype<string>(out);
76
71
  }
77
72
 
78
- // @ts-expect-error: @inline is a valid decorator
79
- @inline function writeStringToField_SIMD(
73
+ function writeStringToField_SIMD(
80
74
  dstFieldPtr: usize,
81
75
  srcStart: usize,
82
76
  byteLength: u32,
@@ -107,11 +101,7 @@ import { hex4_to_u16_swar } from "../../util/swar";
107
101
  // handling (no closing-quote search). Same HYBRID strategy as the field path
108
102
  // (see deserializeEscapedStringField_SIMD): escape blocks use a free
109
103
  // whole-block v128 store for the plain prefix; clean runs stream the first
110
- // block then bulk-memcpy the remainder. Output is sliced out of `bs` scratch.
111
- //
112
- // Deliberately NOT @inline: cold escape path. Inlining the nested-loop v128
113
- // body at every call site explodes `--converge` compile time on large schemas
114
- // for no runtime gain (one call per escaped string).
104
+
115
105
  function deserializeEscapedString_SIMD(
116
106
  payloadStart: usize,
117
107
  escapeStart: usize,
@@ -233,16 +223,16 @@ export function deserializeString_SIMD(srcStart: usize, srcEnd: usize): string {
233
223
  }
234
224
 
235
225
  const laneIdx = usize(ctz(mask) << 1);
236
- return inline.always(
237
- deserializeEscapedString_SIMD(payloadStart, srcStart + laneIdx, srcEnd),
226
+ return deserializeEscapedString_SIMD(
227
+ payloadStart,
228
+ srcStart + laneIdx,
229
+ srcEnd,
238
230
  );
239
231
  }
240
232
 
241
233
  while (srcStart < srcEnd) {
242
234
  if (load<u16>(srcStart) == BACK_SLASH) {
243
- return inline.always(
244
- deserializeEscapedString_SIMD(payloadStart, srcStart, srcEnd),
245
- );
235
+ return deserializeEscapedString_SIMD(payloadStart, srcStart, srcEnd);
246
236
  }
247
237
  srcStart += 2;
248
238
  }
@@ -255,18 +245,14 @@ export function deserializeString_SIMD(srcStart: usize, srcEnd: usize): string {
255
245
  // reused `bs` scratch buffer, then written once via writeStringToField_SIMD.
256
246
  //
257
247
  // Strategy (validated against run-copy and pure-stream variants across escape
258
- // densities see __benches__/custom/simd-string-deser-variants-h2h):
248
+ // densities - see __benches__/custom/simd-string-deser-variants-h2h):
259
249
  // * Escape-bearing block: a single whole-block v128 store copies the plain
260
250
  // prefix for free; then the escape is decoded scalar.
261
251
  // * Clean block: stream the first one cheaply, but if the clean run keeps
262
- // going, switch to one bulk memory.copy for the remainder bandwidth-
252
+ // going, switch to one bulk memory.copy for the remainder - bandwidth-
263
253
  // optimal on long sparse runs, avoiding a per-block-store cliff on large
264
254
  // inputs. This dominates both alternatives: stream-cheap on dense escapes,
265
- // memcpy-fast on long runs.
266
- //
267
- // Deliberately NOT @inline: cold escape path. As an @inline it was inlined into
268
- // deserializeStringField_SIMD at every struct string-field site, exploding
269
- // `--converge` compile time ~24x on large schemas (4s → 99s) for no runtime
255
+
270
256
  // gain. The hot no-escape scan + writeStringToField stay inline in the caller.
271
257
  function deserializeEscapedStringField_SIMD(
272
258
  payloadStart: usize,
@@ -387,10 +373,6 @@ function deserializeEscapedStringField_SIMD(
387
373
  return srcStart;
388
374
  }
389
375
 
390
- // NOT @inline: as an @inline entry, binaryen inlined the (loop-bearing) escaped
391
- // scanner into every per-field copy, exploding `large` SIMD compile ~24x
392
- // (4s→99s, 221KB→555KB wasm). Kept as a single shared function — matches
393
- // deserializeStringField_SWAR (also non-inline) and costs only one call/field.
394
376
  export function deserializeStringField_SIMD<T extends string | null>(
395
377
  srcStart: usize,
396
378
  srcEnd: usize,
@@ -427,13 +409,11 @@ export function deserializeStringField_SIMD<T extends string | null>(
427
409
  return srcIdx + 2;
428
410
  }
429
411
  // backslash → vectorized escaped scan (no more SWAR fallback)
430
- return inline.always(
431
- deserializeEscapedStringField_SIMD(
432
- payloadStart,
433
- srcIdx,
434
- srcEnd,
435
- dstFieldPtr,
436
- ),
412
+ return deserializeEscapedStringField_SIMD(
413
+ payloadStart,
414
+ srcIdx,
415
+ srcEnd,
416
+ dstFieldPtr,
437
417
  );
438
418
  }
439
419
 
@@ -448,13 +428,11 @@ export function deserializeStringField_SIMD<T extends string | null>(
448
428
  return srcStart + 2;
449
429
  }
450
430
  if (char == BACK_SLASH) {
451
- return inline.always(
452
- deserializeEscapedStringField_SIMD(
453
- payloadStart,
454
- srcStart,
455
- srcEnd,
456
- dstFieldPtr,
457
- ),
431
+ return deserializeEscapedStringField_SIMD(
432
+ payloadStart,
433
+ srcStart,
434
+ srcEnd,
435
+ dstFieldPtr,
458
436
  );
459
437
  }
460
438
  srcStart += 2;
@@ -2,8 +2,7 @@ import { JSON } from "../../..";
2
2
  import { deserializeGenericArrayBody } from "./generic";
3
3
  import { ensureArrayField } from "./shared";
4
4
 
5
-
6
- @inline export function deserializeArbitraryArrayField(
5
+ export function deserializeArbitraryArrayField(
7
6
  srcStart: usize,
8
7
  srcEnd: usize,
9
8
  fieldPtr: usize,
@@ -3,8 +3,7 @@ import { BRACKET_LEFT, BRACKET_RIGHT, COMMA } from "../../../custom/chars";
3
3
  import { deserializeFloatArrayBody } from "./float";
4
4
  import { ensureArrayField, scanValueEnd, skipWhitespace } from "./shared";
5
5
 
6
-
7
- @inline export function deserializeArrayArrayBody<T extends unknown[][]>(
6
+ export function deserializeArrayArrayBody<T extends unknown[][]>(
8
7
  srcStart: usize,
9
8
  srcEnd: usize,
10
9
  out: T,
@@ -91,8 +90,7 @@ import { ensureArrayField, scanValueEnd, skipWhitespace } from "./shared";
91
90
  throw new Error("Failed to parse JSON!");
92
91
  }
93
92
 
94
-
95
- @inline export function deserializeArrayArrayField<T extends unknown[][]>(
93
+ export function deserializeArrayArrayField<T extends unknown[][]>(
96
94
  srcStart: usize,
97
95
  srcEnd: usize,
98
96
  fieldPtr: usize,
@@ -8,8 +8,7 @@ import {
8
8
  import { isSpace } from "../../../util";
9
9
  import { ensureArrayElementSlot, ensureArrayField } from "./shared";
10
10
 
11
-
12
- @inline function deserializeBooleanArrayBody<T extends boolean[]>(
11
+ function deserializeBooleanArrayBody<T extends boolean[]>(
13
12
  srcStart: usize,
14
13
  srcEnd: usize,
15
14
  out: T,
@@ -60,8 +59,7 @@ import { ensureArrayElementSlot, ensureArrayField } from "./shared";
60
59
  throw new Error("Failed to parse JSON!");
61
60
  }
62
61
 
63
-
64
- @inline export function deserializeBooleanArrayField<T extends boolean[]>(
62
+ export function deserializeBooleanArrayField<T extends boolean[]>(
65
63
  srcStart: usize,
66
64
  srcEnd: usize,
67
65
  fieldPtr: usize,
@@ -2,8 +2,7 @@ import { JSON } from "../../..";
2
2
  import { deserializeGenericArrayBody } from "./generic";
3
3
  import { ensureArrayField } from "./shared";
4
4
 
5
-
6
- @inline export function deserializeBoxArrayField<T extends JSON.Box<any>[]>(
5
+ export function deserializeBoxArrayField<T extends JSON.Box<any>[]>(
7
6
  srcStart: usize,
8
7
  srcEnd: usize,
9
8
  fieldPtr: usize,
@@ -8,21 +8,11 @@ import { parse4Digits_PairMul } from "../../../util/swar-int";
8
8
  import { loadPow10, MAX_EXACT_MANTISSA, MAX_EXACT_POW10 } from "../float";
9
9
  import { isSpace } from "../../../util";
10
10
 
11
-
12
- @inline function skipFloatArrayWhitespace(
13
- srcStart: usize,
14
- srcEnd: usize,
15
- ): usize {
11
+ function skipFloatArrayWhitespace(srcStart: usize, srcEnd: usize): usize {
16
12
  while (srcStart < srcEnd && isSpace(load<u16>(srcStart))) srcStart += 2;
17
13
  return srcStart;
18
14
  }
19
-
20
- // @ts-ignore: inline
21
- @inline function fallbackStore<E>(
22
- origStart: usize,
23
- end: usize,
24
- slot: usize,
25
- ): void {
15
+ function fallbackStore<E>(origStart: usize, end: usize, slot: usize): void {
26
16
  const s = ptrToStr(origStart, end);
27
17
  if (sizeof<E>() == sizeof<f32>()) {
28
18
  store<f32>(slot, f32.parse(s));
@@ -46,8 +36,7 @@ import { isSpace } from "../../../util";
46
36
  * digit, lone minus, malformed exponent suffix). Valid-but-out-of-range
47
37
  * numbers are handled inline.
48
38
  */
49
- // @ts-expect-error: decorators valid here
50
- @inline export function parseFloatElementSWAR<E>(
39
+ export function parseFloatElementSWAR<E>(
51
40
  srcStart: usize,
52
41
  srcEnd: usize,
53
42
  slot: usize,
@@ -78,7 +67,7 @@ import { isSpace } from "../../../util";
78
67
  }
79
68
 
80
69
  // Fractional mantissa: parse4 SWAR stride + scalar tail. Same u64
81
- // accumulator as the integer part exponent compensates for fracDigits.
70
+ // accumulator as the integer part - exponent compensates for fracDigits.
82
71
  let fracDigits: i32 = 0;
83
72
  if (p < srcEnd && load<u16>(p) == 46) {
84
73
  p += 2;
@@ -165,7 +154,7 @@ import { isSpace } from "../../../util";
165
154
  // the `ptrToStr` allocation + strtod re-parse.
166
155
  result = scientific(mantissa, exponent);
167
156
  } else {
168
- // >19 mantissa digits beyond u64 capacity, may need strtod's sticky-bit
157
+ // >19 mantissa digits - beyond u64 capacity, may need strtod's sticky-bit
169
158
  // pattern. Hand off to f*.parse on the float's substring.
170
159
  fallbackStore<E>(origStart, p, slot);
171
160
  return p;
@@ -256,7 +245,7 @@ export function deserializeFloatArray_SWAR<T extends number[]>(
256
245
  }
257
246
 
258
247
  /**
259
- * Field/into variant parses `[..]` into the existing `out` array and
248
+ * Field/into variant - parses `[..]` into the existing `out` array and
260
249
  * returns the cursor past the closing `]`.
261
250
  *
262
251
  * Worst-case pre-sizing (`(srcEnd - srcStart) >> 2`) used by the top-level
@@ -265,7 +254,7 @@ export function deserializeFloatArray_SWAR<T extends number[]>(
265
254
  * `[lon,lat]` would over-allocate megabytes of f64 capacity. Instead we
266
255
  * use `ensureArrayElementSlot`'s grow-or-reuse strategy.
267
256
  */
268
- @inline export function deserializeFloatArrayBody<T extends number[]>(
257
+ export function deserializeFloatArrayBody<T extends number[]>(
269
258
  srcStart: usize,
270
259
  srcEnd: usize,
271
260
  out: T,
@@ -316,9 +305,7 @@ export function deserializeFloatArray_SWAR<T extends number[]>(
316
305
 
317
306
  throw new Error("Failed to parse JSON!");
318
307
  }
319
-
320
-
321
- @inline export function deserializeFloatArrayField<T extends number[]>(
308
+ export function deserializeFloatArrayField<T extends number[]>(
322
309
  srcStart: usize,
323
310
  srcEnd: usize,
324
311
  fieldPtr: usize,
@@ -7,8 +7,7 @@ import {
7
7
  skipWhitespace,
8
8
  } from "./shared";
9
9
 
10
-
11
- @inline export function deserializeGenericArrayBody<T extends unknown[]>(
10
+ export function deserializeGenericArrayBody<T extends unknown[]>(
12
11
  srcStart: usize,
13
12
  srcEnd: usize,
14
13
  out: T,
@@ -48,8 +47,7 @@ import {
48
47
  throw new Error("Failed to parse JSON!");
49
48
  }
50
49
 
51
-
52
- @inline export function deserializeGenericArrayField<T extends unknown[]>(
50
+ export function deserializeGenericArrayField<T extends unknown[]>(
53
51
  srcStart: usize,
54
52
  srcEnd: usize,
55
53
  fieldPtr: usize,