[vm] Handle new AST invocation nodes in VM kernel transformations

This change extends VM-specific kernel transformations to handle
new AST invocation nodes. The transformations may still generate
old nodes, but they should accept and handle new nodes coming from
the front-end.

TEST=Manual testing with new invocation nodes enabled.

Issue: https://github.com/dart-lang/sdk/issues/45340
Change-Id: I2de9f0eb00fcf844ba62fdc93b15a907c2d6b69d
Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/197443
Commit-Queue: Alexander Markov <alexmarkov@google.com>
Reviewed-by: Aske Simon Christensen <askesc@google.com>
Reviewed-by: Johnni Winther <johnniwinther@google.com>
diff --git a/pkg/kernel/lib/transformations/async.dart b/pkg/kernel/lib/transformations/async.dart
index f7b74c7..d80784a 100644
--- a/pkg/kernel/lib/transformations/async.dart
+++ b/pkg/kernel/lib/transformations/async.dart
@@ -159,6 +159,7 @@
   TreeNode visitInvalidExpression(InvalidExpression expr) => nullary(expr);
   TreeNode visitSuperPropertyGet(SuperPropertyGet expr) => nullary(expr);
   TreeNode visitStaticGet(StaticGet expr) => nullary(expr);
+  TreeNode visitStaticTearOff(StaticTearOff expr) => nullary(expr);
   TreeNode visitRethrow(Rethrow expr) => nullary(expr);
 
   // Getting a final or const variable is not an effect so it can be evaluated
@@ -211,15 +212,32 @@
     });
   }
 
+  @override
   TreeNode visitVariableSet(VariableSet expr) => unary(expr);
+  @override
   TreeNode visitPropertyGet(PropertyGet expr) => unary(expr);
+  @override
+  TreeNode visitInstanceGet(InstanceGet expr) => unary(expr);
+  @override
+  TreeNode visitDynamicGet(DynamicGet expr) => unary(expr);
+  @override
+  TreeNode visitInstanceTearOff(InstanceTearOff expr) => unary(expr);
+  @override
+  TreeNode visitFunctionTearOff(FunctionTearOff expr) => unary(expr);
+  @override
   TreeNode visitSuperPropertySet(SuperPropertySet expr) => unary(expr);
+  @override
   TreeNode visitStaticSet(StaticSet expr) => unary(expr);
+  @override
   TreeNode visitNot(Not expr) => unary(expr);
+  @override
   TreeNode visitIsExpression(IsExpression expr) => unary(expr);
+  @override
   TreeNode visitAsExpression(AsExpression expr) => unary(expr);
+  @override
   TreeNode visitThrow(Throw expr) => unary(expr);
 
+  @override
   TreeNode visitPropertySet(PropertySet expr) {
     return transformTreeNode(expr, () {
       expr.value = transform(expr.value)..parent = expr;
@@ -227,6 +245,22 @@
     });
   }
 
+  @override
+  TreeNode visitInstanceSet(InstanceSet expr) {
+    return transformTreeNode(expr, () {
+      expr.value = transform(expr.value)..parent = expr;
+      expr.receiver = transform(expr.receiver)..parent = expr;
+    });
+  }
+
+  @override
+  TreeNode visitDynamicSet(DynamicSet expr) {
+    return transformTreeNode(expr, () {
+      expr.value = transform(expr.value)..parent = expr;
+      expr.receiver = transform(expr.receiver)..parent = expr;
+    });
+  }
+
   TreeNode visitArguments(Arguments args) {
     for (var named in args.named.reversed) {
       named.value = transform(named.value)..parent = named;
@@ -240,6 +274,7 @@
     return args;
   }
 
+  @override
   TreeNode visitMethodInvocation(MethodInvocation expr) {
     return transformTreeNode(expr, () {
       visitArguments(expr.arguments);
@@ -247,6 +282,48 @@
     });
   }
 
+  @override
+  TreeNode visitInstanceInvocation(InstanceInvocation expr) {
+    return transformTreeNode(expr, () {
+      visitArguments(expr.arguments);
+      expr.receiver = transform(expr.receiver)..parent = expr;
+    });
+  }
+
+  @override
+  TreeNode visitLocalFunctionInvocation(LocalFunctionInvocation expr) {
+    return transformTreeNode(expr, () {
+      visitArguments(expr.arguments);
+    });
+  }
+
+  @override
+  TreeNode visitDynamicInvocation(DynamicInvocation expr) {
+    return transformTreeNode(expr, () {
+      visitArguments(expr.arguments);
+      expr.receiver = transform(expr.receiver)..parent = expr;
+    });
+  }
+
+  @override
+  TreeNode visitFunctionInvocation(FunctionInvocation expr) {
+    return transformTreeNode(expr, () {
+      visitArguments(expr.arguments);
+      expr.receiver = transform(expr.receiver)..parent = expr;
+    });
+  }
+
+  @override
+  TreeNode visitEqualsNull(EqualsNull expr) => unary(expr);
+
+  @override
+  TreeNode visitEqualsCall(EqualsCall expr) {
+    return transformTreeNode(expr, () {
+      expr.right = transform(expr.right)..parent = expr;
+      expr.left = transform(expr.left)..parent = expr;
+    });
+  }
+
   TreeNode visitSuperMethodInvocation(SuperMethodInvocation expr) {
     return transformTreeNode(expr, () {
       visitArguments(expr.arguments);
diff --git a/pkg/vm/lib/transformations/call_site_annotator.dart b/pkg/vm/lib/transformations/call_site_annotator.dart
index e3722a1..c843506 100644
--- a/pkg/vm/lib/transformations/call_site_annotator.dart
+++ b/pkg/vm/lib/transformations/call_site_annotator.dart
@@ -55,6 +55,11 @@
         receiverType: receiver.getStaticType(_staticTypeContext!));
   }
 
+  void annotateWithFunctionType(TreeNode node, FunctionType type) {
+    _metadata.mapping[node] =
+        new CallSiteAttributesMetadata(receiverType: type);
+  }
+
   @override
   visitPropertySet(PropertySet node) {
     super.visitPropertySet(node);
@@ -65,6 +70,15 @@
   }
 
   @override
+  visitInstanceSet(InstanceSet node) {
+    super.visitInstanceSet(node);
+
+    if (hasGenericCovariantParameters(node.interfaceTarget)) {
+      annotateWithType(node, node.receiver);
+    }
+  }
+
+  @override
   visitMethodInvocation(MethodInvocation node) {
     super.visitMethodInvocation(node);
 
@@ -76,6 +90,46 @@
     }
   }
 
+  @override
+  visitInstanceInvocation(InstanceInvocation node) {
+    super.visitInstanceInvocation(node);
+
+    // TODO(34162): We don't need to save the type here for calls, just whether
+    // or not it's a statically-checked call.
+    if (hasGenericCovariantParameters(node.interfaceTarget)) {
+      annotateWithType(node, node.receiver);
+    }
+  }
+
+  @override
+  visitLocalFunctionInvocation(LocalFunctionInvocation node) {
+    super.visitLocalFunctionInvocation(node);
+
+    // TODO(34162): We don't need to save the type here for calls, just whether
+    // or not it's a statically-checked call.
+    annotateWithFunctionType(node, node.functionType);
+  }
+
+  @override
+  visitFunctionInvocation(FunctionInvocation node) {
+    super.visitFunctionInvocation(node);
+
+    // TODO(34162): We don't need to save the type here for calls, just whether
+    // or not it's a statically-checked call.
+    annotateWithType(node, node.receiver);
+  }
+
+  @override
+  visitEqualsCall(EqualsCall node) {
+    super.visitEqualsCall(node);
+
+    // TODO(34162): We don't need to save the type here for calls, just whether
+    // or not it's a statically-checked call.
+    if (hasGenericCovariantParameters(node.interfaceTarget)) {
+      annotateWithType(node, node.left);
+    }
+  }
+
   /// Return [true] if the given list of [VariableDeclaration] contains
   /// any annotated with generic-covariant-impl.
   static bool containsGenericCovariantImpl(List<VariableDeclaration> decls) =>
diff --git a/pkg/vm/lib/transformations/devirtualization.dart b/pkg/vm/lib/transformations/devirtualization.dart
index a81d089..16189aa 100644
--- a/pkg/vm/lib/transformations/devirtualization.dart
+++ b/pkg/vm/lib/transformations/devirtualization.dart
@@ -101,11 +101,8 @@
     super.visitLibrary(node);
   }
 
-  @override
-  visitMethodInvocation(MethodInvocation node) {
-    super.visitMethodInvocation(node);
-
-    final Member target = node.interfaceTarget;
+  void _handleMethodInvocation(
+      TreeNode node, Member target, Arguments arguments) {
     if (target != null && !isMethod(target)) {
       return;
     }
@@ -116,17 +113,42 @@
     // check into an assertion once front-end implements all override checks.
     if ((directCall != null) &&
         isMethod(directCall.target) &&
-        isLegalTargetForMethodInvocation(directCall.target, node.arguments) &&
+        isLegalTargetForMethodInvocation(directCall.target, arguments) &&
         !hasExtraTargetForNull(directCall)) {
       makeDirectCall(node, target, directCall);
     }
   }
 
   @override
-  visitPropertyGet(PropertyGet node) {
-    super.visitPropertyGet(node);
+  visitMethodInvocation(MethodInvocation node) {
+    super.visitMethodInvocation(node);
+    _handleMethodInvocation(node, node.interfaceTarget, node.arguments);
+  }
 
-    final Member target = node.interfaceTarget;
+  @override
+  visitInstanceInvocation(InstanceInvocation node) {
+    super.visitInstanceInvocation(node);
+    _handleMethodInvocation(node, node.interfaceTarget, node.arguments);
+  }
+
+  @override
+  visitDynamicInvocation(DynamicInvocation node) {
+    super.visitDynamicInvocation(node);
+    _handleMethodInvocation(node, null, node.arguments);
+  }
+
+  @override
+  visitEqualsCall(EqualsCall node) {
+    super.visitEqualsCall(node);
+
+    final target = node.interfaceTarget;
+    final DirectCallMetadata directCall = getDirectCall(node, target);
+    if (directCall != null && !directCall.checkReceiverForNull) {
+      makeDirectCall(node, target, directCall);
+    }
+  }
+
+  void _handlePropertyGet(TreeNode node, Member target) {
     if (target != null && !isFieldOrGetter(target)) {
       return;
     }
@@ -141,16 +163,48 @@
   }
 
   @override
-  visitPropertySet(PropertySet node) {
-    super.visitPropertySet(node);
+  visitPropertyGet(PropertyGet node) {
+    super.visitPropertyGet(node);
+    _handlePropertyGet(node, node.interfaceTarget);
+  }
 
-    final Member target = node.interfaceTarget;
+  @override
+  visitInstanceGet(InstanceGet node) {
+    super.visitInstanceGet(node);
+    _handlePropertyGet(node, node.interfaceTarget);
+  }
+
+  @override
+  visitDynamicGet(DynamicGet node) {
+    super.visitDynamicGet(node);
+    _handlePropertyGet(node, null);
+  }
+
+  void _handlePropertySet(TreeNode node, Member target) {
     final DirectCallMetadata directCall =
         getDirectCall(node, target, setter: true);
     if (directCall != null) {
       makeDirectCall(node, target, directCall);
     }
   }
+
+  @override
+  visitPropertySet(PropertySet node) {
+    super.visitPropertySet(node);
+    _handlePropertySet(node, node.interfaceTarget);
+  }
+
+  @override
+  visitInstanceSet(InstanceSet node) {
+    super.visitInstanceSet(node);
+    _handlePropertySet(node, node.interfaceTarget);
+  }
+
+  @override
+  visitDynamicSet(DynamicSet node) {
+    super.visitDynamicSet(node);
+    _handlePropertySet(node, null);
+  }
 }
 
 /// Devirtualization based on the closed-world class hierarchy analysis.
diff --git a/pkg/vm/lib/transformations/ffi_use_sites.dart b/pkg/vm/lib/transformations/ffi_use_sites.dart
index a094f53..153a07a 100644
--- a/pkg/vm/lib/transformations/ffi_use_sites.dart
+++ b/pkg/vm/lib/transformations/ffi_use_sites.dart
@@ -704,6 +704,44 @@
     return node;
   }
 
+  @override
+  visitInstanceInvocation(InstanceInvocation node) {
+    super.visitInstanceInvocation(node);
+
+    final Member target = node.interfaceTarget;
+    try {
+      if (target == elementAtMethod) {
+        final DartType pointerType =
+            node.receiver.getStaticType(_staticTypeContext);
+        final DartType nativeType = _pointerTypeGetTypeArg(pointerType);
+
+        _ensureNativeTypeValid(nativeType, node, allowCompounds: true);
+
+        Expression inlineSizeOf = _inlineSizeOf(nativeType);
+        if (inlineSizeOf != null) {
+          // Generates `receiver.offsetBy(inlineSizeOfExpression)`.
+          return MethodInvocation(
+              node.receiver,
+              offsetByMethod.name,
+              Arguments([
+                MethodInvocation(
+                    node.arguments.positional.single,
+                    numMultiplication.name,
+                    Arguments([inlineSizeOf]),
+                    numMultiplication)
+              ]),
+              offsetByMethod);
+        }
+      }
+    } on _FfiStaticTypeError {
+      // It's OK to swallow the exception because the diagnostics issued will
+      // cause compilation to fail. By continuing, we can report more
+      // diagnostics before compilation ends.
+    }
+
+    return node;
+  }
+
   DartType _pointerTypeGetTypeArg(DartType pointerType) {
     return pointerType is InterfaceType ? pointerType.typeArguments[0] : null;
   }
diff --git a/pkg/vm/lib/transformations/mixin_deduplication.dart b/pkg/vm/lib/transformations/mixin_deduplication.dart
index a328961..8cfc503 100644
--- a/pkg/vm/lib/transformations/mixin_deduplication.dart
+++ b/pkg/vm/lib/transformations/mixin_deduplication.dart
@@ -172,18 +172,51 @@
   }
 
   @override
+  visitInstanceGet(InstanceGet node) {
+    node.interfaceTarget = _resolveNewInterfaceTarget(node.interfaceTarget)!;
+    super.visitInstanceGet(node);
+  }
+
+  @override
+  visitInstanceTearOff(InstanceTearOff node) {
+    node.interfaceTarget =
+        _resolveNewInterfaceTarget(node.interfaceTarget) as Procedure;
+    super.visitInstanceTearOff(node);
+  }
+
+  @override
   visitPropertySet(PropertySet node) {
     node.interfaceTarget = _resolveNewInterfaceTarget(node.interfaceTarget);
     super.visitPropertySet(node);
   }
 
   @override
+  visitInstanceSet(InstanceSet node) {
+    node.interfaceTarget = _resolveNewInterfaceTarget(node.interfaceTarget)!;
+    super.visitInstanceSet(node);
+  }
+
+  @override
   visitMethodInvocation(MethodInvocation node) {
     node.interfaceTarget = _resolveNewInterfaceTarget(node.interfaceTarget);
     super.visitMethodInvocation(node);
   }
 
   @override
+  visitInstanceInvocation(InstanceInvocation node) {
+    node.interfaceTarget =
+        _resolveNewInterfaceTarget(node.interfaceTarget) as Procedure;
+    super.visitInstanceInvocation(node);
+  }
+
+  @override
+  visitEqualsCall(EqualsCall node) {
+    node.interfaceTarget =
+        _resolveNewInterfaceTarget(node.interfaceTarget) as Procedure;
+    super.visitEqualsCall(node);
+  }
+
+  @override
   visitSuperPropertyGet(SuperPropertyGet node) {
     node.interfaceTarget = _resolveNewInterfaceTarget(node.interfaceTarget);
     super.visitSuperPropertyGet(node);
diff --git a/pkg/vm/lib/transformations/no_dynamic_invocations_annotator.dart b/pkg/vm/lib/transformations/no_dynamic_invocations_annotator.dart
index 9b7e27c..0f9284b 100644
--- a/pkg/vm/lib/transformations/no_dynamic_invocations_annotator.dart
+++ b/pkg/vm/lib/transformations/no_dynamic_invocations_annotator.dart
@@ -190,6 +190,28 @@
   }
 
   @override
+  visitInstanceInvocation(InstanceInvocation node) {
+    super.visitInstanceInvocation(node);
+    if (node.receiver is! ThisExpression) {
+      nonThisSelectors.add(new Selector.doInvoke(node.name));
+    }
+  }
+
+  @override
+  visitDynamicInvocation(DynamicInvocation node) {
+    super.visitDynamicInvocation(node);
+    dynamicSelectors.add(new Selector.doInvoke(node.name));
+  }
+
+  @override
+  visitEqualsCall(EqualsCall node) {
+    super.visitEqualsCall(node);
+    if (node.left is! ThisExpression) {
+      nonThisSelectors.add(new Selector.doInvoke(Name('==')));
+    }
+  }
+
+  @override
   visitPropertyGet(PropertyGet node) {
     super.visitPropertyGet(node);
 
@@ -209,6 +231,29 @@
   }
 
   @override
+  visitInstanceGet(InstanceGet node) {
+    super.visitInstanceGet(node);
+    if (node.receiver is! ThisExpression) {
+      nonThisSelectors.add(new Selector.doGet(node.name));
+    }
+  }
+
+  @override
+  visitDynamicGet(DynamicGet node) {
+    super.visitDynamicGet(node);
+    dynamicSelectors.add(new Selector.doGet(node.name));
+  }
+
+  @override
+  visitInstanceTearOff(InstanceTearOff node) {
+    super.visitInstanceTearOff(node);
+    if (node.receiver is! ThisExpression) {
+      nonThisSelectors.add(new Selector.doGet(node.name));
+    }
+    tearOffSelectors.add(new Selector.doInvoke(node.name));
+  }
+
+  @override
   visitPropertySet(PropertySet node) {
     super.visitPropertySet(node);
 
@@ -221,4 +266,18 @@
       }
     }
   }
+
+  @override
+  visitInstanceSet(InstanceSet node) {
+    super.visitInstanceSet(node);
+    if (node.receiver is! ThisExpression) {
+      nonThisSelectors.add(new Selector.doSet(node.name));
+    }
+  }
+
+  @override
+  visitDynamicSet(DynamicSet node) {
+    super.visitDynamicSet(node);
+    dynamicSelectors.add(new Selector.doSet(node.name));
+  }
 }
diff --git a/pkg/vm/lib/transformations/type_flow/protobuf_handler.dart b/pkg/vm/lib/transformations/type_flow/protobuf_handler.dart
index 7643e45..865f56d 100644
--- a/pkg/vm/lib/transformations/type_flow/protobuf_handler.dart
+++ b/pkg/vm/lib/transformations/type_flow/protobuf_handler.dart
@@ -143,7 +143,8 @@
     Statistics.protobufMetadataFieldsPruned += cls.numberOfFieldsPruned;
   }
 
-  bool _isUnusedMetadata(_MessageClass cls, MethodInvocation node) {
+  bool _isUnusedMetadataMethodInvocation(
+      _MessageClass cls, MethodInvocation node) {
     if (node.interfaceTarget != null &&
         node.interfaceTarget.enclosingClass == _builderInfoClass &&
         fieldAddingMethods.contains(node.name.text)) {
@@ -152,6 +153,15 @@
     }
     return false;
   }
+
+  bool _isUnusedMetadata(_MessageClass cls, InstanceInvocation node) {
+    if (node.interfaceTarget.enclosingClass == _builderInfoClass &&
+        fieldAddingMethods.contains(node.name.text)) {
+      final tagNumber = (node.arguments.positional[0] as IntLiteral).value;
+      return !cls._usedTags.contains(tagNumber);
+    }
+    return false;
+  }
 }
 
 class _MessageClass {
@@ -170,7 +180,7 @@
 
   @override
   TreeNode visitMethodInvocation(MethodInvocation node) {
-    if (!ph._isUnusedMetadata(cls, node)) {
+    if (!ph._isUnusedMetadataMethodInvocation(cls, node)) {
       super.visitMethodInvocation(node);
       return node;
     }
@@ -197,4 +207,34 @@
         ph._builderInfoAddMethod)
       ..fileOffset = node.fileOffset;
   }
+
+  @override
+  TreeNode visitInstanceInvocation(InstanceInvocation node) {
+    if (!ph._isUnusedMetadata(cls, node)) {
+      super.visitInstanceInvocation(node);
+      return node;
+    }
+    // Replace the field metadata method with a dummy call to
+    // `BuilderInfo.add`. This is to preserve the index calculations when
+    // removing a field.
+    // Change the tag-number to 0. Otherwise the decoder will get confused.
+    ++numberOfFieldsPruned;
+    return MethodInvocation(
+        node.receiver,
+        ph._builderInfoAddMethod.name,
+        Arguments(
+          <Expression>[
+            IntLiteral(0), // tagNumber
+            NullLiteral(), // name
+            NullLiteral(), // fieldType
+            NullLiteral(), // defaultOrMaker
+            NullLiteral(), // subBuilder
+            NullLiteral(), // valueOf
+            NullLiteral(), // enumValues
+          ],
+          types: <DartType>[const NullType()],
+        ),
+        ph._builderInfoAddMethod)
+      ..fileOffset = node.fileOffset;
+  }
 }
diff --git a/pkg/vm/lib/transformations/type_flow/signature_shaking.dart b/pkg/vm/lib/transformations/type_flow/signature_shaking.dart
index c6c7608..709604c 100644
--- a/pkg/vm/lib/transformations/type_flow/signature_shaking.dart
+++ b/pkg/vm/lib/transformations/type_flow/signature_shaking.dart
@@ -233,7 +233,8 @@
         shaker.typeFlowAnalysis.nativeCodeOracle
             .isMemberReferencedFromNativeCode(member) ||
         shaker.typeFlowAnalysis.nativeCodeOracle.isRecognized(member) ||
-        getExternalName(member) != null) {
+        getExternalName(member) != null ||
+        member.name.text == '==') {
       info.eligible = false;
     }
   }
@@ -302,6 +303,12 @@
   }
 
   @override
+  void visitInstanceInvocation(InstanceInvocation node) {
+    collectCall(node.interfaceTarget, node.arguments);
+    super.visitInstanceInvocation(node);
+  }
+
+  @override
   void visitSuperMethodInvocation(SuperMethodInvocation node) {
     collectCall(node.interfaceTarget, node.arguments);
     super.visitSuperMethodInvocation(node);
@@ -639,6 +646,12 @@
   }
 
   @override
+  void visitInstanceInvocation(InstanceInvocation node) {
+    super.visitInstanceInvocation(node);
+    transformCall(node.interfaceTarget, node, node.receiver, node.arguments);
+  }
+
+  @override
   void visitSuperMethodInvocation(SuperMethodInvocation node) {
     super.visitSuperMethodInvocation(node);
     transformCall(node.interfaceTarget, node, null, node.arguments);
diff --git a/pkg/vm/lib/transformations/type_flow/summary_collector.dart b/pkg/vm/lib/transformations/type_flow/summary_collector.dart
index 34c375b..a20c840 100644
--- a/pkg/vm/lib/transformations/type_flow/summary_collector.dart
+++ b/pkg/vm/lib/transformations/type_flow/summary_collector.dart
@@ -1131,7 +1131,8 @@
 
   TypeExpr _makeNarrowNotNull(TreeNode node, TypeExpr arg) {
     assert(node is NullCheck ||
-        node is MethodInvocation && isComparisonWithNull(node));
+        node is MethodInvocation && isComparisonWithNull(node) ||
+        node is EqualsNull);
     if (arg is NarrowNotNull) {
       nullTests[node] = arg;
       return arg;
@@ -1388,6 +1389,40 @@
         _variableValues = null;
         return;
       }
+    } else if (node is EqualsCall && node.left is VariableGet) {
+      final lhs = node.left as VariableGet;
+      final rhs = node.right;
+      if ((rhs is IntLiteral &&
+              _isSubtype(lhs.variable.type,
+                  _environment.coreTypes.intLegacyRawType)) ||
+          (rhs is StringLiteral &&
+              _isSubtype(lhs.variable.type,
+                  _environment.coreTypes.stringLegacyRawType)) ||
+          (rhs is ConstantExpression &&
+              !_hasOverriddenEquals(lhs.variable.type))) {
+        // 'x == c', where x is a variable and c is a constant.
+        _addUse(_visit(node));
+        final int varIndex = _variablesInfo.varIndex[lhs.variable];
+        if (_variableCells[varIndex] == null) {
+          trueState[varIndex] = _visit(rhs);
+        }
+        _variableValues = null;
+        return;
+      }
+    } else if (node is EqualsNull && node.expression is VariableGet) {
+      final lhs = node.expression as VariableGet;
+      // 'x == null', where x is a variable.
+      final expr = _visit(lhs);
+      _makeCall(node, DirectSelector(_environment.coreTypes.objectEquals),
+          Args<TypeExpr>([expr, _nullType]));
+      final narrowedNotNull = _makeNarrowNotNull(node, expr);
+      final int varIndex = _variablesInfo.varIndex[lhs.variable];
+      if (_variableCells[varIndex] == null) {
+        trueState[varIndex] = _nullType;
+        falseState[varIndex] = narrowedNotNull;
+      }
+      _variableValues = null;
+      return;
     } else if (node is IsExpression && node.operand is VariableGet) {
       // Handle 'x is T', where x is a variable.
       final operand = node.operand as VariableGet;
@@ -1630,6 +1665,30 @@
     return result;
   }
 
+  @override
+  TypeExpr visitInstanceInvocation(InstanceInvocation node) {
+    final receiverNode = node.receiver;
+    final receiver = _visit(receiverNode);
+    final args = _visitArguments(receiver, node.arguments);
+    final target = node.interfaceTarget;
+    if (receiverNode is ConstantExpression && node.name.text == '[]') {
+      Constant constant = receiverNode.constant;
+      if (constant is ListConstant) {
+        return _handleIndexingIntoListConstant(constant);
+      }
+    }
+    assert(target is Procedure && !target.isGetter);
+    // TODO(alexmarkov): overloaded arithmetic operators
+    final result = _makeCall(
+        node,
+        (node.receiver is ThisExpression)
+            ? new VirtualSelector(target)
+            : new InterfaceSelector(target),
+        args);
+    _updateReceiverAfterCall(receiverNode, receiver, node.name);
+    return result;
+  }
+
   TypeExpr _handleIndexingIntoListConstant(ListConstant list) {
     final elementTypes = new Set<Type>();
     for (var element in list.entries) {
@@ -1649,27 +1708,103 @@
   }
 
   @override
-  TypeExpr visitPropertyGet(PropertyGet node) {
-    var receiver = _visit(node.receiver);
-    var args = new Args<TypeExpr>([receiver]);
+  TypeExpr visitDynamicInvocation(DynamicInvocation node) {
+    final receiverNode = node.receiver;
+    final receiver = _visit(receiverNode);
+    final args = _visitArguments(receiver, node.arguments);
+    final result =
+        _makeCall(node, new DynamicSelector(CallKind.Method, node.name), args);
+    _updateReceiverAfterCall(receiverNode, receiver, node.name);
+    return result;
+  }
+
+  @override
+  TypeExpr visitLocalFunctionInvocation(LocalFunctionInvocation node) {
+    _visitArguments(null, node.arguments);
+    return _staticType(node);
+  }
+
+  @override
+  TypeExpr visitFunctionInvocation(FunctionInvocation node) {
+    final receiverNode = node.receiver;
+    final receiver = _visit(receiverNode);
+    _visitArguments(receiver, node.arguments);
+    final result = _staticType(node);
+    _updateReceiverAfterCall(receiverNode, receiver, Name('call'));
+    return result;
+  }
+
+  @override
+  TypeExpr visitEqualsCall(EqualsCall node) {
+    final left = _visit(node.left);
+    final right = _visit(node.right);
     final target = node.interfaceTarget;
+    return _makeCall(
+        node,
+        (node.left is ThisExpression)
+            ? new VirtualSelector(target)
+            : new InterfaceSelector(target),
+        Args<TypeExpr>([left, right]));
+  }
+
+  @override
+  TypeExpr visitEqualsNull(EqualsNull node) {
+    final arg = _visit(node.expression);
+    _makeNarrowNotNull(node, arg);
+    _makeCall(node, DirectSelector(_environment.coreTypes.objectEquals),
+        Args<TypeExpr>([arg, _nullType]));
+    return _boolType;
+  }
+
+  TypeExpr _handlePropertyGet(
+      TreeNode node, Expression receiverNode, Member target, Name selector) {
+    var receiver = _visit(receiverNode);
+    var args = new Args<TypeExpr>([receiver]);
     TypeExpr result;
     if (target == null) {
       result = _makeCall(
-          node, new DynamicSelector(CallKind.PropertyGet, node.name), args);
+          node, new DynamicSelector(CallKind.PropertyGet, selector), args);
     } else {
       result = _makeCall(
           node,
-          (node.receiver is ThisExpression)
+          (receiverNode is ThisExpression)
               ? new VirtualSelector(target, callKind: CallKind.PropertyGet)
               : new InterfaceSelector(target, callKind: CallKind.PropertyGet),
           args);
     }
-    _updateReceiverAfterCall(node.receiver, receiver, node.name);
+    _updateReceiverAfterCall(receiverNode, receiver, selector);
     return result;
   }
 
   @override
+  TypeExpr visitPropertyGet(PropertyGet node) {
+    return _handlePropertyGet(
+        node, node.receiver, node.interfaceTarget, node.name);
+  }
+
+  @override
+  TypeExpr visitInstanceGet(InstanceGet node) {
+    return _handlePropertyGet(
+        node, node.receiver, node.interfaceTarget, node.name);
+  }
+
+  @override
+  TypeExpr visitInstanceTearOff(InstanceTearOff node) {
+    return _handlePropertyGet(
+        node, node.receiver, node.interfaceTarget, node.name);
+  }
+
+  @override
+  TypeExpr visitFunctionTearOff(FunctionTearOff node) {
+    return _handlePropertyGet(node, node.receiver, null, Name('call'));
+  }
+
+  @override
+  TypeExpr visitDynamicGet(DynamicGet node) {
+    return _handlePropertyGet(node, node.receiver, null, node.name);
+  }
+
+  @override
   TypeExpr visitPropertySet(PropertySet node) {
     var receiver = _visit(node.receiver);
     var value = _visit(node.value);
@@ -1693,6 +1828,35 @@
   }
 
   @override
+  TypeExpr visitInstanceSet(InstanceSet node) {
+    var receiver = _visit(node.receiver);
+    var value = _visit(node.value);
+    var args = new Args<TypeExpr>([receiver, value]);
+    final target = node.interfaceTarget;
+    assert((target is Field) || ((target is Procedure) && target.isSetter));
+    _makeCall(
+        node,
+        (node.receiver is ThisExpression)
+            ? new VirtualSelector(target, callKind: CallKind.PropertySet)
+            : new InterfaceSelector(target, callKind: CallKind.PropertySet),
+        args);
+    _updateReceiverAfterCall(node.receiver, receiver, node.name,
+        isSetter: true);
+    return value;
+  }
+
+  @override
+  TypeExpr visitDynamicSet(DynamicSet node) {
+    var receiver = _visit(node.receiver);
+    var value = _visit(node.value);
+    var args = new Args<TypeExpr>([receiver, value]);
+    _makeCall(node, new DynamicSelector(CallKind.PropertySet, node.name), args);
+    _updateReceiverAfterCall(node.receiver, receiver, node.name,
+        isSetter: true);
+    return value;
+  }
+
+  @override
   TypeExpr visitSuperMethodInvocation(SuperMethodInvocation node) {
     assert(kPartialMixinResolution);
     assert(_receiver != null, "Should have receiver. Node: $node");
diff --git a/pkg/vm/lib/transformations/type_flow/transformer.dart b/pkg/vm/lib/transformations/type_flow/transformer.dart
index 427af73..e7ac652 100644
--- a/pkg/vm/lib/transformations/type_flow/transformer.dart
+++ b/pkg/vm/lib/transformations/type_flow/transformer.dart
@@ -256,7 +256,13 @@
     }
 
     final bool markSkipCheck = !callSite.useCheckedEntry &&
-        (node is MethodInvocation || node is PropertySet);
+        (node is MethodInvocation ||
+            node is InstanceInvocation ||
+            node is DynamicInvocation ||
+            node is EqualsCall ||
+            node is PropertySet ||
+            node is InstanceSet ||
+            node is DynamicSet);
 
     bool markReceiverNotInt = false;
 
@@ -264,7 +270,8 @@
       // No information is needed for static calls.
       if (node is! StaticInvocation &&
           node is! StaticSet &&
-          node is! StaticGet) {
+          node is! StaticGet &&
+          node is! StaticTearOff) {
         // The compiler uses another heuristic in addition to the call-site
         // annotation: if the call-site is non-dynamic and the interface target does
         // not exist in the parent chain of _Smi (int is used as an approxmiation
@@ -298,11 +305,17 @@
     // Tell the table selector assigner about the callsite.
     final Selector selector = callSite.selector;
     if (selector is InterfaceSelector && !_callSiteUsesDirectCall(node)) {
-      if (node is PropertyGet) {
+      if (node is PropertyGet ||
+          node is InstanceGet ||
+          node is InstanceTearOff) {
         _tableSelectorAssigner.registerGetterCall(
             selector.member, callSite.isNullableReceiver);
       } else {
-        assert(node is MethodInvocation || node is PropertySet);
+        assert(node is MethodInvocation ||
+            node is InstanceInvocation ||
+            node is EqualsCall ||
+            node is PropertySet ||
+            node is InstanceSet);
         _tableSelectorAssigner.registerMethodOrSetterCall(
             selector.member, callSite.isNullableReceiver);
       }
@@ -428,18 +441,84 @@
   }
 
   @override
+  visitInstanceInvocation(InstanceInvocation node) {
+    _annotateCallSite(node, node.interfaceTarget);
+    super.visitInstanceInvocation(node);
+  }
+
+  @override
+  visitDynamicInvocation(DynamicInvocation node) {
+    _annotateCallSite(node, null);
+    super.visitDynamicInvocation(node);
+  }
+
+  @override
+  visitLocalFunctionInvocation(LocalFunctionInvocation node) {
+    _annotateCallSite(node, null);
+    super.visitLocalFunctionInvocation(node);
+  }
+
+  @override
+  visitFunctionInvocation(FunctionInvocation node) {
+    _annotateCallSite(node, null);
+    super.visitFunctionInvocation(node);
+  }
+
+  @override
+  visitEqualsCall(EqualsCall node) {
+    _annotateCallSite(node, null);
+    super.visitEqualsCall(node);
+  }
+
+  @override
   visitPropertyGet(PropertyGet node) {
     _annotateCallSite(node, node.interfaceTarget);
     super.visitPropertyGet(node);
   }
 
   @override
+  visitInstanceGet(InstanceGet node) {
+    _annotateCallSite(node, node.interfaceTarget);
+    super.visitInstanceGet(node);
+  }
+
+  @override
+  visitInstanceTearOff(InstanceTearOff node) {
+    _annotateCallSite(node, node.interfaceTarget);
+    super.visitInstanceTearOff(node);
+  }
+
+  @override
+  visitFunctionTearOff(FunctionTearOff node) {
+    _annotateCallSite(node, null);
+    super.visitFunctionTearOff(node);
+  }
+
+  @override
+  visitDynamicGet(DynamicGet node) {
+    _annotateCallSite(node, null);
+    super.visitDynamicGet(node);
+  }
+
+  @override
   visitPropertySet(PropertySet node) {
     _annotateCallSite(node, node.interfaceTarget);
     super.visitPropertySet(node);
   }
 
   @override
+  visitInstanceSet(InstanceSet node) {
+    _annotateCallSite(node, node.interfaceTarget);
+    super.visitInstanceSet(node);
+  }
+
+  @override
+  visitDynamicSet(DynamicSet node) {
+    _annotateCallSite(node, null);
+    super.visitDynamicSet(node);
+  }
+
+  @override
   visitSuperMethodInvocation(SuperMethodInvocation node) {
     _annotateCallSite(node, node.interfaceTarget);
     super.visitSuperMethodInvocation(node);
@@ -999,6 +1078,78 @@
   }
 
   @override
+  TreeNode visitInstanceInvocation(
+      InstanceInvocation node, TreeNode removalSentinel) {
+    node.transformOrRemoveChildren(this);
+    if (_isUnreachable(node)) {
+      return _makeUnreachableCall(
+          _flattenArguments(node.arguments, receiver: node.receiver));
+    }
+    node.interfaceTarget =
+        fieldMorpher.adjustInstanceCallTarget(node.interfaceTarget);
+    shaker.addUsedMember(node.interfaceTarget);
+    return node;
+  }
+
+  @override
+  TreeNode visitDynamicInvocation(
+      DynamicInvocation node, TreeNode removalSentinel) {
+    node.transformOrRemoveChildren(this);
+    if (_isUnreachable(node)) {
+      return _makeUnreachableCall(
+          _flattenArguments(node.arguments, receiver: node.receiver));
+    }
+    return node;
+  }
+
+  @override
+  TreeNode visitLocalFunctionInvocation(
+      LocalFunctionInvocation node, TreeNode removalSentinel) {
+    node.transformOrRemoveChildren(this);
+    if (_isUnreachable(node)) {
+      return _makeUnreachableCall(_flattenArguments(node.arguments));
+    }
+    return node;
+  }
+
+  @override
+  TreeNode visitFunctionInvocation(
+      FunctionInvocation node, TreeNode removalSentinel) {
+    node.transformOrRemoveChildren(this);
+    if (_isUnreachable(node)) {
+      return _makeUnreachableCall(
+          _flattenArguments(node.arguments, receiver: node.receiver));
+    }
+    return node;
+  }
+
+  @override
+  TreeNode visitEqualsCall(EqualsCall node, TreeNode removalSentinel) {
+    node.transformOrRemoveChildren(this);
+    if (_isUnreachable(node)) {
+      return _makeUnreachableCall([node.left, node.right]);
+    }
+    node.interfaceTarget =
+        fieldMorpher.adjustInstanceCallTarget(node.interfaceTarget);
+    shaker.addUsedMember(node.interfaceTarget);
+    return node;
+  }
+
+  @override
+  TreeNode visitEqualsNull(EqualsNull node, TreeNode removalSentinel) {
+    node.transformOrRemoveChildren(this);
+    if (_isUnreachable(node)) {
+      return _makeUnreachableCall([node.expression]);
+    }
+    final nullTest = _getNullTest(node);
+    if (nullTest.isAlwaysNull || nullTest.isAlwaysNotNull) {
+      return _evaluateArguments(
+          [node.expression], BoolLiteral(nullTest.isAlwaysNull));
+    }
+    return node;
+  }
+
+  @override
   TreeNode visitPropertyGet(PropertyGet node, TreeNode removalSentinel) {
     node.transformOrRemoveChildren(this);
     if (_isUnreachable(node)) {
@@ -1014,6 +1165,54 @@
   }
 
   @override
+  TreeNode visitInstanceGet(InstanceGet node, TreeNode removalSentinel) {
+    node.transformOrRemoveChildren(this);
+    if (_isUnreachable(node)) {
+      return _makeUnreachableCall([node.receiver]);
+    } else {
+      node.interfaceTarget =
+          fieldMorpher.adjustInstanceCallTarget(node.interfaceTarget);
+      shaker.addUsedMember(node.interfaceTarget);
+      return node;
+    }
+  }
+
+  @override
+  TreeNode visitInstanceTearOff(
+      InstanceTearOff node, TreeNode removalSentinel) {
+    node.transformOrRemoveChildren(this);
+    if (_isUnreachable(node)) {
+      return _makeUnreachableCall([node.receiver]);
+    } else {
+      node.interfaceTarget =
+          fieldMorpher.adjustInstanceCallTarget(node.interfaceTarget);
+      shaker.addUsedMember(node.interfaceTarget);
+      return node;
+    }
+  }
+
+  @override
+  TreeNode visitDynamicGet(DynamicGet node, TreeNode removalSentinel) {
+    node.transformOrRemoveChildren(this);
+    if (_isUnreachable(node)) {
+      return _makeUnreachableCall([node.receiver]);
+    } else {
+      return node;
+    }
+  }
+
+  @override
+  TreeNode visitFunctionTearOff(
+      FunctionTearOff node, TreeNode removalSentinel) {
+    node.transformOrRemoveChildren(this);
+    if (_isUnreachable(node)) {
+      return _makeUnreachableCall([node.receiver]);
+    } else {
+      return node;
+    }
+  }
+
+  @override
   TreeNode visitPropertySet(PropertySet node, TreeNode removalSentinel) {
     node.transformOrRemoveChildren(this);
     if (_isUnreachable(node)) {
@@ -1029,6 +1228,29 @@
   }
 
   @override
+  TreeNode visitInstanceSet(InstanceSet node, TreeNode removalSentinel) {
+    node.transformOrRemoveChildren(this);
+    if (_isUnreachable(node)) {
+      return _makeUnreachableCall([node.receiver, node.value]);
+    } else {
+      node.interfaceTarget = fieldMorpher
+          .adjustInstanceCallTarget(node.interfaceTarget, isSetter: true);
+      shaker.addUsedMember(node.interfaceTarget);
+      return node;
+    }
+  }
+
+  @override
+  TreeNode visitDynamicSet(DynamicSet node, TreeNode removalSentinel) {
+    node.transformOrRemoveChildren(this);
+    if (_isUnreachable(node)) {
+      return _makeUnreachableCall([node.receiver, node.value]);
+    } else {
+      return node;
+    }
+  }
+
+  @override
   TreeNode visitSuperMethodInvocation(
       SuperMethodInvocation node, TreeNode removalSentinel) {
     node.transformOrRemoveChildren(this);