[dart2wasm] Make json parser use cache of boxed integers <=255

Many json files may have small integer numbers in them. Both dart2js and
VM don't need to actually box those small numbers as they have small
tagged integer support. Though dart2wasm boxes all integers when they
flow into top types.

=> We can use a cache of boxed integer numbers <= 255.

It does seem to overall improve json decoding benchmarks and
will reduce memory usage / pressure on the GC.

Change-Id: I026831e0f0841ae84a66652c0cc0e4689a4ab75e
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/410000
Commit-Queue: Martin Kustermann <kustermann@google.com>
Reviewed-by: Ömer Ağacan <omersa@google.com>
This commit is contained in:
Martin Kustermann
2025-02-18 04:16:29 -08:00
committed by Commit Queue
parent 6273c19a78
commit 5e8bd02433
2 changed files with 60 additions and 6 deletions
+13 -4
View File
@@ -301,6 +301,12 @@ class Translator with KernelNodes {
w.NumType.f64: boxedDoubleClass,
};
late final Set<Class> boxClasses = {
boxedBoolClass,
boxedIntClass,
boxedDoubleClass,
};
/// Classes whose identity hash code is their hash code rather than the
/// identity hash code field in the struct. Each implementation class maps to
/// the class containing the implementation of its `hashCode` getter.
@@ -689,7 +695,7 @@ class Translator with KernelNodes {
bool isWasmType(Class cls) =>
cls == wasmTypesBaseClass || _hasSuperclass(cls, wasmTypesBaseClass);
w.StorageType translateStorageType(DartType type) {
w.StorageType translateStorageType(DartType type, {bool unbox = true}) {
bool nullable = type.isPotentiallyNullable;
if (type is InterfaceType) {
Class cls = type.classNode;
@@ -741,7 +747,8 @@ class Translator with KernelNodes {
}
// Other built-in type?
w.StorageType? builtin = builtinTypes[cls];
w.StorageType? builtin =
(unbox || !boxClasses.contains(cls)) ? builtinTypes[cls] : null;
if (builtin != null) {
if (!nullable) {
return builtin;
@@ -816,8 +823,10 @@ class Translator with KernelNodes {
while (type is TypeParameterType) {
type = type.bound;
}
return wasmArrayType(
translateStorageType(type), type.toText(defaultAstTextStrategy),
// If we write `WasmArray<BoxedInt>` we actually want an array of boxed
// integers and not a `WasmArray<WasmI64>`.
return wasmArrayType(translateStorageType(type, unbox: false),
type.toText(defaultAstTextStrategy),
mutable: mutable);
}
+47 -2
View File
@@ -2,6 +2,7 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
import "dart:_boxed_int";
import "dart:_compact_hash" show createMapFromStringKeyValueListUnsafe;
import "dart:_error_utils";
import "dart:_internal"
@@ -176,6 +177,15 @@ class _JsonListener {
this.value = value;
}
@pragma('wasm:prefer-inline')
void handleIntegerNumber(int value) {
if (value.toWasmI64().leU(0xff.toWasmI64())) {
handleNumber(_intBoxes256[value]);
return;
}
handleNumber(value);
}
void handleNumber(num value) {
this.value = value;
}
@@ -1433,7 +1443,7 @@ mixin _ChunkedJsonParser<T> on _ChunkedJsonParserState {
void finishChunkNumber(int state, int start, int end) {
if (state == NUM_ZERO) {
listener.handleNumber(0);
listener.handleIntegerNumber(0);
numberBuffer.clear();
return;
}
@@ -1578,7 +1588,7 @@ mixin _ChunkedJsonParser<T> on _ChunkedJsonParserState {
if (!isDouble) {
int bitFlag = -(sign + 1) >> 1; // 0 if sign == -1, -1 if sign == 1
// Negate if bitFlag is -1 by doing ~intValue + 1
listener.handleNumber((intValue ^ bitFlag) - bitFlag);
listener.handleIntegerNumber((intValue ^ bitFlag) - bitFlag);
return position;
}
// Double values at or above this value (2 ** 53) may have lost precision.
@@ -2795,3 +2805,38 @@ double _jsParseFloat(String string) => JS<double>(
'(s) => parseFloat(s)',
jsStringFromDartString(string).toExternRef,
);
const ImmutableWasmArray<BoxedInt> _intBoxes256 = ImmutableWasmArray.literal([
0, 1, 2, 3, 4, 5, 6, 7, //
8, 9, 10, 11, 12, 13, 14, 15, //
16, 17, 18, 19, 20, 21, 22, 23, //
24, 25, 26, 27, 28, 29, 30, 31, //
32, 33, 34, 35, 36, 37, 38, 39, //
40, 41, 42, 43, 44, 45, 46, 47, //
48, 49, 50, 51, 52, 53, 54, 55, //
56, 57, 58, 59, 60, 61, 62, 63, //
64, 65, 66, 67, 68, 69, 70, 71, //
72, 73, 74, 75, 76, 77, 78, 79, //
80, 81, 82, 83, 84, 85, 86, 87, //
88, 89, 90, 91, 92, 93, 94, 95, //
96, 97, 98, 99, 100, 101, 102, 103, //
104, 105, 106, 107, 108, 109, 110, 111, //
112, 113, 114, 115, 116, 117, 118, 119, //
120, 121, 122, 123, 124, 125, 126, 127, //
128, 129, 130, 131, 132, 133, 134, 135, //
136, 137, 138, 139, 140, 141, 142, 143, //
144, 145, 146, 147, 148, 149, 150, 151, //
152, 153, 154, 155, 156, 157, 158, 159, //
160, 161, 162, 163, 164, 165, 166, 167, //
168, 169, 170, 171, 172, 173, 174, 175, //
176, 177, 178, 179, 180, 181, 182, 183, //
184, 185, 186, 187, 188, 189, 190, 191, //
192, 193, 194, 195, 196, 197, 198, 199, //
200, 201, 202, 203, 204, 205, 206, 207, //
208, 209, 210, 211, 212, 213, 214, 215, //
216, 217, 218, 219, 220, 221, 222, 223, //
224, 225, 226, 227, 228, 229, 230, 231, //
232, 233, 234, 235, 236, 237, 238, 239, //
240, 241, 242, 243, 244, 245, 246, 247, //
248, 249, 250, 251, 252, 253, 254, 255, //
]);