json-as 1.5.0 → 1.6.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.
- package/CHANGELOG.md +5 -1
- package/README.md +42 -0
- package/assembly/deserialize/error.ts +21 -0
- package/assembly/deserialize/index/arbitrary.ts +29 -8
- package/assembly/deserialize/index/array.ts +2 -1
- package/assembly/deserialize/index/bool.ts +1 -1
- package/assembly/deserialize/index/object.ts +3 -0
- package/assembly/deserialize/index/string.ts +37 -0
- package/assembly/deserialize/index.ts +0 -1
- package/assembly/deserialize/naive/array/arbitrary.ts +3 -2
- package/assembly/deserialize/naive/array/array.ts +1 -0
- package/assembly/deserialize/naive/array/bool.ts +21 -11
- package/assembly/deserialize/naive/array/box.ts +13 -33
- package/assembly/deserialize/naive/array/float.ts +23 -13
- package/assembly/deserialize/naive/array/integer.ts +33 -21
- package/assembly/deserialize/naive/array/object.ts +1 -0
- package/assembly/deserialize/naive/array/string.ts +29 -16
- package/assembly/deserialize/naive/bool.ts +17 -5
- package/assembly/deserialize/naive/float.ts +1 -2
- package/assembly/deserialize/naive/map.ts +339 -39
- package/assembly/deserialize/naive/object.ts +122 -65
- package/assembly/deserialize/naive/raw.ts +13 -1
- package/assembly/deserialize/naive/set.ts +0 -1
- package/assembly/deserialize/naive/staticarray.ts +3 -2
- package/assembly/deserialize/naive/string.ts +41 -52
- package/assembly/deserialize/parseMode.ts +216 -0
- package/assembly/deserialize/simd/array/integer.ts +6 -3
- package/assembly/deserialize/simd/float.ts +35 -29
- package/assembly/deserialize/simd/string.ts +79 -17
- package/assembly/deserialize/string-validation.ts +34 -0
- package/assembly/deserialize/swar/array/array.ts +63 -13
- package/assembly/deserialize/swar/array/bool.ts +14 -3
- package/assembly/deserialize/swar/array/float.ts +394 -13
- package/assembly/deserialize/swar/array/generic.ts +12 -2
- package/assembly/deserialize/swar/array/integer.ts +22 -62
- package/assembly/deserialize/swar/array/object.ts +11 -2
- package/assembly/deserialize/swar/array/shared.ts +1 -1
- package/assembly/deserialize/swar/array/string.ts +34 -5
- package/assembly/deserialize/swar/array/struct.ts +109 -15
- package/assembly/deserialize/swar/float.ts +19 -12
- package/assembly/deserialize/swar/string.ts +70 -111
- package/assembly/index.d.ts +6 -0
- package/assembly/index.ts +411 -33
- package/assembly/serialize/index/bool.ts +1 -1
- package/assembly/serialize/index/float.ts +1 -5
- package/assembly/serialize/index/integer.ts +1 -1
- package/assembly/serialize/index/object.ts +17 -0
- package/assembly/serialize/naive/array.ts +64 -0
- package/assembly/serialize/naive/float.ts +0 -5
- package/assembly/serialize/naive/map.ts +37 -0
- package/assembly/serialize/naive/set.ts +0 -1
- package/assembly/serialize/naive/staticarray.ts +0 -1
- package/assembly/serialize/naive/string.ts +0 -6
- package/assembly/serialize/naive/typedarray.ts +0 -1
- package/assembly/util/eisel-lemire.ts +179 -0
- package/assembly/util/prettyWhitespaceSimd.ts +69 -0
- package/assembly/util/scanValueEndSimd.ts +59 -36
- package/assembly/util/validateJson.ts +338 -0
- package/lib/as-bs.ts +28 -6
- package/package.json +13 -3
- package/transform/lib/index.d.ts +6 -0
- package/transform/lib/index.js +770 -111
- package/transform/lib/types.d.ts +1 -0
- package/transform/lib/types.js +3 -0
- package/assembly/deserialize/index/struct.ts +0 -1
- package/assembly/deserialize/naive/struct.ts +0 -21
package/transform/lib/index.js
CHANGED
|
@@ -50,6 +50,7 @@ function envFlagDefaultTrue(value) {
|
|
|
50
50
|
}
|
|
51
51
|
const USE_FAST_PATH = envFlagDefaultTrue(process.env["JSON_USE_FAST_PATH"]);
|
|
52
52
|
const THROW_FAST_PATH = process.env["JSON_FAST_PATH_THROW"]?.trim() === "1";
|
|
53
|
+
const USE_DEFAULT_OBJECT_SPECIALIZATION = true;
|
|
53
54
|
function parseJSONCacheConfig(value) {
|
|
54
55
|
if (!value)
|
|
55
56
|
return { enabled: false, bytes: 0 };
|
|
@@ -115,6 +116,20 @@ function getSerializeCall(type, realName) {
|
|
|
115
116
|
if (type == "ArrayBuffer") {
|
|
116
117
|
return `JSON.__serialize<ArrayBuffer>(load<ArrayBuffer>(ptr, offsetof<this>(${JSON.stringify(realName)})));\n`;
|
|
117
118
|
}
|
|
119
|
+
if (type == "bool" ||
|
|
120
|
+
type == "boolean" ||
|
|
121
|
+
type == "i8" ||
|
|
122
|
+
type == "i16" ||
|
|
123
|
+
type == "i32" ||
|
|
124
|
+
type == "i64" ||
|
|
125
|
+
type == "isize" ||
|
|
126
|
+
type == "u8" ||
|
|
127
|
+
type == "u16" ||
|
|
128
|
+
type == "u32" ||
|
|
129
|
+
type == "u64" ||
|
|
130
|
+
type == "usize") {
|
|
131
|
+
return `JSON.__serializePrimitiveUnsafe<${type}>(load<${type}>(ptr, offsetof<this>(${JSON.stringify(realName)})));\n`;
|
|
132
|
+
}
|
|
118
133
|
return needsReferenceLoad(type)
|
|
119
134
|
? `JSON.__serialize<${type}>(changetype<${type}>(load<usize>(ptr, offsetof<this>(${JSON.stringify(realName)}))));\n`
|
|
120
135
|
: `JSON.__serialize<${type}>(load<${type}>(ptr, offsetof<this>(${JSON.stringify(realName)})));\n`;
|
|
@@ -287,6 +302,174 @@ export class JSONTransform extends Visitor {
|
|
|
287
302
|
}
|
|
288
303
|
return type;
|
|
289
304
|
}
|
|
305
|
+
getDefaultSchema(owner, type) {
|
|
306
|
+
const name = stripNull(type).trim();
|
|
307
|
+
const matches = (schema) => schema.name == name ||
|
|
308
|
+
schema.name.endsWith("." + name) ||
|
|
309
|
+
name.endsWith("." + schema.name);
|
|
310
|
+
if (matches(owner))
|
|
311
|
+
return owner;
|
|
312
|
+
for (const dep of owner.deps) {
|
|
313
|
+
if (dep && matches(dep))
|
|
314
|
+
return dep;
|
|
315
|
+
}
|
|
316
|
+
if (owner.parent && matches(owner.parent))
|
|
317
|
+
return owner.parent;
|
|
318
|
+
return null;
|
|
319
|
+
}
|
|
320
|
+
getDefaultElementType(type) {
|
|
321
|
+
const value = stripNull(type).trim();
|
|
322
|
+
if (value.startsWith("Array<") && value.endsWith(">"))
|
|
323
|
+
return value.slice(6, -1).trim();
|
|
324
|
+
if (value.startsWith("StaticArray<") && value.endsWith(">"))
|
|
325
|
+
return value.slice(12, -1).trim();
|
|
326
|
+
return null;
|
|
327
|
+
}
|
|
328
|
+
getDefaultExpressionJSON(expression, type, owner, visiting) {
|
|
329
|
+
if (expression.kind == NodeKind.Parenthesized) {
|
|
330
|
+
return this.getDefaultExpressionJSON(expression.expression, type, owner, visiting);
|
|
331
|
+
}
|
|
332
|
+
if (expression.kind == NodeKind.Assertion) {
|
|
333
|
+
return this.getDefaultExpressionJSON(expression.expression, type, owner, visiting);
|
|
334
|
+
}
|
|
335
|
+
if (expression.kind == NodeKind.Null)
|
|
336
|
+
return "null";
|
|
337
|
+
if (expression.kind == NodeKind.True)
|
|
338
|
+
return "true";
|
|
339
|
+
if (expression.kind == NodeKind.False)
|
|
340
|
+
return "false";
|
|
341
|
+
if (expression.kind == NodeKind.Literal) {
|
|
342
|
+
const literal = expression;
|
|
343
|
+
if (literal.literalKind == 2)
|
|
344
|
+
return JSON.stringify(literal.value);
|
|
345
|
+
if (literal.literalKind == 1) {
|
|
346
|
+
const value = toString(expression).trim();
|
|
347
|
+
return /^\d+$/.test(value) ? value : null;
|
|
348
|
+
}
|
|
349
|
+
if (literal.literalKind == 5) {
|
|
350
|
+
const elementType = this.getDefaultElementType(type);
|
|
351
|
+
if (!elementType)
|
|
352
|
+
return null;
|
|
353
|
+
const values = [];
|
|
354
|
+
for (const element of literal
|
|
355
|
+
.elementExpressions) {
|
|
356
|
+
const value = this.getDefaultExpressionJSON(element, elementType, owner, visiting);
|
|
357
|
+
if (value == null)
|
|
358
|
+
return null;
|
|
359
|
+
values.push(value);
|
|
360
|
+
}
|
|
361
|
+
return "[" + values.join(",") + "]";
|
|
362
|
+
}
|
|
363
|
+
return null;
|
|
364
|
+
}
|
|
365
|
+
if (expression.kind == NodeKind.UnaryPrefix) {
|
|
366
|
+
const value = toString(expression).trim();
|
|
367
|
+
return /^-\d+$/.test(value) ? value : null;
|
|
368
|
+
}
|
|
369
|
+
if (expression.kind == NodeKind.New) {
|
|
370
|
+
const value = expression;
|
|
371
|
+
if (value.args.length != 0)
|
|
372
|
+
return null;
|
|
373
|
+
const constructed = toString(value.typeName).trim();
|
|
374
|
+
if (constructed == "Array" ||
|
|
375
|
+
constructed.startsWith("Array<") ||
|
|
376
|
+
constructed == "StaticArray" ||
|
|
377
|
+
constructed.startsWith("StaticArray<"))
|
|
378
|
+
return "[]";
|
|
379
|
+
const nested = this.getDefaultSchema(owner, type) ||
|
|
380
|
+
this.getDefaultSchema(owner, constructed);
|
|
381
|
+
return nested ? this.getDefaultObjectJSON(nested, visiting) : null;
|
|
382
|
+
}
|
|
383
|
+
return null;
|
|
384
|
+
}
|
|
385
|
+
getImplicitDefaultJSON(member, owner, visiting) {
|
|
386
|
+
if (member.node.type.isNullable)
|
|
387
|
+
return "null";
|
|
388
|
+
const type = stripNull(member.type).trim();
|
|
389
|
+
if (isBoolean(type))
|
|
390
|
+
return "false";
|
|
391
|
+
if (isPrimitive(type) ||
|
|
392
|
+
isEnum(type, this.sources.get(owner.node.range.source), this.parser))
|
|
393
|
+
return "0";
|
|
394
|
+
if (isString(type))
|
|
395
|
+
return '""';
|
|
396
|
+
if (this.getDefaultElementType(type))
|
|
397
|
+
return "[]";
|
|
398
|
+
const nested = this.getDefaultSchema(owner, type);
|
|
399
|
+
return nested ? this.getDefaultObjectJSON(nested, visiting) : null;
|
|
400
|
+
}
|
|
401
|
+
getDefaultObjectJSON(schema, visiting = new Set()) {
|
|
402
|
+
if (visiting.has(schema) ||
|
|
403
|
+
schema.custom ||
|
|
404
|
+
!schema.static ||
|
|
405
|
+
schema.node.isGeneric ||
|
|
406
|
+
schema.members.some((member) => member.flags.size != 0 || member.custom || member.generic))
|
|
407
|
+
return null;
|
|
408
|
+
visiting.add(schema);
|
|
409
|
+
const fields = [];
|
|
410
|
+
for (const member of schema.members) {
|
|
411
|
+
const value = member.node.initializer
|
|
412
|
+
? this.getDefaultExpressionJSON(member.node.initializer, member.type, schema, visiting)
|
|
413
|
+
: this.getImplicitDefaultJSON(member, schema, visiting);
|
|
414
|
+
if (value == null) {
|
|
415
|
+
visiting.delete(schema);
|
|
416
|
+
return null;
|
|
417
|
+
}
|
|
418
|
+
fields.push(JSON.stringify(member.alias || member.name) + ":" + value);
|
|
419
|
+
}
|
|
420
|
+
visiting.delete(schema);
|
|
421
|
+
return "{" + fields.join(",") + "}";
|
|
422
|
+
}
|
|
423
|
+
getDefaultMatcherSource(defaultJSON) {
|
|
424
|
+
const literal = JSON.stringify(defaultJSON);
|
|
425
|
+
if (defaultJSON.length > 256)
|
|
426
|
+
return (`@inline __DESERIALIZE_DEFAULT(srcStart: usize, srcEnd: usize, knownMatch: bool = false): this {\n` +
|
|
427
|
+
` if (!knownMatch && !JSON.Util.matchesLiteral(srcStart, srcEnd, ${literal})) return changetype<this>(0);\n` +
|
|
428
|
+
` return changetype<this>(__new(offsetof<this>(), idof<this>())).__INITIALIZE();\n` +
|
|
429
|
+
`}`);
|
|
430
|
+
const bytes = [];
|
|
431
|
+
for (let i = 0; i < defaultJSON.length; i++) {
|
|
432
|
+
const code = defaultJSON.charCodeAt(i);
|
|
433
|
+
bytes.push(code & 0xff, code >>> 8);
|
|
434
|
+
}
|
|
435
|
+
const mismatches = [];
|
|
436
|
+
let offset = 0;
|
|
437
|
+
for (; offset + 16 <= bytes.length; offset += 16) {
|
|
438
|
+
const lanes = bytes
|
|
439
|
+
.slice(offset, offset + 16)
|
|
440
|
+
.map((value) => (value < 128 ? value : value - 256))
|
|
441
|
+
.join(", ");
|
|
442
|
+
mismatches.push(`v128.xor(v128.load(srcStart, ${offset}), v128(${lanes}))`);
|
|
443
|
+
}
|
|
444
|
+
const checks = [];
|
|
445
|
+
if (mismatches.length != 0) {
|
|
446
|
+
checks.push(` let mismatch = ${mismatches[0]};`);
|
|
447
|
+
for (let i = 1; i < mismatches.length; i++)
|
|
448
|
+
checks.push(` mismatch = v128.or(mismatch, ${mismatches[i]});`);
|
|
449
|
+
checks.push(" if (v128.any_true(mismatch)) return false;");
|
|
450
|
+
}
|
|
451
|
+
const scalar = (start, size) => {
|
|
452
|
+
let value = 0n;
|
|
453
|
+
for (let i = 0; i < size; i++)
|
|
454
|
+
value |= BigInt(bytes[start + i]) << BigInt(i << 3);
|
|
455
|
+
return "0x" + value.toString(16);
|
|
456
|
+
};
|
|
457
|
+
for (; offset + 8 <= bytes.length; offset += 8)
|
|
458
|
+
checks.push(` if (load<u64>(srcStart, ${offset}) != ${scalar(offset, 8)}) return false;`);
|
|
459
|
+
for (; offset + 4 <= bytes.length; offset += 4)
|
|
460
|
+
checks.push(` if (load<u32>(srcStart, ${offset}) != ${scalar(offset, 4)}) return false;`);
|
|
461
|
+
for (; offset + 2 <= bytes.length; offset += 2)
|
|
462
|
+
checks.push(` if (load<u16>(srcStart, ${offset}) != ${scalar(offset, 2)}) return false;`);
|
|
463
|
+
return (`@inline __DESERIALIZE_DEFAULT(srcStart: usize, srcEnd: usize, knownMatch: bool = false): this {\n` +
|
|
464
|
+
` if (!knownMatch) {\n` +
|
|
465
|
+
` if (srcEnd - srcStart != ${bytes.length}) return changetype<this>(0);\n` +
|
|
466
|
+
checks
|
|
467
|
+
.join("\n")
|
|
468
|
+
.replaceAll(" ", " ")
|
|
469
|
+
.replaceAll("return false;", "return changetype<this>(0);") +
|
|
470
|
+
`\n }` +
|
|
471
|
+
`\n return changetype<this>(__new(offsetof<this>(), idof<this>())).__INITIALIZE();\n}`);
|
|
472
|
+
}
|
|
290
473
|
visitClassDeclaration(node) {
|
|
291
474
|
if (!node.decorators?.length)
|
|
292
475
|
return;
|
|
@@ -676,9 +859,10 @@ export class JSONTransform extends Visitor {
|
|
|
676
859
|
this.visitedClasses.add(fullClassPath);
|
|
677
860
|
const requestedFastPath = USE_FAST_PATH;
|
|
678
861
|
let SERIALIZE = "__SERIALIZE(ptr: usize): void {\n";
|
|
679
|
-
let INITIALIZE = " __INITIALIZE(): this {\n";
|
|
862
|
+
let INITIALIZE = "@inline __INITIALIZE(): this {\n";
|
|
680
863
|
let DESERIALIZE = "__DESERIALIZE_SLOW<__JSON_T>(srcStart: usize, srcEnd: usize, out: __JSON_T): usize {\n";
|
|
681
864
|
let DESERIALIZE_FAST = "__DESERIALIZE_FAST<__JSON_T>(srcStart: usize, srcEnd: usize, out: __JSON_T): usize {\n";
|
|
865
|
+
let fastPrettyTailStart = 0;
|
|
682
866
|
let DESERIALIZE_CUSTOM = "";
|
|
683
867
|
let SERIALIZE_CUSTOM = "";
|
|
684
868
|
if (DEBUG > 0)
|
|
@@ -793,6 +977,7 @@ export class JSONTransform extends Visitor {
|
|
|
793
977
|
this.generateEmptyMethods(node);
|
|
794
978
|
return;
|
|
795
979
|
}
|
|
980
|
+
const defaultStringLiterals = new Map();
|
|
796
981
|
for (const member of members) {
|
|
797
982
|
if (!member.type)
|
|
798
983
|
throwError("Fields must be strongly typed", node.range);
|
|
@@ -809,6 +994,18 @@ export class JSONTransform extends Visitor {
|
|
|
809
994
|
mem.value = value;
|
|
810
995
|
mem.node = member;
|
|
811
996
|
mem.byteSize = estimatedSerializedByteSize(mem.type, source, this.parser);
|
|
997
|
+
if (member.initializer?.kind == NodeKind.Literal &&
|
|
998
|
+
member.initializer.literalKind ==
|
|
999
|
+
2 &&
|
|
1000
|
+
isString(stripNull(mem.type))) {
|
|
1001
|
+
const literal = member.initializer;
|
|
1002
|
+
const encoded = JSON.stringify(literal.value);
|
|
1003
|
+
mem.byteSize = encoded.length << 1;
|
|
1004
|
+
defaultStringLiterals.set(mem.name, {
|
|
1005
|
+
expression: toString(member.initializer),
|
|
1006
|
+
encoded,
|
|
1007
|
+
});
|
|
1008
|
+
}
|
|
812
1009
|
mem.custom = schema.deps.some((dep) => dep?.name == stripNull(type) && dep.custom);
|
|
813
1010
|
const lzInner = lazyInner.get(name.text);
|
|
814
1011
|
if (lzInner !== undefined) {
|
|
@@ -898,8 +1095,24 @@ export class JSONTransform extends Visitor {
|
|
|
898
1095
|
let isRegular = isPure;
|
|
899
1096
|
let isFirst = true;
|
|
900
1097
|
const serValue = (member, realName) => {
|
|
901
|
-
if (!member.flags.has(PropertyFlags.Lazy))
|
|
1098
|
+
if (!member.flags.has(PropertyFlags.Lazy)) {
|
|
1099
|
+
const defaultString = defaultStringLiterals.get(member.name);
|
|
1100
|
+
if (defaultString) {
|
|
1101
|
+
const stores = this.getStores(defaultString.encoded, this.program.options.hasFeature(16)).join("\n");
|
|
1102
|
+
return (`{\n` +
|
|
1103
|
+
` const __str = load<${member.type}>(ptr, offsetof<this>(${JSON.stringify(realName)}));\n` +
|
|
1104
|
+
` if (changetype<usize>(__str) == changetype<usize>(${defaultString.expression})) {\n` +
|
|
1105
|
+
stores
|
|
1106
|
+
.split("\n")
|
|
1107
|
+
.map((line) => ` ${line}\n`)
|
|
1108
|
+
.join("") +
|
|
1109
|
+
` } else {\n` +
|
|
1110
|
+
` JSON.__serialize<${member.type}>(__str);\n` +
|
|
1111
|
+
` }\n` +
|
|
1112
|
+
`}\n`);
|
|
1113
|
+
}
|
|
902
1114
|
return getSerializeCall(member.type, realName);
|
|
1115
|
+
}
|
|
903
1116
|
const T = member.lazyInner;
|
|
904
1117
|
const baseName = realName.slice(0, -3);
|
|
905
1118
|
const baseT = stripNull(T);
|
|
@@ -1131,7 +1344,10 @@ export class JSONTransform extends Visitor {
|
|
|
1131
1344
|
type.startsWith("JSON.Box<") ||
|
|
1132
1345
|
isEnum(type, this.sources.get(this.schema.node.range.source), this.parser))
|
|
1133
1346
|
sortedMembers.number.push(member);
|
|
1134
|
-
else if (isArray(type) ||
|
|
1347
|
+
else if (isArray(type) ||
|
|
1348
|
+
type == "JSON.Arr" ||
|
|
1349
|
+
type == "Arr" ||
|
|
1350
|
+
needsReferenceLoad(type))
|
|
1135
1351
|
sortedMembers.array.push(member);
|
|
1136
1352
|
else
|
|
1137
1353
|
sortedMembers.object.push(member);
|
|
@@ -1183,6 +1399,8 @@ export class JSONTransform extends Visitor {
|
|
|
1183
1399
|
const FLOAT_TYPES = ["f32", "f64"];
|
|
1184
1400
|
const INTEGER_TYPES = [...UNSIGNED_INTEGER_TYPES, ...SIGNED_INTEGER_TYPES];
|
|
1185
1401
|
const STRING_FIELD_DESERIALIZER = "__deserializeStringField";
|
|
1402
|
+
const STRING_FIELD_TRUSTED_DESERIALIZER = "__deserializeStringFieldTrusted";
|
|
1403
|
+
const getCustomDeserializeExpression = (type, valueStart, valueEnd) => `changetype<nonnull<${stripNull(type)}>>(0).__DESERIALIZE_CUSTOM(JSON.Util.ptrToStr(${valueStart}, ${valueEnd}))`;
|
|
1186
1404
|
const getArrayValueType = (type) => {
|
|
1187
1405
|
if (!type.startsWith("Array<") && !type.startsWith("StaticArray<"))
|
|
1188
1406
|
return null;
|
|
@@ -1219,7 +1437,32 @@ export class JSONTransform extends Visitor {
|
|
|
1219
1437
|
out.push(` ${srcPtr} = ${valuePtr} + 8;`);
|
|
1220
1438
|
out.push(" } else {");
|
|
1221
1439
|
}
|
|
1222
|
-
|
|
1440
|
+
const declaredDefaultString = defaultStringLiterals.get(member.name);
|
|
1441
|
+
const defaultString = declaredDefaultString?.encoded == '""'
|
|
1442
|
+
? undefined
|
|
1443
|
+
: declaredDefaultString;
|
|
1444
|
+
const stringFieldDeserializer = fastPath && keyOffset && !member.node.type.isNullable
|
|
1445
|
+
? STRING_FIELD_TRUSTED_DESERIALIZER
|
|
1446
|
+
: STRING_FIELD_DESERIALIZER;
|
|
1447
|
+
const stringValuePtr = stringFieldDeserializer == STRING_FIELD_TRUSTED_DESERIALIZER
|
|
1448
|
+
? `${valuePtr} + 2`
|
|
1449
|
+
: valuePtr;
|
|
1450
|
+
const stringFieldCall = stringFieldDeserializer == STRING_FIELD_TRUSTED_DESERIALIZER
|
|
1451
|
+
? stringFieldDeserializer
|
|
1452
|
+
: `${stringFieldDeserializer}<${member.type}>`;
|
|
1453
|
+
if (defaultString) {
|
|
1454
|
+
const encodedBytes = defaultString.encoded.length << 1;
|
|
1455
|
+
const comparisons = getComparisions(defaultString.encoded, valuePtr, "==").join(" && ");
|
|
1456
|
+
out.push(` if (${valuePtr} + ${encodedBytes} <= srcEnd && ${comparisons}) {`);
|
|
1457
|
+
out.push(` store<${member.type}>(${outPtr}, ${defaultString.expression}, ${fieldOffset});`);
|
|
1458
|
+
out.push(` ${srcPtr} = ${valuePtr} + ${encodedBytes};`);
|
|
1459
|
+
out.push(" } else {");
|
|
1460
|
+
out.push(` ${srcPtr} = ${stringFieldCall}(${stringValuePtr}, srcEnd, ${outPtr}, ${fieldOffset});`);
|
|
1461
|
+
out.push(" }");
|
|
1462
|
+
}
|
|
1463
|
+
else {
|
|
1464
|
+
out.push(` ${srcPtr} = ${stringFieldCall}(${stringValuePtr}, srcEnd, ${outPtr}, ${fieldOffset});`);
|
|
1465
|
+
}
|
|
1223
1466
|
if (member.node.type.isNullable) {
|
|
1224
1467
|
out.push(" }");
|
|
1225
1468
|
}
|
|
@@ -1290,37 +1533,11 @@ export class JSONTransform extends Visitor {
|
|
|
1290
1533
|
}
|
|
1291
1534
|
else if (resolvedType == "JSON.Raw") {
|
|
1292
1535
|
out.push("{");
|
|
1293
|
-
out.push(` const valueStart = ${
|
|
1294
|
-
out.push(
|
|
1295
|
-
out.push("
|
|
1296
|
-
out.push(`
|
|
1297
|
-
out.push(`
|
|
1298
|
-
out.push(" if (inString) {");
|
|
1299
|
-
out.push(` if (code == 0x22 && load<u16>(${srcPtr} - 2) != 0x5c) inString = false;`);
|
|
1300
|
-
out.push(` ${srcPtr} += 2;`);
|
|
1301
|
-
out.push(" continue;");
|
|
1302
|
-
out.push(" }");
|
|
1303
|
-
out.push(" if (code == 0x22) {");
|
|
1304
|
-
out.push(" inString = true;");
|
|
1305
|
-
out.push(` ${srcPtr} += 2;`);
|
|
1306
|
-
out.push(" continue;");
|
|
1307
|
-
out.push(" }");
|
|
1308
|
-
out.push(" if (code == 0x7b || code == 0x5b) {");
|
|
1309
|
-
out.push(" depth++;");
|
|
1310
|
-
out.push(` ${srcPtr} += 2;`);
|
|
1311
|
-
out.push(" continue;");
|
|
1312
|
-
out.push(" }");
|
|
1313
|
-
out.push(" if (code == 0x7d || code == 0x5d) {");
|
|
1314
|
-
out.push(" if (depth == 0) break;");
|
|
1315
|
-
out.push(" depth--;");
|
|
1316
|
-
out.push(` ${srcPtr} += 2;`);
|
|
1317
|
-
out.push(" continue;");
|
|
1318
|
-
out.push(" }");
|
|
1319
|
-
out.push(" if (code == 0x2c && depth == 0) break;");
|
|
1320
|
-
out.push(` ${srcPtr} += 2;`);
|
|
1321
|
-
out.push(" }");
|
|
1322
|
-
out.push(` if (inString || depth != 0 || ${srcPtr} <= valueStart) break;`);
|
|
1323
|
-
out.push(` store<${member.type}>(${outPtr}, JSON.Raw.from(JSON.Util.ptrToStr(valueStart, ${srcPtr})), ${fieldOffset});`);
|
|
1536
|
+
out.push(` const valueStart = ${valuePtr};`);
|
|
1537
|
+
out.push(` const valueEnd = JSON.Util.scanValueEnd<JSON.Raw>(valueStart, srcEnd);`);
|
|
1538
|
+
out.push(" if (!valueEnd) break;");
|
|
1539
|
+
out.push(` store<${member.type}>(${outPtr}, JSON.Raw.from(JSON.Util.ptrToStr(valueStart, valueEnd)), ${fieldOffset});`);
|
|
1540
|
+
out.push(` ${srcPtr} = valueEnd;`);
|
|
1324
1541
|
out.push("}");
|
|
1325
1542
|
}
|
|
1326
1543
|
else if (isBoolean(resolvedType)) {
|
|
@@ -1339,6 +1556,24 @@ export class JSONTransform extends Visitor {
|
|
|
1339
1556
|
else if (FLOAT_TYPES.includes(resolvedType)) {
|
|
1340
1557
|
out.push(`${srcPtr} = __deserializeFloatField<${resolvedType}>(${valuePtr}, srcEnd, ${outPtr}, ${fieldOffset});`);
|
|
1341
1558
|
}
|
|
1559
|
+
else if (resolvedSchema?.custom) {
|
|
1560
|
+
out.push("{");
|
|
1561
|
+
if (member.node.type.isNullable) {
|
|
1562
|
+
out.push(` if (load<u64>(${valuePtr}) == 30399761348886638) {`);
|
|
1563
|
+
out.push(` store<${member.type}>(${outPtr}, changetype<${member.type}>(0), ${fieldOffset});`);
|
|
1564
|
+
out.push(` ${srcPtr} = ${valuePtr} + 8;`);
|
|
1565
|
+
out.push(" } else {");
|
|
1566
|
+
}
|
|
1567
|
+
out.push(` const valueStart = ${valuePtr};`);
|
|
1568
|
+
out.push(` const valueEnd = JSON.Util.scanValueEnd<${resolvedType}>(valueStart, srcEnd);`);
|
|
1569
|
+
out.push(" if (!valueEnd) break;");
|
|
1570
|
+
out.push(` store<${member.type}>(${outPtr}, ${getCustomDeserializeExpression(resolvedType, "valueStart", "valueEnd")}, ${fieldOffset});`);
|
|
1571
|
+
out.push(` ${srcPtr} = valueEnd;`);
|
|
1572
|
+
if (member.node.type.isNullable) {
|
|
1573
|
+
out.push(" }");
|
|
1574
|
+
}
|
|
1575
|
+
out.push("}");
|
|
1576
|
+
}
|
|
1342
1577
|
else if (resolvedSchema && !resolvedSchema.custom) {
|
|
1343
1578
|
if (fastPath) {
|
|
1344
1579
|
out.push("{");
|
|
@@ -1417,25 +1652,29 @@ export class JSONTransform extends Visitor {
|
|
|
1417
1652
|
out.push(` store<${resolvedType}>(${outPtr}, value, ${fieldOffset});`);
|
|
1418
1653
|
out.push(" }");
|
|
1419
1654
|
out.push(" let index = 0;");
|
|
1655
|
+
out.push(" const reusableLength = value.length;");
|
|
1656
|
+
out.push(" const reusableDataStart = value.dataStart;");
|
|
1420
1657
|
out.push(` ${srcPtr} = ${valuePtr} + 2;`);
|
|
1421
1658
|
out.push(` ${srcPtr} = JSON.Util.skipWhitespace(${srcPtr}, srcEnd);`);
|
|
1422
1659
|
out.push(` if (load<u16>(${srcPtr}) == 0x5d) {`);
|
|
1423
|
-
out.push(" value.length = 0;");
|
|
1660
|
+
out.push(" if (value.length != 0) value.length = 0;");
|
|
1424
1661
|
out.push(` ${srcPtr} += 2;`);
|
|
1425
1662
|
out.push(" } else while (true) {");
|
|
1426
1663
|
out.push(` ${srcPtr} = JSON.Util.skipWhitespace(${srcPtr}, srcEnd);`);
|
|
1427
1664
|
if (elementNullable) {
|
|
1428
|
-
out.push(` if (index >=
|
|
1665
|
+
out.push(` if (index >= reusableLength) value.push(changetype<${valueType} | null>(0));`);
|
|
1666
|
+
out.push(` const slot = index < reusableLength ? reusableDataStart + ((<usize>index) << alignof<${valueType}>()) : value.dataStart + ((<usize>index) << alignof<${valueType}>());`);
|
|
1429
1667
|
out.push(` if (load<u64>(${srcPtr}) == 30399761348886638) {`);
|
|
1430
|
-
out.push(
|
|
1668
|
+
out.push(" store<usize>(slot, 0);");
|
|
1431
1669
|
out.push(` ${srcPtr} += 8;`);
|
|
1432
1670
|
out.push(" } else {");
|
|
1433
|
-
out.push(` ${srcPtr} = ${STRING_FIELD_DESERIALIZER}<${valueType}>(${srcPtr}, srcEnd,
|
|
1671
|
+
out.push(` ${srcPtr} = ${STRING_FIELD_DESERIALIZER}<${valueType}>(${srcPtr}, srcEnd, slot);`);
|
|
1434
1672
|
out.push(" }");
|
|
1435
1673
|
}
|
|
1436
1674
|
else {
|
|
1437
|
-
out.push(' if (index >=
|
|
1438
|
-
out.push(`
|
|
1675
|
+
out.push(' if (index >= reusableLength) value.push("");');
|
|
1676
|
+
out.push(` const slot = index < reusableLength ? reusableDataStart + ((<usize>index) << alignof<${valueType}>()) : value.dataStart + ((<usize>index) << alignof<${valueType}>());`);
|
|
1677
|
+
out.push(` ${srcPtr} = ${STRING_FIELD_DESERIALIZER}<${valueType}>(${srcPtr}, srcEnd, slot);`);
|
|
1439
1678
|
}
|
|
1440
1679
|
out.push(" index++;");
|
|
1441
1680
|
out.push(` ${srcPtr} = JSON.Util.skipWhitespace(${srcPtr}, srcEnd);`);
|
|
@@ -1445,7 +1684,7 @@ export class JSONTransform extends Visitor {
|
|
|
1445
1684
|
out.push(" continue;");
|
|
1446
1685
|
out.push(" }");
|
|
1447
1686
|
out.push(" if (code == 0x5d) {");
|
|
1448
|
-
out.push(" value.length = index;");
|
|
1687
|
+
out.push(" if (index != reusableLength) value.length = index;");
|
|
1449
1688
|
out.push(` ${srcPtr} += 2;`);
|
|
1450
1689
|
out.push(" break;");
|
|
1451
1690
|
out.push(" }");
|
|
@@ -1466,18 +1705,21 @@ export class JSONTransform extends Visitor {
|
|
|
1466
1705
|
out.push(` store<${resolvedType}>(${outPtr}, value, ${fieldOffset});`);
|
|
1467
1706
|
out.push(" }");
|
|
1468
1707
|
out.push(" let index = 0;");
|
|
1708
|
+
out.push(" const reusableLength = value.length;");
|
|
1709
|
+
out.push(" const reusableDataStart = value.dataStart;");
|
|
1469
1710
|
out.push(` ${srcPtr} = ${valuePtr} + 2;`);
|
|
1470
1711
|
out.push(` ${srcPtr} = JSON.Util.skipWhitespace(${srcPtr}, srcEnd);`);
|
|
1471
1712
|
out.push(` if (load<u16>(${srcPtr}) == 0x5d) {`);
|
|
1472
|
-
out.push(" value.length = 0;");
|
|
1713
|
+
out.push(" if (value.length != 0) value.length = 0;");
|
|
1473
1714
|
out.push(` ${srcPtr} += 2;`);
|
|
1474
1715
|
out.push(" } else while (true) {");
|
|
1475
1716
|
out.push(` let item: ${valueType};`);
|
|
1476
|
-
out.push(" if (index <
|
|
1477
|
-
out.push(
|
|
1717
|
+
out.push(" if (index < reusableLength) {");
|
|
1718
|
+
out.push(` const itemSlot = reusableDataStart + ((<usize>index) << alignof<${valueType}>());`);
|
|
1719
|
+
out.push(` item = load<${valueType}>(itemSlot);`);
|
|
1478
1720
|
out.push(" if (changetype<usize>(item) == 0) {");
|
|
1479
1721
|
out.push(` item = changetype<${valueType}>(__new(offsetof<nonnull<${valueType}>>(), idof<nonnull<${valueType}>>()));`);
|
|
1480
|
-
out.push(
|
|
1722
|
+
out.push(` store<${valueType}>(itemSlot, item);`);
|
|
1481
1723
|
out.push(` changetype<nonnull<${valueType}>>(item).__INITIALIZE();`);
|
|
1482
1724
|
out.push(" }");
|
|
1483
1725
|
out.push(" } else {");
|
|
@@ -1504,7 +1746,7 @@ export class JSONTransform extends Visitor {
|
|
|
1504
1746
|
out.push(" continue;");
|
|
1505
1747
|
out.push(" }");
|
|
1506
1748
|
out.push(" if (code == 0x5d) {");
|
|
1507
|
-
out.push(" value.length = index;");
|
|
1749
|
+
out.push(" if (reusableLength != index) value.length = index;");
|
|
1508
1750
|
out.push(` ${srcPtr} += 2;`);
|
|
1509
1751
|
out.push(" break;");
|
|
1510
1752
|
out.push(" }");
|
|
@@ -1516,8 +1758,25 @@ export class JSONTransform extends Visitor {
|
|
|
1516
1758
|
out.push("}");
|
|
1517
1759
|
return out;
|
|
1518
1760
|
}
|
|
1519
|
-
|
|
1520
|
-
|
|
1761
|
+
if (valueType == "i64") {
|
|
1762
|
+
out.push(` if (load<u32>(${valuePtr}) == 0x005d005b) {`);
|
|
1763
|
+
out.push(` let value = load<${resolvedType}>(${outPtr}, ${fieldOffset});`);
|
|
1764
|
+
out.push(" if (changetype<usize>(value) == 0) {");
|
|
1765
|
+
out.push(` value = instantiate<nonnull<${resolvedType}>>();`);
|
|
1766
|
+
out.push(` store<${resolvedType}>(${outPtr}, value, ${fieldOffset});`);
|
|
1767
|
+
out.push(" } else if (value.length != 0) {");
|
|
1768
|
+
out.push(" value.length = 0;");
|
|
1769
|
+
out.push(" }");
|
|
1770
|
+
out.push(` ${srcPtr} = ${valuePtr} + 4;`);
|
|
1771
|
+
out.push(" } else {");
|
|
1772
|
+
out.push(` ${srcPtr} = __deserializeArrayField_SWAR<nonnull<${resolvedType}>>(${valuePtr}, srcEnd, ${outPtr}, ${fieldOffset});`);
|
|
1773
|
+
out.push(` if (!${srcPtr}) break;`);
|
|
1774
|
+
out.push(" }");
|
|
1775
|
+
}
|
|
1776
|
+
else {
|
|
1777
|
+
out.push(` ${srcPtr} = __deserializeArrayField_SWAR<nonnull<${resolvedType}>>(${valuePtr}, srcEnd, ${outPtr}, ${fieldOffset});`);
|
|
1778
|
+
out.push(` if (!${srcPtr}) break;`);
|
|
1779
|
+
}
|
|
1521
1780
|
if (member.node.type.isNullable) {
|
|
1522
1781
|
out.push(" }");
|
|
1523
1782
|
}
|
|
@@ -1570,8 +1829,25 @@ export class JSONTransform extends Visitor {
|
|
|
1570
1829
|
const chunkFastBlocksOptional = (blocks, _tag, _callIndent, _needsKp) => {
|
|
1571
1830
|
return blocks.join("");
|
|
1572
1831
|
};
|
|
1832
|
+
const traceOptionalObject = supportsFastOptionalPath && this.schema.members.length <= 63;
|
|
1833
|
+
const objectTraceHeader = traceOptionalObject
|
|
1834
|
+
? " const __traceToken = JSON.Util.beginObjectTrace(dst, start, " +
|
|
1835
|
+
JSON.stringify(this.schema.name) +
|
|
1836
|
+
");\n" +
|
|
1837
|
+
" const __traceActive = __traceToken != i32.MIN_VALUE;\n" +
|
|
1838
|
+
" const __traceHit = __traceActive && __traceToken < 0;\n" +
|
|
1839
|
+
" const __traceSlot = __traceHit ? ~__traceToken : __traceToken;\n" +
|
|
1840
|
+
" const __traceMask = __traceHit ? JSON.Util.getObjectTraceMask(__traceSlot) : <u64>0;\n" +
|
|
1841
|
+
" const __traceTier = __traceHit ? JSON.Util.getObjectTraceTier(__traceSlot) : <u8>0;\n" +
|
|
1842
|
+
" let __tracePresent: u64 = 0;\n"
|
|
1843
|
+
: "";
|
|
1573
1844
|
DESERIALIZE_FAST += indent + "const start = srcStart;\n";
|
|
1574
1845
|
DESERIALIZE_FAST += indent + "const dst = changetype<usize>(out);\n";
|
|
1846
|
+
if (traceOptionalObject) {
|
|
1847
|
+
DESERIALIZE_FAST += objectTraceHeader;
|
|
1848
|
+
DESERIALIZE_FAST += indent + "if (__traceTier < 2) {\n";
|
|
1849
|
+
indent += " ";
|
|
1850
|
+
}
|
|
1575
1851
|
DESERIALIZE_FAST += indent + "do {\n";
|
|
1576
1852
|
indent += " ";
|
|
1577
1853
|
if (supportsFastOptionalPath) {
|
|
@@ -1585,25 +1861,40 @@ export class JSONTransform extends Visitor {
|
|
|
1585
1861
|
const key = JSON.stringify(member.alias || member.name);
|
|
1586
1862
|
if (key.length <= 2)
|
|
1587
1863
|
throw new Error("Key cannot be empty!");
|
|
1588
|
-
const firstKeySection = key + ":";
|
|
1589
|
-
const nextKeySection = "," + key + ":";
|
|
1590
|
-
const firstKeyOffset = firstKeySection.length << 1;
|
|
1591
|
-
const nextKeyOffset = nextKeySection.length << 1;
|
|
1592
1864
|
const resolvedType = stripNull(member.type);
|
|
1593
1865
|
const inlineStringValue = ["string", "String"].includes(resolvedType);
|
|
1594
|
-
const
|
|
1595
|
-
const
|
|
1866
|
+
const packedQuote = inlineStringValue && !member.node.type.isNullable ? '"' : "";
|
|
1867
|
+
const firstKeySection = key + ":" + packedQuote;
|
|
1868
|
+
const nextKeySection = "," + key + ":" + packedQuote;
|
|
1869
|
+
const firstKeyOffset = firstKeySection.length << 1;
|
|
1870
|
+
const nextKeyOffset = nextKeySection.length << 1;
|
|
1871
|
+
const trustedStringValue = packedQuote.length != 0;
|
|
1872
|
+
const firstValueOffset = trustedStringValue
|
|
1873
|
+
? firstKeyOffset - 2
|
|
1874
|
+
: firstKeyOffset;
|
|
1875
|
+
const nextValueOffset = trustedStringValue
|
|
1876
|
+
? nextKeyOffset - 2
|
|
1877
|
+
: nextKeyOffset;
|
|
1878
|
+
const deserializerFirst = getDeserializer(member.type, "srcStart", "dst", member, inlineStringValue ? firstValueOffset : 0, true);
|
|
1879
|
+
const deserializerNext = getDeserializer(member.type, "srcStart", "dst", member, inlineStringValue ? nextValueOffset : 0, true);
|
|
1596
1880
|
const isOptional = member.flags.has(PropertyFlags.OmitNull) ||
|
|
1597
1881
|
member.flags.has(PropertyFlags.OmitIf);
|
|
1882
|
+
const traceBit = `<u64>1 << ${i}`;
|
|
1883
|
+
const firstMismatch = getComparisions(firstKeySection, "srcStart", "!=").join(" || ");
|
|
1884
|
+
const nextMismatch = getComparisions(nextKeySection, "srcStart", "!=").join(" || ");
|
|
1885
|
+
const firstAbsent = traceOptionalObject
|
|
1886
|
+
? `__traceHit ? (__traceMask & (${traceBit})) == 0 : (${firstMismatch})`
|
|
1887
|
+
: firstMismatch;
|
|
1888
|
+
const nextAbsent = traceOptionalObject
|
|
1889
|
+
? `__traceHit ? (__traceMask & (${traceBit})) == 0 : (${nextMismatch})`
|
|
1890
|
+
: nextMismatch;
|
|
1598
1891
|
if (!deserializerFirst.length || !deserializerNext.length) {
|
|
1599
1892
|
t1opt.push(indent + "break;\n\n");
|
|
1600
1893
|
continue;
|
|
1601
1894
|
}
|
|
1602
1895
|
let blk = indent + "if (!seenAny) {\n";
|
|
1603
1896
|
indent += " ";
|
|
1604
|
-
blk +=
|
|
1605
|
-
indent +
|
|
1606
|
-
`if ( // ${firstKeySection}\n${(indent += " ")}${getComparisions(firstKeySection, "srcStart", "!=").join("\n" + indent + "|| ")}\n${(indent = indent.slice(0, -2))}) {\n`;
|
|
1897
|
+
blk += indent + `if (${firstAbsent}) {\n`;
|
|
1607
1898
|
indent += " ";
|
|
1608
1899
|
if (isOptional) {
|
|
1609
1900
|
blk += indent + "// optional @omitnull field omitted\n";
|
|
@@ -1616,19 +1907,20 @@ export class JSONTransform extends Visitor {
|
|
|
1616
1907
|
indent += " ";
|
|
1617
1908
|
if (!inlineStringValue)
|
|
1618
1909
|
blk += indent + `srcStart += ${firstKeyOffset};\n`;
|
|
1619
|
-
|
|
1620
|
-
|
|
1621
|
-
|
|
1910
|
+
if (!trustedStringValue)
|
|
1911
|
+
blk +=
|
|
1912
|
+
indent +
|
|
1913
|
+
`if (JSON.Util.isSpace(load<u16>(${inlineStringValue ? `srcStart + ${firstValueOffset}` : "srcStart"}))) break;\n`;
|
|
1622
1914
|
blk += indent + deserializerFirst.join("\n" + indent) + "\n";
|
|
1915
|
+
if (traceOptionalObject)
|
|
1916
|
+
blk += indent + `__tracePresent |= ${traceBit};\n`;
|
|
1623
1917
|
blk += indent + "seenAny = true;\n";
|
|
1624
1918
|
indent = indent.slice(0, -2);
|
|
1625
1919
|
blk += indent + "}\n";
|
|
1626
1920
|
indent = indent.slice(0, -2);
|
|
1627
1921
|
blk += indent + "} else {\n";
|
|
1628
1922
|
indent += " ";
|
|
1629
|
-
blk +=
|
|
1630
|
-
indent +
|
|
1631
|
-
`if ( // ${nextKeySection}\n${(indent += " ")}${getComparisions(nextKeySection, "srcStart", "!=").join("\n" + indent + "|| ")}\n${(indent = indent.slice(0, -2))}) {\n`;
|
|
1923
|
+
blk += indent + `if (${nextAbsent}) {\n`;
|
|
1632
1924
|
indent += " ";
|
|
1633
1925
|
if (isOptional) {
|
|
1634
1926
|
blk += indent + "// optional @omitnull field omitted\n";
|
|
@@ -1641,10 +1933,13 @@ export class JSONTransform extends Visitor {
|
|
|
1641
1933
|
indent += " ";
|
|
1642
1934
|
if (!inlineStringValue)
|
|
1643
1935
|
blk += indent + `srcStart += ${nextKeyOffset};\n`;
|
|
1644
|
-
|
|
1645
|
-
|
|
1646
|
-
|
|
1936
|
+
if (!trustedStringValue)
|
|
1937
|
+
blk +=
|
|
1938
|
+
indent +
|
|
1939
|
+
`if (JSON.Util.isSpace(load<u16>(${inlineStringValue ? `srcStart + ${nextValueOffset}` : "srcStart"}))) break;\n`;
|
|
1647
1940
|
blk += indent + deserializerNext.join("\n" + indent) + "\n";
|
|
1941
|
+
if (traceOptionalObject)
|
|
1942
|
+
blk += indent + `__tracePresent |= ${traceBit};\n`;
|
|
1648
1943
|
indent = indent.slice(0, -2);
|
|
1649
1944
|
blk += indent + "}\n";
|
|
1650
1945
|
indent = indent.slice(0, -2);
|
|
@@ -1660,24 +1955,27 @@ export class JSONTransform extends Visitor {
|
|
|
1660
1955
|
const key = JSON.stringify(member.alias || member.name);
|
|
1661
1956
|
if (key.length <= 2)
|
|
1662
1957
|
throw new Error("Key cannot be empty!");
|
|
1663
|
-
const keySection = (i == 0 ? "{" : ",") + key + ":";
|
|
1664
|
-
let blk = indent +
|
|
1665
|
-
`if ( // ${keySection}\n${(indent += " ")}${getComparisions(keySection, "srcStart", "!=").join("\n" + indent + "|| ")}\n${(indent = indent.slice(0, -2))}) break;\n`;
|
|
1666
|
-
const keyOffset = keySection.length << 1;
|
|
1667
1958
|
const resolvedType = stripNull(member.type);
|
|
1668
1959
|
const inlineStringValue = ["string", "String"].includes(resolvedType);
|
|
1960
|
+
const trustedStringValue = inlineStringValue && !member.node.type.isNullable;
|
|
1961
|
+
const keySection = (i == 0 ? "{" : ",") + key + ":" + (trustedStringValue ? '"' : "");
|
|
1962
|
+
let blk = indent +
|
|
1963
|
+
`if (${getComparisions(keySection, "srcStart", "!=").join(" || ")}) break;\n`;
|
|
1964
|
+
const keyOffset = keySection.length << 1;
|
|
1965
|
+
const valueOffset = trustedStringValue ? keyOffset - 2 : keyOffset;
|
|
1669
1966
|
if (!inlineStringValue) {
|
|
1670
1967
|
blk += indent + `srcStart += ${keyOffset};\n\n`;
|
|
1671
1968
|
}
|
|
1672
|
-
const deserializer = getDeserializer(member.type, "srcStart", "dst", member, inlineStringValue ?
|
|
1969
|
+
const deserializer = getDeserializer(member.type, "srcStart", "dst", member, inlineStringValue ? valueOffset : 0, true);
|
|
1673
1970
|
if (!deserializer.length) {
|
|
1674
1971
|
blk += indent + "break;\n\n";
|
|
1675
1972
|
t1blocks.push(blk);
|
|
1676
1973
|
continue;
|
|
1677
1974
|
}
|
|
1678
|
-
|
|
1679
|
-
|
|
1680
|
-
|
|
1975
|
+
if (!trustedStringValue)
|
|
1976
|
+
blk +=
|
|
1977
|
+
indent +
|
|
1978
|
+
`if (JSON.Util.isSpace(load<u16>(${inlineStringValue ? `srcStart + ${valueOffset}` : "srcStart"}))) break;\n`;
|
|
1681
1979
|
blk += indent + deserializer.join("\n" + indent) + "\n\n";
|
|
1682
1980
|
t1blocks.push(blk);
|
|
1683
1981
|
}
|
|
@@ -1686,9 +1984,18 @@ export class JSONTransform extends Visitor {
|
|
|
1686
1984
|
DESERIALIZE_FAST +=
|
|
1687
1985
|
indent + "if (load<u16>(srcStart) !== 0x7d) break; // }\n";
|
|
1688
1986
|
DESERIALIZE_FAST += indent + "srcStart += 2;\n";
|
|
1987
|
+
if (traceOptionalObject)
|
|
1988
|
+
DESERIALIZE_FAST +=
|
|
1989
|
+
indent +
|
|
1990
|
+
"if (__traceActive) JSON.Util.saveObjectTrace(__traceSlot, __tracePresent, 1);\n";
|
|
1689
1991
|
DESERIALIZE_FAST += indent + "return srcStart;\n";
|
|
1690
1992
|
indent = indent.slice(0, -2);
|
|
1691
1993
|
DESERIALIZE_FAST += indent + "} while (false);\n\n";
|
|
1994
|
+
if (traceOptionalObject) {
|
|
1995
|
+
indent = indent.slice(0, -2);
|
|
1996
|
+
DESERIALIZE_FAST += indent + "}\n\n";
|
|
1997
|
+
}
|
|
1998
|
+
fastPrettyTailStart = DESERIALIZE_FAST.length;
|
|
1692
1999
|
const tier2Desers = this.schema.members.map((member) => getDeserializer(member.type, "srcStart", "dst", member, 0, true));
|
|
1693
2000
|
const tier2Ok = tier2Desers.every((d) => d.length && !(d.length === 1 && d[0].trim() === "break;"));
|
|
1694
2001
|
if (tier2Ok && !supportsFastOptionalPath) {
|
|
@@ -1709,9 +2016,7 @@ export class JSONTransform extends Visitor {
|
|
|
1709
2016
|
blk += skip;
|
|
1710
2017
|
blk +=
|
|
1711
2018
|
i2 +
|
|
1712
|
-
`if (
|
|
1713
|
-
getComparisions(key, "srcStart", "!=").join("\n" + i2 + " || ") +
|
|
1714
|
-
`\n${i2}) break;\n`;
|
|
2019
|
+
`if (${getComparisions(key, "srcStart", "!=").join(" || ")}) break;\n`;
|
|
1715
2020
|
blk += i2 + `srcStart += ${keyBytes};\n`;
|
|
1716
2021
|
blk += skip;
|
|
1717
2022
|
blk += i2 + "if (load<u16>(srcStart) != 0x3a) break; // :\n";
|
|
@@ -1740,6 +2045,16 @@ export class JSONTransform extends Visitor {
|
|
|
1740
2045
|
const i3 = " ";
|
|
1741
2046
|
DESERIALIZE_FAST += i1 + "srcStart = start;\n";
|
|
1742
2047
|
DESERIALIZE_FAST += i1 + "do {\n";
|
|
2048
|
+
if (traceOptionalObject) {
|
|
2049
|
+
DESERIALIZE_FAST += i2 + "__tracePresent = 0;\n";
|
|
2050
|
+
DESERIALIZE_FAST +=
|
|
2051
|
+
i2 +
|
|
2052
|
+
"const __traceSeparator = __traceHit ? JSON.Util.getObjectTraceSeparator(__traceSlot) : <usize>0;\n";
|
|
2053
|
+
DESERIALIZE_FAST += i2 + "let __traceCandidateSeparator: usize = 0;\n";
|
|
2054
|
+
DESERIALIZE_FAST += i2 + "let __traceSeparatorStart: usize = 0;\n";
|
|
2055
|
+
DESERIALIZE_FAST += i2 + "let __traceSeparatorSeen = false;\n";
|
|
2056
|
+
DESERIALIZE_FAST += i2 + "let __traceCanonicalPretty = true;\n";
|
|
2057
|
+
}
|
|
1743
2058
|
DESERIALIZE_FAST +=
|
|
1744
2059
|
i2 + "srcStart = JSON.Util.skipWhitespace(srcStart, srcEnd);\n";
|
|
1745
2060
|
DESERIALIZE_FAST += i2 + "if (load<u16>(srcStart) != 0x7b) break; // {\n";
|
|
@@ -1752,23 +2067,91 @@ export class JSONTransform extends Visitor {
|
|
|
1752
2067
|
const member = this.schema.members[i];
|
|
1753
2068
|
const key = JSON.stringify(member.alias || member.name);
|
|
1754
2069
|
const keyBytes = key.length << 1;
|
|
2070
|
+
const traceBit = `<u64>1 << ${i}`;
|
|
2071
|
+
const keyMatches = getComparisions(key, "kp", "==").join(" && ");
|
|
2072
|
+
const presentCondition = traceOptionalObject
|
|
2073
|
+
? `__traceHit ? (__traceMask & (${traceBit})) != 0 : (${keyMatches})`
|
|
2074
|
+
: keyMatches;
|
|
1755
2075
|
let blk = "\n";
|
|
1756
|
-
|
|
1757
|
-
|
|
2076
|
+
if (traceOptionalObject) {
|
|
2077
|
+
blk += i2 + `if (__traceHit && (${traceBit} & __traceMask) != 0) {\n`;
|
|
2078
|
+
blk += i3 + "kp = srcStart;\n";
|
|
2079
|
+
if (multi && i > 0) {
|
|
2080
|
+
blk += i3 + "if (seenAny) {\n";
|
|
2081
|
+
blk += i3 + " if (load<u16>(kp) != 0x2c) break; // ,\n";
|
|
2082
|
+
blk += i3 + " kp += 2;\n";
|
|
2083
|
+
blk += i3 + "}\n";
|
|
2084
|
+
}
|
|
2085
|
+
blk += i3 + "if (__traceTier == 3) kp += __traceSeparator;\n";
|
|
2086
|
+
blk += i3 + "else kp = JSON.Util.skipWhitespace(kp, srcEnd);\n";
|
|
2087
|
+
blk += i2 + "} else if (!__traceHit) {\n";
|
|
2088
|
+
blk += i3 + "__traceSeparatorStart = srcStart;\n";
|
|
2089
|
+
blk += i3 + "kp = JSON.Util.skipWhitespace(srcStart, srcEnd);\n";
|
|
2090
|
+
if (multi && i > 0) {
|
|
2091
|
+
blk += i3 + "if (seenAny && load<u16>(kp) == 0x2c) {\n";
|
|
2092
|
+
blk +=
|
|
2093
|
+
i3 + " if (kp != srcStart) __traceCanonicalPretty = false;\n";
|
|
2094
|
+
blk += i3 + " __traceSeparatorStart = kp + 2;\n";
|
|
2095
|
+
blk +=
|
|
2096
|
+
i3 +
|
|
2097
|
+
" kp = JSON.Util.skipWhitespace(__traceSeparatorStart, srcEnd);\n";
|
|
2098
|
+
blk += i3 + "}\n";
|
|
2099
|
+
}
|
|
2100
|
+
blk += i2 + "}\n";
|
|
2101
|
+
}
|
|
2102
|
+
else {
|
|
2103
|
+
blk += i2 + "kp = JSON.Util.skipWhitespace(srcStart, srcEnd);\n";
|
|
2104
|
+
if (multi && i > 0) {
|
|
2105
|
+
blk +=
|
|
2106
|
+
i2 +
|
|
2107
|
+
"if (seenAny && load<u16>(kp) == 0x2c) kp = JSON.Util.skipWhitespace(kp + 2, srcEnd);\n";
|
|
2108
|
+
}
|
|
2109
|
+
}
|
|
2110
|
+
blk += i2 + `if (${presentCondition}) {\n`;
|
|
2111
|
+
if (traceOptionalObject) {
|
|
2112
|
+
blk += i3 + "if (__traceHit && __traceTier == 3) {\n";
|
|
2113
|
+
blk += i3 + ` kp += ${keyBytes};\n`;
|
|
2114
|
+
blk += i3 + " if (load<u16>(kp) != 0x3a) break; // :\n";
|
|
2115
|
+
blk += i3 + " if (load<u16>(kp + 2) != 0x20) break; // space\n";
|
|
2116
|
+
blk += i3 + " srcStart = kp + 4;\n";
|
|
2117
|
+
blk += i3 + "} else {\n";
|
|
2118
|
+
blk += i3 + " if (!__traceHit) {\n";
|
|
2119
|
+
blk +=
|
|
2120
|
+
i3 +
|
|
2121
|
+
" const __traceCurrentSeparator = kp - __traceSeparatorStart;\n";
|
|
2122
|
+
blk += i3 + " if (__traceSeparatorSeen) {\n";
|
|
2123
|
+
blk +=
|
|
2124
|
+
i3 +
|
|
2125
|
+
" if (__traceCurrentSeparator != __traceCandidateSeparator) __traceCanonicalPretty = false;\n";
|
|
2126
|
+
blk += i3 + " } else {\n";
|
|
2127
|
+
blk +=
|
|
2128
|
+
i3 + " __traceCandidateSeparator = __traceCurrentSeparator;\n";
|
|
2129
|
+
blk += i3 + " __traceSeparatorSeen = true;\n";
|
|
2130
|
+
blk += i3 + " }\n";
|
|
2131
|
+
blk += i3 + " }\n";
|
|
2132
|
+
blk += i3 + ` kp += ${keyBytes};\n`;
|
|
2133
|
+
blk += i3 + " const __traceKeyEnd = kp;\n";
|
|
2134
|
+
blk += i3 + " kp = JSON.Util.skipWhitespace(kp, srcEnd);\n";
|
|
2135
|
+
blk +=
|
|
2136
|
+
i3 +
|
|
2137
|
+
" if (!__traceHit && kp != __traceKeyEnd) __traceCanonicalPretty = false;\n";
|
|
2138
|
+
blk += i3 + " if (load<u16>(kp) != 0x3a) break; // :\n";
|
|
2139
|
+
blk +=
|
|
2140
|
+
i3 + " srcStart = JSON.Util.skipWhitespace(kp + 2, srcEnd);\n";
|
|
1758
2141
|
blk +=
|
|
1759
|
-
|
|
1760
|
-
"if (
|
|
2142
|
+
i3 +
|
|
2143
|
+
" if (!__traceHit && (load<u16>(kp + 2) != 0x20 || srcStart != kp + 4)) __traceCanonicalPretty = false;\n";
|
|
2144
|
+
blk += i3 + "}\n";
|
|
2145
|
+
}
|
|
2146
|
+
else {
|
|
2147
|
+
blk += i3 + `kp += ${keyBytes};\n`;
|
|
2148
|
+
blk += i3 + "kp = JSON.Util.skipWhitespace(kp, srcEnd);\n";
|
|
2149
|
+
blk += i3 + "if (load<u16>(kp) != 0x3a) break; // :\n";
|
|
2150
|
+
blk += i3 + "srcStart = JSON.Util.skipWhitespace(kp + 2, srcEnd);\n";
|
|
1761
2151
|
}
|
|
1762
|
-
blk +=
|
|
1763
|
-
i2 +
|
|
1764
|
-
`if ( // ${key}\n${i2} ` +
|
|
1765
|
-
getComparisions(key, "kp", "==").join("\n" + i2 + " && ") +
|
|
1766
|
-
`\n${i2}) {\n`;
|
|
1767
|
-
blk += i3 + `kp += ${keyBytes};\n`;
|
|
1768
|
-
blk += i3 + "kp = JSON.Util.skipWhitespace(kp, srcEnd);\n";
|
|
1769
|
-
blk += i3 + "if (load<u16>(kp) != 0x3a) break; // :\n";
|
|
1770
|
-
blk += i3 + "srcStart = JSON.Util.skipWhitespace(kp + 2, srcEnd);\n";
|
|
1771
2152
|
blk += i3 + tier2Desers[i].join("\n" + i3) + "\n";
|
|
2153
|
+
if (traceOptionalObject)
|
|
2154
|
+
blk += i3 + `__tracePresent |= ${traceBit};\n`;
|
|
1772
2155
|
if (multi)
|
|
1773
2156
|
blk += i3 + "seenAny = true;\n";
|
|
1774
2157
|
blk += i2 + "}\n";
|
|
@@ -1780,6 +2163,137 @@ export class JSONTransform extends Visitor {
|
|
|
1780
2163
|
i2 + "srcStart = JSON.Util.skipWhitespace(srcStart, srcEnd);\n";
|
|
1781
2164
|
DESERIALIZE_FAST += i2 + "if (load<u16>(srcStart) != 0x7d) break; // }\n";
|
|
1782
2165
|
DESERIALIZE_FAST += i2 + "srcStart += 2;\n";
|
|
2166
|
+
if (traceOptionalObject)
|
|
2167
|
+
DESERIALIZE_FAST +=
|
|
2168
|
+
i2 +
|
|
2169
|
+
"if (__traceActive) JSON.Util.saveObjectTrace(__traceSlot, __tracePresent, __traceHit ? __traceTier : (__traceCanonicalPretty && __traceSeparatorSeen ? 3 : 2), __traceHit ? __traceSeparator : __traceCandidateSeparator);\n";
|
|
2170
|
+
DESERIALIZE_FAST += i2 + "return srcStart;\n";
|
|
2171
|
+
DESERIALIZE_FAST += i1 + "} while (false);\n\n";
|
|
2172
|
+
}
|
|
2173
|
+
const keyedUnionAlternatives = this.schema.members.filter((member) => member.node.type.isNullable &&
|
|
2174
|
+
this.getSchema(stripNull(member.type)) != null).length;
|
|
2175
|
+
const scalarKeyedSchema = this.schema.members.every((member) => {
|
|
2176
|
+
const type = stripNull(member.type);
|
|
2177
|
+
return (INTEGER_TYPES.includes(type) ||
|
|
2178
|
+
FLOAT_TYPES.includes(type) ||
|
|
2179
|
+
["string", "String"].includes(type) ||
|
|
2180
|
+
isBoolean(type));
|
|
2181
|
+
});
|
|
2182
|
+
const structKeyedSchema = this.schema.members.every((member) => {
|
|
2183
|
+
const type = stripNull(member.type);
|
|
2184
|
+
return (INTEGER_TYPES.includes(type) ||
|
|
2185
|
+
FLOAT_TYPES.includes(type) ||
|
|
2186
|
+
["string", "String"].includes(type) ||
|
|
2187
|
+
isBoolean(type) ||
|
|
2188
|
+
this.getSchema(type) != null);
|
|
2189
|
+
});
|
|
2190
|
+
const keyedFallbackEnabled = tier2Ok &&
|
|
2191
|
+
this.schema.members.length > 0 &&
|
|
2192
|
+
this.schema.members.length <= 24 &&
|
|
2193
|
+
(keyedUnionAlternatives >= 2 ||
|
|
2194
|
+
(scalarKeyedSchema && this.schema.members.length >= 12) ||
|
|
2195
|
+
(structKeyedSchema && hasExplicitOptionalMembers));
|
|
2196
|
+
if (keyedFallbackEnabled) {
|
|
2197
|
+
const i1 = " ";
|
|
2198
|
+
const i2 = " ";
|
|
2199
|
+
const i3 = " ";
|
|
2200
|
+
const keyedResets = this.schema.members.map((member) => {
|
|
2201
|
+
const offset = `offsetof<this>(${JSON.stringify(member.name)})`;
|
|
2202
|
+
if (member.value)
|
|
2203
|
+
return `store<${member.type}>(dst, ${member.value}, ${offset});`;
|
|
2204
|
+
if (member.node.type.isNullable)
|
|
2205
|
+
return `store<${member.type}>(dst, null, ${offset});`;
|
|
2206
|
+
if (this.getSchema(member.type))
|
|
2207
|
+
return (`store<${member.type}>(dst, ` +
|
|
2208
|
+
`changetype<nonnull<${member.type}>>(__new(offsetof<nonnull<${member.type}>>(), idof<nonnull<${member.type}>>())).__INITIALIZE(), ${offset});`);
|
|
2209
|
+
if (["string", "String"].includes(member.type))
|
|
2210
|
+
return `store<${member.type}>(dst, "", ${offset});`;
|
|
2211
|
+
if (member.type.endsWith("[]")) {
|
|
2212
|
+
const element = member.type.slice(0, -2).trim();
|
|
2213
|
+
return `store<${member.type}>(dst, new Array<${element}>(), ${offset});`;
|
|
2214
|
+
}
|
|
2215
|
+
if (member.type.startsWith("Array<") ||
|
|
2216
|
+
member.type.startsWith("Map<") ||
|
|
2217
|
+
member.type.startsWith("Set<"))
|
|
2218
|
+
return `store<${member.type}>(dst, new ${member.type}(), ${offset});`;
|
|
2219
|
+
if (member.type.startsWith("StaticArray<")) {
|
|
2220
|
+
const element = member.type.slice("StaticArray<".length, -1).trim();
|
|
2221
|
+
return `store<${member.type}>(dst, new StaticArray<${element}>(0), ${offset});`;
|
|
2222
|
+
}
|
|
2223
|
+
return `store<${member.type}>(dst, 0, ${offset});`;
|
|
2224
|
+
});
|
|
2225
|
+
DESERIALIZE_FAST += i1 + "srcStart = start;\n";
|
|
2226
|
+
DESERIALIZE_FAST += i1 + "do {\n";
|
|
2227
|
+
DESERIALIZE_FAST +=
|
|
2228
|
+
i2 + "srcStart = JSON.Util.skipWhitespace(srcStart, srcEnd);\n";
|
|
2229
|
+
DESERIALIZE_FAST += i2 + "if (load<u16>(srcStart) != 0x7b) break; // {\n";
|
|
2230
|
+
DESERIALIZE_FAST += i2 + "srcStart += 2;\n";
|
|
2231
|
+
DESERIALIZE_FAST += i2 + "let seen: u32 = 0;\n";
|
|
2232
|
+
DESERIALIZE_FAST += i2 + "let complete = false;\n";
|
|
2233
|
+
DESERIALIZE_FAST += i2 + "while (true) {\n";
|
|
2234
|
+
DESERIALIZE_FAST +=
|
|
2235
|
+
i3 + "srcStart = JSON.Util.skipWhitespace(srcStart, srcEnd);\n";
|
|
2236
|
+
DESERIALIZE_FAST += i3 + "let code = load<u16>(srcStart);\n";
|
|
2237
|
+
DESERIALIZE_FAST += i3 + "if (code == 0x7d) {\n";
|
|
2238
|
+
DESERIALIZE_FAST += i3 + " srcStart += 2;\n";
|
|
2239
|
+
DESERIALIZE_FAST += i3 + " complete = true;\n";
|
|
2240
|
+
DESERIALIZE_FAST += i3 + " break;\n";
|
|
2241
|
+
DESERIALIZE_FAST += i3 + "}\n";
|
|
2242
|
+
DESERIALIZE_FAST += i3 + "if (code != 0x22) break; // opening quote\n";
|
|
2243
|
+
DESERIALIZE_FAST += i3 + "const keyStart = srcStart;\n";
|
|
2244
|
+
DESERIALIZE_FAST +=
|
|
2245
|
+
i3 +
|
|
2246
|
+
"const keyEnd = JSON.Util.scanValueEnd<string>(keyStart, srcEnd);\n";
|
|
2247
|
+
DESERIALIZE_FAST += i3 + "if (!keyEnd) break;\n";
|
|
2248
|
+
DESERIALIZE_FAST +=
|
|
2249
|
+
i3 + "srcStart = JSON.Util.skipWhitespace(keyEnd, srcEnd);\n";
|
|
2250
|
+
DESERIALIZE_FAST += i3 + "if (load<u16>(srcStart) != 0x3a) break; // :\n";
|
|
2251
|
+
DESERIALIZE_FAST +=
|
|
2252
|
+
i3 + "srcStart = JSON.Util.skipWhitespace(srcStart + 2, srcEnd);\n";
|
|
2253
|
+
DESERIALIZE_FAST += i3 + "const keyBytes = keyEnd - keyStart;\n";
|
|
2254
|
+
DESERIALIZE_FAST += i3 + "let matched = false;\n";
|
|
2255
|
+
for (let i = 0; i < this.schema.members.length; i++) {
|
|
2256
|
+
const member = this.schema.members[i];
|
|
2257
|
+
const key = JSON.stringify(member.alias || member.name);
|
|
2258
|
+
const condition = [
|
|
2259
|
+
`keyBytes == ${key.length << 1}`,
|
|
2260
|
+
...getComparisions(key, "keyStart", "=="),
|
|
2261
|
+
].join(" &&\n" + i3 + " ");
|
|
2262
|
+
DESERIALIZE_FAST += i3 + `if (!matched && (${condition})) {\n`;
|
|
2263
|
+
DESERIALIZE_FAST += i3 + " matched = true;\n";
|
|
2264
|
+
DESERIALIZE_FAST +=
|
|
2265
|
+
i3 + " " + tier2Desers[i].join("\n" + i3 + " ") + "\n";
|
|
2266
|
+
DESERIALIZE_FAST += i3 + ` seen |= <u32>1 << ${i};\n`;
|
|
2267
|
+
DESERIALIZE_FAST += i3 + "}\n";
|
|
2268
|
+
}
|
|
2269
|
+
DESERIALIZE_FAST += i3 + "if (!matched) {\n";
|
|
2270
|
+
if (STRICT) {
|
|
2271
|
+
DESERIALIZE_FAST += i3 + " break;\n";
|
|
2272
|
+
}
|
|
2273
|
+
else {
|
|
2274
|
+
DESERIALIZE_FAST +=
|
|
2275
|
+
i3 +
|
|
2276
|
+
" const valueEnd = JSON.Util.scanValueEnd<usize>(srcStart, srcEnd);\n";
|
|
2277
|
+
DESERIALIZE_FAST += i3 + " if (!valueEnd) break;\n";
|
|
2278
|
+
DESERIALIZE_FAST += i3 + " srcStart = valueEnd;\n";
|
|
2279
|
+
}
|
|
2280
|
+
DESERIALIZE_FAST += i3 + "}\n";
|
|
2281
|
+
DESERIALIZE_FAST +=
|
|
2282
|
+
i3 + "srcStart = JSON.Util.skipWhitespace(srcStart, srcEnd);\n";
|
|
2283
|
+
DESERIALIZE_FAST += i3 + "code = load<u16>(srcStart);\n";
|
|
2284
|
+
DESERIALIZE_FAST += i3 + "if (code == 0x7d) {\n";
|
|
2285
|
+
DESERIALIZE_FAST += i3 + " srcStart += 2;\n";
|
|
2286
|
+
DESERIALIZE_FAST += i3 + " complete = true;\n";
|
|
2287
|
+
DESERIALIZE_FAST += i3 + " break;\n";
|
|
2288
|
+
DESERIALIZE_FAST += i3 + "}\n";
|
|
2289
|
+
DESERIALIZE_FAST += i3 + "if (code != 0x2c) break; // comma\n";
|
|
2290
|
+
DESERIALIZE_FAST += i3 + "srcStart += 2;\n";
|
|
2291
|
+
DESERIALIZE_FAST += i2 + "}\n";
|
|
2292
|
+
DESERIALIZE_FAST += i2 + "if (!complete) break;\n";
|
|
2293
|
+
for (let i = 0; i < keyedResets.length; i++) {
|
|
2294
|
+
DESERIALIZE_FAST +=
|
|
2295
|
+
i2 + `if ((seen & (<u32>1 << ${i})) == 0) ${keyedResets[i]}\n`;
|
|
2296
|
+
}
|
|
1783
2297
|
DESERIALIZE_FAST += i2 + "return srcStart;\n";
|
|
1784
2298
|
DESERIALIZE_FAST += i1 + "} while (false);\n\n";
|
|
1785
2299
|
}
|
|
@@ -1812,19 +2326,48 @@ export class JSONTransform extends Visitor {
|
|
|
1812
2326
|
" while (srcEnd > srcStart && JSON.Util.isSpace(load<u16>(srcEnd - 2))) srcEnd -= 2;\n";
|
|
1813
2327
|
DESERIALIZE +=
|
|
1814
2328
|
indent +
|
|
1815
|
-
|
|
2329
|
+
" if (srcStart == srcEnd) return JSON.Util.failProductionParse();\n";
|
|
1816
2330
|
DESERIALIZE +=
|
|
1817
2331
|
indent +
|
|
1818
|
-
" if (load<u16>(srcStart) != 123)
|
|
2332
|
+
" if (load<u16>(srcStart) != 123) return JSON.Util.failProductionParse();\n";
|
|
1819
2333
|
DESERIALIZE +=
|
|
1820
2334
|
indent +
|
|
1821
|
-
" if (load<u16>(srcEnd - 2) != 125)
|
|
2335
|
+
" if (load<u16>(srcEnd - 2) != 125) return JSON.Util.failProductionParse();\n";
|
|
2336
|
+
DESERIALIZE += indent + " const objectStart = srcStart;\n";
|
|
1822
2337
|
DESERIALIZE += indent + " srcStart += 2;\n\n";
|
|
1823
2338
|
DESERIALIZE += indent + " while (srcStart < srcEnd) {\n";
|
|
1824
2339
|
DESERIALIZE += indent + " let code = load<u16>(srcStart);\n";
|
|
2340
|
+
DESERIALIZE += indent + " while (JSON.Util.isSpace(code)) {\n";
|
|
2341
|
+
DESERIALIZE += indent + " srcStart += 2;\n";
|
|
1825
2342
|
DESERIALIZE +=
|
|
1826
2343
|
indent +
|
|
1827
|
-
"
|
|
2344
|
+
" if (srcStart >= srcEnd) return JSON.Util.failProductionParse();\n";
|
|
2345
|
+
DESERIALIZE += indent + " code = load<u16>(srcStart);\n";
|
|
2346
|
+
DESERIALIZE += indent + " }\n";
|
|
2347
|
+
DESERIALIZE += indent + " if (keyStart == 0 && !isKey) {\n";
|
|
2348
|
+
DESERIALIZE += indent + " let prev = srcStart - 2;\n";
|
|
2349
|
+
DESERIALIZE +=
|
|
2350
|
+
indent +
|
|
2351
|
+
" while (prev > objectStart && JSON.Util.isSpace(load<u16>(prev))) prev -= 2;\n";
|
|
2352
|
+
DESERIALIZE += indent + " const prevCode = load<u16>(prev);\n";
|
|
2353
|
+
DESERIALIZE += indent + " if (code == 125) {\n";
|
|
2354
|
+
DESERIALIZE +=
|
|
2355
|
+
indent +
|
|
2356
|
+
" if (prevCode == 44) return JSON.Util.failProductionParse();\n";
|
|
2357
|
+
DESERIALIZE += indent + " return srcStart + 2;\n";
|
|
2358
|
+
DESERIALIZE += indent + " }\n";
|
|
2359
|
+
DESERIALIZE += indent + " if (code == 44) {\n";
|
|
2360
|
+
DESERIALIZE +=
|
|
2361
|
+
indent +
|
|
2362
|
+
" if (prevCode == 123 || prevCode == 44) return JSON.Util.failProductionParse();\n";
|
|
2363
|
+
DESERIALIZE += indent + " } else if (code == 34) {\n";
|
|
2364
|
+
DESERIALIZE +=
|
|
2365
|
+
indent +
|
|
2366
|
+
" if (prevCode != 123 && prevCode != 44) return JSON.Util.failProductionParse();\n";
|
|
2367
|
+
DESERIALIZE += indent + " } else {\n";
|
|
2368
|
+
DESERIALIZE += indent + " return JSON.Util.failProductionParse();\n";
|
|
2369
|
+
DESERIALIZE += indent + " }\n";
|
|
2370
|
+
DESERIALIZE += indent + " }\n";
|
|
1828
2371
|
DESERIALIZE += indent + " if (keyStart == 0) {\n";
|
|
1829
2372
|
DESERIALIZE +=
|
|
1830
2373
|
indent + " if (code == 34 && load<u16>(srcStart - 2) !== 92) {\n";
|
|
@@ -1837,20 +2380,16 @@ export class JSONTransform extends Visitor {
|
|
|
1837
2380
|
' console.log("Key: " + JSON.Util.ptrToStr(keyStart, keyEnd));\n';
|
|
1838
2381
|
DESERIALIZE +=
|
|
1839
2382
|
indent +
|
|
1840
|
-
"
|
|
2383
|
+
" do { srcStart += 2; if (srcStart >= srcEnd) return JSON.Util.failProductionParse(); code = load<u16>(srcStart); } while (JSON.Util.isSpace(code));\n";
|
|
1841
2384
|
DESERIALIZE +=
|
|
1842
2385
|
indent +
|
|
1843
|
-
" if (code !== 58)
|
|
2386
|
+
" if (code !== 58) return JSON.Util.failProductionParse();\n";
|
|
1844
2387
|
DESERIALIZE += indent + " isKey = false;\n";
|
|
1845
2388
|
DESERIALIZE += indent + " } else {\n";
|
|
1846
2389
|
DESERIALIZE += indent + " isKey = true;\n";
|
|
1847
2390
|
DESERIALIZE += indent + " lastIndex = srcStart + 2;\n";
|
|
1848
2391
|
DESERIALIZE += indent + " }\n";
|
|
1849
2392
|
DESERIALIZE += indent + " }\n";
|
|
1850
|
-
if (STRICT)
|
|
1851
|
-
DESERIALIZE +=
|
|
1852
|
-
indent +
|
|
1853
|
-
' else if (!isKey && code != 44 && code != 125) throw new Error("Expected \'\\"\' to start key in JSON object at position " + (srcEnd - srcStart).toString());\n';
|
|
1854
2393
|
DESERIALIZE += indent + " srcStart += 2;\n";
|
|
1855
2394
|
DESERIALIZE += indent + " } else {\n";
|
|
1856
2395
|
const groupMembers = (members) => {
|
|
@@ -1953,8 +2492,18 @@ export class JSONTransform extends Visitor {
|
|
|
1953
2492
|
const getSlowValueStore = (member, valueStart, valueEnd, prefix) => {
|
|
1954
2493
|
if (member.flags.has(PropertyFlags.Lazy))
|
|
1955
2494
|
return getLazyRangeStore(member, valueStart, valueEnd, prefix);
|
|
2495
|
+
const offset = JSON.stringify(member.name);
|
|
2496
|
+
const memberSchema = this.getSchema(member.type);
|
|
2497
|
+
if (memberSchema?.custom) {
|
|
2498
|
+
return (prefix +
|
|
2499
|
+
`store<${member.type}>(changetype<usize>(out), ${getCustomDeserializeExpression(member.type, valueStart, valueEnd)}, offsetof<this>(${offset}));\n`);
|
|
2500
|
+
}
|
|
2501
|
+
if (needsReferenceLoad(member.type)) {
|
|
2502
|
+
return (prefix +
|
|
2503
|
+
`store<${member.type}>(changetype<usize>(out), JSON.__deserialize<${member.type}>(${valueStart}, ${valueEnd}, changetype<usize>(load<${member.type}>(changetype<usize>(out), offsetof<this>(${offset})))), offsetof<this>(${offset}));\n`);
|
|
2504
|
+
}
|
|
1956
2505
|
return (prefix +
|
|
1957
|
-
`store<${member.type}>(changetype<usize>(out), JSON.__deserialize<${member.type}>(${valueStart}, ${valueEnd}), offsetof<this>(${
|
|
2506
|
+
`store<${member.type}>(changetype<usize>(out), JSON.__deserialize<${member.type}>(${valueStart}, ${valueEnd}), offsetof<this>(${offset}));\n`);
|
|
1958
2507
|
};
|
|
1959
2508
|
const getSlowBooleanStore = (member, value, valueStart, valueEnd, prefix) => {
|
|
1960
2509
|
if (member.flags.has(PropertyFlags.Lazy))
|
|
@@ -1980,10 +2529,10 @@ export class JSONTransform extends Visitor {
|
|
|
1980
2529
|
DESERIALIZE += mbElse + "if (code == 34) {\n";
|
|
1981
2530
|
DESERIALIZE += " lastIndex = srcStart;\n";
|
|
1982
2531
|
DESERIALIZE += " srcStart += 2;\n";
|
|
2532
|
+
DESERIALIZE += " let escaped = false;\n";
|
|
1983
2533
|
DESERIALIZE += " while (srcStart < srcEnd) {\n";
|
|
1984
2534
|
DESERIALIZE += " const code = load<u16>(srcStart);\n";
|
|
1985
|
-
DESERIALIZE +=
|
|
1986
|
-
" if (code == 34 && load<u16>(srcStart - 2) !== 92) {\n";
|
|
2535
|
+
DESERIALIZE += " if (code == 34 && !escaped) {\n";
|
|
1987
2536
|
if (DEBUG > 1)
|
|
1988
2537
|
DESERIALIZE +=
|
|
1989
2538
|
' console.log("Value (string, ' +
|
|
@@ -2039,6 +2588,7 @@ export class JSONTransform extends Visitor {
|
|
|
2039
2588
|
}
|
|
2040
2589
|
}, "string");
|
|
2041
2590
|
DESERIALIZE += " }\n";
|
|
2591
|
+
DESERIALIZE += " escaped = code == 92 ? !escaped : false;\n";
|
|
2042
2592
|
DESERIALIZE += " srcStart += 2;\n";
|
|
2043
2593
|
DESERIALIZE += " }\n";
|
|
2044
2594
|
DESERIALIZE += " }\n";
|
|
@@ -2468,6 +3018,11 @@ export class JSONTransform extends Visitor {
|
|
|
2468
3018
|
indentDec();
|
|
2469
3019
|
DESERIALIZE += ` }\n`;
|
|
2470
3020
|
indentDec();
|
|
3021
|
+
DESERIALIZE +=
|
|
3022
|
+
` if (srcStart == srcEnd && lastIndex != 0) {\n` +
|
|
3023
|
+
` const lastCode = load<u16>(lastIndex);\n` +
|
|
3024
|
+
` if (lastCode == 123 || lastCode == 91) return 0;\n` +
|
|
3025
|
+
` }\n`;
|
|
2471
3026
|
DESERIALIZE += ` return srcStart;\n}\n`;
|
|
2472
3027
|
indent = " ";
|
|
2473
3028
|
this.schema.byteSize += 2;
|
|
@@ -2488,11 +3043,6 @@ export class JSONTransform extends Visitor {
|
|
|
2488
3043
|
console.log(INITIALIZE);
|
|
2489
3044
|
console.log(DESERIALIZE_CUSTOM || DESERIALIZE);
|
|
2490
3045
|
}
|
|
2491
|
-
const WIDE_STRUCT_FIELD_LIMIT = 32;
|
|
2492
|
-
if (this.schema.members.length > WIDE_STRUCT_FIELD_LIMIT) {
|
|
2493
|
-
INITIALIZE = INITIALIZE.replace(/^@inline /, "");
|
|
2494
|
-
DESERIALIZE_FAST = DESERIALIZE_FAST.replace(/^@inline /, "");
|
|
2495
|
-
}
|
|
2496
3046
|
const SERIALIZE_METHOD = SimpleParser.parseClassMember(SERIALIZE_CUSTOM || SERIALIZE, node);
|
|
2497
3047
|
const INITIALIZE_METHOD = SimpleParser.parseClassMember(INITIALIZE, node);
|
|
2498
3048
|
const DESERIALIZE_CUSTOM_METHOD = DESERIALIZE_CUSTOM
|
|
@@ -2502,6 +3052,86 @@ export class JSONTransform extends Visitor {
|
|
|
2502
3052
|
const DESERIALIZE_FAST_METHOD = useFastPath
|
|
2503
3053
|
? SimpleParser.parseClassMember(DESERIALIZE_FAST, node)
|
|
2504
3054
|
: null;
|
|
3055
|
+
const mapHeavySource = source
|
|
3056
|
+
.getClasses()
|
|
3057
|
+
.some((candidate) => candidate.members.some((member) => member.kind == NodeKind.FieldDeclaration &&
|
|
3058
|
+
toString(member.type).includes("Map<")));
|
|
3059
|
+
let DESERIALIZE_FAST_PRETTY_METHOD = null;
|
|
3060
|
+
let PRETTY_SPECIALIZED_METHOD = null;
|
|
3061
|
+
if (this.program.options.hasFeature(16) &&
|
|
3062
|
+
useFastPath &&
|
|
3063
|
+
mapHeavySource) {
|
|
3064
|
+
let prettyTail = DESERIALIZE_FAST.slice(fastPrettyTailStart);
|
|
3065
|
+
prettyTail = prettyTail.replaceAll(" if (load<u16>(srcStart) != 0x3a) break; // :\n" +
|
|
3066
|
+
" srcStart += 2;\n" +
|
|
3067
|
+
" srcStart = JSON.Util.skipWhitespace(srcStart, srcEnd);\n", " if (load<u16>(srcStart) != 0x3a) break; // :\n" +
|
|
3068
|
+
" srcStart += 2;\n" +
|
|
3069
|
+
" if (load<u16>(srcStart) == 0x20) srcStart += 2;\n" +
|
|
3070
|
+
" else srcStart = JSON.Util.skipWhitespace(srcStart, srcEnd);\n");
|
|
3071
|
+
const prettyFast = ("__DESERIALIZE_FAST_PRETTY<__JSON_T>(srcStart: usize, srcEnd: usize, out: __JSON_T): usize {\n" +
|
|
3072
|
+
" const start = srcStart;\n" +
|
|
3073
|
+
" const dst = changetype<usize>(out);\n" +
|
|
3074
|
+
objectTraceHeader +
|
|
3075
|
+
prettyTail)
|
|
3076
|
+
.replaceAll("JSON.Util.skipWhitespace(", "JSON.Util.skipPrettyWhitespace(")
|
|
3077
|
+
.replaceAll(".__DESERIALIZE_FAST<", ".__DESERIALIZE_FAST_PRETTY<")
|
|
3078
|
+
.replaceAll(".__DESERIALIZE_FAST(", ".__DESERIALIZE_FAST_PRETTY(");
|
|
3079
|
+
DESERIALIZE_FAST_PRETTY_METHOD = SimpleParser.parseClassMember(prettyFast, node);
|
|
3080
|
+
PRETTY_SPECIALIZED_METHOD = SimpleParser.parseClassMember("__DESERIALIZE_PRETTY_SPECIALIZED(): void {}", node);
|
|
3081
|
+
}
|
|
3082
|
+
else if (this.program.options.hasFeature(16) && useFastPath) {
|
|
3083
|
+
const prettyTail = DESERIALIZE_FAST.slice(fastPrettyTailStart);
|
|
3084
|
+
DESERIALIZE_FAST_PRETTY_METHOD = SimpleParser.parseClassMember("__DESERIALIZE_FAST_PRETTY<__JSON_T>(srcStart: usize, srcEnd: usize, out: __JSON_T): usize {\n" +
|
|
3085
|
+
" const start = srcStart;\n" +
|
|
3086
|
+
" const dst = changetype<usize>(out);\n" +
|
|
3087
|
+
objectTraceHeader +
|
|
3088
|
+
prettyTail +
|
|
3089
|
+
"}", node);
|
|
3090
|
+
}
|
|
3091
|
+
else if (useFastPath) {
|
|
3092
|
+
DESERIALIZE_FAST_PRETTY_METHOD = SimpleParser.parseClassMember("__DESERIALIZE_FAST_PRETTY<__JSON_T>(srcStart: usize, srcEnd: usize, out: __JSON_T): usize {\n" +
|
|
3093
|
+
" return this.__DESERIALIZE_FAST(srcStart, srcEnd, out);\n" +
|
|
3094
|
+
"}", node);
|
|
3095
|
+
}
|
|
3096
|
+
const sourceFreeDeserialize = !DESERIALIZE_CUSTOM &&
|
|
3097
|
+
this.schema.members.every((member) => {
|
|
3098
|
+
const type = stripNull(member.type);
|
|
3099
|
+
return (!member.flags.has(PropertyFlags.Lazy) &&
|
|
3100
|
+
(isPrimitive(type) ||
|
|
3101
|
+
isString(type) ||
|
|
3102
|
+
type == "Date" ||
|
|
3103
|
+
type == "JSON.Raw" ||
|
|
3104
|
+
type == "Raw"));
|
|
3105
|
+
});
|
|
3106
|
+
const SOURCE_FREE_METHOD = sourceFreeDeserialize
|
|
3107
|
+
? SimpleParser.parseClassMember("__DESERIALIZE_SOURCE_FREE(): void {}", node)
|
|
3108
|
+
: null;
|
|
3109
|
+
const FULL_WRITE_METHOD = useFastPath && !supportsFastOptionalPath
|
|
3110
|
+
? SimpleParser.parseClassMember("__DESERIALIZE_FULL_WRITE(): void {}", node)
|
|
3111
|
+
: null;
|
|
3112
|
+
const defaultObjectJSON = USE_DEFAULT_OBJECT_SPECIALIZATION &&
|
|
3113
|
+
this.program.options.hasFeature(16) &&
|
|
3114
|
+
useFastPath &&
|
|
3115
|
+
!supportsFastOptionalPath &&
|
|
3116
|
+
!DESERIALIZE_CUSTOM &&
|
|
3117
|
+
!node.extendsType &&
|
|
3118
|
+
!node.is(2) &&
|
|
3119
|
+
!source.getClasses().some((candidate) => {
|
|
3120
|
+
if (!candidate.extendsType)
|
|
3121
|
+
return false;
|
|
3122
|
+
const base = source.resolveExtendsName(candidate);
|
|
3123
|
+
return base == this.schema.name || base == node.name.text;
|
|
3124
|
+
})
|
|
3125
|
+
? this.getDefaultObjectJSON(this.schema)
|
|
3126
|
+
: null;
|
|
3127
|
+
const DEFAULT_OBJECT_METHOD = defaultObjectJSON
|
|
3128
|
+
? SimpleParser.parseClassMember(this.getDefaultMatcherSource(defaultObjectJSON), node)
|
|
3129
|
+
: null;
|
|
3130
|
+
const DEFAULT_OBJECT_FACTORY_METHOD = defaultObjectJSON
|
|
3131
|
+
? SimpleParser.parseClassMember("@inline __DESERIALIZE_DEFAULT_NEW(): this {\n" +
|
|
3132
|
+
" return changetype<this>(__new(offsetof<this>(), idof<this>())).__INITIALIZE();\n" +
|
|
3133
|
+
"}", node)
|
|
3134
|
+
: null;
|
|
2505
3135
|
if (!node.members.find((v) => v.name.text == "__SERIALIZE"))
|
|
2506
3136
|
node.members.push(SERIALIZE_METHOD);
|
|
2507
3137
|
if (INITIALIZE_METHOD &&
|
|
@@ -2519,6 +3149,26 @@ export class JSONTransform extends Visitor {
|
|
|
2519
3149
|
DESERIALIZE_FAST_METHOD &&
|
|
2520
3150
|
!node.members.find((v) => v.name.text == "__DESERIALIZE_FAST"))
|
|
2521
3151
|
node.members.push(DESERIALIZE_FAST_METHOD);
|
|
3152
|
+
if (!DESERIALIZE_CUSTOM &&
|
|
3153
|
+
DESERIALIZE_FAST_PRETTY_METHOD &&
|
|
3154
|
+
!node.members.find((v) => v.name.text == "__DESERIALIZE_FAST_PRETTY"))
|
|
3155
|
+
node.members.push(DESERIALIZE_FAST_PRETTY_METHOD);
|
|
3156
|
+
if (!DESERIALIZE_CUSTOM &&
|
|
3157
|
+
PRETTY_SPECIALIZED_METHOD &&
|
|
3158
|
+
!node.members.find((v) => v.name.text == "__DESERIALIZE_PRETTY_SPECIALIZED"))
|
|
3159
|
+
node.members.push(PRETTY_SPECIALIZED_METHOD);
|
|
3160
|
+
if (SOURCE_FREE_METHOD &&
|
|
3161
|
+
!node.members.find((v) => v.name.text == "__DESERIALIZE_SOURCE_FREE"))
|
|
3162
|
+
node.members.push(SOURCE_FREE_METHOD);
|
|
3163
|
+
if (FULL_WRITE_METHOD &&
|
|
3164
|
+
!node.members.find((v) => v.name.text == "__DESERIALIZE_FULL_WRITE"))
|
|
3165
|
+
node.members.push(FULL_WRITE_METHOD);
|
|
3166
|
+
if (DEFAULT_OBJECT_METHOD &&
|
|
3167
|
+
!node.members.find((v) => v.name.text == "__DESERIALIZE_DEFAULT"))
|
|
3168
|
+
node.members.push(DEFAULT_OBJECT_METHOD);
|
|
3169
|
+
if (DEFAULT_OBJECT_FACTORY_METHOD &&
|
|
3170
|
+
!node.members.find((v) => v.name.text == "__DESERIALIZE_DEFAULT_NEW"))
|
|
3171
|
+
node.members.push(DEFAULT_OBJECT_FACTORY_METHOD);
|
|
2522
3172
|
if (useFastPath && !DESERIALIZE_CUSTOM) {
|
|
2523
3173
|
for (const chunk of fastChunkMethods) {
|
|
2524
3174
|
const chunkMethod = SimpleParser.parseClassMember(chunk, node);
|
|
@@ -2530,9 +3180,16 @@ export class JSONTransform extends Visitor {
|
|
|
2530
3180
|
}
|
|
2531
3181
|
getSchema(name) {
|
|
2532
3182
|
name = stripNull(name);
|
|
2533
|
-
|
|
3183
|
+
const local = this.schemas
|
|
2534
3184
|
.get(this.schema.node.range.source.internalPath)
|
|
2535
|
-
.find((s) => s.name == name) || null
|
|
3185
|
+
.find((s) => s.name == name) || null;
|
|
3186
|
+
if (local)
|
|
3187
|
+
return local;
|
|
3188
|
+
const exact = this.schema.deps.filter((schema) => schema && schema.name == name);
|
|
3189
|
+
if (exact.length == 1)
|
|
3190
|
+
return exact[0];
|
|
3191
|
+
const qualified = this.schema.deps.filter((schema) => schema && schema.name.endsWith("." + name));
|
|
3192
|
+
return qualified.length == 1 ? qualified[0] : null;
|
|
2536
3193
|
}
|
|
2537
3194
|
generateEmptyMethods(node) {
|
|
2538
3195
|
const SERIALIZE_EMPTY = "__SERIALIZE(ptr: usize): void {\n bs.proposeSize(4);\n store<u32>(bs.offset, 8192123);\n bs.offset += 4;\n}";
|
|
@@ -2632,6 +3289,7 @@ export class JSONTransform extends Visitor {
|
|
|
2632
3289
|
fieldHelper("deserializeUnsignedField", "__deserializeUnsignedField"),
|
|
2633
3290
|
fieldHelper("deserializeFloatField", "__deserializeFloatField"),
|
|
2634
3291
|
fieldHelper("deserializeStringField", "__deserializeStringField"),
|
|
3292
|
+
fieldHelper("deserializeStringFieldTrusted", "__deserializeStringFieldTrusted"),
|
|
2635
3293
|
fieldHelper("deserializeArrayField_SWAR", "__deserializeArrayField_SWAR"),
|
|
2636
3294
|
fieldHelper("deserializeMapField", "__deserializeMapField"),
|
|
2637
3295
|
fieldHelper("deserializeSetField", "__deserializeSetField"),
|
|
@@ -2784,6 +3442,7 @@ export default class Transformer extends Transform {
|
|
|
2784
3442
|
MODE_TEXT +
|
|
2785
3443
|
" mode");
|
|
2786
3444
|
program.registerConstantInteger("JSON_MODE", Type.i32, i64_new(MODE));
|
|
3445
|
+
program.registerConstantInteger("JSON_STRICT", Type.bool, STRICT ? i64_one : i64_zero);
|
|
2787
3446
|
if (JSON_CACHE_CONFIG.enabled) {
|
|
2788
3447
|
program.registerConstantInteger("JSON_CACHE", Type.bool, i64_one);
|
|
2789
3448
|
program.registerConstantInteger("JSON_CACHE_SIZE", Type.u32, i64_new(JSON_CACHE_CONFIG.bytes));
|