mirror of
https://github.com/dart-lang/sdk
synced 2024-09-15 22:00:09 +00:00
[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>
This commit is contained in:
parent
e31cc74d54
commit
c6a061f41d
|
@ -1975,6 +1975,34 @@ class CodeGenerator extends ExpressionVisitor1<w.ValueType, w.ValueType>
|
|||
return mapLocal.type;
|
||||
}
|
||||
|
||||
@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);
|
||||
|
|
|
@ -596,13 +596,6 @@ class ConstantCreator extends ConstantVisitor<ConstantInfo?> {
|
|||
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 @@ class ConstantCreator extends ConstantVisitor<ConstantInfo?> {
|
|||
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
|
||||
|
@ -623,6 +616,46 @@ class ConstantCreator extends ConstantVisitor<ConstantInfo?> {
|
|||
});
|
||||
}
|
||||
|
||||
@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 =
|
||||
|
|
|
@ -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);
|
||||
});
|
||||
}
|
||||
}
|
|
@ -168,7 +168,7 @@ class Intrinsifier {
|
|||
}
|
||||
|
||||
// _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);
|
||||
|
|
|
@ -21,21 +21,20 @@ import 'package:vm/transformations/ffi/definitions.dart'
|
|||
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 @@ class WasmTarget extends Target {
|
|||
DiagnosticReporter diagnosticReporter,
|
||||
{void Function(String msg)? logger,
|
||||
ChangedStructureNotifier? changedStructureNotifier}) {
|
||||
constantsBackend = WasmConstantsBackend(coreTypes);
|
||||
_patchHostEndian(coreTypes);
|
||||
}
|
||||
|
||||
|
@ -167,7 +165,7 @@ class WasmTarget extends Target {
|
|||
}
|
||||
|
||||
@override
|
||||
bool get supportsSetLiterals => false;
|
||||
bool get supportsSetLiterals => true;
|
||||
|
||||
@override
|
||||
int get enabledLateLowerings => LateLowering.all;
|
||||
|
@ -213,14 +211,14 @@ class WasmTarget extends Target {
|
|||
|
||||
@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
|
||||
|
|
|
@ -83,6 +83,7 @@ class Translator {
|
|||
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 @@ class Translator {
|
|||
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 @@ class Translator {
|
|||
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 @@ class Translator {
|
|||
.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 = {
|
||||
|
|
|
@ -1096,6 +1096,9 @@ class _CompactLinkedCustomHashSet<E> extends _HashFieldBase
|
|||
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;
|
||||
|
||||
|
|
|
@ -46,6 +46,10 @@ class LinkedHashSet<E> {
|
|||
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 @@ class _WasmImmutableLinkedHashMap<K, V> extends _HashWasmImmutableBase
|
|||
"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");
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue