Open askeksa-google opened 4 years ago
@askeksa-google I'm not able to reproduce this on the tip of the tree.
There are no Dead instance call executed.
strings in disassembly, and if I add UNREACHABLE()
diff --git a/runtime/vm/compiler/aot/aot_call_specializer.cc b/runtime/vm/compiler/aot/aot_call_specializer.cc
index 9e52a228ad..32a9f52e8c 100644
--- a/runtime/vm/compiler/aot/aot_call_specializer.cc
+++ b/runtime/vm/compiler/aot/aot_call_specializer.cc
@@ -1294,6 +1294,7 @@ void AotCallSpecializer::TryReplaceWithDispatchTableCall(
if (selector == nullptr) {
// Target functions were removed by tree shaking. This call is dead code,
// or the receiver is always null.
+ UNREACHABLE();
#if defined(DEBUG)
AddCheckNull(receiver->CopyWithType(Z), call->function_name(),
DeoptId::kNone, call->env(), call);
It isn't hit when compiling dart2js.
Right, the reproduction description was incomplete. The dead calls only show up once the unused table selector elimination is activated.
There is currently 1 such dead instance call when compiling dart2js. It occurs inside closure in _HttpClient._findCredentials
:
Here is the smaller repro:
// @dart=2.10
class A {
bool get foo1 => true;
int get foo2 => 42;
}
@pragma('vm:never-inline')
doTest(v) {
(value) {
A a = value as A;
if (a.foo1) {
print(a.foo2);
}
}.call(v);
}
void main() {
doTest(null);
}
The problem is that in most cases TFA propagates types without specializing them. In the smaller repro, after value as A
cast the type of a
is (A+)?
(nullable subtypes of A
). After the first call a.foo1
this value is narrowed to A+
(non-nullable subtypes of A
). It is in fact empty, as instances of A
are not allocated, but analysis doesn't know that without calculating type specialization.
When analyzing a.foo2
, in order to determine if it is reachable, analysis looks at types of arguments and checks if any of them is empty. At that point A+
is considered non-empty and call site is marked as reachable.
Sometimes, the table dispatch transformation encounters instance calls for which no targets exist in the program. This happens when the TFA tree shaker has deemed all of those targets unreachable but hasn't removed the calls to them. Logically, such a call is itself either unreachable, or the receiver is always null.
In debug mode, the table dispatch transformation inserts a null check followed by a breakpoint with a comment saying
Dead instance call executed.
. Searching for that comment in the disassembly reveals the offending calls. For instance, runningreveals 7 such callsites.