Version 1.2.1 (stable channel)

svn merge -c 33118 https://dart.googlecode.com/svn/branches/bleeding_edge 1.2
svn merge -c 33152 https://dart.googlecode.com/svn/branches/bleeding_edge 1.2

git-svn-id: http://dart.googlecode.com/svn/branches/1.2@33265 260f80e4-7a28-3924-810f-c04153c831b5
diff --git a/runtime/vm/flow_graph_optimizer.cc b/runtime/vm/flow_graph_optimizer.cc
index ce258c0..d312b0a 100644
--- a/runtime/vm/flow_graph_optimizer.cc
+++ b/runtime/vm/flow_graph_optimizer.cc
@@ -5478,7 +5478,6 @@
                       result->id());
           }
         }
-
         phi_moves->CreateOutgoingMove(block->PredecessorAt(j),
                                       result->id(),
                                       place->id());
@@ -5636,8 +5635,6 @@
   // Loads that are locally redundant will be replaced as we go through
   // instructions.
   void ComputeInitialSets() {
-    BitVector* forwarded_loads = new BitVector(aliased_set_->max_place_id());
-
     for (BlockIterator block_it = graph_->reverse_postorder_iterator();
          !block_it.Done();
          block_it.Advance()) {
@@ -5797,12 +5794,6 @@
         (*out_values)[place_id] = defn;
       }
 
-      PhiPlaceMoves::MovesList phi_moves =
-          aliased_set_->phi_moves()->GetOutgoingMoves(block);
-      if (phi_moves != NULL) {
-        PerformPhiMoves(phi_moves, gen, forwarded_loads);
-      }
-
       exposed_values_[preorder_number] = exposed_values;
       out_values_[preorder_number] = out_values;
     }
@@ -5839,6 +5830,7 @@
   void ComputeOutSets() {
     BitVector* temp = new BitVector(aliased_set_->max_place_id());
     BitVector* forwarded_loads = new BitVector(aliased_set_->max_place_id());
+    BitVector* temp_out = new BitVector(aliased_set_->max_place_id());
 
     bool changed = true;
     while (changed) {
@@ -5866,9 +5858,17 @@
           for (intptr_t i = 0; i < block->PredecessorCount(); i++) {
             BlockEntryInstr* pred = block->PredecessorAt(i);
             BitVector* pred_out = out_[pred->preorder_number()];
-            if (pred_out != NULL) {
-              temp->Intersect(pred_out);
+            if (pred_out == NULL) continue;
+            PhiPlaceMoves::MovesList phi_moves =
+                aliased_set_->phi_moves()->GetOutgoingMoves(pred);
+            if (phi_moves != NULL) {
+              // If there are phi moves, perform intersection with
+              // a copy of pred_out where the phi moves are applied.
+              temp_out->CopyFrom(pred_out);
+              PerformPhiMoves(phi_moves, temp_out, forwarded_loads);
+              pred_out = temp_out;
             }
+            temp->Intersect(pred_out);
           }
         }
 
@@ -5879,12 +5879,6 @@
           temp->RemoveAll(block_kill);
           temp->AddAll(block_gen);
 
-          PhiPlaceMoves::MovesList phi_moves =
-              aliased_set_->phi_moves()->GetOutgoingMoves(block);
-          if (phi_moves != NULL) {
-            PerformPhiMoves(phi_moves, temp, forwarded_loads);
-          }
-
           if ((block_out == NULL) || !block_out->Equals(*temp)) {
             if (block_out == NULL) {
               block_out = out_[preorder_number] =
diff --git a/sdk/lib/_internal/compiler/implementation/inferrer/inferrer_visitor.dart b/sdk/lib/_internal/compiler/implementation/inferrer/inferrer_visitor.dart
index c9646c3..3207932 100644
--- a/sdk/lib/_internal/compiler/implementation/inferrer/inferrer_visitor.dart
+++ b/sdk/lib/_internal/compiler/implementation/inferrer/inferrer_visitor.dart
@@ -812,14 +812,19 @@
     } else if ("&&" == op.source) {
       conditionIsSimple = false;
       bool oldAccumulateIsChecks = accumulateIsChecks;
-      accumulateIsChecks = true;
-      if (isChecks == null) isChecks = <Send>[];
+      List<Send> oldIsChecks = isChecks;
+      if (!accumulateIsChecks) {
+        accumulateIsChecks = true;
+        isChecks = <Send>[];
+      }
       visit(node.receiver);
-      accumulateIsChecks = oldAccumulateIsChecks;
-      if (!accumulateIsChecks) isChecks = null;
       LocalsHandler<T> saved = locals;
       locals = new LocalsHandler<T>.from(locals, node);
       updateIsChecks(isChecks, usePositive: true);
+      if (!oldAccumulateIsChecks) {
+        accumulateIsChecks = false;
+        isChecks = oldIsChecks;
+      }
       visit(node.arguments.head);
       saved.mergeDiamondFlow(locals, null);
       locals = saved;
@@ -827,10 +832,10 @@
     } else if ("||" == op.source) {
       conditionIsSimple = false;
       List<Send> tests = <Send>[];
-      handleCondition(node.receiver, tests);
+      bool isSimple = handleCondition(node.receiver, tests);
       LocalsHandler<T> saved = locals;
       locals = new LocalsHandler<T>.from(locals, node);
-      updateIsChecks(tests, usePositive: false);
+      if (isSimple) updateIsChecks(tests, usePositive: false);
       bool oldAccumulateIsChecks = accumulateIsChecks;
       accumulateIsChecks = false;
       visit(node.arguments.head);
diff --git a/tests/compiler/dart2js/simple_inferrer_and_or_test.dart b/tests/compiler/dart2js/simple_inferrer_and_or_test.dart
index 19926f0..67004a3 100644
--- a/tests/compiler/dart2js/simple_inferrer_and_or_test.dart
+++ b/tests/compiler/dart2js/simple_inferrer_and_or_test.dart
@@ -44,6 +44,39 @@
   return a;
 }
 
+returnDyn7b(x) => x;
+
+returnDyn7() {
+  var a = "foo";
+  if (a.length == 3) a = 52;
+  if ((a is int) || (a is String && true)) returnDyn7b(a);
+  return a;
+}
+
+returnDyn8(x) => x;
+
+test8() {
+  var a = "foo";
+  if (a.length == 3) a = 52;
+  if ((false && a is! String) || returnDyn8(a)) return a;
+}
+
+returnDyn9(x) => x;
+
+test9() {
+  var a = "foo";
+  if (a.length == 3) a = 52;
+  if (!(a is bool && a is bool)) returnDyn9(a);
+}
+
+returnString(x) => x;
+
+test10() {
+  var a = "foo";
+  if (a.length == 3) a = 52;
+  if (!(a is num) && a is String) returnString(a);
+}
+
 main() {
   returnDyn1();
   returnDyn2();
@@ -51,6 +84,10 @@
   returnDyn4();
   returnDyn5();
   returnDyn6();
+  returnDyn7();
+  test8();
+  test9();
+  test10();
 }
 """;
 
@@ -76,5 +113,10 @@
     checkReturn('returnDyn4', compiler.typesTask.dynamicType.nonNullable());
     checkReturn('returnDyn5', compiler.typesTask.dynamicType.nonNullable());
     checkReturn('returnDyn6', compiler.typesTask.dynamicType.nonNullable());
+    checkReturn('returnDyn7', subclassOfInterceptor);
+    checkReturn('returnDyn7b', subclassOfInterceptor);
+    checkReturn('returnDyn8', subclassOfInterceptor);
+    checkReturn('returnDyn9', subclassOfInterceptor);
+    checkReturn('returnString', compiler.typesTask.stringType);
   }));
 }
diff --git a/tests/language/logical_expression2_test.dart b/tests/language/logical_expression2_test.dart
new file mode 100644
index 0000000..7d6ddd5
--- /dev/null
+++ b/tests/language/logical_expression2_test.dart
@@ -0,0 +1,31 @@
+// Copyright (c) 2014, 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.
+
+import "package:expect/expect.dart";
+
+// Regression test for issue 17149.
+
+int globalCounter = 0;
+
+void nonInlinedUse(Object object) {
+  if (new DateTime.now().millisecondsSinceEpoch == 42) nonInlinedUse(object);
+  if (object is! String) globalCounter++;
+}
+
+int confuse(x) {
+  if (new DateTime.now().millisecondsSinceEpoch == 42) return confuse(x - 1);
+  return x;
+}
+
+main() {
+  var o = [ "foo", 499 ][confuse(1)];
+
+  // The `o is String` check in the rhs of the logical or must not be
+  // propagated to the `if` body.
+  if ((o is num) ||
+      (o is String && true)) {
+    nonInlinedUse(o);
+  }
+  Expect.equals(1, globalCounter);
+}
diff --git a/tests/language/logical_expression3_test.dart b/tests/language/logical_expression3_test.dart
new file mode 100644
index 0000000..2a90d70
--- /dev/null
+++ b/tests/language/logical_expression3_test.dart
@@ -0,0 +1,29 @@
+// Copyright (c) 2014, 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.
+
+import "package:expect/expect.dart";
+
+bool nonInlinedNumTypeCheck(Object object) {
+  if (new DateTime.now().millisecondsSinceEpoch == 42) {
+    return nonInlinedNumTypeCheck(object);
+  }
+  return object is num;
+}
+
+int confuse(x) {
+  if (new DateTime.now().millisecondsSinceEpoch == 42) return confuse(x - 1);
+  return x;
+}
+
+main() {
+  var o = [ "foo", 499 ][confuse(0)];
+
+  // When the lhs of a logical or fails, it must not assume that all negative is
+  // checks in it, have failed.
+  // Here, the `o is! num` check succeeds, but the length test failed.
+  if ((o is! num && o.length == 4) ||
+      (nonInlinedNumTypeCheck(o))) {
+    Expect.fail("Type-check failed");
+  }
+}
diff --git a/tests/language/logical_expression4_test.dart b/tests/language/logical_expression4_test.dart
new file mode 100644
index 0000000..4799a88
--- /dev/null
+++ b/tests/language/logical_expression4_test.dart
@@ -0,0 +1,27 @@
+// Copyright (c) 2014, 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.
+
+import "package:expect/expect.dart";
+
+bool nonInlinedNumTypeCheck(Object object) {
+  if (new DateTime.now().millisecondsSinceEpoch == 42) {
+    return nonInlinedNumTypeCheck(object);
+  }
+  return object is num;
+}
+
+int confuse(x) {
+  if (new DateTime.now().millisecondsSinceEpoch == 42) return confuse(x - 1);
+  return x;
+}
+
+main() {
+  var o = [ "foo", 499 ][confuse(0)];
+
+  // The is-checks in the '!' must not be propagated to the if-body.
+  // This was a bug in dart2js.
+  if (!(o is num && o is num)) {
+    Expect.isFalse((nonInlinedNumTypeCheck(o)));
+  }
+}
diff --git a/tests/language/logical_expression5_test.dart b/tests/language/logical_expression5_test.dart
new file mode 100644
index 0000000..5d983e0
--- /dev/null
+++ b/tests/language/logical_expression5_test.dart
@@ -0,0 +1,35 @@
+// Copyright (c) 2014, 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.
+
+import 'package:expect/expect.dart';
+
+bool nonInlinedNumTypeCheck(Object object) {
+  if (new DateTime.now().millisecondsSinceEpoch == 42) {
+    return nonInlinedNumTypeCheck(object);
+  }
+  return object is num;
+}
+
+bool nonInlinedStringTypeCheck(Object object) {
+  if (new DateTime.now().millisecondsSinceEpoch == 42) {
+    return nonInlinedStringTypeCheck(object);
+  }
+  return object is String;
+}
+
+int confuse(x) {
+  if (new DateTime.now().millisecondsSinceEpoch == 42) return confuse(x - 1);
+  return x;
+}
+
+main() {
+  var o = [ "foo", 499 ][confuse(0)];
+
+  // The is-checks in the '!' must not be propagated to the if-body, but
+  // the second is-check should.
+  if (!(o is num) && o is String) {
+    Expect.isFalse((nonInlinedNumTypeCheck(o)));
+    Expect.isTrue((nonInlinedStringTypeCheck(o)));
+  }
+}
diff --git a/tests/language/vm/load_to_load_forwarding_vm_test.dart b/tests/language/vm/load_to_load_forwarding_vm_test.dart
index 4a0faed..18cd44c 100644
--- a/tests/language/vm/load_to_load_forwarding_vm_test.dart
+++ b/tests/language/vm/load_to_load_forwarding_vm_test.dart
@@ -169,6 +169,27 @@
                      0.1, 0.0, -0.1], result);
 }
 
+
+class C {
+  C(this.box, this.parent);
+  final box;
+  final C parent;
+}
+
+testPhiForwarding5(C c) {
+  var s = 0;
+  var tmp = c;
+  var a = c.parent;
+  if (a.box + tmp.box != 1) throw "failed";
+  do {
+    s += tmp.box + a.box;
+    tmp = a;
+    a = a.parent;
+  } while (a != null);
+  return s;
+}
+
+
 class U {
   var x, y;
   U() : x = 0, y = 0;
@@ -260,6 +281,8 @@
 
   final obj = new X(new X(new X(null)));
 
+  final cs = new C(0, new C(1, new C(2, null))); 
+
   for (var i = 0; i < 20; i++) {
     Expect.listEquals([0x02010000, 0x03020100], foo(new A(0, 0)));
     Expect.listEquals([0x02010000, 0x03020100], bar(new A(0, 0), false));
@@ -270,6 +293,7 @@
     testPhiForwarding2(obj);
     testPhiForwarding3();
     testPhiForwarding4();
+    Expect.equals(4, testPhiForwarding5(cs));
     testEqualPhisElimination();
   }
 
diff --git a/tools/VERSION b/tools/VERSION
index 0fc6d04..abd8144 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -26,6 +26,6 @@
 CHANNEL stable
 MAJOR 1
 MINOR 2
-PATCH 0
+PATCH 1
 PRERELEASE 0
 PRERELEASE_PATCH 0