Skip to content

Commit

Permalink
[dart2wasm] Make use of ImmutableWasmArray in core libraries
Browse files Browse the repository at this point in the history
This can allow tools such as binaryen or V8 optimize loads from the
arrays better.

We'd also want to make some other uses of wasm arrays immutable (e.g.
`WasmArray<_Type>` used in RTT implementation) but it's currently not
easily possible to create immutable wasm arrays of unknown length from
another mutable array (see [0]).

[0] WebAssembly/gc#570

Change-Id: Ia5270bad238c3dc6ea1086677395091d441d9398
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/392904
Reviewed-by: Ömer Ağacan <[email protected]>
Commit-Queue: Martin Kustermann <[email protected]>
  • Loading branch information
mkustermann authored and Commit Queue committed Oct 31, 2024
1 parent a96ad1b commit 45a32ec
Show file tree
Hide file tree
Showing 8 changed files with 32 additions and 21 deletions.
3 changes: 2 additions & 1 deletion pkg/dart2wasm/lib/constants.dart
Original file line number Diff line number Diff line change
Expand Up @@ -243,7 +243,8 @@ class Constants {
...type.named.map((named) => named.type),
]);
final names = makeArrayOf(coreTypes.stringNonNullableRawType,
type.named.map((t) => StringConstant(t.name)).toList());
type.named.map((t) => StringConstant(t.name)).toList(),
mutable: false);
return _makeTypeConstant(translator.recordTypeClass, type.nullability, {
translator.recordTypeFieldTypesField.fieldReference: fieldTypes,
translator.recordTypeNamesField.fieldReference: names,
Expand Down
29 changes: 19 additions & 10 deletions pkg/dart2wasm/lib/record_class_generator.dart
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,9 @@ import 'records.dart';
/// Record_2_a(this.$1, this.$2, this.a);
///
/// @pragma('wasm:entry-point')
/// bool _checkRecordType(WasmArray<_Type> types, WasmArray<String> names) {
/// bool _checkRecordType(WasmArray<_Type> types, ImmutableWasmArray<String> names) {
/// if (types.length != 3) return false;
/// if (!identical(names, const WasmArray(["a"]))) return false;
/// if (!identical(names, const ImmutableWasmArray(["a"]))) return false;
///
/// if (!_isSubtype($1, types[0])) return false;
/// if (!_isSubtype($2, types[1])) return false;
Expand All @@ -44,7 +44,7 @@ import 'records.dart';
/// @pragma('wasm:entry-point')
/// _Type get _masqueradedRecordRuntimeType =>
/// _RecordType(
/// const WasmArray(["a"]),
/// const ImmutableWasmArray(["a"]),
/// WasmArray.literal([
/// _getMasqueradedRuntimeTypeNullable($1),
/// _getMasqueradedRuntimeTypeNullable($2),
Expand All @@ -54,7 +54,7 @@ import 'records.dart';
/// @pragma('wasm:entry-point')
/// _Type get _recordRuntimeType =>
/// _RecordType(
/// const WasmArray(["a"]),
/// const ImmutableWasmArray(["a"]),
/// WasmArray.literal([
/// _getActualRuntimeTypeNullable($1),
/// _getActualRuntimeTypeNullable($2),
Expand Down Expand Up @@ -126,6 +126,9 @@ class _RecordClassGenerator {
late final Class wasmArrayClass =
coreTypes.index.getClass('dart:_wasm', 'WasmArray');

late final Class immutableWasmArrayClass =
coreTypes.index.getClass('dart:_wasm', 'ImmutableWasmArray');

late final Procedure wasmArrayRefLength =
coreTypes.index.getProcedure('dart:_wasm', 'WasmArrayRef', 'get:length');

Expand All @@ -144,11 +147,16 @@ class _RecordClassGenerator {
late final Field wasmArrayValueField =
coreTypes.index.getField("dart:_wasm", "WasmArray", "_value");

late final Field immutableWasmArrayValueField =
coreTypes.index.getField("dart:_wasm", "ImmutableWasmArray", "_value");

late final InterfaceType wasmArrayOfType = InterfaceType(
wasmArrayClass, Nullability.nonNullable, [nonNullableTypeType]);

late final InterfaceType wasmArrayOfString = InterfaceType(
wasmArrayClass, Nullability.nonNullable, [nonNullableStringType]);
late final InterfaceType immutableWasmArrayOfString = InterfaceType(
immutableWasmArrayClass,
Nullability.nonNullable,
[nonNullableStringType]);

late final InterfaceType runtimeTypeType =
InterfaceType(typeRuntimetypeTypeClass, Nullability.nonNullable);
Expand Down Expand Up @@ -414,7 +422,7 @@ class _RecordClassGenerator {
Procedure _generateCheckRecordType(RecordShape shape, List<Field> fields) {
final typesParameter = VariableDeclaration('types', type: wasmArrayOfType);
final namesParameter =
VariableDeclaration('names', type: wasmArrayOfString);
VariableDeclaration('names', type: immutableWasmArrayOfString);

final List<Statement> statements = [];

Expand Down Expand Up @@ -502,7 +510,7 @@ class _RecordClassGenerator {
String name, Procedure target, RecordShape shape, List<Field> fields) {
final List<Statement> statements = [];

// const WasmArray(["name1", "name2", ...])
// const ImmutableWasmArray(["name1", "name2", ...])
final fieldNamesList = ConstantExpression(_fieldNamesConstant(shape));

Expression fieldRuntimeTypeExpr(Field field) => StaticInvocation(
Expand Down Expand Up @@ -548,10 +556,11 @@ class _RecordClassGenerator {
}

Constant _fieldNamesConstant(RecordShape shape) {
return InstanceConstant(wasmArrayClass.reference, [
return InstanceConstant(immutableWasmArrayClass.reference, [
nonNullableStringType
], {
wasmArrayValueField.fieldReference: ListConstant(nonNullableStringType,
immutableWasmArrayValueField.fieldReference: ListConstant(
nonNullableStringType,
shape.names.map((name) => StringConstant(name)).toList())
});
}
Expand Down
3 changes: 2 additions & 1 deletion pkg/dart2wasm/lib/types.dart
Original file line number Diff line number Diff line change
Expand Up @@ -202,7 +202,8 @@ class Types {

final names = translator.constants.makeArrayOf(
translator.coreTypes.stringNonNullableRawType,
type.named.map((t) => StringConstant(t.name)).toList());
type.named.map((t) => StringConstant(t.name)).toList(),
mutable: false);

translator.constants.instantiateConstant(
codeGen.b, names, recordTypeNamesFieldExpectedType);
Expand Down
5 changes: 2 additions & 3 deletions sdk/lib/_internal/wasm/lib/convert_patch.dart
Original file line number Diff line number Diff line change
Expand Up @@ -1067,8 +1067,7 @@ mixin _ChunkedJsonParser<T> on _JsonParserWithListener {
* }
* ```
*/
static const WasmArray<WasmI8> _characterAttributes =
WasmArray<WasmI8>.literal([
static const _characterAttributes = ImmutableWasmArray<WasmI8>.literal([
33, 33, 33, 33, 33, 33, 33, 33, 33, 35, 35, 33, 33, 35, 33, 33, 33, 33, //
33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 33, 34, 32, 33, 32, //
32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, 32, //
Expand Down Expand Up @@ -1776,7 +1775,7 @@ class _Utf8Decoder {
// Non-BMP 'R' = 64 + (2 | flagNonLatin1);
// Illegal 'a' = 64 + (1 | flagIllegal);
// Illegal 'b' = 64 + (2 | flagIllegal);
static const WasmArray<WasmI8> scanTable = WasmArray<WasmI8>.literal([
static const scanTable = ImmutableWasmArray<WasmI8>.literal([
// 00-1F
65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65,
65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65, 65,
Expand Down
2 changes: 1 addition & 1 deletion sdk/lib/_internal/wasm/lib/int_patch.dart
Original file line number Diff line number Diff line change
Expand Up @@ -210,7 +210,7 @@ class int {
}

// For each radix, 2-36, how many digits are guaranteed to fit in an `int`.
static const _PARSE_LIMITS = const WasmArray<WasmI64>.literal([
static const _PARSE_LIMITS = const ImmutableWasmArray<WasmI64>.literal([
0, // unused
0, // unused
63, // radix: 2
Expand Down
3 changes: 2 additions & 1 deletion sdk/lib/_internal/wasm/lib/record_patch.dart
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@ abstract class Record {
_RecordType get _masqueradedRecordRuntimeType;
_RecordType get _recordRuntimeType;

bool _checkRecordType(WasmArray<_Type> types, WasmArray<String> names);
bool _checkRecordType(
WasmArray<_Type> types, ImmutableWasmArray<String> names);

@pragma("wasm:prefer-inline")
static _RecordType _getRecordRuntimeType(Record record) =>
Expand Down
4 changes: 2 additions & 2 deletions sdk/lib/_internal/wasm/lib/string.dart
Original file line number Diff line number Diff line change
Expand Up @@ -1452,7 +1452,7 @@ final class OneByteString extends StringBase {
// Lower-case conversion table for Latin-1 as string.
// Upper-case ranges: 0x41-0x5a ('A' - 'Z'), 0xc0-0xd6, 0xd8-0xde.
// Conversion to lower case performed by adding 0x20.
static const WasmArray<WasmI8> _LC_TABLE = WasmArray<WasmI8>.literal([
static const _LC_TABLE = ImmutableWasmArray<WasmI8>.literal([
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, //
0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, //
0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, //
Expand Down Expand Up @@ -1484,7 +1484,7 @@ final class OneByteString extends StringBase {
// The German "sharp s" \xdf (ß) should be converted into two characters (SS),
// and is also marked with 0x00.
// Conversion to lower case performed by subtracting 0x20.
static const WasmArray<WasmI8> _UC_TABLE = WasmArray<WasmI8>.literal([
static const _UC_TABLE = ImmutableWasmArray<WasmI8>.literal([
0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, //
0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, //
0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, //
Expand Down
4 changes: 2 additions & 2 deletions sdk/lib/_internal/wasm/lib/type.dart
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ extension on WasmArray<_NamedParameter> {
}
}

extension on WasmArray<String> {
extension on ImmutableWasmArray<String> {
@pragma("wasm:prefer-inline")
bool get isNotEmpty => length != 0;
}
Expand Down Expand Up @@ -544,7 +544,7 @@ class _AbstractRecordType extends _Type {

@pragma("wasm:entry-point")
class _RecordType extends _Type {
final WasmArray<String> names;
final ImmutableWasmArray<String> names;
final WasmArray<_Type> fieldTypes;

@pragma("wasm:entry-point")
Expand Down

0 comments on commit 45a32ec

Please sign in to comment.