VM: Fix bug in type propagation at conditionals.

Propagating type/cid at conditional branches is not possible because
it may cause invalid code motion.

For this to be safe we need to explicitly represent the dependency
between checks eliminated in a branch and the condition that constrains the type/cid.

BUG=
R=vegorov@google.com

Review URL: https://codereview.chromium.org/1491373005 .
diff --git a/runtime/vm/flow_graph_type_propagator.cc b/runtime/vm/flow_graph_type_propagator.cc
index 3448fd0..29ec735 100644
--- a/runtime/vm/flow_graph_type_propagator.cc
+++ b/runtime/vm/flow_graph_type_propagator.cc
@@ -149,8 +149,6 @@
     }
   }
 
-  HandleBranchOnStrictCompare(block);
-
   for (intptr_t i = 0; i < block->dominated_blocks().length(); ++i) {
     PropagateRecursive(block->dominated_blocks()[i]);
   }
@@ -159,61 +157,6 @@
 }
 
 
-void FlowGraphTypePropagator::HandleBranchOnStrictCompare(
-    BlockEntryInstr* block) {
-  BranchInstr* branch = block->last_instruction()->AsBranch();
-  if (branch == NULL) {
-    return;
-  }
-
-  StrictCompareInstr* compare = branch->comparison()->AsStrictCompare();
-  if ((compare == NULL) || !compare->right()->BindsToConstant()) {
-    return;
-  }
-
-  const intptr_t rollback_point = rollback_.length();
-
-  Definition* defn = compare->left()->definition();
-  const Object& right = compare->right()->BoundConstant();
-  intptr_t cid = right.GetClassId();
-
-  if (defn->IsLoadClassId() && right.IsSmi()) {
-    defn = defn->AsLoadClassId()->object()->definition();
-    cid = Smi::Cast(right).Value();
-  }
-
-  if (!CheckClassInstr::IsImmutableClassId(cid)) {
-    if ((cid == kOneByteStringCid) || (cid == kTwoByteStringCid)) {
-      SetTypeOf(defn, ZoneCompileType::Wrap(CompileType::String()));
-      PropagateRecursive((compare->kind() == Token::kEQ_STRICT) ?
-          branch->true_successor() : branch->false_successor());
-      RollbackTo(rollback_point);
-    }
-    return;
-  }
-
-  if (compare->kind() == Token::kEQ_STRICT) {
-    if (cid == kNullCid) {
-      branch->set_constrained_type(MarkNonNullable(defn));
-      PropagateRecursive(branch->false_successor());
-    }
-
-    SetCid(defn, cid);
-    PropagateRecursive(branch->true_successor());
-  } else if (compare->kind() == Token::kNE_STRICT) {
-    if (cid == kNullCid) {
-      branch->set_constrained_type(MarkNonNullable(defn));
-      PropagateRecursive(branch->true_successor());
-    }
-
-    SetCid(defn, cid);
-    PropagateRecursive(branch->false_successor());
-  }
-
-  RollbackTo(rollback_point);
-}
-
-
 void FlowGraphTypePropagator::RollbackTo(intptr_t rollback_point) {
   for (intptr_t i = rollback_.length() - 1; i >= rollback_point; i--) {
     types_[rollback_[i].index()] = rollback_[i].type();
diff --git a/runtime/vm/flow_graph_type_propagator.h b/runtime/vm/flow_graph_type_propagator.h
index 4b1baf4..3c10917 100644
--- a/runtime/vm/flow_graph_type_propagator.h
+++ b/runtime/vm/flow_graph_type_propagator.h
@@ -20,7 +20,6 @@
   void Propagate();
 
   void PropagateRecursive(BlockEntryInstr* block);
-  void HandleBranchOnStrictCompare(BlockEntryInstr* block);
 
   void RollbackTo(intptr_t rollback_point);
 
diff --git a/tests/language/vm/type_propagation_test.dart b/tests/language/vm/type_propagation_test.dart
new file mode 100644
index 0000000..935c096
--- /dev/null
+++ b/tests/language/vm/type_propagation_test.dart
@@ -0,0 +1,56 @@
+// Copyright (c) 2015, 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.
+// VMOptions=--optimization-counter-threshold=1000 --max-polymorphic-checks=1
+
+// Test correct loop invariant code motion and type propagation from is-checks
+// and null-comparisons. 
+
+class B {
+  var b;
+  B(this.b);
+}
+
+class C {
+  final f0;
+
+  final a;
+  C() : a = new B(0);
+}
+
+foo(x) {
+  for (var i = 0; i < 10; i++) {
+    i + i;
+    i + i;
+    if (x is C) {
+      x.a.b < 0;
+    }
+  }
+}
+
+class Y { var f = null; }
+
+bar(y) {
+  var x = y.f;
+  for (var i = 0; i < 10; i++) {
+    if (x != null) {
+      x.a.b < 0;
+    }
+  }
+}
+
+
+main () {
+  var o = new Y();
+  o.f = new C();
+  bar(o);
+  o.f = null;
+  bar(o);
+
+  for (var i = 0; i < 1000; i++) bar(o);
+
+  foo(new C());
+  foo(0);
+
+  for (var i = 0; i < 1000; i++) foo(0);
+}