[dart2wasm] Fix unreachable instance call issue

When a call is unreachable we used to generate sometimes a block with no
outputs, but callers expected an output which they may drop. That caused
stack discipline mismatch.

Instead we should simply emit an unreachable and tell the caller there's
no value.

Issue https://github.com/dart-lang/sdk/issues/63454

Change-Id: I81be6729fd578e237c4e6483539a9d53a9ed355e
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/506960
Commit-Queue: Martin Kustermann <kustermann@google.com>
Reviewed-by: Slava Egorov <vegorov@google.com>
This commit is contained in:
Martin Kustermann
2026-05-28 03:37:13 -07:00
committed by dart-scoped@luci-project-accounts.iam.gserviceaccount.com
parent 6c88c6f2ba
commit 5423762c21
3 changed files with 22 additions and 10 deletions
+1 -6
View File
@@ -2047,13 +2047,8 @@ abstract class AstCodeGenerator
" at ${node.location}",
);
pushArguments(signature, selector.paramInfo);
for (int i = 0; i < signature.inputs.length; ++i) {
b.drop();
}
b.block(const [], signature.outputs);
b.unreachable();
b.end();
return translator.outputOrVoid(signature.outputs);
return voidMarker;
}
if (directCall) {
final target = translator.getFunctionEntry(
+2 -4
View File
@@ -245,10 +245,8 @@ class SelectorInfo {
// This happens if the selector doesn't have any targets. Any call site of
// such a selector is unreachable. Though such call sites still have to
// evaluate receiver and arguments. Doing so requires the signature. So we
// create a dummy signature with top types. Receivers specifically should
// be non-nullable since we must be invoking a selector on some object.
assert(!isReceiver);
return isReceiver ? translator.topTypeNonNullable : translator.topType;
// create a dummy signature with top types.
return translator.topType;
}
if (!ensureBoxed && types.length == 1 && types.single.isPrimitive) {
// Unboxed primitive.
+19
View File
@@ -0,0 +1,19 @@
// Copyright (c) 2026, 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.
main() {
print('main start');
final value = Object();
final map = <Unused, int>{};
for (final entry in map.entries) {
print('before');
entry.key.foo = value;
print('after');
}
print('main end');
}
class Unused {
Object? foo;
}