[vm/aot/tfa] More precise handling of constructor invocations

Avoid marking class as allocated immediately when building a summary
and visiting ConstructorInvocation node. Instead, mark class as
allocated later when interpreting Call which corresponds to
a constructor invocation. This is more precise if an argument of
the constructor Call is evaluated to an EmptyType (which means
that the constructor invocation is unreachable). Otherwise it is
possible that class is marked as allocated but its constructors
are not used.

Flutter gallery AOT snapshot size:
* release mode -0.36% (both armv7 and armv8)
* release-sizeopt mode -0.39% (both armv7 and armv8)

TEST=existing tests

Change-Id: I51bdf2f1a60dda88bc2c788339ee4d4ab79d8cd2
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/205802
Reviewed-by: Slava Egorov <vegorov@google.com>
Reviewed-by: Martin Kustermann <kustermann@google.com>
Commit-Queue: Alexander Markov <alexmarkov@google.com>
diff --git a/pkg/vm/lib/transformations/type_flow/summary.dart b/pkg/vm/lib/transformations/type_flow/summary.dart
index b8033f9..002acc1 100644
--- a/pkg/vm/lib/transformations/type_flow/summary.dart
+++ b/pkg/vm/lib/transformations/type_flow/summary.dart
@@ -18,6 +18,7 @@
   Type applyCall(Call callSite, Selector selector, Args<Type> args,
       {bool isResultUsed});
   void typeCheckTriggered();
+  void addAllocatedClass(Class c);
 }
 
 /// Base class for all statements in a summary.
@@ -230,12 +231,16 @@
   final Args<TypeExpr> args;
   final Type staticResultType;
 
-  Call(this.selector, this.args, this.staticResultType) {
+  Call(this.selector, this.args, this.staticResultType,
+      bool isInstanceCreation) {
     // TODO(sjindel/tfa): Support inferring unchecked entry-points for dynamic
     // and direct calls as well.
     if (selector is DynamicSelector || selector is DirectSelector) {
       setUseCheckedEntry();
     }
+    if (isInstanceCreation) {
+      setInstanceCreation();
+    }
   }
 
   @override
@@ -260,12 +265,18 @@
     if (selector is! DirectSelector) {
       _observeReceiverType(argTypes[0], typeHierarchy);
     }
+    if (isInstanceCreation) {
+      callHandler
+          .addAllocatedClass((argTypes[0] as ConcreteType).cls.classNode);
+    }
     final Stopwatch timer = kPrintTimings ? (new Stopwatch()..start()) : null;
     Type result = callHandler.applyCall(
         this, selector, new Args<Type>(argTypes, names: args.names),
         isResultUsed: isResultUsed);
     summary.calleeTime += kPrintTimings ? timer.elapsedMicroseconds : 0;
-    if (isResultUsed) {
+    if (isInstanceCreation) {
+      result = argTypes[0];
+    } else if (isResultUsed) {
       if (staticResultType != null) {
         result = result.intersection(staticResultType, typeHierarchy);
       }
@@ -287,6 +298,7 @@
   static const int kReachable = (1 << 4);
   static const int kUseCheckedEntry = (1 << 5);
   static const int kReceiverMayBeInt = (1 << 6);
+  static const int kInstanceCreation = (1 << 7);
 
   Member _monomorphicTarget;
 
@@ -306,6 +318,8 @@
 
   bool get useCheckedEntry => (_flags & kUseCheckedEntry) != 0;
 
+  bool get isInstanceCreation => (_flags & kInstanceCreation) != 0;
+
   Type get resultType => _resultType;
 
   void setUseCheckedEntry() {
@@ -320,6 +334,10 @@
     _flags |= kReachable;
   }
 
+  void setInstanceCreation() {
+    _flags |= kInstanceCreation;
+  }
+
   void setPolymorphic() {
     _flags = (_flags & ~kMonomorphic) | kPolymorphic;
     _monomorphicTarget = null;
diff --git a/pkg/vm/lib/transformations/type_flow/summary_collector.dart b/pkg/vm/lib/transformations/type_flow/summary_collector.dart
index fac8e00..362bc5c 100644
--- a/pkg/vm/lib/transformations/type_flow/summary_collector.dart
+++ b/pkg/vm/lib/transformations/type_flow/summary_collector.dart
@@ -127,8 +127,13 @@
           // This pattern may appear after approximations during summary
           // normalization (so it's not enough to handle it in _makeNarrow).
           final arg = st.arg;
-          if (arg is Type && st.type == const AnyType()) {
-            return (arg is NullableType) ? arg.baseType : arg;
+          if (st.type is AnyType) {
+            if (arg is Type) {
+              return (arg is NullableType) ? arg.baseType : arg;
+            }
+            if (arg is Call && arg.isInstanceCreation) {
+              return arg;
+            }
           }
         }
 
@@ -1073,7 +1078,8 @@
     _declareVariable(decl, _typesBuilder.fromStaticType(decl.type, true));
   }
 
-  Call _makeCall(TreeNode node, Selector selector, Args<TypeExpr> args) {
+  Call _makeCall(TreeNode node, Selector selector, Args<TypeExpr> args,
+      {bool isInstanceCreation = false}) {
     Type staticResultType = null;
     Member target;
     if (selector is DirectSelector) {
@@ -1086,7 +1092,7 @@
         node is Expression) {
       staticResultType = _staticType(node);
     }
-    Call call = new Call(selector, args, staticResultType);
+    Call call = new Call(selector, args, staticResultType, isInstanceCreation);
     _summary.add(call);
     if (node != null) {
       callSites[node] = call;
@@ -1109,6 +1115,8 @@
       if (type == const AnyType()) {
         return (arg is NullableType) ? arg.baseType : arg;
       }
+    } else if (arg is Call && arg.isInstanceCreation && type is AnyType) {
+      return arg;
     }
     if (type is NullableType && type.baseType == const AnyType()) {
       return arg;
@@ -1495,12 +1503,12 @@
   @override
   TypeExpr visitConstructorInvocation(ConstructorInvocation node) {
     ConcreteType klass =
-        _entryPointsListener.addAllocatedClass(node.constructedType.classNode);
+        _typesBuilder.getTFClass(node.constructedType.classNode).concreteType;
     TypeExpr receiver =
         _translator.instantiateConcreteType(klass, node.arguments.types);
     final args = _visitArguments(receiver, node.arguments);
-    _makeCall(node, new DirectSelector(node.target), args);
-    return receiver;
+    return _makeCall(node, new DirectSelector(node.target), args,
+        isInstanceCreation: true);
   }
 
   @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 bbd410a..b9d7b32 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
@@ -34,8 +34,8 @@
 %a2 = _Parameter #2 [_T (dart.core::Object)+?]
 %a3 = _Parameter #3 [_T (dart.core::Object)+?]
 %a4 = _Parameter #4 [_T (dart.core::Object)+?]
-t5 = _Call direct [#lib::B.] (_T (#lib::B))
-t6 = _Call [#lib::A.foo1] (%aa, _T (#lib::B))
+t5* = _Call direct [#lib::B.] (_T (#lib::B))
+t6 = _Call [#lib::A.foo1] (%aa, t5)
 t7 = _Narrow (%aa to _T ANY)
 t8* = _Call get [#lib::A.foo2] (t7)
 t9 = _TypeCheck (t8 against dart.core::int*) (for aa.{#lib::A.foo2} as dart.core::int*)
@@ -50,8 +50,8 @@
 %a2 = _Parameter #2 [_T (dart.core::Object)+?]
 %a3 = _Parameter #3 [_T (dart.core::Object)+?]
 %a4 = _Parameter #4 [_T (dart.core::Object)+?]
-t5 = _Call direct [#lib::B.] (_T (#lib::B))
-t6 = _Call dynamic [foo1] (%aa, _T (#lib::B))
+t5* = _Call direct [#lib::B.] (_T (#lib::B))
+t6 = _Call dynamic [foo1] (%aa, t5)
 t7 = _Narrow (%aa to _T ANY)
 t8* = _Call dynamic get [foo2] (t7)
 t9 = _Call dynamic set [foo3] (t7, t8)
diff --git a/pkg/vm/testcases/transformations/type_flow/summary_collector/class_generics_basic.dart.expect b/pkg/vm/testcases/transformations/type_flow/summary_collector/class_generics_basic.dart.expect
index 6f36339..9a4772b 100644
--- a/pkg/vm/testcases/transformations/type_flow/summary_collector/class_generics_basic.dart.expect
+++ b/pkg/vm/testcases/transformations/type_flow/summary_collector/class_generics_basic.dart.expect
@@ -6,8 +6,8 @@
 %this = _Parameter #0 [_T (#lib::C)+]
 t1 = _Extract (%this[#lib::C/0]*)
 t2 = _CreateConcreteType (#lib::D @ (t1))
-t3 = _Call direct [#lib::D.] (t2)
-RESULT: t2
+t3* = _Call direct [#lib::D.] (t2)
+RESULT: t3
 ------------ C.id1 ------------
 %this = _Parameter #0 [_T (#lib::C)+]
 %x = _Parameter #1
@@ -36,14 +36,14 @@
 %this = _Parameter #0 [_T (#lib::E)+]
 t1 = _Extract (%this[#lib::E/0]*)
 t2 = _CreateConcreteType (#lib::D @ (t1))
-t3 = _Call direct [#lib::D.] (t2)
-RESULT: t2
+t3* = _Call direct [#lib::D.] (t2)
+RESULT: t3
 ------------ E.baz ------------
 %this = _Parameter #0 [_T (#lib::E)+]
 t1 = _Extract (%this[#lib::E/1]*)
 t2 = _CreateConcreteType (#lib::D @ (t1))
-t3 = _Call direct [#lib::D.] (t2)
-RESULT: t2
+t3* = _Call direct [#lib::D.] (t2)
+RESULT: t3
 ------------ X. ------------
 %this = _Parameter #0 [_T (#lib::X)+]
 t1 = _Call direct [dart.core::Object.] (%this)
@@ -88,21 +88,21 @@
 t5 = _TypeCheck (%x against t4) (for #lib::K<#lib::I<#lib::C2.T*>*>* x;)
 RESULT: t5
 ------------ main ------------
-t0 = _Call direct [#lib::C.] (_T (#lib::C<dart.core::int*>))
-t1 = _Call [#lib::C.foo] (_T (#lib::C<dart.core::int*>))
-t2 = _Call direct [#lib::E.] (_T (#lib::E<dart.core::int*, dart.core::String*>))
-t3 = _Call [#lib::E.foo] (_T (#lib::E<dart.core::int*, dart.core::String*>))
-t4 = _Call direct [#lib::E.] (_T (#lib::E<dart.core::int*, dart.core::String*>))
-t5 = _Call [#lib::E.bar] (_T (#lib::E<dart.core::int*, dart.core::String*>))
-t6 = _Call direct [#lib::E.] (_T (#lib::E<dart.core::int*, dart.core::String*>))
-t7* = _Call [#lib::E.baz] (_T (#lib::E<dart.core::int*, dart.core::String*>))
-t8 = _Call direct [#lib::C.] (_T (#lib::C<#lib::Y*>))
-t9 = _Call direct [#lib::Y.] (_T (#lib::Y))
-t10 = _Call [#lib::C.id1] (_T (#lib::C<#lib::Y*>), _T (#lib::Y))
-t11 = _Call direct [#lib::Z.] (_T (#lib::Z))
-t12 = _Call [#lib::C.id2] (_T (#lib::C<#lib::Y*>), _T (#lib::Z))
-t13 = _Call direct [#lib::C2.] (_T (#lib::C2<dart.core::num*>))
-t14 = _Call [#lib::C2.id3] (_T (#lib::C2<dart.core::num*>), _T (dart.core::_Double, 3.0))
-t15 = _Call direct [#lib::K.] (_T (#lib::K<#lib::J*>))
-t16 = _Call [#lib::C2.id4] (_T (#lib::C2<dart.core::num*>), _T (#lib::K<#lib::J*>))
+t0* = _Call direct [#lib::C.] (_T (#lib::C<dart.core::int*>))
+t1 = _Call [#lib::C.foo] (t0)
+t2* = _Call direct [#lib::E.] (_T (#lib::E<dart.core::int*, dart.core::String*>))
+t3 = _Call [#lib::E.foo] (t2)
+t4* = _Call direct [#lib::E.] (_T (#lib::E<dart.core::int*, dart.core::String*>))
+t5 = _Call [#lib::E.bar] (t4)
+t6* = _Call direct [#lib::E.] (_T (#lib::E<dart.core::int*, dart.core::String*>))
+t7* = _Call [#lib::E.baz] (t6)
+t8* = _Call direct [#lib::C.] (_T (#lib::C<#lib::Y*>))
+t9* = _Call direct [#lib::Y.] (_T (#lib::Y))
+t10 = _Call [#lib::C.id1] (t8, t9)
+t11* = _Call direct [#lib::Z.] (_T (#lib::Z))
+t12 = _Call [#lib::C.id2] (t8, t11)
+t13* = _Call direct [#lib::C2.] (_T (#lib::C2<dart.core::num*>))
+t14 = _Call [#lib::C2.id3] (t13, _T (dart.core::_Double, 3.0))
+t15* = _Call direct [#lib::K.] (_T (#lib::K<#lib::J*>))
+t16 = _Call [#lib::C2.id4] (t13, t15)
 RESULT: t7
diff --git a/pkg/vm/testcases/transformations/type_flow/summary_collector/class_generics_case1.dart.expect b/pkg/vm/testcases/transformations/type_flow/summary_collector/class_generics_case1.dart.expect
index 0eea29d..ad64881 100644
--- a/pkg/vm/testcases/transformations/type_flow/summary_collector/class_generics_case1.dart.expect
+++ b/pkg/vm/testcases/transformations/type_flow/summary_collector/class_generics_case1.dart.expect
@@ -6,8 +6,8 @@
 %K = _Parameter #0
 %V = _Parameter #1
 t2 = _CreateConcreteType (#lib::_NotRealHashMap @ (%K, %V))
-t3 = _Call direct [#lib::_NotRealHashMap.] (t2)
-RESULT: t2
+t3* = _Call direct [#lib::_NotRealHashMap.] (t2)
+RESULT: t3
 ------------ _NotRealHashMap. ------------
 %this = _Parameter #0 [_T (#lib::_NotRealHashMap)+]
 t1 = _Call direct [dart.core::Object.] (%this)
@@ -37,8 +37,8 @@
 t1* = _Call direct [#lib::MockHashMap.] (#lib::Element*, dart.core::Object*)
 RESULT: t1
 ------------ main ------------
-t0 = _Call direct [#lib::InheritedElement.] (_T (#lib::InheritedElement))
-t1 = _Call [#lib::InheritedElement.setDependencies] (_T (#lib::InheritedElement), _T (#lib::InheritedElement), _T (dart.core::_Smi, 0))
-t2 = _Call direct [#lib::Element.] (_T (#lib::Element))
-t3 = _Call [#lib::InheritedElement.setDependencies] (_T (#lib::InheritedElement), _T (#lib::Element), _T {}?)
+t0* = _Call direct [#lib::InheritedElement.] (_T (#lib::InheritedElement))
+t1 = _Call [#lib::InheritedElement.setDependencies] (t0, t0, _T (dart.core::_Smi, 0))
+t2* = _Call direct [#lib::Element.] (_T (#lib::Element))
+t3 = _Call [#lib::InheritedElement.setDependencies] (t0, t2, _T {}?)
 RESULT: _T {}?
diff --git a/pkg/vm/testcases/transformations/type_flow/summary_collector/control_flow.dart.expect b/pkg/vm/testcases/transformations/type_flow/summary_collector/control_flow.dart.expect
index d0227dd..e434ee3 100644
--- a/pkg/vm/testcases/transformations/type_flow/summary_collector/control_flow.dart.expect
+++ b/pkg/vm/testcases/transformations/type_flow/summary_collector/control_flow.dart.expect
@@ -47,53 +47,53 @@
 ------------ sequence ------------
 t0 = _Call direct [#lib::C1.] (_T (#lib::C1))
 t1 = _Call direct [#lib::C2.] (_T (#lib::C2))
-t2 = _Call direct [#lib::C3.] (_T (#lib::C3))
-RESULT: _T (#lib::C3)
+t2* = _Call direct [#lib::C3.] (_T (#lib::C3))
+RESULT: t2
 ------------ if1 ------------
 %cond = _Parameter #0 [_T (dart.core::bool)+?]
-t1 = _Call direct [#lib::C1.] (_T (#lib::C1))
-t2 = _Call direct [#lib::C2.] (_T (#lib::C2))
-t3 = _Call direct [#lib::foo] (_T (#lib::C2))
-x_0 = _Join [dynamic] (_T (#lib::C2), _T (#lib::C1))
+t1* = _Call direct [#lib::C1.] (_T (#lib::C1))
+t2* = _Call direct [#lib::C2.] (_T (#lib::C2))
+t3 = _Call direct [#lib::foo] (t2)
+x_0 = _Join [dynamic] (t2, t1)
 RESULT: x_0
 ------------ if2 ------------
 %cond1 = _Parameter #0 [_T (dart.core::bool)+?]
 %cond2 = _Parameter #1 [_T (dart.core::bool)+?]
-t2 = _Call direct [#lib::C1.] (_T (#lib::C1))
-t3 = _Call direct [#lib::foo] (_T (#lib::C1))
-t4 = _Call direct [#lib::C2.] (_T (#lib::C2))
-t5 = _Call direct [#lib::bar] (_T (#lib::C2))
-x_0 = _Join [dynamic] (_T (#lib::C1), _T (#lib::C2))
+t2* = _Call direct [#lib::C1.] (_T (#lib::C1))
+t3 = _Call direct [#lib::foo] (t2)
+t4* = _Call direct [#lib::C2.] (_T (#lib::C2))
+t5 = _Call direct [#lib::bar] (t4)
+x_0 = _Join [dynamic] (t2, t4)
 RESULT: x_0
 ------------ if3 ------------
 %cond1 = _Parameter #0 [_T (dart.core::bool)+?]
 %cond2 = _Parameter #1 [_T (dart.core::bool)+?]
 t2 = _Call direct [#lib::C1.] (_T (#lib::C1))
-t3 = _Call direct [#lib::C2.] (_T (#lib::C2))
-t4* = _Call direct [#lib::foo] (_T (#lib::C2))
+t3* = _Call direct [#lib::C2.] (_T (#lib::C2))
+t4* = _Call direct [#lib::foo] (t3)
 t5 = _TypeCheck (t4 against dart.core::bool*) (for #lib::foo(x = new #lib::C2()) as dart.core::bool*)
-t6 = _Call direct [#lib::C3.] (_T (#lib::C3))
-t7* = _Call direct [#lib::foo] (_T (#lib::C3))
+t6* = _Call direct [#lib::C3.] (_T (#lib::C3))
+t7* = _Call direct [#lib::foo] (t6)
 t8 = _TypeCheck (t7 against dart.core::bool*) (for #lib::foo(x = new #lib::C3()) as dart.core::bool*)
-x_0 = _Join [dynamic] (_T (#lib::C2), _T (#lib::C3))
+x_0 = _Join [dynamic] (t3, t6)
 t10 = _Call direct [#lib::bar] (x_0)
 RESULT: x_0
 ------------ if4 ------------
 t0 = _Call direct [#lib::C1.] (_T (#lib::C1))
-t1 = _Call direct [#lib::C2.] (_T (#lib::C2))
-t2* = _Call direct [#lib::foo] (_T (#lib::C2))
+t1* = _Call direct [#lib::C2.] (_T (#lib::C2))
+t2* = _Call direct [#lib::foo] (t1)
 t3 = _TypeCheck (t2 against dart.core::bool*) (for #lib::foo(x = new #lib::C2()) as dart.core::bool*)
-t4 = _Call direct [#lib::C3.] (_T (#lib::C3))
-t5* = _Call direct [#lib::foo] (_T (#lib::C3))
+t4* = _Call direct [#lib::C3.] (_T (#lib::C3))
+t5* = _Call direct [#lib::foo] (t4)
 t6 = _TypeCheck (t5 against dart.core::bool*) (for #lib::foo(x = new #lib::C3()) as dart.core::bool*)
-t7 = _Call direct [#lib::bar] (_T (#lib::C3))
-x_0 = _Join [dynamic] (_T (#lib::C2), _T (#lib::C3))
+t7 = _Call direct [#lib::bar] (t4)
+x_0 = _Join [dynamic] (t1, t4)
 RESULT: x_0
 ------------ if5 ------------
 %cond = _Parameter #0 [_T (dart.core::bool)+?]
-t1 = _Call direct [#lib::C1.] (_T (#lib::C1))
+t1* = _Call direct [#lib::C1.] (_T (#lib::C1))
 t2 = _Call direct [#lib::C2.] (_T (#lib::C2))
-t3 = _Call direct [#lib::foo] (_T (#lib::C1))
+t3 = _Call direct [#lib::foo] (t1)
 RESULT: _T {}?
 ------------ if6a ------------
 %x = _Parameter #0 [_T (dart.core::bool)+?]
@@ -136,14 +136,14 @@
 %cond1 = _Parameter #0 [_T (dart.core::bool)+?]
 %cond2 = _Parameter #1 [_T (dart.core::bool)+?]
 t2 = _Call direct [#lib::C1.] (_T (#lib::C1))
-t3 = _Call direct [#lib::C2.] (_T (#lib::C2))
-t4* = _Call direct [#lib::foo] (_T (#lib::C2))
+t3* = _Call direct [#lib::C2.] (_T (#lib::C2))
+t4* = _Call direct [#lib::foo] (t3)
 t5 = _TypeCheck (t4 against dart.core::bool*) (for #lib::foo(x = new #lib::C2()) as dart.core::bool*)
-t6 = _Call direct [#lib::C3.] (_T (#lib::C3))
-t7 = _Call direct [#lib::C4.] (_T (#lib::C4))
-x_0 = _Join [dynamic] (_T (#lib::C3), _T (#lib::C4))
+t6* = _Call direct [#lib::C3.] (_T (#lib::C3))
+t7* = _Call direct [#lib::C4.] (_T (#lib::C4))
+x_0 = _Join [dynamic] (t6, t7)
 t9 = _Call direct [#lib::foo] (x_0)
-t10 = _Join [dart.core::Object*] (_T (#lib::C3), _T (#lib::C4))
+t10 = _Join [dart.core::Object*] (t6, t7)
 t11 = _Narrow (t10 to _T (dart.core::Object)+?)
 t12 = _Call direct [#lib::bar] (t11)
 RESULT: _T {}?
@@ -151,125 +151,125 @@
 %cond1 = _Parameter #0 [_T (dart.core::bool)+?]
 %cond2 = _Parameter #1 [_T (dart.core::bool)+?]
 t2 = _Call direct [#lib::C1.] (_T (#lib::C1))
-t3 = _Call direct [#lib::C2.] (_T (#lib::C2))
-t4* = _Call direct [#lib::foo] (_T (#lib::C2))
+t3* = _Call direct [#lib::C2.] (_T (#lib::C2))
+t4* = _Call direct [#lib::foo] (t3)
 t5 = _TypeCheck (t4 against dart.core::bool*) (for #lib::foo(x = new #lib::C2()) as dart.core::bool*)
-t6 = _Call direct [#lib::C3.] (_T (#lib::C3))
-t7 = _Call direct [#lib::C4.] (_T (#lib::C4))
-t8* = _Call direct [dart.core::_GrowableList._literal2] (#lib::C4*, _T (#lib::C4), _T {})
+t6* = _Call direct [#lib::C3.] (_T (#lib::C3))
+t7* = _Call direct [#lib::C4.] (_T (#lib::C4))
+t8* = _Call direct [dart.core::_GrowableList._literal2] (#lib::C4*, t7, _T {})
 t9* = _Call direct [#lib::foo] (t8)
-t10 = _Call direct [#lib::foo] (_T (#lib::C3))
-t11 = _Join [dynamic] (_T (#lib::C3), t9)
+t10 = _Call direct [#lib::foo] (t6)
+t11 = _Join [dynamic] (t6, t9)
 t12 = _Call direct [#lib::bar] (t11)
 RESULT: _T {}?
 ------------ loop1 ------------
-t0 = _Call direct [#lib::C1.] (_T (#lib::C1))
-x_0 = _Join [dynamic] (_T (#lib::C1), _T (#lib::C2))
-t2* = _Call direct [#lib::foo] (x_0)
-t3 = _TypeCheck (t2 against dart.core::bool*) (for #lib::foo(x) as dart.core::bool*)
-t4 = _Call direct [#lib::C2.] (_T (#lib::C2))
+t0* = _Call direct [#lib::C1.] (_T (#lib::C1))
+t1* = _Call direct [#lib::C2.] (_T (#lib::C2))
+x_0 = _Join [dynamic] (t0, t1)
+t3* = _Call direct [#lib::foo] (x_0)
+t4 = _TypeCheck (t3 against dart.core::bool*) (for #lib::foo(x) as dart.core::bool*)
 t5 = _Call direct [#lib::bar] (x_0)
 RESULT: x_0
 ------------ loop2 ------------
-t0 = _Call direct [#lib::C1.] (_T (#lib::C1))
-x_0 = _Join [dynamic] (_T (#lib::C1), _T (#lib::C3))
-t2 = _Call direct [#lib::foo] (x_0)
-t3 = _Call direct [#lib::C2.] (_T (#lib::C2))
-t4 = _Call direct [#lib::bar] (_T (#lib::C2))
-t5 = _Call direct [#lib::C3.] (_T (#lib::C3))
-t6* = _Call direct [#lib::bar] (_T (#lib::C3))
+t0* = _Call direct [#lib::C1.] (_T (#lib::C1))
+t1* = _Call direct [#lib::C3.] (_T (#lib::C3))
+x_0 = _Join [dynamic] (t0, t1)
+t3 = _Call direct [#lib::foo] (x_0)
+t4* = _Call direct [#lib::C2.] (_T (#lib::C2))
+t5 = _Call direct [#lib::bar] (t4)
+t6* = _Call direct [#lib::bar] (t1)
 t7 = _TypeCheck (t6 against dart.core::bool*) (for #lib::bar(x = new #lib::C3()) as dart.core::bool*)
-RESULT: _T (#lib::C3)
+RESULT: t1
 ------------ loop3 ------------
 t0 = _Call direct [#lib::C1.] (_T (#lib::C1))
-t1 = _Call direct [#lib::C2.] (_T (#lib::C2))
-t2* = _Call direct [#lib::foo] (_T (#lib::C2))
+t1* = _Call direct [#lib::C2.] (_T (#lib::C2))
+t2* = _Call direct [#lib::foo] (t1)
 t3 = _TypeCheck (t2 against dart.core::bool*) (for #lib::foo(x = new #lib::C2()) as dart.core::bool*)
 t4 = _Call direct [#lib::C3.] (_T (#lib::C3))
-t5 = _Call direct [#lib::bar] (_T (#lib::C2))
-RESULT: _T (#lib::C2)
+t5 = _Call direct [#lib::bar] (t1)
+RESULT: t1
 ------------ loop4 ------------
 t0 = _Call direct [#lib::C1.] (_T (#lib::C1))
-t1 = _Call direct [#lib::C2.] (_T (#lib::C2))
-t2* = _Call direct [#lib::foo] (_T (#lib::C2))
+t1* = _Call direct [#lib::C2.] (_T (#lib::C2))
+t2* = _Call direct [#lib::foo] (t1)
 t3* = _Call direct [dart.core::_GrowableList._literal1] (dynamic?, t2)
 t4* = _Call get [dart.core::Iterable.iterator] (t3)
 t5* = _Call [dart.core::Iterator.moveNext] (t4)
 t6 = _Narrow (t4 to _T ANY)
 t7 = _Call get [dart.core::Iterator.current] (t6)
-x_0 = _Join [dynamic] (_T (#lib::C2), _T (#lib::C3))
-t9 = _Call direct [#lib::foo] (x_0)
-t10 = _Call direct [#lib::C3.] (_T (#lib::C3))
+t8* = _Call direct [#lib::C3.] (_T (#lib::C3))
+x_0 = _Join [dynamic] (t1, t8)
+t10 = _Call direct [#lib::foo] (x_0)
 RESULT: x_0
 ------------ loop5 ------------
-t0 = _Call direct [#lib::C1.] (_T (#lib::C1))
-x_0 = _Join [dynamic] (_T (#lib::C1), _T (#lib::C3))
-t2* = _Call direct [#lib::foo] (x_0)
-t3 = _TypeCheck (t2 against dart.core::bool*) (for #lib::foo(x) as dart.core::bool*)
-t4 = _Call direct [#lib::C2.] (_T (#lib::C2))
-t5* = _Call direct [#lib::bar] (_T (#lib::C2))
-t6 = _TypeCheck (t5 against dart.core::bool*) (for #lib::bar(x) as dart.core::bool*)
-t7 = _Call direct [#lib::C3.] (_T (#lib::C3))
-x_1 = _Join [dynamic] (x_0, _T (#lib::C2))
-RESULT: x_1
------------- loop6 ------------
-t0 = _Call direct [#lib::C1.] (_T (#lib::C1))
-x_1 = _Join [dynamic] (_T (#lib::C3), _T (#lib::C2))
-x_0 = _Join [dynamic] (_T (#lib::C1), x_1)
+t0* = _Call direct [#lib::C1.] (_T (#lib::C1))
+t1* = _Call direct [#lib::C3.] (_T (#lib::C3))
+x_0 = _Join [dynamic] (t0, t1)
 t3* = _Call direct [#lib::foo] (x_0)
 t4 = _TypeCheck (t3 against dart.core::bool*) (for #lib::foo(x) as dart.core::bool*)
-t5 = _Call direct [#lib::C2.] (_T (#lib::C2))
-t6* = _Call direct [#lib::bar] (_T (#lib::C2))
+t5* = _Call direct [#lib::C2.] (_T (#lib::C2))
+t6* = _Call direct [#lib::bar] (t5)
 t7 = _TypeCheck (t6 against dart.core::bool*) (for #lib::bar(x) as dart.core::bool*)
-t8 = _Call direct [#lib::C3.] (_T (#lib::C3))
+x_1 = _Join [dynamic] (x_0, t5)
+RESULT: x_1
+------------ loop6 ------------
+t0* = _Call direct [#lib::C1.] (_T (#lib::C1))
+t1* = _Call direct [#lib::C3.] (_T (#lib::C3))
+t2* = _Call direct [#lib::C2.] (_T (#lib::C2))
+x_1 = _Join [dynamic] (t1, t2)
+x_0 = _Join [dynamic] (t0, x_1)
+t5* = _Call direct [#lib::foo] (x_0)
+t6 = _TypeCheck (t5 against dart.core::bool*) (for #lib::foo(x) as dart.core::bool*)
+t7* = _Call direct [#lib::bar] (t2)
+t8 = _TypeCheck (t7 against dart.core::bool*) (for #lib::bar(x) as dart.core::bool*)
 RESULT: x_0
 ------------ try1 ------------
-t0 = _Call direct [#lib::C1.] (_T (#lib::C1))
-t1 = _Call direct [#lib::C2.] (_T (#lib::C2))
-x_0 = _Join [dynamic] (_T (#lib::C1), _T (#lib::C2), _T (#lib::C3))
-t3 = _Call direct [#lib::foo] (x_0)
-t4 = _Call direct [#lib::C3.] (_T (#lib::C3))
+t0* = _Call direct [#lib::C1.] (_T (#lib::C1))
+t1* = _Call direct [#lib::C2.] (_T (#lib::C2))
+t2* = _Call direct [#lib::C3.] (_T (#lib::C3))
+x_0 = _Join [dynamic] (t0, t1, t2)
+t4 = _Call direct [#lib::foo] (x_0)
 t5 = _Call direct [#lib::bar] (x_0)
-t6 = _Call direct [#lib::C4.] (_T (#lib::C4))
-RESULT: _T (#lib::C4)
+t6* = _Call direct [#lib::C4.] (_T (#lib::C4))
+RESULT: t6
 ------------ closure1 ------------
-t0 = _Call direct [#lib::C1.] (_T (#lib::C1))
-x_0 = _Join [dynamic] (_T (#lib::C1), _T (#lib::C2))
-t2 = _Call direct [#lib::foo] (x_0)
-t3 = _Call direct [#lib::bar] (x_0)
-t4 = _Call direct [#lib::foo] (_T ANY?)
-t5 = _Call direct [#lib::C2.] (_T (#lib::C2))
+t0* = _Call direct [#lib::C1.] (_T (#lib::C1))
+t1* = _Call direct [#lib::C2.] (_T (#lib::C2))
+x_0 = _Join [dynamic] (t0, t1)
+t3 = _Call direct [#lib::foo] (x_0)
+t4 = _Call direct [#lib::bar] (x_0)
+t5 = _Call direct [#lib::foo] (_T ANY?)
 RESULT: _T {}?
 ------------ closure2 ------------
-t0 = _Call direct [#lib::C1.] (_T (#lib::C1))
-x_0 = _Join [dynamic] (_T (#lib::C1), _T (#lib::C2))
-t2 = _Call direct [#lib::foo] (x_0)
-t3 = _Call direct [#lib::C2.] (_T (#lib::C2))
+t0* = _Call direct [#lib::C1.] (_T (#lib::C1))
+t1* = _Call direct [#lib::C2.] (_T (#lib::C2))
+x_0 = _Join [dynamic] (t0, t1)
+t3 = _Call direct [#lib::foo] (x_0)
 t4 = _Call direct [#lib::foo] (_T ANY?)
 RESULT: x_0
 ------------ switch1 ------------
 %selector = _Parameter #0 [_T (dart.core::int)+?]
-t1 = _Call direct [#lib::C1.] (_T (#lib::C1))
-t2 = _Call direct [#lib::C2.] (_T (#lib::C2))
-t3 = _Call direct [#lib::C3.] (_T (#lib::C3))
-x_2 = _Join [dynamic] (_T (#lib::C3), _T (#lib::C1))
-x_3 = _Join [dynamic] (x_2, _T (#lib::C2))
+t1* = _Call direct [#lib::C1.] (_T (#lib::C1))
+t2* = _Call direct [#lib::C2.] (_T (#lib::C2))
+t3* = _Call direct [#lib::C3.] (_T (#lib::C3))
+x_2 = _Join [dynamic] (t3, t1)
+x_3 = _Join [dynamic] (x_2, t2)
 RESULT: x_3
 ------------ switch2 ------------
 %selector = _Parameter #0 [_T (dart.core::int)+?]
 t1 = _Call direct [#lib::C1.] (_T (#lib::C1))
-t2 = _Call direct [#lib::C2.] (_T (#lib::C2))
-t3 = _Call direct [#lib::C3.] (_T (#lib::C3))
-x_2 = _Join [dynamic] (_T (#lib::C3), _T (#lib::C2))
+t2* = _Call direct [#lib::C2.] (_T (#lib::C2))
+t3* = _Call direct [#lib::C3.] (_T (#lib::C3))
+x_2 = _Join [dynamic] (t3, t2)
 RESULT: x_2
 ------------ switch3 ------------
 %selector = _Parameter #0 [_T (dart.core::int)+?]
-t1 = _Call direct [#lib::C1.] (_T (#lib::C1))
-t2 = _Call direct [#lib::C2.] (_T (#lib::C2))
-x_1 = _Join [dynamic] (_T (#lib::C1), _T (#lib::C2))
+t1* = _Call direct [#lib::C1.] (_T (#lib::C1))
+t2* = _Call direct [#lib::C2.] (_T (#lib::C2))
+x_1 = _Join [dynamic] (t1, t2)
 t4 = _Call direct [#lib::foo] (x_1)
-t5 = _Call direct [#lib::C3.] (_T (#lib::C3))
-x_2 = _Join [dynamic] (_T (#lib::C1), _T (#lib::C3))
+t5* = _Call direct [#lib::C3.] (_T (#lib::C3))
+x_2 = _Join [dynamic] (t1, t5)
 RESULT: x_2
 ------------ cast1 ------------
 %x = _Parameter #0 [_T ANY?]
diff --git a/pkg/vm/testcases/transformations/type_flow/summary_collector/implicit_return_null.dart.expect b/pkg/vm/testcases/transformations/type_flow/summary_collector/implicit_return_null.dart.expect
index b584c86..8b3a909 100644
--- a/pkg/vm/testcases/transformations/type_flow/summary_collector/implicit_return_null.dart.expect
+++ b/pkg/vm/testcases/transformations/type_flow/summary_collector/implicit_return_null.dart.expect
@@ -15,16 +15,16 @@
 
 RESULT: _T {}?
 ------------ return1 ------------
-t0 = _Call direct [#lib::T.] (_T (#lib::T))
-RESULT: _T (#lib::T)
+t0* = _Call direct [#lib::T.] (_T (#lib::T))
+RESULT: t0
 ------------ return2 ------------
 %i = _Parameter #0 [_T (dart.core::int)+?]
 t1* = _Call [dart.core::num.-] (%i, _T (dart.core::_Smi, 1))
 t2* = _Call direct [#lib::return2] (t1)
 RESULT: t2
 ------------ return3 ------------
-t0 = _Call direct [#lib::T.] (_T (#lib::T))
-RESULT: _T (#lib::T)
+t0* = _Call direct [#lib::T.] (_T (#lib::T))
+RESULT: t0
 ------------ return4 ------------
 
 RESULT: _T {}?
@@ -33,16 +33,16 @@
 RESULT: _T {}?
 ------------ expr2 ------------
 %c = _Parameter #0 [_T (dart.core::bool)+?]
-t1 = _Call direct [#lib::T.] (_T (#lib::T))
+t1* = _Call direct [#lib::T.] (_T (#lib::T))
 t2 = _Call direct [#lib::T.] (_T (#lib::T))
-%result = _Join [dynamic] (_T (#lib::T), _T {}?)
+%result = _Join [dynamic] (t1, _T {}?)
 RESULT: %result
 ------------ expr3 ------------
 %c = _Parameter #0 [_T (dart.core::bool)+?]
 %x = _Parameter #1 [_T (dart.core::Object)+?]
-t2 = _Call direct [#lib::T.] (_T (#lib::T))
+t2* = _Call direct [#lib::T.] (_T (#lib::T))
 t3 = _Call [dart.core::Object.toString] (%x)
-%result = _Join [dynamic] (_T (#lib::T), _T {}?)
+%result = _Join [dynamic] (t2, _T {}?)
 RESULT: %result
 ------------ throw1 ------------
 %c = _Parameter #0 [_T (dart.core::bool)+?]
@@ -51,8 +51,8 @@
 ------------ throw2 ------------
 %c = _Parameter #0 [_T (dart.core::bool)+?]
 %x = _Parameter #1 [_T (dart.core::Object)+?]
-t2 = _Call direct [#lib::T.] (_T (#lib::T))
-RESULT: _T (#lib::T)
+t2* = _Call direct [#lib::T.] (_T (#lib::T))
+RESULT: t2
 ------------ loop1 ------------
 %c = _Parameter #0 [_T (dart.core::bool)+?]
 %x = _Parameter #1 [_T (dart.core::Object)+?]
@@ -60,29 +60,29 @@
 ------------ loop2 ------------
 %c = _Parameter #0 [_T (dart.core::bool)+?]
 %x = _Parameter #1 [_T (dart.core::Object)+?]
-t2 = _Call direct [#lib::T.] (_T (#lib::T))
-%result = _Join [dynamic] (_T (#lib::T), _T {}?)
+t2* = _Call direct [#lib::T.] (_T (#lib::T))
+%result = _Join [dynamic] (t2, _T {}?)
 RESULT: %result
 ------------ loop3 ------------
 %c = _Parameter #0 [_T (dart.core::bool)+?]
 %x = _Parameter #1 [_T (dart.core::Object)+?]
-t2 = _Call direct [#lib::T.] (_T (#lib::T))
-%result = _Join [dynamic] (_T (#lib::T), _T {}?)
+t2* = _Call direct [#lib::T.] (_T (#lib::T))
+%result = _Join [dynamic] (t2, _T {}?)
 RESULT: %result
 ------------ switch_ ------------
 %c = _Parameter #0 [_T (dart.core::bool)+?]
 %i = _Parameter #1 [_T (dart.core::int)+?]
-t2 = _Call direct [#lib::T.] (_T (#lib::T))
-%result = _Join [dynamic] (_T (#lib::T), _T {}?)
+t2* = _Call direct [#lib::T.] (_T (#lib::T))
+%result = _Join [dynamic] (t2, _T {}?)
 RESULT: %result
 ------------ if1 ------------
 %c = _Parameter #0 [_T (dart.core::bool)+?]
-t1 = _Call direct [#lib::T.] (_T (#lib::T))
-RESULT: _T (#lib::T)
+t1* = _Call direct [#lib::T.] (_T (#lib::T))
+RESULT: t1
 ------------ if2 ------------
 %c = _Parameter #0 [_T (dart.core::bool)+?]
-t1 = _Call direct [#lib::T.] (_T (#lib::T))
-%result = _Join [dynamic] (_T (#lib::T), _T {}?)
+t1* = _Call direct [#lib::T.] (_T (#lib::T))
+%result = _Join [dynamic] (t1, _T {}?)
 RESULT: %result
 ------------ if3 ------------
 %c = _Parameter #0 [_T (dart.core::bool)+?]
@@ -98,36 +98,36 @@
 RESULT: %result
 ------------ label1 ------------
 %c = _Parameter #0 [_T (dart.core::bool)+?]
-t1 = _Call direct [#lib::T.] (_T (#lib::T))
-%result = _Join [dynamic] (_T (#lib::T), _T {}?)
+t1* = _Call direct [#lib::T.] (_T (#lib::T))
+%result = _Join [dynamic] (t1, _T {}?)
 RESULT: %result
 ------------ try1 ------------
 %c = _Parameter #0 [_T (dart.core::bool)+?]
-t1 = _Call direct [#lib::T.] (_T (#lib::T))
-%result = _Join [dynamic] (_T (#lib::T), _T {}?)
+t1* = _Call direct [#lib::T.] (_T (#lib::T))
+%result = _Join [dynamic] (t1, _T {}?)
 RESULT: %result
 ------------ try2 ------------
-t0 = _Call direct [#lib::T.] (_T (#lib::T))
-%result = _Join [dynamic] (_T (#lib::T), _T {}?)
+t0* = _Call direct [#lib::T.] (_T (#lib::T))
+%result = _Join [dynamic] (t0, _T {}?)
 RESULT: %result
 ------------ try3 ------------
-t0 = _Call direct [#lib::T.] (_T (#lib::T))
-RESULT: _T (#lib::T)
+t0* = _Call direct [#lib::T.] (_T (#lib::T))
+RESULT: t0
 ------------ try4 ------------
 %c = _Parameter #0 [_T (dart.core::bool)+?]
-t1 = _Call direct [#lib::T.] (_T (#lib::T))
-%result = _Join [dynamic] (_T (#lib::T), _T {}?)
+t1* = _Call direct [#lib::T.] (_T (#lib::T))
+%result = _Join [dynamic] (t1, _T {}?)
 RESULT: %result
 ------------ try5 ------------
-t0 = _Call direct [#lib::T.] (_T (#lib::T))
-RESULT: _T (#lib::T)
+t0* = _Call direct [#lib::T.] (_T (#lib::T))
+RESULT: t0
 ------------ try6 ------------
-t0 = _Call direct [#lib::T.] (_T (#lib::T))
-RESULT: _T (#lib::T)
+t0* = _Call direct [#lib::T.] (_T (#lib::T))
+RESULT: t0
 ------------ try7 ------------
 %c = _Parameter #0 [_T (dart.core::bool)+?]
-t1 = _Call direct [#lib::T.] (_T (#lib::T))
-RESULT: _T (#lib::T)
+t1* = _Call direct [#lib::T.] (_T (#lib::T))
+RESULT: t1
 ------------ main ------------
 
 RESULT: _T {}?
diff --git a/pkg/vm/testcases/transformations/type_flow/summary_collector/vars.dart.expect b/pkg/vm/testcases/transformations/type_flow/summary_collector/vars.dart.expect
index d46d957..4bba0a1 100644
--- a/pkg/vm/testcases/transformations/type_flow/summary_collector/vars.dart.expect
+++ b/pkg/vm/testcases/transformations/type_flow/summary_collector/vars.dart.expect
@@ -10,12 +10,12 @@
 %a1 = _Parameter #0 [_T (dart.core::Object)+?]
 %a2 = _Parameter #1 [_T (dart.core::Object)+?]
 t2* = _Call direct get [#lib::someStatic] ()
-t3 = _Call direct [#lib::A.] (_T (#lib::A))
-a1_0 = _Join [dart.core::Object*] (_T (#lib::A), %a1)
+t3* = _Call direct [#lib::A.] (_T (#lib::A))
+a1_0 = _Join [dart.core::Object*] (t3, %a1)
 t5 = _Call direct [#lib::bar] (a1_0, _T (dart.core::_Smi, 42))
-t6 = _Call direct [#lib::B.] (_T (#lib::B))
-t7* = _Call [dart.core::Object.==] (_T (#lib::B), %a2)
-t8 = _Join [dart.core::Object*] (_T (#lib::B), %a2)
+t6* = _Call direct [#lib::B.] (_T (#lib::B))
+t7* = _Call [dart.core::Object.==] (t6, %a2)
+t8 = _Join [dart.core::Object*] (t6, %a2)
 t9 = _Narrow (t8 to _T (dart.core::Object)+?)
 RESULT: t9
 ------------ bar ------------