[dart2wasm] Implement identityHashCode via br_table.

This saves the space for the `_identityHashCode` method in the
dispatch table and allows customizing `identityHashCode` for classes
not in `dart:core`.

Change-Id: I829fb0f53dea1f3baf92e12079b9772ce2ff8c2a
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/292820
Commit-Queue: Aske Simon Christensen <askesc@google.com>
Reviewed-by: Joshua Litt <joshualitt@google.com>
Auto-Submit: Aske Simon Christensen <askesc@google.com>
This commit is contained in:
Aske Simon Christensen
2023-04-13 16:45:14 +00:00
committed by Commit Queue
parent 2954986a7e
commit d8b53d97ff
9 changed files with 70 additions and 7 deletions
+5
View File
@@ -452,6 +452,11 @@ class ClassInfoCollector {
// parameters.
_initialize(translator.typeClass);
// Initialize value classes to make sure they have low class IDs.
for (Class cls in translator.valueClasses.keys) {
_initialize(cls);
}
// Initialize masquerade classes to make sure they have low class IDs.
for (Class cls in _masquerades.values) {
_initialize(cls);
+51
View File
@@ -1305,6 +1305,57 @@ class Intrinsifier {
return true;
}
if (member.enclosingLibrary == translator.coreTypes.coreLibrary &&
name == "identityHashCode") {
final w.Local arg = paramLocals[0];
final w.Local nonNullArg =
function.addLocal(translator.topInfo.nonNullableType);
final List<int> classIds = translator.valueClasses.keys
.map((cls) => translator.classInfo[cls]!.classId)
.toList()
..sort();
// If the argument is `null`, return the hash code of `null`.
final w.Label notNull =
b.block(const [], [translator.topInfo.nonNullableType]);
b.local_get(arg);
b.br_on_non_null(notNull);
b.i64_const(null.hashCode);
b.return_();
b.end(); // notNull
b.local_set(nonNullArg);
// Branch on class ID.
final w.Label defaultLabel = b.block();
final List<w.Label> labels =
List.generate(classIds.length, (_) => b.block());
b.local_get(nonNullArg);
b.struct_get(translator.topInfo.struct, FieldIndex.classId);
int labelIndex = 0;
final List<w.Label> targets = List.generate(classIds.last + 1, (id) {
return id == classIds[labelIndex] ? labels[labelIndex++] : defaultLabel;
});
b.br_table(targets, defaultLabel);
// For value classes, dispatch to their `hashCode` implementation.
for (final int id in classIds.reversed) {
final Class cls = translator.valueClasses[translator.classes[id].cls!]!;
final Procedure hashCodeProcedure =
cls.procedures.firstWhere((p) => p.name.text == "hashCode");
b.end(); // Jump target for class ID
b.local_get(nonNullArg);
codeGen.call(hashCodeProcedure.reference);
b.return_();
}
// For all other classes, dispatch to the `hashCode` implementation in
// `Object`.
b.end(); // defaultLabel
b.local_get(nonNullArg);
codeGen.call(translator.objectHashCode.reference);
return true;
}
// _typeArguments
if (member.name.text == "_typeArguments") {
Class cls = member.enclosingClass!;
+2
View File
@@ -160,6 +160,8 @@ mixin KernelNodes {
"dart:collection", "_HashAbstractImmutableBase", "get:_indexNullable");
// dart:core various procedures
late final Procedure objectHashCode =
index.getProcedure("dart:core", "Object", "get:hashCode");
late final Procedure objectNoSuchMethod =
index.getProcedure("dart:core", "Object", "noSuchMethod");
late final Procedure objectGetTypeArguments =
+11
View File
@@ -151,6 +151,17 @@ class Translator with KernelNodes {
w.NumType.f64: boxedDoubleClass,
};
/// Classes whose identity hash code is their hash code rather than the
/// identity hash code field in the struct. Each implementation class maps to
/// the class containing the implementation of its `hashCode` getter.
late final Map<Class, Class> valueClasses = {
boxedIntClass: boxedIntClass,
boxedDoubleClass: boxedDoubleClass,
boxedBoolClass: coreTypes.boolClass,
oneByteStringClass: stringBaseClass,
twoByteStringClass: stringBaseClass,
};
/// Type for vtable entries for dynamic calls. These entries are used in
/// dynamic invocations and `Function.apply`.
late final w.FunctionType dynamicCallVtableEntryFunctionType =
-1
View File
@@ -68,7 +68,6 @@ final class _BoxedDouble extends double {
static const int _mantissaMask = 0x000FFFFFFFFFFFFF;
int get hashCode => _doubleHashCode(this);
int get _identityHashCode => _doubleHashCode(this);
static int _doubleHashCode(double value) {
const int maxInt = 0x7FFFFFFFFFFFFFFF;
@@ -8,5 +8,4 @@ part of "core_patch.dart";
external bool identical(Object? a, Object? b);
@patch
int identityHashCode(Object? object) =>
object == null ? Null._HASH_CODE : object._identityHashCode;
external int identityHashCode(Object? object);
-1
View File
@@ -517,7 +517,6 @@ final class _BoxedInt extends int {
}
int get hashCode => _intHashCode(this);
int get _identityHashCode => _intHashCode(this);
static int _intHashCode(int value) {
const int magic = 0x2D51;
@@ -32,7 +32,6 @@ class Object {
@patch
int get hashCode => _objectHashCode(this);
int get _identityHashCode => _objectHashCode(this);
/// Concrete subclasses of [Object] will have overrides of [_typeArguments]
/// which return their type arguments.
@@ -105,8 +105,6 @@ abstract final class _StringBase implements String {
int _computeHashCode();
int get _identityHashCode => hashCode;
bool get _isOneByte {
// Alternatively return false and override it on one-byte string classes.
return this is _OneByteString;