[dart2wasm] Implement set literals in the backend
Change-Id: I678a6c16248bfafce2e39c6c3e39505109250f35
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/242861
Reviewed-by: Joshua Litt <joshualitt@google.com>
Commit-Queue: Aske Simon Christensen <askesc@google.com>
diff --git a/pkg/dart2wasm/lib/code_generator.dart b/pkg/dart2wasm/lib/code_generator.dart
index 821c38f..4a0d1c3 100644
--- a/pkg/dart2wasm/lib/code_generator.dart
+++ b/pkg/dart2wasm/lib/code_generator.dart
@@ -1976,6 +1976,34 @@
}
@override
+ w.ValueType visitSetLiteral(SetLiteral node, w.ValueType expectedType) {
+ w.BaseFunction setFactory =
+ translator.functions.getFunction(translator.setFactory.reference);
+ w.ValueType factoryReturnType = setFactory.type.outputs.single;
+ types.makeType(this, node.typeArgument, node);
+ b.call(setFactory);
+ if (node.expressions.isEmpty) {
+ return factoryReturnType;
+ }
+ w.BaseFunction setAdd =
+ translator.functions.getFunction(translator.setAdd.reference);
+ w.ValueType addReceiverType = setAdd.type.inputs[0];
+ w.ValueType addKeyType = setAdd.type.inputs[1];
+ w.Local setLocal = addLocal(addReceiverType);
+ translator.convertType(function, factoryReturnType, setLocal.type);
+ b.local_set(setLocal);
+ for (Expression element in node.expressions) {
+ b.local_get(setLocal);
+ translator.convertType(function, setLocal.type, addReceiverType);
+ wrap(element, addKeyType);
+ b.call(setAdd);
+ b.drop();
+ }
+ b.local_get(setLocal);
+ return setLocal.type;
+ }
+
+ @override
w.ValueType visitTypeLiteral(TypeLiteral node, w.ValueType expectedType) {
return types.makeType(this, node.type, node);
}
diff --git a/pkg/dart2wasm/lib/constants.dart b/pkg/dart2wasm/lib/constants.dart
index 7a1a84a..412bd0b 100644
--- a/pkg/dart2wasm/lib/constants.dart
+++ b/pkg/dart2wasm/lib/constants.dart
@@ -596,13 +596,6 @@
translator.functions.allocateClass(info.classId);
w.RefType type = info.nonNullableType;
return createConstant(constant, type, (function, b) {
- // This computation of the hash mask follows the computations in
- // [_ImmutableLinkedHashMapMixin._createIndex] and
- // [_HashBase._indexSizeToHashMask].
- const int initialIndexSize = 8;
- final int indexSize = max(dataElements.length, initialIndexSize);
- final int hashMask = (1 << (31 - (indexSize - 1).bitLength)) - 1;
-
w.RefType indexType =
info.struct.fields[FieldIndex.hashBaseIndex].type as w.RefType;
w.RefType dataType =
@@ -611,7 +604,7 @@
b.i32_const(info.classId);
b.i32_const(initialIdentityHash);
b.ref_null(indexType.heapType); // _index
- b.i64_const(hashMask); // _hashMask
+ b.i64_const(_computeHashMask(constant.entries.length)); // _hashMask
constants.instantiateConstant(function, b, dataList, dataType); // _data
b.i64_const(dataElements.length); // _usedData
b.i64_const(0); // _deletedKeys
@@ -624,6 +617,46 @@
}
@override
+ ConstantInfo? visitSetConstant(SetConstant constant) {
+ Constant elementTypeConstant = TypeLiteralConstant(constant.typeArgument);
+ ensureConstant(elementTypeConstant);
+ ListConstant dataList = ListConstant(const DynamicType(), constant.entries);
+ ensureConstant(dataList);
+
+ ClassInfo info = translator.classInfo[translator.immutableSetClass]!;
+ translator.functions.allocateClass(info.classId);
+ w.RefType type = info.nonNullableType;
+ return createConstant(constant, type, (function, b) {
+ w.RefType indexType =
+ info.struct.fields[FieldIndex.hashBaseIndex].type as w.RefType;
+ w.RefType dataType =
+ info.struct.fields[FieldIndex.hashBaseData].type as w.RefType;
+
+ b.i32_const(info.classId);
+ b.i32_const(initialIdentityHash);
+ b.ref_null(indexType.heapType); // _index
+ b.i64_const(_computeHashMask(constant.entries.length)); // _hashMask
+ constants.instantiateConstant(function, b, dataList, dataType); // _data
+ b.i64_const(constant.entries.length); // _usedData
+ b.i64_const(0); // _deletedKeys
+ constants.instantiateConstant(
+ function, b, elementTypeConstant, constants.typeInfo.nullableType);
+ translator.struct_new(b, info);
+ });
+ }
+
+ int _computeHashMask(int entries) {
+ // This computation of the hash mask follows the computations in
+ // [_ImmutableLinkedHashMapMixin._createIndex],
+ // [_ImmutableLinkedHashSetMixin._createIndex] and
+ // [_HashBase._indexSizeToHashMask].
+ const int initialIndexSize = 8;
+ final int indexSize = max(entries * 2, initialIndexSize);
+ final int hashMask = (1 << (31 - (indexSize - 1).bitLength)) - 1;
+ return hashMask;
+ }
+
+ @override
ConstantInfo? visitStaticTearOffConstant(StaticTearOffConstant constant) {
w.DefinedFunction closureFunction =
translator.getTearOffFunction(constant.targetReference.asProcedure);
diff --git a/pkg/dart2wasm/lib/constants_backend.dart b/pkg/dart2wasm/lib/constants_backend.dart
deleted file mode 100644
index 17e4bf4..0000000
--- a/pkg/dart2wasm/lib/constants_backend.dart
+++ /dev/null
@@ -1,59 +0,0 @@
-// Copyright (c) 2022, the Dart project authors. Please see the AUTHORS file
-// 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 'package:kernel/ast.dart';
-import 'package:kernel/target/targets.dart';
-import 'package:kernel/core_types.dart';
-
-class WasmConstantsBackend extends ConstantsBackend {
- final Class unmodifiableSetClass;
- final Field unmodifiableSetMap;
-
- WasmConstantsBackend._(this.unmodifiableSetMap, this.unmodifiableSetClass);
-
- factory WasmConstantsBackend(CoreTypes coreTypes) {
- Field unmodifiableSetMap =
- coreTypes.index.getField('dart:collection', '_UnmodifiableSet', '_map');
-
- return new WasmConstantsBackend._(
- unmodifiableSetMap, unmodifiableSetMap.enclosingClass!);
- }
-
- @override
- Constant lowerSetConstant(SetConstant constant) {
- final DartType elementType = constant.typeArgument;
- final List<Constant> entries = constant.entries;
- final List<ConstantMapEntry> mapEntries =
- new List<ConstantMapEntry>.generate(entries.length, (int index) {
- return new ConstantMapEntry(entries[index], new NullConstant());
- });
- Constant map = lowerMapConstant(
- new MapConstant(elementType, const NullType(), mapEntries));
- return new InstanceConstant(unmodifiableSetClass.reference, [elementType],
- <Reference, Constant>{unmodifiableSetMap.getterReference: map});
- }
-
- @override
- bool isLoweredSetConstant(Constant constant) {
- if (constant is InstanceConstant &&
- constant.classNode == unmodifiableSetClass) {
- InstanceConstant instance = constant;
- return isLoweredMapConstant(
- instance.fieldValues[unmodifiableSetMap.getterReference]!);
- }
- return false;
- }
-
- @override
- void forEachLoweredSetConstantElement(
- Constant constant, void Function(Constant element) f) {
- assert(isLoweredSetConstant(constant));
- final InstanceConstant instance = constant as InstanceConstant;
- final Constant mapConstant =
- instance.fieldValues[unmodifiableSetMap.getterReference]!;
- forEachLoweredMapConstantEntry(mapConstant, (Constant key, Constant value) {
- f(key);
- });
- }
-}
diff --git a/pkg/dart2wasm/lib/intrinsics.dart b/pkg/dart2wasm/lib/intrinsics.dart
index bb31c61..84535f6 100644
--- a/pkg/dart2wasm/lib/intrinsics.dart
+++ b/pkg/dart2wasm/lib/intrinsics.dart
@@ -168,7 +168,7 @@
}
// _HashAbstractImmutableBase._indexNullable
- if (target == translator.immutableMapIndexNullable) {
+ if (target == translator.hashImmutableIndexNullable) {
ClassInfo info = translator.classInfo[translator.hashFieldBaseClass]!;
codeGen.wrap(receiver, info.nullableType);
b.struct_get(info.struct, FieldIndex.hashBaseIndex);
diff --git a/pkg/dart2wasm/lib/target.dart b/pkg/dart2wasm/lib/target.dart
index 2a2f425..b2c8a13 100644
--- a/pkg/dart2wasm/lib/target.dart
+++ b/pkg/dart2wasm/lib/target.dart
@@ -21,21 +21,20 @@
import 'package:vm/transformations/ffi/use_sites.dart' as transformFfiUseSites
show transformLibraries;
-import 'package:dart2wasm/constants_backend.dart';
import 'package:dart2wasm/transformers.dart' as wasmTrans;
class WasmTarget extends Target {
Class? _growableList;
Class? _immutableList;
Class? _wasmImmutableLinkedHashMap;
- Class? _unmodifiableSet;
+ Class? _wasmImmutableLinkedHashSet;
Class? _compactLinkedCustomHashMap;
- Class? _compactLinkedHashSet;
+ Class? _compactLinkedCustomHashSet;
Class? _oneByteString;
Class? _twoByteString;
@override
- late final ConstantsBackend constantsBackend;
+ ConstantsBackend get constantsBackend => const ConstantsBackend();
@override
String get name => 'wasm';
@@ -85,7 +84,6 @@
DiagnosticReporter diagnosticReporter,
{void Function(String msg)? logger,
ChangedStructureNotifier? changedStructureNotifier}) {
- constantsBackend = WasmConstantsBackend(coreTypes);
_patchHostEndian(coreTypes);
}
@@ -167,7 +165,7 @@
}
@override
- bool get supportsSetLiterals => false;
+ bool get supportsSetLiterals => true;
@override
int get enabledLateLowerings => LateLowering.all;
@@ -213,14 +211,14 @@
@override
Class concreteSetLiteralClass(CoreTypes coreTypes) {
- return _compactLinkedHashSet ??=
- coreTypes.index.getClass('dart:collection', '_CompactLinkedHashSet');
+ return _compactLinkedCustomHashSet ??= coreTypes.index
+ .getClass('dart:collection', '_CompactLinkedCustomHashSet');
}
@override
Class concreteConstSetLiteralClass(CoreTypes coreTypes) {
- return _unmodifiableSet ??=
- coreTypes.index.getClass('dart:collection', '_UnmodifiableSet');
+ return _wasmImmutableLinkedHashSet ??= coreTypes.index
+ .getClass('dart:collection', '_WasmImmutableLinkedHashSet');
}
@override
diff --git a/pkg/dart2wasm/lib/translator.dart b/pkg/dart2wasm/lib/translator.dart
index d6711a2..fa258cf 100644
--- a/pkg/dart2wasm/lib/translator.dart
+++ b/pkg/dart2wasm/lib/translator.dart
@@ -83,6 +83,7 @@
late final Class growableListClass;
late final Class immutableListClass;
late final Class immutableMapClass;
+ late final Class immutableSetClass;
late final Class hashFieldBaseClass;
late final Class stringBaseClass;
late final Class oneByteStringClass;
@@ -105,7 +106,9 @@
late final Procedure throwWasmRefError;
late final Procedure mapFactory;
late final Procedure mapPut;
- late final Procedure immutableMapIndexNullable;
+ late final Procedure setFactory;
+ late final Procedure setAdd;
+ late final Procedure hashImmutableIndexNullable;
late final Map<Class, w.StorageType> builtinTypes;
late final Map<w.ValueType, Class> boxedClasses;
@@ -183,6 +186,7 @@
growableListClass = lookupCore("_GrowableList");
immutableListClass = lookupCore("_ImmutableList");
immutableMapClass = lookupCollection("_WasmImmutableLinkedHashMap");
+ immutableSetClass = lookupCollection("_WasmImmutableLinkedHashSet");
hashFieldBaseClass = lookupCollection("_HashFieldBase");
stringBaseClass = lookupCore("_StringBase");
oneByteStringClass = lookupCore("_OneByteString");
@@ -216,7 +220,13 @@
.superclass! // _LinkedHashMapMixin<K, V>
.procedures
.firstWhere((p) => p.name.text == "[]=");
- immutableMapIndexNullable = lookupCollection("_HashAbstractImmutableBase")
+ setFactory = lookupCollection("LinkedHashSet").procedures.firstWhere(
+ (p) => p.kind == ProcedureKind.Factory && p.name.text == "_default");
+ setAdd = lookupCollection("_CompactLinkedCustomHashSet")
+ .superclass! // _LinkedHashSetMixin<K, V>
+ .procedures
+ .firstWhere((p) => p.name.text == "add");
+ hashImmutableIndexNullable = lookupCollection("_HashAbstractImmutableBase")
.procedures
.firstWhere((p) => p.name.text == "_indexNullable");
builtinTypes = {
diff --git a/sdk/lib/_internal/vm/lib/compact_hash.dart b/sdk/lib/_internal/vm/lib/compact_hash.dart
index c49bb48..003be2c 100644
--- a/sdk/lib/_internal/vm/lib/compact_hash.dart
+++ b/sdk/lib/_internal/vm/lib/compact_hash.dart
@@ -1096,6 +1096,9 @@
E? lookup(Object? o) => _validKey(o) ? super.lookup(o) : null;
bool remove(Object? o) => _validKey(o) ? super.remove(o) : false;
+ @pragma("wasm:entry-point")
+ bool add(E key);
+
_CompactLinkedCustomHashSet(this._equality, this._hasher, validKey)
: _validKey = (validKey != null) ? validKey : new _TypeTest<E>().test;
diff --git a/sdk/lib/_internal/wasm/lib/hash_factories.dart b/sdk/lib/_internal/wasm/lib/hash_factories.dart
index 8159f09..c0f6160 100644
--- a/sdk/lib/_internal/wasm/lib/hash_factories.dart
+++ b/sdk/lib/_internal/wasm/lib/hash_factories.dart
@@ -46,6 +46,10 @@
return new _CompactLinkedCustomHashSet<E>(equals, hashCode, isValidKey);
}
+ @pragma("wasm:entry-point")
+ factory LinkedHashSet._default() =>
+ _CompactLinkedCustomHashSet<E>(_defaultEquals, _defaultHashCode, null);
+
@patch
factory LinkedHashSet.identity() => new _CompactLinkedIdentityHashSet<E>();
}
@@ -70,3 +74,19 @@
"Immutable maps can only be instantiated via constants");
}
}
+
+@pragma("wasm:entry-point")
+class _WasmImmutableLinkedHashSet<E> extends _HashWasmImmutableBase
+ with
+ SetMixin<E>,
+ _HashBase,
+ _OperatorEqualsAndHashCode,
+ _LinkedHashSetMixin<E>,
+ _UnmodifiableSetMixin<E>,
+ _ImmutableLinkedHashSetMixin<E>
+ implements LinkedHashSet<E> {
+ factory _WasmImmutableLinkedHashSet._uninstantiable() {
+ throw new UnsupportedError(
+ "Immutable sets can only be instantiated via constants");
+ }
+}