[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 <kustermann@google.com> Reviewed-by: Ömer Ağacan <omersa@google.com>
This commit is contained in:
committed by
Commit Queue
parent
6ad56c68dc
commit
73629e6946
@@ -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<Constant, ConstantInfo> constantInfo = {};
|
||||
final Map<Constant, ConstantInfo> dynamicModuleConstantInfo = {};
|
||||
w.DataSegmentBuilder? oneByteStringSegment;
|
||||
w.DataSegmentBuilder? twoByteStringSegment;
|
||||
w.DataSegmentBuilder? int32Segment;
|
||||
late final ClassInfo typeInfo = translator.classInfo[translator.typeClass]!;
|
||||
|
||||
final Map<DartType, InstanceConstant> _loweredTypeConstants = {};
|
||||
@@ -673,6 +674,37 @@ class ConstantCreator extends ConstantVisitor<ConstantInfo?>
|
||||
return createConstant(constant, w.RefType.def(arrayType, nullable: false),
|
||||
lazy: lazy, (b) {
|
||||
if (tooLargeForArrayNewFixed) {
|
||||
// We use WasmArray<WasmI32> 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: <XXX>}`
|
||||
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.
|
||||
//
|
||||
|
||||
Reference in New Issue
Block a user