[dart2wasm] Make the index field in _HashFieldBase nullable

This is to allow `_HashFieldBase` to be used for immutable maps and
sets (which initialize their index lazily) without using an intrinsics
hack to allow a non-nullable field to be `null`.

This change is necessary for the upcoming optimization that will
use non-nullable Wasm types for non-nullable Dart fields.

Even though this code is shared with the VM, the change doesn't affect
VM performance in practice, since the VM compiler is able to infer
that the field is always non-null. Benchmark runs see no measurable
performance difference.

Change-Id: I3ba2f78044f965473a0ab10ddf864c78e7095634
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/321400
Commit-Queue: Aske Simon Christensen <askesc@google.com>
Reviewed-by: Jess Lally <jessicalally@google.com>
This commit is contained in:
Aske Simon Christensen 2023-08-18 10:19:22 +00:00 committed by Commit Queue
parent 851e696270
commit da758538d3
4 changed files with 25 additions and 25 deletions

View file

@ -85,7 +85,8 @@ class FieldIndex {
check(translator.twoByteStringClass, "_array", FieldIndex.stringArray);
check(translator.listBaseClass, "_length", FieldIndex.listLength);
check(translator.listBaseClass, "_data", FieldIndex.listArray);
check(translator.hashFieldBaseClass, "_index", FieldIndex.hashBaseIndex);
check(translator.hashFieldBaseClass, "_indexNullable",
FieldIndex.hashBaseIndex);
check(translator.hashFieldBaseClass, "_data", FieldIndex.hashBaseData);
check(translator.closureClass, "context", FieldIndex.closureContext);
check(translator.typeClass, "isDeclaredNullable",

View file

@ -182,14 +182,6 @@ class Intrinsifier {
return w.NumType.i64;
}
// _HashAbstractImmutableBase._indexNullable
if (target == translator.hashImmutableIndexNullable) {
ClassInfo info = translator.classInfo[translator.hashFieldBaseClass]!;
codeGen.wrap(receiver, info.nonNullableType);
b.struct_get(info.struct, FieldIndex.hashBaseIndex);
return info.struct.fields[FieldIndex.hashBaseIndex].type.unpacked;
}
// _Compound._typedDataBase
if (cls == translator.ffiCompoundClass && name == '_typedDataBase') {
// A compound (subclass of Struct or Union) is represented by its i32

View file

@ -36,11 +36,10 @@ abstract class _HashAbstractBase {
}
abstract class _HashAbstractImmutableBase extends _HashAbstractBase {
@pragma("wasm:entry-point")
Uint32List? get _indexNullable;
}
abstract class _HashFieldBase implements _HashAbstractBase {
abstract class _HashFieldBase implements _HashAbstractImmutableBase {
// Each occupied entry in _index is a fixed-size integer that encodes a pair:
// [ hash pattern for key | index of entry in _data ]
// The hash pattern is based on hashCode, but is guaranteed to be non-zero.
@ -48,7 +47,16 @@ abstract class _HashFieldBase implements _HashAbstractBase {
// least one unoccupied entry.
// NOTE: When maps are deserialized, their _index and _hashMask is regenerated
// eagerly by _regenerateIndex.
Uint32List _index = _uninitializedIndex;
Uint32List? _indexNullable = _uninitializedIndex;
@pragma("vm:exact-result-type", "dart:typed_data#_Uint32List")
@pragma("vm:prefer-inline")
@pragma("wasm:prefer-inline")
Uint32List get _index => _indexNullable!;
@pragma("vm:prefer-inline")
@pragma("wasm:prefer-inline")
void set _index(Uint32List value) => _indexNullable = value;
// Cached in-place mask for the hash pattern component.
int _hashMask = _HashBase._UNINITIALIZED_HASH_MASK;

View file

@ -92,13 +92,8 @@ base class _WasmDefaultSet<E> extends _HashFieldBase
Set<E> toSet() => _WasmDefaultSet<E>()..addAll(this);
}
abstract class _HashWasmImmutableBase extends _HashFieldBase
implements _HashAbstractImmutableBase {
external Uint32List? get _indexNullable;
}
@pragma("wasm:entry-point")
base class _WasmImmutableMap<K, V> extends _HashWasmImmutableBase
base class _WasmImmutableMap<K, V> extends _HashFieldBase
with
MapMixin<K, V>,
_HashBase,
@ -107,14 +102,16 @@ base class _WasmImmutableMap<K, V> extends _HashWasmImmutableBase
_UnmodifiableMapMixin<K, V>,
_ImmutableLinkedHashMapMixin<K, V>
implements LinkedHashMap<K, V> {
factory _WasmImmutableMap._uninstantiable() {
throw UnsupportedError(
"Immutable maps can only be instantiated via constants");
// Dummy constructor to prevent the TFA from concluding that `_indexNullable`
// is never `null`.
@pragma("wasm:entry-point")
_WasmImmutableMap._() {
_indexNullable = null;
}
}
@pragma("wasm:entry-point")
base class _WasmImmutableSet<E> extends _HashWasmImmutableBase
base class _WasmImmutableSet<E> extends _HashFieldBase
with
SetMixin<E>,
_HashBase,
@ -123,9 +120,11 @@ base class _WasmImmutableSet<E> extends _HashWasmImmutableBase
_UnmodifiableSetMixin<E>,
_ImmutableLinkedHashSetMixin<E>
implements LinkedHashSet<E> {
factory _WasmImmutableSet._uninstantiable() {
throw UnsupportedError(
"Immutable sets can only be instantiated via constants");
// Dummy constructor to prevent the TFA from concluding that `_indexNullable`
// is never `null`.
@pragma("wasm:entry-point")
_WasmImmutableSet._() {
_indexNullable = null;
}
Set<R> cast<R>() => Set.castFrom<E, R>(this, newSet: _newEmpty);