Version 1.8.6

svn merge -c 43014 https://dart.googlecode.com/svn/branches/bleeding_edge 1.8
svn merge -c 42396 https://dart.googlecode.com/svn/branches/bleeding_edge 1.8
svn merge -c 44046 https://dart.googlecode.com/svn/branches/bleeding_edge 1.8 --accept working

R=vegorov@google.com

Review URL: https://codereview.chromium.org//963483002

git-svn-id: http://dart.googlecode.com/svn/branches/1.8@44048 260f80e4-7a28-3924-810f-c04153c831b5
diff --git a/runtime/vm/flow_graph_compiler.cc b/runtime/vm/flow_graph_compiler.cc
index 5bb8e09..adf62e1 100644
--- a/runtime/vm/flow_graph_compiler.cc
+++ b/runtime/vm/flow_graph_compiler.cc
@@ -685,57 +685,11 @@
   //    corresponding spill slot locations.
   for (Environment::DeepIterator it(env); !it.Done(); it.Advance()) {
     Location loc = it.CurrentLocation();
-    if (loc.IsRegister()) {
-      intptr_t index = cpu_reg_slots[loc.reg()];
-      ASSERT(index >= 0);
-      it.SetCurrentLocation(Location::StackSlot(index));
-    } else if (loc.IsFpuRegister()) {
-      intptr_t index = fpu_reg_slots[loc.fpu_reg()];
-      ASSERT(index >= 0);
-      Value* value = it.CurrentValue();
-      switch (value->definition()->representation()) {
-        case kUnboxedDouble:
-          it.SetCurrentLocation(Location::DoubleStackSlot(index));
-          break;
-        case kUnboxedFloat32x4:
-        case kUnboxedInt32x4:
-        case kUnboxedFloat64x2:
-          it.SetCurrentLocation(Location::QuadStackSlot(index));
-          break;
-        default:
-          UNREACHABLE();
-      }
-    } else if (loc.IsPairLocation()) {
-      intptr_t representation =
-          it.CurrentValue()->definition()->representation();
-      ASSERT(representation == kUnboxedMint);
-      PairLocation* value_pair = loc.AsPairLocation();
-      intptr_t index_lo;
-      intptr_t index_hi;
-      if (value_pair->At(0).IsRegister()) {
-        index_lo = cpu_reg_slots[value_pair->At(0).reg()];
-      } else {
-        ASSERT(value_pair->At(0).IsStackSlot());
-        index_lo = value_pair->At(0).stack_index();
-      }
-      if (value_pair->At(1).IsRegister()) {
-        index_hi = cpu_reg_slots[value_pair->At(1).reg()];
-      } else {
-        ASSERT(value_pair->At(1).IsStackSlot());
-        index_hi = value_pair->At(1).stack_index();
-      }
-      it.SetCurrentLocation(Location::Pair(Location::StackSlot(index_lo),
-                                           Location::StackSlot(index_hi)));
-    } else if (loc.IsInvalid()) {
-      Definition* def =
-          it.CurrentValue()->definition();
-      ASSERT(def != NULL);
-      if (def->IsMaterializeObject()) {
-        def->AsMaterializeObject()->RemapRegisters(fpu_reg_slots,
-                                                   cpu_reg_slots);
-      }
-    }
+    Value* value = it.CurrentValue();
+    it.SetCurrentLocation(loc.RemapForSlowPath(
+        value->definition(), cpu_reg_slots, fpu_reg_slots));
   }
+
   return env;
 }
 
diff --git a/runtime/vm/flow_graph_range_analysis.cc b/runtime/vm/flow_graph_range_analysis.cc
index d4f192a..c752e93 100644
--- a/runtime/vm/flow_graph_range_analysis.cc
+++ b/runtime/vm/flow_graph_range_analysis.cc
@@ -2540,12 +2540,22 @@
       ((left_max == 0) || (right_max <= kMaxInt64 / left_max))) {
     // Product of left and right max values stays in 64 bit range.
     const int64_t mul_max = left_max * right_max;
-    const int64_t r_min =
-        OnlyPositiveOrZero(*left_range, *right_range) ? 0 : -mul_max;
-    *result_min = RangeBoundary::FromConstant(r_min);
-    const int64_t r_max =
-        OnlyNegativeOrZero(*left_range, *right_range) ? 0 : mul_max;
-    *result_max = RangeBoundary::FromConstant(r_max);
+    if (OnlyPositiveOrZero(*left_range, *right_range) ||
+        OnlyNegativeOrZero(*left_range, *right_range)) {
+      // If both ranges are of the same sign then the range of the result
+      // is positive and is between multiplications of absolute minimums
+      // and absolute maximums.
+      const int64_t mul_min =
+          ConstantAbsMin(left_range) * ConstantAbsMin(right_range);
+      *result_min = RangeBoundary::FromConstant(mul_min);
+      *result_max = RangeBoundary::FromConstant(mul_max);
+    } else {
+      // If ranges have mixed signs then use conservative approximation:
+      // absolute value of the result is less or equal to multiplication
+      // of absolute maximums.
+      *result_min = RangeBoundary::FromConstant(-mul_max);
+      *result_max = RangeBoundary::FromConstant(mul_max);
+    }
     return;
   }
 
@@ -2585,6 +2595,17 @@
 }
 
 
+// Return the minimum absolute value included in range.
+int64_t Range::ConstantAbsMin(const Range* range) {
+  if (range == NULL) {
+    return 0;
+  }
+  const int64_t abs_min = Utils::Abs(Range::ConstantMin(range).ConstantValue());
+  const int64_t abs_max = Utils::Abs(Range::ConstantMax(range).ConstantValue());
+  return Utils::Minimum(abs_min, abs_max);
+}
+
+
 void Range::BinaryOp(const Token::Kind op,
                      const Range* left_range,
                      const Range* right_range,
diff --git a/runtime/vm/flow_graph_range_analysis.h b/runtime/vm/flow_graph_range_analysis.h
index 3b39ba2..7ab76a0 100644
--- a/runtime/vm/flow_graph_range_analysis.h
+++ b/runtime/vm/flow_graph_range_analysis.h
@@ -473,6 +473,9 @@
   // Return the maximum absolute value included in range.
   static int64_t ConstantAbsMax(const Range* range);
 
+  // Return the minimum absolute value included in range.
+  static int64_t ConstantAbsMin(const Range* range);
+
   static void BinaryOp(const Token::Kind op,
                        const Range* left_range,
                        const Range* right_range,
diff --git a/runtime/vm/intermediate_language.cc b/runtime/vm/intermediate_language.cc
index 8040c50..2a05f0d 100644
--- a/runtime/vm/intermediate_language.cc
+++ b/runtime/vm/intermediate_language.cc
@@ -191,7 +191,7 @@
   ASSERT(IsDenseSwitch());
   intptr_t mask = 0;
   for (intptr_t i = 0; i < cids_.length(); ++i) {
-    mask |= 1 << (cids_[i] - cids_[0]);
+    mask |= static_cast<intptr_t>(1) << (cids_[i] - cids_[0]);
   }
   return mask;
 }
@@ -2632,42 +2632,16 @@
 
 // This function should be kept in sync with
 // FlowGraphCompiler::SlowPathEnvironmentFor().
-void MaterializeObjectInstr::RemapRegisters(intptr_t* fpu_reg_slots,
-                                            intptr_t* cpu_reg_slots) {
+void MaterializeObjectInstr::RemapRegisters(intptr_t* cpu_reg_slots,
+                                            intptr_t* fpu_reg_slots) {
   if (registers_remapped_) {
     return;
   }
   registers_remapped_ = true;
 
   for (intptr_t i = 0; i < InputCount(); i++) {
-    Location loc = LocationAt(i);
-    if (loc.IsRegister()) {
-      intptr_t index = cpu_reg_slots[loc.reg()];
-      ASSERT(index >= 0);
-      locations_[i] = Location::StackSlot(index);
-    } else if (loc.IsFpuRegister()) {
-      intptr_t index = fpu_reg_slots[loc.fpu_reg()];
-      ASSERT(index >= 0);
-      Value* value = InputAt(i);
-      switch (value->definition()->representation()) {
-        case kUnboxedDouble:
-          locations_[i] = Location::DoubleStackSlot(index);
-          break;
-        case kUnboxedFloat32x4:
-        case kUnboxedInt32x4:
-        case kUnboxedFloat64x2:
-          locations_[i] = Location::QuadStackSlot(index);
-          break;
-        default:
-          UNREACHABLE();
-      }
-    } else if (loc.IsPairLocation()) {
-      UNREACHABLE();
-    } else if (loc.IsInvalid() &&
-               InputAt(i)->definition()->IsMaterializeObject()) {
-      InputAt(i)->definition()->AsMaterializeObject()->RemapRegisters(
-          fpu_reg_slots, cpu_reg_slots);
-    }
+    locations_[i] = LocationAt(i).RemapForSlowPath(
+        InputAt(i)->definition(), cpu_reg_slots, fpu_reg_slots);
   }
 }
 
diff --git a/runtime/vm/intermediate_language.h b/runtime/vm/intermediate_language.h
index b877e93..5552b74 100644
--- a/runtime/vm/intermediate_language.h
+++ b/runtime/vm/intermediate_language.h
@@ -3926,8 +3926,8 @@
 
   virtual bool MayThrow() const { return false; }
 
-  void RemapRegisters(intptr_t* fpu_reg_slots,
-                      intptr_t* cpu_reg_slots);
+  void RemapRegisters(intptr_t* cpu_reg_slots,
+                      intptr_t* fpu_reg_slots);
 
   bool was_visited_for_liveness() const { return visited_for_liveness_; }
   void mark_visited_for_liveness() {
diff --git a/runtime/vm/locations.cc b/runtime/vm/locations.cc
index 0951aa9..2419594 100644
--- a/runtime/vm/locations.cc
+++ b/runtime/vm/locations.cc
@@ -244,6 +244,59 @@
 }
 
 
+Location Location::RemapForSlowPath(Definition* def,
+                                    intptr_t* cpu_reg_slots,
+                                    intptr_t* fpu_reg_slots) const {
+  if (IsRegister()) {
+    intptr_t index = cpu_reg_slots[reg()];
+    ASSERT(index >= 0);
+    return Location::StackSlot(index);
+  } else if (IsFpuRegister()) {
+    intptr_t index = fpu_reg_slots[fpu_reg()];
+    ASSERT(index >= 0);
+    switch (def->representation()) {
+      case kUnboxedDouble:
+        return Location::DoubleStackSlot(index);
+
+      case kUnboxedFloat32x4:
+      case kUnboxedInt32x4:
+      case kUnboxedFloat64x2:
+        return Location::QuadStackSlot(index);
+
+      default:
+        UNREACHABLE();
+    }
+  } else if (IsPairLocation()) {
+    ASSERT(def->representation() == kUnboxedMint);
+    PairLocation* value_pair = AsPairLocation();
+    intptr_t index_lo;
+    intptr_t index_hi;
+
+    if (value_pair->At(0).IsRegister()) {
+      index_lo = cpu_reg_slots[value_pair->At(0).reg()];
+    } else {
+      ASSERT(value_pair->At(0).IsStackSlot());
+      index_lo = value_pair->At(0).stack_index();
+    }
+
+    if (value_pair->At(1).IsRegister()) {
+      index_hi = cpu_reg_slots[value_pair->At(1).reg()];
+    } else {
+      ASSERT(value_pair->At(1).IsStackSlot());
+      index_hi = value_pair->At(1).stack_index();
+    }
+
+    return Location::Pair(Location::StackSlot(index_lo),
+                          Location::StackSlot(index_hi));
+  } else if (IsInvalid() && def->IsMaterializeObject()) {
+    def->AsMaterializeObject()->RemapRegisters(cpu_reg_slots, fpu_reg_slots);
+    return *this;
+  }
+
+  return *this;
+}
+
+
 void LocationSummary::PrintTo(BufferFormatter* f) const {
   if (input_count() > 0) {
     f->Print(" (");
diff --git a/runtime/vm/locations.h b/runtime/vm/locations.h
index e4bf340..0b9bf50 100644
--- a/runtime/vm/locations.h
+++ b/runtime/vm/locations.h
@@ -11,10 +11,12 @@
 
 namespace dart {
 
+
 class BufferFormatter;
-class Value;
-class PairLocation;
 class ConstantInstr;
+class Definition;
+class PairLocation;
+class Value;
 
 
 enum Representation {
@@ -370,6 +372,10 @@
 
   Location Copy() const;
 
+  Location RemapForSlowPath(Definition* def,
+                            intptr_t* cpu_reg_slots,
+                            intptr_t* fpu_reg_slots) const;
+
  private:
   explicit Location(uword value) : value_(value) { }
 
diff --git a/tests/language/vm/optimized_check_class_test.dart b/tests/language/vm/optimized_check_class_test.dart
new file mode 100644
index 0000000..c1e32bf
--- /dev/null
+++ b/tests/language/vm/optimized_check_class_test.dart
@@ -0,0 +1,70 @@
+// 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=10 --no-use-osr
+
+import "package:expect/expect.dart";
+
+// Test dense class-id checks. Regression test for issue 22104.
+
+class A {
+  toString() => "an A";
+}
+
+class A1 extends A { }
+class A2 extends A { }
+class A3 extends A { }
+class A4 extends A { toString() => "ha"; }
+class A5 extends A { }
+class A6 extends A { }
+class A7 extends A { }
+class A8 extends A { }
+class A9 extends A { }
+class A10 extends A { }
+class A11 extends A { }
+class A12 extends A { }
+class A13 extends A { }
+class A14 extends A { }
+class A15 extends A { }
+class A16 extends A { }
+class A17 extends A { }
+class A18 extends A { }
+class A19 extends A { }
+class A20 extends A { }
+class A21 extends A { }
+class A22 extends A { }
+class A23 extends A { }
+class A24 extends A { }
+class A25 extends A { }
+class A26 extends A { }
+class A27 extends A { }
+class A28 extends A { }
+class A29 extends A { }
+class A30 extends A { }
+class A31 extends A { }
+class A32 extends A { }
+class A33 extends A { }
+class A34 extends A { }
+class A35 extends A { }
+class A36 extends A { }
+
+test_class_check(e) => e.toString();
+
+main() {
+  var list = [
+    new A1(),
+    new A2(),
+    new A11(),
+    new A36()
+  ];
+  for (var i = 0; i < list.length; i++) {
+    test_class_check(list[i]);
+  }
+  for (var i = 0; i < 100; i++) {
+    Expect.equals("an A", test_class_check(new A1()));
+  }
+  Expect.equals("ha", test_class_check(new A4()));
+}
+
+
+
diff --git a/tests/language/vm/regress_22541_vm_test.dart b/tests/language/vm/regress_22541_vm_test.dart
new file mode 100644
index 0000000..36b4618
--- /dev/null
+++ b/tests/language/vm/regress_22541_vm_test.dart
@@ -0,0 +1,22 @@
+// 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.
+// Test range inference for multiplication of two negative values.
+// VMOptions=--optimization-counter-threshold=10 --no-use-osr
+
+import 'package:expect/expect.dart';
+
+test(a) {
+  var x = a ? -1 : -2;
+  if (0 < (x * x)) {
+    return "ok";
+  } else {
+    return "fail";
+  }
+}
+
+main() {
+  for (var j = 0; j < 20; j++) {
+    Expect.equals("ok", test(false));
+  }
+}
diff --git a/tests/standalone/pair_location_remapping_test.dart b/tests/standalone/pair_location_remapping_test.dart
new file mode 100644
index 0000000..277ccc5
--- /dev/null
+++ b/tests/standalone/pair_location_remapping_test.dart
@@ -0,0 +1,30 @@
+// 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.
+// Test that pair locations are remaped in slow path environments.
+// VMOptions=--optimization_counter_threshold=10 --no-use-osr
+
+import "package:expect/expect.dart";
+
+class A {
+  final f;
+  A(this.f);
+}
+
+foo(i) {
+  var j = 0x7fffffffffffffff + i;
+  var c = new A(j);  // allocation will be sunk
+  var r = 0;
+  for (var k = 0; k < 10; k++) {
+    if ((j & (1 << k)) != 0) {
+      r++;
+    }
+  }
+  return c.f - r;
+}
+
+main() {
+  for (var i = 0; i < 1000; i++) {
+    Expect.equals(0x7fffffffffffffff - 10, foo(0));
+  }
+}
diff --git a/tests/standalone/standalone.status b/tests/standalone/standalone.status
index d51d56e..a9ebe42 100644
--- a/tests/standalone/standalone.status
+++ b/tests/standalone/standalone.status
@@ -88,6 +88,7 @@
 javascript_compatibility_errors_test: Skip
 javascript_compatibility_warnings_test: Skip
 unboxed_int_converter_test: Skip
+pair_location_remapping_test: Skip
 
 [ $compiler == dart2js && $jscl ]
 assert_test: RuntimeError, OK # Assumes unspecified fields on the AssertionError.
diff --git a/tools/VERSION b/tools/VERSION
index ad37b7d..3a08bad 100644
--- a/tools/VERSION
+++ b/tools/VERSION
@@ -26,6 +26,6 @@
 CHANNEL stable
 MAJOR 1
 MINOR 8
-PATCH 5
+PATCH 6
 PRERELEASE 0
 PRERELEASE_PATCH 0