[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:
committed by
Commit Queue
parent
d6baf58b74
commit
2bdcfb7035
@@ -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_();
|
||||
}
|
||||
|
||||
|
||||
@@ -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 =
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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 '';
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user