Skip to content

Commit

Permalink
[stable] [dart2wasm] Fix array.new_fixed calls with too large size
Browse files Browse the repository at this point in the history
Currently `array.new_fixed` has the upper size limit of 10,000.

Larger arrays need to be initialized with `array.new` or
`array.new_default`.

We handle this correctly in constant list and strings, but we didn't
handle it in `WasmArray.literal` consturctor. This CL fixes it.

Bug: #55396
Bug: #55872

Cherry-pick: https://dart-review.googlesource.com/c/sdk/+/361780
Cherry-pick-request: #55873
Change-Id: I97c8dc104cb4231ba0508d9cd87690cf1bbe95a9
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/368644
Reviewed-by: Slava Egorov <[email protected]>
Commit-Queue: Martin Kustermann <[email protected]>
Reviewed-by: Ömer Ağacan <[email protected]>
  • Loading branch information
mkustermann authored and Commit Queue committed May 30, 2024
1 parent 16c3fef commit c907b4b
Show file tree
Hide file tree
Showing 3 changed files with 889 additions and 4 deletions.
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,13 @@ This is a patch release that:
- Fixes an issue where `DART_VM_OPTIONS` were not correctly parsed for
standalone Dart executables created with `dart compile exe` (issue [#55767]).

- Fixes a bug in dart2wasm that can result in a runtime error that says
`array.new_fixed()` has a constant larger than 10000 (issues [#55872],
[#55876]).

[#55767]: https://github.com/dart-lang/sdk/issues/55767
[#55872]: https://github.com/dart-lang/sdk/issues/55872
[#55876]: https://github.com/dart-lang/sdk/issues/55876

## 3.4.2 - 2024-05-29

Expand Down
48 changes: 44 additions & 4 deletions pkg/dart2wasm/lib/constants.dart
Original file line number Diff line number Diff line change
Expand Up @@ -439,17 +439,57 @@ class ConstantCreator extends ConstantVisitor<ConstantInfo?>

List<Constant> elements =
(constant.fieldValues.values.single as ListConstant).entries;
bool lazy = false;
final tooLargeForArrayNewFixed = elements.length > maxArrayNewFixedLength;
bool lazy = tooLargeForArrayNewFixed;
for (Constant element in elements) {
lazy |= ensureConstant(element)?.isLazy ?? false;
}

return createConstant(constant, w.RefType.def(arrayType, nullable: false),
lazy: lazy, (function, b) {
for (Constant element in elements) {
constants.instantiateConstant(function, b, element, elementType);
if (tooLargeForArrayNewFixed) {
// We will initialize the array with one of the elements (using
// `array.new`) and update the fields.
//
// For the initial element pick the one that occurs the most to save
// some work when the array has duplicates.
final Map<Constant, int> occurrences = {};
for (final element in elements) {
occurrences.update(element, (i) => i + 1, ifAbsent: () => 1);
}

var initialElement = elements[0];
var initialElementOccurrences = 1;
for (final entry in occurrences.entries) {
if (entry.value > initialElementOccurrences) {
initialElementOccurrences = entry.value;
initialElement = entry.key;
}
}

w.Local arrayLocal =
function!.addLocal(w.RefType.def(arrayType, nullable: false));
constants.instantiateConstant(function, b, initialElement, elementType);
b.i32_const(elements.length);
b.array_new(arrayType);
b.local_set(arrayLocal);
for (int i = 0; i < elements.length; i++) {
final element = elements[i];
if (element == initialElement) {
continue;
}
b.local_get(arrayLocal);
b.i32_const(i);
constants.instantiateConstant(function, b, element, elementType);
b.array_set(arrayType);
}
b.local_get(arrayLocal);
} else {
for (Constant element in elements) {
constants.instantiateConstant(function, b, element, elementType);
}
b.array_new_fixed(arrayType, elements.length);
}
b.array_new_fixed(arrayType, elements.length);
});
}

Expand Down
Loading

0 comments on commit c907b4b

Please sign in to comment.