From 5e8bd0243347ebd01c22d127e32dc58956bc97d5 Mon Sep 17 00:00:00 2001 From: Martin Kustermann Date: Tue, 18 Feb 2025 04:16:29 -0800 Subject: [PATCH] [dart2wasm] Make json parser use cache of boxed integers <=255 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 Reviewed-by: Ömer Ağacan --- pkg/dart2wasm/lib/translator.dart | 17 +++++-- sdk/lib/_internal/wasm/lib/convert_patch.dart | 49 ++++++++++++++++++- 2 files changed, 60 insertions(+), 6 deletions(-) diff --git a/pkg/dart2wasm/lib/translator.dart b/pkg/dart2wasm/lib/translator.dart index 357de979bfe..4220112bd03 100644 --- a/pkg/dart2wasm/lib/translator.dart +++ b/pkg/dart2wasm/lib/translator.dart @@ -301,6 +301,12 @@ class Translator with KernelNodes { w.NumType.f64: boxedDoubleClass, }; + late final Set 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` we actually want an array of boxed + // integers and not a `WasmArray`. + return wasmArrayType(translateStorageType(type, unbox: false), + type.toText(defaultAstTextStrategy), mutable: mutable); } diff --git a/sdk/lib/_internal/wasm/lib/convert_patch.dart b/sdk/lib/_internal/wasm/lib/convert_patch.dart index 21752fb1db9..f86ffcb669e 100644 --- a/sdk/lib/_internal/wasm/lib/convert_patch.dart +++ b/sdk/lib/_internal/wasm/lib/convert_patch.dart @@ -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 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 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( '(s) => parseFloat(s)', jsStringFromDartString(string).toExternRef, ); + +const ImmutableWasmArray _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, // +]);