From 73629e694643efa76470f8361c753597d05e8016 Mon Sep 17 00:00:00 2001 From: Martin Kustermann Date: Fri, 21 Mar 2025 06:53:58 -0700 Subject: [PATCH] [dart2wasm] Prefer to initialize large 32-bit integer arrays from data section MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When crossing the 10k array limit we have to construct `const WasmArray` arrays lazily. We do that by array allocation followed by individual stores to initialize it. This can cause rather large wasm functions to be generated, which are slow to validate, compile & run. Instead initialize such arrays from the data section. This may increase the wasm file size a bit, but seems to decrease the compressed wasm file and increases validation & initialization time. The ACX gallery for example will benefit from this. Change-Id: I42609e83059cd1543df401efdb30c1cbd72e6296 Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/417161 Commit-Queue: Martin Kustermann Reviewed-by: Ömer Ağacan --- pkg/dart2wasm/lib/constants.dart | 36 ++++++++++++++++++++++++++++++-- 1 file changed, 34 insertions(+), 2 deletions(-) diff --git a/pkg/dart2wasm/lib/constants.dart b/pkg/dart2wasm/lib/constants.dart index 65a4b235f9d..6c43e6b9ea1 100644 --- a/pkg/dart2wasm/lib/constants.dart +++ b/pkg/dart2wasm/lib/constants.dart @@ -2,6 +2,8 @@ // 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:typed_data'; + import 'package:kernel/ast.dart'; import 'package:kernel/core_types.dart'; import 'package:kernel/type_algebra.dart' @@ -69,8 +71,7 @@ class Constants { final Translator translator; final Map constantInfo = {}; final Map dynamicModuleConstantInfo = {}; - w.DataSegmentBuilder? oneByteStringSegment; - w.DataSegmentBuilder? twoByteStringSegment; + w.DataSegmentBuilder? int32Segment; late final ClassInfo typeInfo = translator.classInfo[translator.typeClass]!; final Map _loweredTypeConstants = {}; @@ -673,6 +674,37 @@ class ConstantCreator extends ConstantVisitor return createConstant(constant, w.RefType.def(arrayType, nullable: false), lazy: lazy, (b) { if (tooLargeForArrayNewFixed) { + // We use WasmArray for some RTT data structures. Those arrays + // can get rather large and cross the 10k limit. + // + // If so, we prefer to initialize the array from data section over + // emitting a *lot* of code to store individual array elements. + // + // This can be a little bit larger than individual array stores, but the + // data section will compress better, so for app.wasm.gz it'a a win and + // will cause much faster validation & faster initialization. + if (arrayType.elementType.type == w.NumType.i32) { + // Initialize array contents from passive data segment. + final w.DataSegmentBuilder segment = + constants.int32Segment ??= targetModule.dataSegments.define(); + + final field = translator.wasmI32Value.fieldReference; + + final list = Uint32List(elements.length); + for (int i = 0; i < list.length; ++i) { + // The constant is a `const WasmI32 {WasmI32._value: }` + final constant = elements[i] as InstanceConstant; + assert(constant.classNode == translator.wasmI32Class); + list[i] = (constant.fieldValues[field] as IntConstant).value; + } + final offset = segment.length; + segment.append(list.buffer.asUint8List()); + b.i32_const(offset); + b.i32_const(elements.length); + b.array_new_data(arrayType, segment); + return; + } + // We will initialize the array with one of the elements (using // `array.new`) and update the fields. //