Skip to content

Commit 73629e6

Browse files
mkustermannCommit Queue
authored andcommitted
[dart2wasm] Prefer to initialize large 32-bit integer arrays from data section
When crossing the 10k array limit we have to construct `const WasmArray<WasmI32>` 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 <[email protected]> Reviewed-by: Ömer Ağacan <[email protected]>
1 parent 6ad56c6 commit 73629e6

File tree

1 file changed

+34
-2
lines changed

1 file changed

+34
-2
lines changed

pkg/dart2wasm/lib/constants.dart

Lines changed: 34 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,8 @@
22
// for details. All rights reserved. Use of this source code is governed by a
33
// BSD-style license that can be found in the LICENSE file.
44

5+
import 'dart:typed_data';
6+
57
import 'package:kernel/ast.dart';
68
import 'package:kernel/core_types.dart';
79
import 'package:kernel/type_algebra.dart'
@@ -69,8 +71,7 @@ class Constants {
6971
final Translator translator;
7072
final Map<Constant, ConstantInfo> constantInfo = {};
7173
final Map<Constant, ConstantInfo> dynamicModuleConstantInfo = {};
72-
w.DataSegmentBuilder? oneByteStringSegment;
73-
w.DataSegmentBuilder? twoByteStringSegment;
74+
w.DataSegmentBuilder? int32Segment;
7475
late final ClassInfo typeInfo = translator.classInfo[translator.typeClass]!;
7576

7677
final Map<DartType, InstanceConstant> _loweredTypeConstants = {};
@@ -673,6 +674,37 @@ class ConstantCreator extends ConstantVisitor<ConstantInfo?>
673674
return createConstant(constant, w.RefType.def(arrayType, nullable: false),
674675
lazy: lazy, (b) {
675676
if (tooLargeForArrayNewFixed) {
677+
// We use WasmArray<WasmI32> for some RTT data structures. Those arrays
678+
// can get rather large and cross the 10k limit.
679+
//
680+
// If so, we prefer to initialize the array from data section over
681+
// emitting a *lot* of code to store individual array elements.
682+
//
683+
// This can be a little bit larger than individual array stores, but the
684+
// data section will compress better, so for app.wasm.gz it'a a win and
685+
// will cause much faster validation & faster initialization.
686+
if (arrayType.elementType.type == w.NumType.i32) {
687+
// Initialize array contents from passive data segment.
688+
final w.DataSegmentBuilder segment =
689+
constants.int32Segment ??= targetModule.dataSegments.define();
690+
691+
final field = translator.wasmI32Value.fieldReference;
692+
693+
final list = Uint32List(elements.length);
694+
for (int i = 0; i < list.length; ++i) {
695+
// The constant is a `const WasmI32 {WasmI32._value: <XXX>}`
696+
final constant = elements[i] as InstanceConstant;
697+
assert(constant.classNode == translator.wasmI32Class);
698+
list[i] = (constant.fieldValues[field] as IntConstant).value;
699+
}
700+
final offset = segment.length;
701+
segment.append(list.buffer.asUint8List());
702+
b.i32_const(offset);
703+
b.i32_const(elements.length);
704+
b.array_new_data(arrayType, segment);
705+
return;
706+
}
707+
676708
// We will initialize the array with one of the elements (using
677709
// `array.new`) and update the fields.
678710
//

0 commit comments

Comments
 (0)