[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:
committed by
Commit Queue
parent
2954986a7e
commit
d8b53d97ff
@@ -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);
|
||||
|
||||
@@ -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!;
|
||||
|
||||
@@ -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 =
|
||||
|
||||
@@ -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 =
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user