[vm/tfa] Streamline handling of tear-offs in TFA
When building a summary, instead of adding a raw call for a torn off
method immediatelly, add a call with PropertyGet kind.
Calls of methods with PropertyGet kind are already handled as
they could appear from dynamic calls.
This has the following advantages:
* Duplicated handling of tear-offs is removed. Now only
_DirectInvocation._processFunction handles tear-offs, both from
dynamic and non-dynamic calls.
* This change allow us to more accurately figure out whether the
tear-off was taken from a particular method, as tear-offs of
interface methods are now routed through a dispatchable call which
figures out targets.
Change-Id: I49692577728c03285cb22863c53e4ea3cdd2ab5e
Reviewed-on: https://dart-review.googlesource.com/75386
Reviewed-by: Vyacheslav Egorov <vegorov@google.com>
Commit-Queue: Alexander Markov <alexmarkov@google.com>
diff --git a/pkg/vm/lib/transformations/type_flow/calls.dart b/pkg/vm/lib/transformations/type_flow/calls.dart
index ac69128..958de82 100644
--- a/pkg/vm/lib/transformations/type_flow/calls.dart
+++ b/pkg/vm/lib/transformations/type_flow/calls.dart
@@ -118,9 +118,7 @@
final Member member;
InterfaceSelector(this.member, {CallKind callKind = CallKind.Method})
- : super(callKind) {
- assertx(memberAgreesToCallKind(member));
- }
+ : super(callKind);
@override
int get hashCode => (super.hashCode ^ member.hashCode + 31) & kHashMask;
diff --git a/pkg/vm/lib/transformations/type_flow/summary_collector.dart b/pkg/vm/lib/transformations/type_flow/summary_collector.dart
index 4aaa33d..984521d 100644
--- a/pkg/vm/lib/transformations/type_flow/summary_collector.dart
+++ b/pkg/vm/lib/transformations/type_flow/summary_collector.dart
@@ -632,17 +632,8 @@
final receiver = _visit(node.receiver);
final args = new Args<TypeExpr>([receiver]);
final target = node.target;
- if ((target is Field) || ((target is Procedure) && target.isGetter)) {
- return _makeCall(node,
- new DirectSelector(target, callKind: CallKind.PropertyGet), args);
- } else {
- // Tear-off.
- // TODO(alexmarkov): Consider cleaning up this code as it duplicates
- // processing in DirectInvocation.
- // TODO(alexmarkov): capture receiver type
- _entryPointsListener.addRawCall(new DirectSelector(target));
- return _staticType(node);
- }
+ return _makeCall(
+ node, new DirectSelector(target, callKind: CallKind.PropertyGet), args);
}
@override
@@ -768,15 +759,8 @@
return _makeCall(
node, new DynamicSelector(CallKind.PropertyGet, node.name), args);
}
- if ((target is Field) || ((target is Procedure) && target.isGetter)) {
- return _makeCall(node,
- new InterfaceSelector(target, callKind: CallKind.PropertyGet), args);
- } else {
- // Tear-off.
- // TODO(alexmarkov): capture receiver type
- _entryPointsListener.addRawCall(new InterfaceSelector(target));
- return _staticType(node);
- }
+ return _makeCall(node,
+ new InterfaceSelector(target, callKind: CallKind.PropertyGet), args);
}
@override
@@ -835,17 +819,8 @@
if (target == null) {
return new Type.empty();
} else {
- if ((target is Field) || ((target is Procedure) && target.isGetter)) {
- return _makeCall(node,
- new DirectSelector(target, callKind: CallKind.PropertyGet), args);
- } else {
- // Tear-off.
- // TODO(alexmarkov): Consider cleaning up this code as it duplicates
- // processing in DirectInvocation.
- // TODO(alexmarkov): capture receiver type
- _entryPointsListener.addRawCall(new DirectSelector(target));
- return _staticType(node);
- }
+ return _makeCall(node,
+ new DirectSelector(target, callKind: CallKind.PropertyGet), args);
}
}
@@ -886,14 +861,8 @@
TypeExpr visitStaticGet(StaticGet node) {
final args = new Args<TypeExpr>(const <TypeExpr>[]);
final target = node.target;
- if ((target is Field) || (target is Procedure) && target.isGetter) {
- return _makeCall(node,
- new DirectSelector(target, callKind: CallKind.PropertyGet), args);
- } else {
- // Tear-off.
- _entryPointsListener.addRawCall(new DirectSelector(target));
- return _staticType(node);
- }
+ return _makeCall(
+ node, new DirectSelector(target, callKind: CallKind.PropertyGet), args);
}
@override
diff --git a/pkg/vm/testcases/transformations/type_flow/summary_collector/calls.dart.expect b/pkg/vm/testcases/transformations/type_flow/summary_collector/calls.dart.expect
index deb849c..e5c30ed 100644
--- a/pkg/vm/testcases/transformations/type_flow/summary_collector/calls.dart.expect
+++ b/pkg/vm/testcases/transformations/type_flow/summary_collector/calls.dart.expect
@@ -39,8 +39,9 @@
t7* = _Call get [#lib::A::foo2] (%aa)
t8 = _Narrow (t7 to _T (dart.core::int)+?)
t9 = _Call set [#lib::A::foo3] (%aa, t8)
-t10* = _Call get [#lib::A::foo2] (%aa)
-t11 = _Call dynamic [call] (t10, %a2, %a3, _T ANY?)
+t10* = _Call get [#lib::A::foo1] (%aa)
+t11* = _Call get [#lib::A::foo2] (%aa)
+t12 = _Call dynamic [call] (t11, %a2, %a3, t10)
a4 = _Join [dart.core::Object] (%a4, _T ANY?)
RESULT: a4
------------ #lib::C::dynamicCalls ------------
@@ -71,8 +72,9 @@
t6* = _Call direct get [#lib::B::bar4] (%this)
t7 = _Call direct set [#lib::B::bar3] (%this, t6)
t8* = _Call direct get [#lib::B::bar2] (%this)
-t9* = _Call dynamic [call] (t8, %a2, %a3, _T ANY?)
-a4 = _Join [dart.core::Object] (%a4, t9)
+t9* = _Call direct get [#lib::B::bar1] (%this)
+t10* = _Call dynamic [call] (t8, %a2, %a3, t9)
+a4 = _Join [dart.core::Object] (%a4, t10)
RESULT: a4
------------ #lib::main ------------
diff --git a/pkg/vm/testcases/transformations/type_flow/transformer/tear_off_interface_method.dart b/pkg/vm/testcases/transformations/type_flow/transformer/tear_off_interface_method.dart
index db52bf0..5ce46d8 100644
--- a/pkg/vm/testcases/transformations/type_flow/transformer/tear_off_interface_method.dart
+++ b/pkg/vm/testcases/transformations/type_flow/transformer/tear_off_interface_method.dart
@@ -11,11 +11,12 @@
}
class B extends A {
- int foo() => 1 + knownResult().foo(); // Should have metadata.
+ int foo() => 1 + knownResult().bar(); // Should have metadata.
+ int bar() => 3;
}
class C implements A {
- int foo() => 2 + knownResult().foo(); // Should be unreachable.
+ int foo() => 2 + knownResult().bar(); // Should be unreachable.
}
class TearOffInterfaceMethod {
diff --git a/pkg/vm/testcases/transformations/type_flow/transformer/tear_off_interface_method.dart.expect b/pkg/vm/testcases/transformations/type_flow/transformer/tear_off_interface_method.dart.expect
index 18c3870..4cf2073 100644
--- a/pkg/vm/testcases/transformations/type_flow/transformer/tear_off_interface_method.dart.expect
+++ b/pkg/vm/testcases/transformations/type_flow/transformer/tear_off_interface_method.dart.expect
@@ -13,7 +13,9 @@
: super self::A::•()
;
method foo() → core::int
- return [@vm.direct-call.metadata=dart.core::_IntegerImplementation::+] [@vm.inferred-type.metadata=int?] 1.{core::num::+}([@vm.direct-call.metadata=#lib::B::foo] [@vm.inferred-type.metadata=int?] [@vm.inferred-type.metadata=#lib::B] self::knownResult().foo() as{TypeError} core::num) as{TypeError} core::int;
+ return [@vm.direct-call.metadata=dart.core::_IntegerImplementation::+] [@vm.inferred-type.metadata=int?] 1.{core::num::+}([@vm.direct-call.metadata=#lib::B::bar] [@vm.inferred-type.metadata=int] [@vm.inferred-type.metadata=#lib::B] self::knownResult().bar() as{TypeError} core::num) as{TypeError} core::int;
+ method bar() → core::int
+ return 3;
}
class TearOffInterfaceMethod extends core::Object {
field dynamic bazz;