[dart2wasm] Fix instantiation closure equality

We can't generate a virtual call to `Object.==` in generated code as
`Object.==` may not be added to the dispatch table, even with
`@pragma(wasm:entry-point)`.

Instead this adds a top-level `_runtimeTypeEquals` function that calls
`==` on the `_Type` argument. Effectively this forces adding `_Type.==`
to the dispatch table and calls it virtually.

Fixes #54926.

Change-Id: Ice3306ed00f66c8abedb3ef11b58c15296457eb0
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/352900
Reviewed-by: Martin Kustermann <kustermann@google.com>
Commit-Queue: Ömer Ağacan <omersa@google.com>
This commit is contained in:
Ömer Sinan Ağacan
2024-02-15 17:33:01 +00:00
committed by Commit Queue
parent d6baf58b74
commit 2bdcfb7035
4 changed files with 40 additions and 13 deletions
+2 -13
View File
@@ -704,19 +704,8 @@ class ClosureLayouter extends RecursiveVisitor {
b.struct_get(contextStructType, typeFieldIdx);
b.local_get(otherContextLocal);
b.struct_get(contextStructType, typeFieldIdx);
// Virtual call to `Object.==`
final selector = translator.dispatchTable
.selectorForTarget(translator.coreTypes.objectEquals.reference);
final selectorOffset = selector.offset!;
b.local_get(thisContextLocal);
b.struct_get(contextStructType, typeFieldIdx);
b.struct_get(translator.topInfo.struct, FieldIndex.classId);
if (selectorOffset != 0) {
b.i32_const(selectorOffset);
b.i32_add();
}
b.call_indirect(selector.signature, translator.dispatchTable.wasmTable);
b.call(translator.functions
.getFunction(translator.runtimeTypeEquals.reference));
b.if_();
}
+2
View File
@@ -215,6 +215,8 @@ mixin KernelNodes {
index.getProcedure("dart:_string", "StringBase", "_interpolate");
late final Procedure truncDiv =
index.getProcedure("dart:core", "_BoxedInt", "_truncDiv");
late final Procedure runtimeTypeEquals =
index.getTopLevelProcedure("dart:core", "_runtimeTypeEquals");
// dart:core invocation/exception procedures
late final Procedure invocationGetterFactory =
+8
View File
@@ -1405,3 +1405,11 @@ _Type _getMasqueradedRuntimeTypeNullable(Object? object) =>
external bool _isObjectClassId(int classId);
external bool _isClosureClassId(int classId);
external bool _isRecordClassId(int classId);
// Used by the generated code to compare types captured by instantiation
// closures. Because we don't have a way of forcing adding a member the
// dispatch table (like the entry-point pragma) we can't generate a virtual
// call to `_Type.==` directly in the generated code.
@pragma("wasm:entry-point")
@pragma("wasm:prefer-inline")
bool _runtimeTypeEquals(_Type t1, _Type t2) => t1 == t2;
+28
View File
@@ -0,0 +1,28 @@
// Copyright (c) 2024, 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.
// Instantiation closure equality check used to generate virtual call to
// `Object.==` when comparing captured types.
//
// When the program is small, `Object.==` is sometimes not added to the
// dispatch table, which causes a crash.
//
// To avoid making the program larger (which can make `Object.==` available for
// virtual calls and hide the bug), this does not use the `expect` library.
class C {
void f<T>(T t) {
print(t);
}
}
void main() {
var f = C().f;
var f1 = f<int>;
var f2 = f<int>;
if (identical(f1, f2) || f1 != f2) {
throw '';
}
}