Revision: 24637
Author:   [email protected]
Date:     Wed Oct 15 13:35:30 2014 UTC
Log:      Version 3.30.11 (based on bleeding_edge revision r24621)

Array.prototype.{every, filter, find, findIndex, forEach, map, some}: Use fresh primitive wrapper for calls (issue 3536).

Correctly expand literal buffer for surrogate pairs (Chromium issue 423212).

Performance and stability improvements on all platforms.
https://code.google.com/p/v8/source/detail?r=24637

Added:
 /trunk/test/cctest/compiler/test-typer.cc
 /trunk/test/mjsunit/asm/int32div.js
 /trunk/test/mjsunit/asm/int32mod.js
 /trunk/test/mjsunit/regress/regress-417709a.js
Modified:
 /trunk/ChangeLog
 /trunk/include/v8.h
 /trunk/src/accessors.cc
 /trunk/src/accessors.h
 /trunk/src/api.cc
 /trunk/src/array.js
 /trunk/src/ast.cc
 /trunk/src/ast.h
 /trunk/src/bootstrapper.cc
 /trunk/src/code-stubs-hydrogen.cc
 /trunk/src/collection.js
 /trunk/src/compiler/arm/code-generator-arm.cc
 /trunk/src/compiler/arm/instruction-codes-arm.h
 /trunk/src/compiler/arm/instruction-selector-arm.cc
 /trunk/src/compiler/arm64/code-generator-arm64.cc
 /trunk/src/compiler/arm64/instruction-codes-arm64.h
 /trunk/src/compiler/arm64/instruction-selector-arm64.cc
 /trunk/src/compiler/code-generator.cc
 /trunk/src/compiler/ia32/code-generator-ia32.cc
 /trunk/src/compiler/ia32/instruction-codes-ia32.h
 /trunk/src/compiler/ia32/instruction-selector-ia32.cc
 /trunk/src/compiler/instruction-selector.cc
 /trunk/src/compiler/instruction.h
 /trunk/src/compiler/js-typed-lowering.cc
 /trunk/src/compiler/machine-operator-reducer.cc
 /trunk/src/compiler/machine-operator-reducer.h
 /trunk/src/compiler/machine-operator.cc
 /trunk/src/compiler/machine-operator.h
 /trunk/src/compiler/mips/code-generator-mips.cc
 /trunk/src/compiler/mips/instruction-codes-mips.h
 /trunk/src/compiler/mips/instruction-selector-mips.cc
 /trunk/src/compiler/opcodes.h
 /trunk/src/compiler/raw-machine-assembler.h
 /trunk/src/compiler/scheduler.cc
 /trunk/src/compiler/typer.cc
 /trunk/src/compiler/typer.h
 /trunk/src/compiler/verifier.cc
 /trunk/src/compiler/x64/code-generator-x64.cc
 /trunk/src/compiler/x64/instruction-codes-x64.h
 /trunk/src/compiler/x64/instruction-selector-x64.cc
 /trunk/src/counters.cc
 /trunk/src/factory.cc
 /trunk/src/factory.h
 /trunk/src/harmony-array.js
 /trunk/src/heap/heap.cc
 /trunk/src/heap/heap.h
 /trunk/src/heap/mark-compact.cc
 /trunk/src/heap/mark-compact.h
 /trunk/src/heap/objects-visiting-inl.h
 /trunk/src/heap/objects-visiting.cc
 /trunk/src/heap/objects-visiting.h
 /trunk/src/ic/ic.h
 /trunk/src/isolate.cc
 /trunk/src/log-inl.h
 /trunk/src/log.cc
 /trunk/src/log.h
 /trunk/src/macros.py
 /trunk/src/mksnapshot.cc
 /trunk/src/objects-debug.cc
 /trunk/src/objects-inl.h
 /trunk/src/objects-printer.cc
 /trunk/src/objects.cc
 /trunk/src/objects.h
 /trunk/src/runtime/runtime-function.cc
 /trunk/src/runtime/runtime-maths.cc
 /trunk/src/runtime/runtime-object.cc
 /trunk/src/scanner.h
 /trunk/src/types.cc
 /trunk/src/types.h
 /trunk/src/version.cc
 /trunk/test/cctest/cctest.gyp
 /trunk/test/cctest/compiler/test-js-constant-cache.cc
 /trunk/test/cctest/compiler/test-js-typed-lowering.cc
 /trunk/test/cctest/compiler/test-run-machops.cc
 /trunk/test/cctest/compiler/test-scheduler.cc
 /trunk/test/cctest/test-api.cc
 /trunk/test/cctest/test-heap.cc
 /trunk/test/cctest/test-serialize.cc
 /trunk/test/cctest/test-types.cc
 /trunk/test/mjsunit/array-iteration.js
 /trunk/test/mjsunit/es6/collections.js
 /trunk/test/mjsunit/harmony/array-find.js
 /trunk/test/mjsunit/harmony/array-findindex.js
 /trunk/test/unittests/compiler/arm/instruction-selector-arm-unittest.cc
 /trunk/test/unittests/compiler/arm64/instruction-selector-arm64-unittest.cc
 /trunk/test/unittests/compiler/graph-unittest.cc
 /trunk/test/unittests/compiler/graph-unittest.h
 /trunk/test/unittests/compiler/ia32/instruction-selector-ia32-unittest.cc
 /trunk/test/unittests/compiler/machine-operator-reducer-unittest.cc
 /trunk/test/unittests/compiler/machine-operator-unittest.cc
 /trunk/test/unittests/compiler/x64/instruction-selector-x64-unittest.cc
 /trunk/tools/push-to-trunk/common_includes.py
 /trunk/tools/whitespace.txt

=======================================
--- /dev/null
+++ /trunk/test/cctest/compiler/test-typer.cc   Wed Oct 15 13:35:30 2014 UTC
@@ -0,0 +1,277 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+
+// This tests the correctness of the typer.
+//
+// For simplicity, it currently only tests it on expression operators that have +// a direct equivalent in C++. Also, testing is currently limited to ranges as
+// input types.
+
+
+#include <functional>
+
+#include "src/compiler/node-properties-inl.h"
+#include "src/compiler/typer.h"
+#include "test/cctest/cctest.h"
+#include "test/cctest/compiler/graph-builder-tester.h"
+
+using namespace v8::internal;
+using namespace v8::internal::compiler;
+
+
+
+class TyperTester : public HandleAndZoneScope, public GraphAndBuilders {
+ public:
+  TyperTester()
+      : GraphAndBuilders(main_zone()),
+        typer_(main_zone()),
+        javascript_(main_zone()) {
+    Node* s = graph()->NewNode(common()->Start(3));
+    graph()->SetStart(s);
+ context_node_ = graph()->NewNode(common()->Parameter(2), graph()->start());
+    rng_ = isolate()->random_number_generator();
+
+    integers.push_back(0);
+    integers.push_back(0);
+    integers.push_back(-1);
+    integers.push_back(+1);
+    integers.push_back(-V8_INFINITY);
+    integers.push_back(+V8_INFINITY);
+    for (int i = 0; i < 5; ++i) {
+      double x = rng_->NextInt();
+      integers.push_back(x);
+      x *= rng_->NextInt();
+      if (!IsMinusZero(x)) integers.push_back(x);
+    }
+
+    int32s.push_back(0);
+    int32s.push_back(0);
+    int32s.push_back(-1);
+    int32s.push_back(+1);
+    int32s.push_back(kMinInt);
+    int32s.push_back(kMaxInt);
+    for (int i = 0; i < 10; ++i) {
+      int32s.push_back(rng_->NextInt());
+    }
+  }
+
+  Typer typer_;
+  JSOperatorBuilder javascript_;
+  Node* context_node_;
+  v8::base::RandomNumberGenerator* rng_;
+  std::vector<double> integers;
+  std::vector<double> int32s;
+
+  Isolate* isolate() { return main_isolate(); }
+  Graph* graph() { return main_graph_; }
+  CommonOperatorBuilder* common() { return &main_common_; }
+
+  Node* Parameter(int index = 0) {
+    return graph()->NewNode(common()->Parameter(index), graph()->start());
+  }
+
+  Type* TypeBinaryOp(const Operator* op, Type* lhs, Type* rhs) {
+    Node* p0 = Parameter(0);
+    Node* p1 = Parameter(1);
+    NodeProperties::SetBounds(p0, Bounds(lhs));
+    NodeProperties::SetBounds(p1, Bounds(rhs));
+    Node* n = graph()->NewNode(
+        op, p0, p1, context_node_, graph()->start(), graph()->start());
+    typer_.Init(n);
+    return NodeProperties::GetBounds(n).upper;
+  }
+
+  Type* RandomRange(bool int32 = false) {
+    std::vector<double>& numbers = int32 ? int32s : integers;
+    Factory* f = isolate()->factory();
+    int i = rng_->NextInt(static_cast<int>(numbers.size()));
+    int j = rng_->NextInt(static_cast<int>(numbers.size()));
+    i::Handle<i::Object> min = f->NewNumber(numbers[i]);
+    i::Handle<i::Object> max = f->NewNumber(numbers[j]);
+    if (min->Number() > max->Number()) std::swap(min, max);
+    return Type::Range(min, max, main_zone());
+  }
+
+  double RandomInt(double min, double max) {
+    switch (rng_->NextInt(4)) {
+      case 0: return min;
+      case 1: return max;
+      default: break;
+    }
+    if (min == +V8_INFINITY) return +V8_INFINITY;
+    if (max == -V8_INFINITY) return -V8_INFINITY;
+    if (min == -V8_INFINITY && max == +V8_INFINITY) {
+      return rng_->NextInt() * static_cast<double>(rng_->NextInt());
+    }
+    double result = nearbyint(min + (max - min) * rng_->NextDouble());
+    if (IsMinusZero(result)) return 0;
+    if (std::isnan(result)) return rng_->NextInt(2) ? min : max;
+    DCHECK(min <= result && result <= max);
+    return result;
+  }
+
+  double RandomInt(Type::RangeType* range) {
+    return RandomInt(range->Min()->Number(), range->Max()->Number());
+  }
+
+  template <class BinaryFunction>
+  void TestBinaryArithOp(const Operator* op, BinaryFunction opfun) {
+    for (int i = 0; i < 100; ++i) {
+      Type::RangeType* r1 = RandomRange()->AsRange();
+      Type::RangeType* r2 = RandomRange()->AsRange();
+      Type* expected_type = TypeBinaryOp(op, r1, r2);
+      double x1 = RandomInt(r1);
+      double x2 = RandomInt(r2);
+      double result_value = opfun(x1, x2);
+      Type* result_type = Type::Constant(
+          isolate()->factory()->NewNumber(result_value), main_zone());
+      CHECK(result_type->Is(expected_type));
+    }
+  }
+
+  template <class BinaryFunction>
+  void TestBinaryCompareOp(const Operator* op, BinaryFunction opfun) {
+    for (int i = 0; i < 100; ++i) {
+      Type::RangeType* r1 = RandomRange()->AsRange();
+      Type::RangeType* r2 = RandomRange()->AsRange();
+      Type* expected_type = TypeBinaryOp(op, r1, r2);
+      double x1 = RandomInt(r1);
+      double x2 = RandomInt(r2);
+      bool result_value = opfun(x1, x2);
+      Type* result_type = Type::Constant(result_value ?
+          isolate()->factory()->true_value() :
+          isolate()->factory()->false_value(), main_zone());
+      CHECK(result_type->Is(expected_type));
+    }
+  }
+
+  template <class BinaryFunction>
+  void TestBinaryBitOp(const Operator* op, BinaryFunction opfun) {
+    for (int i = 0; i < 100; ++i) {
+      Type::RangeType* r1 = RandomRange(true)->AsRange();
+      Type::RangeType* r2 = RandomRange(true)->AsRange();
+      Type* expected_type = TypeBinaryOp(op, r1, r2);
+      int32_t x1 = static_cast<int32_t>(RandomInt(r1));
+      int32_t x2 = static_cast<int32_t>(RandomInt(r2));
+      double result_value = opfun(x1, x2);
+      Type* result_type = Type::Constant(
+          isolate()->factory()->NewNumber(result_value), main_zone());
+      CHECK(result_type->Is(expected_type));
+    }
+  }
+};
+
+
+static int32_t shift_left(int32_t x, int32_t y) { return x << y; }
+static int32_t shift_right(int32_t x, int32_t y) { return x >> y; }
+static int32_t bit_or(int32_t x, int32_t y) { return x | y; }
+static int32_t bit_and(int32_t x, int32_t y) { return x & y; }
+static int32_t bit_xor(int32_t x, int32_t y) { return x ^ y; }
+
+
+TEST(TypeJSAdd) {
+  TyperTester t;
+  t.TestBinaryArithOp(t.javascript_.Subtract(), std::plus<double>());
+}
+
+
+TEST(TypeJSSubtract) {
+  TyperTester t;
+  t.TestBinaryArithOp(t.javascript_.Subtract(), std::minus<double>());
+}
+
+
+TEST(TypeJSMultiply) {
+  TyperTester t;
+  t.TestBinaryArithOp(t.javascript_.Multiply(), std::multiplies<double>());
+}
+
+
+TEST(TypeJSDivide) {
+  TyperTester t;
+  t.TestBinaryArithOp(t.javascript_.Divide(), std::divides<double>());
+}
+
+
+TEST(TypeJSBitwiseOr) {
+  TyperTester t;
+  t.TestBinaryBitOp(t.javascript_.BitwiseOr(), bit_or);
+}
+
+
+TEST(TypeJSBitwiseAnd) {
+  TyperTester t;
+  t.TestBinaryBitOp(t.javascript_.BitwiseAnd(), bit_and);
+}
+
+
+TEST(TypeJSBitwiseXor) {
+  TyperTester t;
+  t.TestBinaryBitOp(t.javascript_.BitwiseXor(), bit_xor);
+}
+
+
+TEST(TypeJSShiftLeft) {
+  TyperTester t;
+  t.TestBinaryBitOp(t.javascript_.ShiftLeft(), shift_left);
+}
+
+
+TEST(TypeJSShiftRight) {
+  TyperTester t;
+  t.TestBinaryBitOp(t.javascript_.ShiftRight(), shift_right);
+}
+
+
+TEST(TypeJSLessThan) {
+  TyperTester t;
+  t.TestBinaryCompareOp(t.javascript_.LessThan(), std::less<double>());
+}
+
+
+TEST(TypeJSLessThanOrEqual) {
+  TyperTester t;
+  t.TestBinaryCompareOp(
+      t.javascript_.LessThanOrEqual(), std::less_equal<double>());
+}
+
+
+TEST(TypeJSGreaterThan) {
+  TyperTester t;
+ t.TestBinaryCompareOp(t.javascript_.GreaterThan(), std::greater<double>());
+}
+
+
+TEST(TypeJSGreaterThanOrEqual) {
+  TyperTester t;
+  t.TestBinaryCompareOp(
+      t.javascript_.GreaterThanOrEqual(), std::greater_equal<double>());
+}
+
+
+TEST(TypeJSEqual) {
+  TyperTester t;
+  t.TestBinaryCompareOp(t.javascript_.Equal(), std::equal_to<double>());
+}
+
+
+TEST(TypeJSNotEqual) {
+  TyperTester t;
+ t.TestBinaryCompareOp(t.javascript_.NotEqual(), std::not_equal_to<double>());
+}
+
+
+// For numbers there's no difference between strict and non-strict equality.
+TEST(TypeJSStrictEqual) {
+  TyperTester t;
+ t.TestBinaryCompareOp(t.javascript_.StrictEqual(), std::equal_to<double>());
+}
+
+
+TEST(TypeJSStrictNotEqual) {
+  TyperTester t;
+  t.TestBinaryCompareOp(
+      t.javascript_.StrictNotEqual(), std::not_equal_to<double>());
+}
=======================================
--- /dev/null
+++ /trunk/test/mjsunit/asm/int32div.js Wed Oct 15 13:35:30 2014 UTC
@@ -0,0 +1,33 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+var stdlib = {};
+var foreign = {};
+var heap = new ArrayBuffer(64 * 1024);
+
+function Int32Div(divisor) {
+  var name = "div_";
+  if (divisor < 0) {
+    name += "minus_";
+  }
+  name += Math.abs(divisor);
+  var m = eval("function Module(stdlib, foreign, heap) {\n"
+      + " \"use asm\";\n"
+      + " function " + name + "(dividend) {\n"
+      + "  return ((dividend | 0) / " + divisor + ") | 0;\n"
+      + " }\n"
+      + " return { f: " + name + "}\n"
+      + "}; Module");
+  return m(stdlib, foreign, heap).f;
+}
+
+var divisors = [-2147483648, -32 * 1024, -1000, -16, -7, -2, -1, 0,
+                1, 3, 4, 10, 64, 100, 1024, 2147483647];
+for (var i in divisors) {
+  var divisor = divisors[i];
+  var div = Int32Div(divisor);
+ for (var dividend = -2147483648; dividend < 2147483648; dividend += 3999773) {
+    assertEquals((dividend / divisor) | 0, div(dividend));
+  }
+}
=======================================
--- /dev/null
+++ /trunk/test/mjsunit/asm/int32mod.js Wed Oct 15 13:35:30 2014 UTC
@@ -0,0 +1,33 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+var stdlib = {};
+var foreign = {};
+var heap = new ArrayBuffer(64 * 1024);
+
+function Int32Mod(divisor) {
+  var name = "mod_";
+  if (divisor < 0) {
+    name += "minus_";
+  }
+  name += Math.abs(divisor);
+  var m = eval("function Module(stdlib, foreign, heap) {\n"
+      + " \"use asm\";\n"
+      + " function " + name + "(dividend) {\n"
+      + "  return ((dividend | 0) % " + divisor + ") | 0;\n"
+      + " }\n"
+      + " return { f: " + name + "}\n"
+      + "}; Module");
+  return m(stdlib, foreign, heap).f;
+}
+
+var divisors = [-2147483648, -32 * 1024, -1000, -16, -7, -2, -1,
+                1, 3, 4, 10, 64, 100, 1024, 2147483647];
+for (var i in divisors) {
+  var divisor = divisors[i];
+  var mod = Int32Mod(divisor);
+ for (var dividend = -2147483648; dividend < 2147483648; dividend += 3999773) {
+    assertEquals((dividend % divisor) | 0, mod(dividend));
+  }
+}
=======================================
--- /dev/null
+++ /trunk/test/mjsunit/regress/regress-417709a.js Wed Oct 15 13:35:30 2014 UTC
@@ -0,0 +1,16 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+// Flags: --stack-size=100
+
+var a = [];
+
+Object.observe(a, function() {});
+
+function f(a, x) {
+  a.length = x;
+  f(a, x + 1);
+}
+
+assertThrows(function() { f(a, 1); }, RangeError);
=======================================
--- /trunk/ChangeLog    Wed Oct 15 00:05:09 2014 UTC
+++ /trunk/ChangeLog    Wed Oct 15 13:35:30 2014 UTC
@@ -1,3 +1,14 @@
+2014-10-15: Version 3.30.11
+
+ Array.prototype.{every, filter, find, findIndex, forEach, map, some}:
+        Use fresh primitive wrapper for calls (issue 3536).
+
+        Correctly expand literal buffer for surrogate pairs (Chromium issue
+        423212).
+
+        Performance and stability improvements on all platforms.
+
+
 2014-10-15: Version 3.30.10

Squeeze the layout of various AST node types (Chromium issue 417697).
=======================================
--- /trunk/include/v8.h Thu Oct  9 00:05:16 2014 UTC
+++ /trunk/include/v8.h Wed Oct 15 13:35:30 2014 UTC
@@ -5927,7 +5927,7 @@
   static const int kNullValueRootIndex = 7;
   static const int kTrueValueRootIndex = 8;
   static const int kFalseValueRootIndex = 9;
-  static const int kEmptyStringRootIndex = 153;
+  static const int kEmptyStringRootIndex = 154;

// The external allocation limit should be below 256 MB on all architectures
   // to avoid that resource-constrained embedders run low on memory.
@@ -5942,7 +5942,7 @@
   static const int kNodeIsIndependentShift = 4;
   static const int kNodeIsPartiallyDependentShift = 5;

-  static const int kJSObjectType = 0xbc;
+  static const int kJSObjectType = 0xbd;
   static const int kFirstNonstringType = 0x80;
   static const int kOddballType = 0x83;
   static const int kForeignType = 0x88;
=======================================
--- /trunk/src/accessors.cc     Fri Oct  3 00:04:58 2014 UTC
+++ /trunk/src/accessors.cc     Wed Oct 15 13:35:30 2014 UTC
@@ -172,7 +172,10 @@
   LookupIterator it(object, Utils::OpenHandle(*name));
   CHECK_EQ(LookupIterator::ACCESSOR, it.state());
   DCHECK(it.HolderIsReceiverOrHiddenPrototype());
-  Object::SetDataProperty(&it, value);
+
+  if (Object::SetDataProperty(&it, value).is_null()) {
+    isolate->OptionalRescheduleException(false);
+  }
 }


@@ -247,7 +250,7 @@

   if (uint32_v->Number() == number_v->Number()) {
     maybe = JSArray::SetElementsLength(array_handle, uint32_v);
-    maybe.Check();
+    if (maybe.is_null()) isolate->OptionalRescheduleException(false);
     return;
   }

@@ -881,9 +884,8 @@
 }


-static Handle<Object> SetFunctionPrototype(Isolate* isolate,
-                                           Handle<JSFunction> function,
-                                           Handle<Object> value) {
+MUST_USE_RESULT static MaybeHandle<Object> SetFunctionPrototype(
+    Isolate* isolate, Handle<JSFunction> function, Handle<Object> value) {
   Handle<Object> old_value;
   bool is_observed = function->map()->is_observed();
   if (is_observed) {
@@ -897,16 +899,17 @@
   DCHECK(function->prototype() == *value);

   if (is_observed && !old_value->SameValue(*value)) {
-    JSObject::EnqueueChangeRecord(
+    MaybeHandle<Object> result = JSObject::EnqueueChangeRecord(
function, "update", isolate->factory()->prototype_string(), old_value);
+    if (result.is_null()) return MaybeHandle<Object>();
   }

   return function;
 }


-Handle<Object> Accessors::FunctionSetPrototype(Handle<JSFunction> function,
-                                               Handle<Object> prototype) {
+MaybeHandle<Object> Accessors::FunctionSetPrototype(Handle<JSFunction> function, + Handle<Object> prototype) {
   DCHECK(function->should_have_prototype());
   Isolate* isolate = function->GetIsolate();
   return SetFunctionPrototype(isolate, function, prototype);
@@ -937,7 +940,9 @@
   }
   Handle<JSFunction> object =
       Handle<JSFunction>::cast(Utils::OpenHandle(*info.Holder()));
-  SetFunctionPrototype(isolate, object, value);
+  if (SetFunctionPrototype(isolate, object, value).is_null()) {
+    isolate->OptionalRescheduleException(false);
+  }
 }


=======================================
--- /trunk/src/accessors.h      Fri Oct  3 00:04:58 2014 UTC
+++ /trunk/src/accessors.h      Wed Oct 15 13:35:30 2014 UTC
@@ -66,8 +66,8 @@
   };

   // Accessor functions called directly from the runtime system.
-  static Handle<Object> FunctionSetPrototype(Handle<JSFunction> object,
-                                             Handle<Object> value);
+  MUST_USE_RESULT static MaybeHandle<Object> FunctionSetPrototype(
+      Handle<JSFunction> object, Handle<Object> value);
   static Handle<Object> FunctionGetArguments(Handle<JSFunction> object);

   // Accessor infos.
=======================================
--- /trunk/src/api.cc   Thu Oct  9 00:05:16 2014 UTC
+++ /trunk/src/api.cc   Wed Oct 15 13:35:30 2014 UTC
@@ -6711,7 +6711,7 @@

 void Isolate::SetEventLogger(LogEventCallback that) {
   // Do not overwrite the event logger if we want to log explicitly.
-  if (i::FLAG_log_timer_events) return;
+  if (i::FLAG_log_internal_timer_events) return;
   i::Isolate* isolate = reinterpret_cast<i::Isolate*>(this);
   isolate->set_event_logger(that);
 }
=======================================
--- /trunk/src/array.js Wed Oct  1 00:05:35 2014 UTC
+++ /trunk/src/array.js Wed Oct 15 13:35:30 2014 UTC
@@ -1133,10 +1133,11 @@
   if (!IS_SPEC_FUNCTION(f)) {
     throw MakeTypeError('called_non_callable', [ f ]);
   }
+  var needs_wrapper = false;
   if (IS_NULL_OR_UNDEFINED(receiver)) {
     receiver = %GetDefaultReceiver(f) || receiver;
-  } else if (!IS_SPEC_OBJECT(receiver) && %IsSloppyModeFunction(f)) {
-    receiver = ToObject(receiver);
+  } else {
+    needs_wrapper = SHOULD_CREATE_WRAPPER(f, receiver);
   }

   var result = new $Array();
@@ -1148,7 +1149,8 @@
       var element = array[i];
       // Prepare break slots for debugger step in.
       if (stepping) %DebugPrepareStepInIfStepping(f);
-      if (%_CallFunction(receiver, element, i, array, f)) {
+      var new_receiver = needs_wrapper ? ToObject(receiver) : receiver;
+      if (%_CallFunction(new_receiver, element, i, array, f)) {
         accumulator[accumulator_length++] = element;
       }
     }
@@ -1169,10 +1171,11 @@
   if (!IS_SPEC_FUNCTION(f)) {
     throw MakeTypeError('called_non_callable', [ f ]);
   }
+  var needs_wrapper = false;
   if (IS_NULL_OR_UNDEFINED(receiver)) {
     receiver = %GetDefaultReceiver(f) || receiver;
-  } else if (!IS_SPEC_OBJECT(receiver) && %IsSloppyModeFunction(f)) {
-    receiver = ToObject(receiver);
+  } else {
+    needs_wrapper = SHOULD_CREATE_WRAPPER(f, receiver);
   }

   var stepping = DEBUG_IS_ACTIVE && %DebugCallbackSupportsStepping(f);
@@ -1181,7 +1184,8 @@
       var element = array[i];
       // Prepare break slots for debugger step in.
       if (stepping) %DebugPrepareStepInIfStepping(f);
-      %_CallFunction(receiver, element, i, array, f);
+      var new_receiver = needs_wrapper ? ToObject(receiver) : receiver;
+      %_CallFunction(new_receiver, element, i, array, f);
     }
   }
 }
@@ -1200,10 +1204,11 @@
   if (!IS_SPEC_FUNCTION(f)) {
     throw MakeTypeError('called_non_callable', [ f ]);
   }
+  var needs_wrapper = false;
   if (IS_NULL_OR_UNDEFINED(receiver)) {
     receiver = %GetDefaultReceiver(f) || receiver;
-  } else if (!IS_SPEC_OBJECT(receiver) && %IsSloppyModeFunction(f)) {
-    receiver = ToObject(receiver);
+  } else {
+    needs_wrapper = SHOULD_CREATE_WRAPPER(f, receiver);
   }

   var stepping = DEBUG_IS_ACTIVE && %DebugCallbackSupportsStepping(f);
@@ -1212,7 +1217,8 @@
       var element = array[i];
       // Prepare break slots for debugger step in.
       if (stepping) %DebugPrepareStepInIfStepping(f);
-      if (%_CallFunction(receiver, element, i, array, f)) return true;
+      var new_receiver = needs_wrapper ? ToObject(receiver) : receiver;
+      if (%_CallFunction(new_receiver, element, i, array, f)) return true;
     }
   }
   return false;
@@ -1230,10 +1236,11 @@
   if (!IS_SPEC_FUNCTION(f)) {
     throw MakeTypeError('called_non_callable', [ f ]);
   }
+  var needs_wrapper = false;
   if (IS_NULL_OR_UNDEFINED(receiver)) {
     receiver = %GetDefaultReceiver(f) || receiver;
-  } else if (!IS_SPEC_OBJECT(receiver) && %IsSloppyModeFunction(f)) {
-    receiver = ToObject(receiver);
+  } else {
+    needs_wrapper = SHOULD_CREATE_WRAPPER(f, receiver);
   }

   var stepping = DEBUG_IS_ACTIVE && %DebugCallbackSupportsStepping(f);
@@ -1242,7 +1249,8 @@
       var element = array[i];
       // Prepare break slots for debugger step in.
       if (stepping) %DebugPrepareStepInIfStepping(f);
-      if (!%_CallFunction(receiver, element, i, array, f)) return false;
+      var new_receiver = needs_wrapper ? ToObject(receiver) : receiver;
+ if (!%_CallFunction(new_receiver, element, i, array, f)) return false;
     }
   }
   return true;
@@ -1259,10 +1267,11 @@
   if (!IS_SPEC_FUNCTION(f)) {
     throw MakeTypeError('called_non_callable', [ f ]);
   }
+  var needs_wrapper = false;
   if (IS_NULL_OR_UNDEFINED(receiver)) {
     receiver = %GetDefaultReceiver(f) || receiver;
-  } else if (!IS_SPEC_OBJECT(receiver) && %IsSloppyModeFunction(f)) {
-    receiver = ToObject(receiver);
+  } else {
+    needs_wrapper = SHOULD_CREATE_WRAPPER(f, receiver);
   }

   var result = new $Array();
@@ -1273,7 +1282,8 @@
       var element = array[i];
       // Prepare break slots for debugger step in.
       if (stepping) %DebugPrepareStepInIfStepping(f);
-      accumulator[i] = %_CallFunction(receiver, element, i, array, f);
+      var new_receiver = needs_wrapper ? ToObject(receiver) : receiver;
+      accumulator[i] = %_CallFunction(new_receiver, element, i, array, f);
     }
   }
   %MoveArrayContents(accumulator, result);
=======================================
--- /trunk/src/ast.cc   Wed Oct 15 00:05:09 2014 UTC
+++ /trunk/src/ast.cc   Wed Oct 15 13:35:30 2014 UTC
@@ -101,6 +101,7 @@
                        Expression* value, int pos, IdGen* id_gen)
     : Expression(zone, pos, num_ids(), id_gen),
       is_uninitialized_(false),
+      key_type_(ELEMENT),
       store_mode_(STANDARD_STORE),
       op_(op),
       target_(target),
=======================================
--- /trunk/src/ast.h    Wed Oct 15 00:05:09 2014 UTC
+++ /trunk/src/ast.h    Wed Oct 15 13:35:30 2014 UTC
@@ -1742,6 +1742,10 @@
   virtual KeyedAccessStoreMode GetStoreMode() OVERRIDE {
     return STANDARD_STORE;
   }
+  virtual IcCheckType GetKeyType() {
+    // PROPERTY key types currently aren't implemented for KeyedLoadICs.
+    return ELEMENT;
+  }
   bool IsUninitialized() { return !is_for_call_ && is_uninitialized_; }
   bool HasNoTypeInformation() {
     return is_uninitialized_;
@@ -2123,6 +2127,7 @@
       : Expression(zone, pos, num_ids(), id_gen),
         op_(op),
         is_prefix_(is_prefix),
+        key_type_(ELEMENT),
         store_mode_(STANDARD_STORE),
         expression_(expr) {}

=======================================
--- /trunk/src/bootstrapper.cc  Thu Oct  9 00:05:16 2014 UTC
+++ /trunk/src/bootstrapper.cc  Wed Oct 15 13:35:30 2014 UTC
@@ -509,7 +509,7 @@
     // prototype, otherwise the missing initial_array_prototype will cause
     // assertions during startup.
     native_context()->set_initial_array_prototype(*prototype);
-    Accessors::FunctionSetPrototype(object_fun, prototype);
+    Accessors::FunctionSetPrototype(object_fun, prototype).Assert();
   }

   // Allocate the empty function as the prototype for function ECMAScript
@@ -1673,7 +1673,7 @@
         isolate()->initial_object_prototype(), Builtins::kIllegal);
     Handle<JSObject> prototype =
         factory()->NewJSObject(isolate()->object_function(), TENURED);
-    Accessors::FunctionSetPrototype(script_fun, prototype);
+    Accessors::FunctionSetPrototype(script_fun, prototype).Assert();
     native_context()->set_script_function(*script_fun);

     Handle<Map> script_map = Handle<Map>(script_fun->initial_map());
@@ -1815,7 +1815,7 @@
         isolate()->initial_object_prototype(), Builtins::kIllegal);
     Handle<JSObject> prototype =
         factory()->NewJSObject(isolate()->object_function(), TENURED);
-    Accessors::FunctionSetPrototype(opaque_reference_fun, prototype);
+ Accessors::FunctionSetPrototype(opaque_reference_fun, prototype).Assert();
     native_context()->set_opaque_reference_function(*opaque_reference_fun);
   }

=======================================
--- /trunk/src/code-stubs-hydrogen.cc   Tue Oct 14 07:51:07 2014 UTC
+++ /trunk/src/code-stubs-hydrogen.cc   Wed Oct 15 13:35:30 2014 UTC
@@ -416,7 +416,12 @@
   HInstruction* boilerplate = Add<HLoadNamedField>(
       allocation_site, static_cast<HValue*>(NULL), access);

- int size = JSObject::kHeaderSize + casted_stub()->length() * kPointerSize;
+  int length = casted_stub()->length();
+  if (length == 0) {
+    // Empty objects have some slack added to them.
+    length = JSObject::kInitialGlobalObjectUnusedPropertiesCount;
+  }
+  int size = JSObject::kHeaderSize + length * kPointerSize;
   int object_size = size;
   if (FLAG_allocation_site_pretenuring) {
     size += AllocationMemento::kSize;
=======================================
--- /trunk/src/collection.js    Thu Aug 21 00:04:56 2014 UTC
+++ /trunk/src/collection.js    Wed Oct 15 13:35:30 2014 UTC
@@ -105,6 +105,12 @@
   if (!IS_SPEC_FUNCTION(f)) {
     throw MakeTypeError('called_non_callable', [f]);
   }
+  var needs_wrapper = false;
+  if (IS_NULL_OR_UNDEFINED(receiver)) {
+    receiver = %GetDefaultReceiver(f) || receiver;
+  } else {
+    needs_wrapper = SHOULD_CREATE_WRAPPER(f, receiver);
+  }

   var iterator = new SetIterator(this, ITERATOR_KIND_VALUES);
   var key;
@@ -113,7 +119,8 @@
   while (%SetIteratorNext(iterator, value_array)) {
     if (stepping) %DebugPrepareStepInIfStepping(f);
     key = value_array[0];
-    %_CallFunction(receiver, key, key, this, f);
+    var new_receiver = needs_wrapper ? ToObject(receiver) : receiver;
+    %_CallFunction(new_receiver, key, key, this, f);
   }
 }

@@ -249,13 +256,20 @@
   if (!IS_SPEC_FUNCTION(f)) {
     throw MakeTypeError('called_non_callable', [f]);
   }
+  var needs_wrapper = false;
+  if (IS_NULL_OR_UNDEFINED(receiver)) {
+    receiver = %GetDefaultReceiver(f) || receiver;
+  } else {
+    needs_wrapper = SHOULD_CREATE_WRAPPER(f, receiver);
+  }

   var iterator = new MapIterator(this, ITERATOR_KIND_ENTRIES);
   var stepping = DEBUG_IS_ACTIVE && %DebugCallbackSupportsStepping(f);
   var value_array = [UNDEFINED, UNDEFINED];
   while (%MapIteratorNext(iterator, value_array)) {
     if (stepping) %DebugPrepareStepInIfStepping(f);
-    %_CallFunction(receiver, value_array[1], value_array[0], this, f);
+    var new_receiver = needs_wrapper ? ToObject(receiver) : receiver;
+    %_CallFunction(new_receiver, value_array[1], value_array[0], this, f);
   }
 }

=======================================
--- /trunk/src/compiler/arm/code-generator-arm.cc Wed Oct 15 00:05:09 2014 UTC +++ /trunk/src/compiler/arm/code-generator-arm.cc Wed Oct 15 13:35:30 2014 UTC
@@ -239,6 +239,15 @@
       DCHECK_EQ(LeaveCC, i.OutputSBit());
       break;
     }
+    case kArmSmmul:
+      __ smmul(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1));
+      DCHECK_EQ(LeaveCC, i.OutputSBit());
+      break;
+    case kArmSmmla:
+      __ smmla(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1),
+               i.InputRegister(2));
+      DCHECK_EQ(LeaveCC, i.OutputSBit());
+      break;
     case kArmSdiv: {
       CpuFeatureScope scope(masm(), SUDIV);
       __ sdiv(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1));
=======================================
--- /trunk/src/compiler/arm/instruction-codes-arm.h Fri Sep 26 00:05:23 2014 UTC +++ /trunk/src/compiler/arm/instruction-codes-arm.h Wed Oct 15 13:35:30 2014 UTC
@@ -26,6 +26,8 @@
   V(ArmMul)                        \
   V(ArmMla)                        \
   V(ArmMls)                        \
+  V(ArmSmmul)                      \
+  V(ArmSmmla)                      \
   V(ArmSdiv)                       \
   V(ArmUdiv)                       \
   V(ArmMov)                        \
=======================================
--- /trunk/src/compiler/arm/instruction-selector-arm.cc Tue Oct 14 07:51:07 2014 UTC +++ /trunk/src/compiler/arm/instruction-selector-arm.cc Wed Oct 15 13:35:30 2014 UTC
@@ -78,6 +78,8 @@
       case kArmMul:
       case kArmMla:
       case kArmMls:
+      case kArmSmmul:
+      case kArmSmmla:
       case kArmSdiv:
       case kArmUdiv:
       case kArmBfc:
@@ -569,6 +571,20 @@
g.UseRegister(mright.right().node()), g.UseRegister(m.left().node()));
     return;
   }
+  if (m.left().IsInt32MulHigh() && CanCover(node, m.left().node())) {
+    Int32BinopMatcher mleft(m.left().node());
+    Emit(kArmSmmla, g.DefineAsRegister(node),
+         g.UseRegister(mleft.left().node()),
+ g.UseRegister(mleft.right().node()), g.UseRegister(m.right().node()));
+    return;
+  }
+  if (m.right().IsInt32MulHigh() && CanCover(node, m.right().node())) {
+    Int32BinopMatcher mright(m.right().node());
+    Emit(kArmSmmla, g.DefineAsRegister(node),
+         g.UseRegister(mright.left().node()),
+ g.UseRegister(mright.right().node()), g.UseRegister(m.left().node()));
+    return;
+  }
   VisitBinop(this, node, kArmAdd, kArmAdd);
 }

@@ -610,6 +626,13 @@
   Emit(kArmMul, g.DefineAsRegister(node), g.UseRegister(m.left().node()),
        g.UseRegister(m.right().node()));
 }
+
+
+void InstructionSelector::VisitInt32MulHigh(Node* node) {
+  ArmOperandGenerator g(this);
+ Emit(kArmSmmul, g.DefineAsRegister(node), g.UseRegister(node->InputAt(0)),
+       g.UseRegister(node->InputAt(1)));
+}


 static void EmitDiv(InstructionSelector* selector, ArchOpcode div_opcode,
=======================================
--- /trunk/src/compiler/arm64/code-generator-arm64.cc Wed Oct 15 00:05:09 2014 UTC +++ /trunk/src/compiler/arm64/code-generator-arm64.cc Wed Oct 15 13:35:30 2014 UTC
@@ -252,6 +252,9 @@
     case kArm64Mul32:
__ Mul(i.OutputRegister32(), i.InputRegister32(0), i.InputRegister32(1));
       break;
+    case kArm64Smull:
+ __ Smull(i.OutputRegister(), i.InputRegister32(0), i.InputRegister32(1));
+      break;
     case kArm64Madd:
       __ Madd(i.OutputRegister(), i.InputRegister(0), i.InputRegister(1),
               i.InputRegister(2));
=======================================
--- /trunk/src/compiler/arm64/instruction-codes-arm64.h Wed Oct 15 00:05:09 2014 UTC +++ /trunk/src/compiler/arm64/instruction-codes-arm64.h Wed Oct 15 13:35:30 2014 UTC
@@ -36,6 +36,7 @@
   V(Arm64Sub32)                    \
   V(Arm64Mul)                      \
   V(Arm64Mul32)                    \
+  V(Arm64Smull)                    \
   V(Arm64Madd)                     \
   V(Arm64Madd32)                   \
   V(Arm64Msub)                     \
=======================================
--- /trunk/src/compiler/arm64/instruction-selector-arm64.cc Wed Oct 15 00:05:09 2014 UTC +++ /trunk/src/compiler/arm64/instruction-selector-arm64.cc Wed Oct 15 13:35:30 2014 UTC
@@ -744,6 +744,16 @@

   VisitRRR(this, kArm64Mul, node);
 }
+
+
+void InstructionSelector::VisitInt32MulHigh(Node* node) {
+  // TODO(arm64): Can we do better here?
+  Arm64OperandGenerator g(this);
+  InstructionOperand* const smull_operand = g.TempRegister();
+  Emit(kArm64Smull, smull_operand, g.UseRegister(node->InputAt(0)),
+       g.UseRegister(node->InputAt(1)));
+ Emit(kArm64Asr, g.DefineAsRegister(node), smull_operand, g.TempImmediate(32));
+}


 void InstructionSelector::VisitInt32Div(Node* node) {
=======================================
--- /trunk/src/compiler/code-generator.cc       Wed Oct 15 00:05:09 2014 UTC
+++ /trunk/src/compiler/code-generator.cc       Wed Oct 15 13:35:30 2014 UTC
@@ -107,8 +107,7 @@
     if (FLAG_code_comments) {
       // TODO(titzer): these code comments are a giant memory leak.
       Vector<char> buffer = Vector<char>::New(32);
-      // TODO(dcarney): should not be rpo number there
-      SNPrintF(buffer, "-- B%d (rpo) start --", current_block_.ToInt());
+      SNPrintF(buffer, "-- B%d start --", block_start->id().ToInt());
       masm()->RecordComment(buffer.start());
     }
     masm()->bind(block_start->label());
=======================================
--- /trunk/src/compiler/ia32/code-generator-ia32.cc Wed Oct 15 00:05:09 2014 UTC +++ /trunk/src/compiler/ia32/code-generator-ia32.cc Wed Oct 15 13:35:30 2014 UTC
@@ -243,6 +243,9 @@
       } else {
         __ imul(i.OutputRegister(), i.InputOperand(1));
       }
+      break;
+    case kIA32ImulHigh:
+      __ imul(i.InputRegister(1));
       break;
     case kIA32Idiv:
       __ cdq();
=======================================
--- /trunk/src/compiler/ia32/instruction-codes-ia32.h Wed Oct 1 00:05:35 2014 UTC +++ /trunk/src/compiler/ia32/instruction-codes-ia32.h Wed Oct 15 13:35:30 2014 UTC
@@ -20,6 +20,7 @@
   V(IA32Xor)                       \
   V(IA32Sub)                       \
   V(IA32Imul)                      \
+  V(IA32ImulHigh)                  \
   V(IA32Idiv)                      \
   V(IA32Udiv)                      \
   V(IA32Not)                       \
=======================================
--- /trunk/src/compiler/ia32/instruction-selector-ia32.cc Wed Oct 15 00:05:09 2014 UTC +++ /trunk/src/compiler/ia32/instruction-selector-ia32.cc Wed Oct 15 13:35:30 2014 UTC
@@ -259,7 +259,18 @@
   size_t output_count = 0;

   // TODO(turbofan): match complex addressing modes.
-  if (g.CanBeImmediate(right)) {
+  if (left == right) {
+ // If both inputs refer to the same operand, enforce allocating a register
+    // for both of them to ensure that we don't end up generating code like
+    // this:
+    //
+    //   mov eax, [ebp-0x10]
+    //   add eax, [ebp-0x10]
+    //   jo label
+    InstructionOperand* const input = g.UseRegister(left);
+    inputs[input_count++] = input;
+    inputs[input_count++] = input;
+  } else if (g.CanBeImmediate(right)) {
     inputs[input_count++] = g.UseRegister(left);
     inputs[input_count++] = g.UseImmediate(right);
   } else {
@@ -453,6 +464,16 @@
          g.Use(right));
   }
 }
+
+
+void InstructionSelector::VisitInt32MulHigh(Node* node) {
+  IA32OperandGenerator g(this);
+  InstructionOperand* temps[] = {g.TempRegister(eax)};
+  size_t temp_count = arraysize(temps);
+  Emit(kIA32ImulHigh, g.DefineAsFixed(node, edx),
+       g.UseFixed(node->InputAt(0), eax), g.UseRegister(node->InputAt(1)),
+       temp_count, temps);
+}


 static inline void VisitDiv(InstructionSelector* selector, Node* node,
@@ -662,13 +683,6 @@
VisitCompare(selector, opcode, g.UseRegister(left), g.Use(right), cont);
   }
 }
-
-
-static void VisitWordTest(InstructionSelector* selector, Node* node,
-                          FlagsContinuation* cont) {
-  IA32OperandGenerator g(selector);
- VisitCompare(selector, kIA32Test, g.Use(node), g.TempImmediate(-1), cont);
-}


 // Shared routine for multiple float compare operations.
@@ -684,7 +698,7 @@

 void InstructionSelector::VisitBranch(Node* branch, BasicBlock* tbranch,
                                       BasicBlock* fbranch) {
-  OperandGenerator g(this);
+  IA32OperandGenerator g(this);
   Node* user = branch;
   Node* value = branch->InputAt(0);

@@ -770,7 +784,7 @@
   }

   // Branch could not be combined with a compare, emit compare against 0.
-  VisitWordTest(this, value, &cont);
+  VisitCompare(this, kIA32Cmp, g.Use(value), g.TempImmediate(0), &cont);
 }


@@ -789,7 +803,6 @@
         default:
           break;
       }
-      return VisitWordTest(this, value, &cont);
     }
   }
   return VisitWordCompare(this, node, kIA32Cmp, &cont, false);
=======================================
--- /trunk/src/compiler/instruction-selector.cc Wed Oct 15 00:05:09 2014 UTC
+++ /trunk/src/compiler/instruction-selector.cc Wed Oct 15 13:35:30 2014 UTC
@@ -658,6 +658,8 @@
       return VisitInt32SubWithOverflow(node);
     case IrOpcode::kInt32Mul:
       return VisitInt32Mul(node);
+    case IrOpcode::kInt32MulHigh:
+      return VisitInt32MulHigh(node);
     case IrOpcode::kInt32Div:
       return VisitInt32Div(node);
     case IrOpcode::kInt32Mod:
=======================================
--- /trunk/src/compiler/instruction.h   Wed Oct 15 00:05:09 2014 UTC
+++ /trunk/src/compiler/instruction.h   Wed Oct 15 13:35:30 2014 UTC
@@ -598,6 +598,7 @@
  public:
   Label* label() { return &label_; }
   BasicBlock::RpoNumber rpo_number() const { return rpo_number_; }
+  BasicBlock::Id id() const { return id_; }

   static BlockStartInstruction* New(Zone* zone, BasicBlock* block) {
     void* buffer = zone->New(sizeof(BlockStartInstruction));
@@ -612,8 +613,10 @@
  private:
   explicit BlockStartInstruction(BasicBlock* block)
       : GapInstruction(kBlockStartInstruction),
+        id_(block->id()),
         rpo_number_(block->GetRpoNumber()) {}

+  BasicBlock::Id id_;
   BasicBlock::RpoNumber rpo_number_;
   Label label_;
 };
=======================================
--- /trunk/src/compiler/js-typed-lowering.cc    Tue Oct 14 07:51:07 2014 UTC
+++ /trunk/src/compiler/js-typed-lowering.cc    Wed Oct 15 13:35:30 2014 UTC
@@ -383,16 +383,6 @@
                                          : jsgraph()->TrueConstant());
     }
   }
-  /* TODO(neis): This is currently unsound.
-  if (!r.left_type()->Maybe(r.right_type())) {
-    // Type intersection is empty; === is always false unless both
-    // inputs could be strings (one internalized and one not).
-    if (r.OneInputCannotBe(Type::String())) {
-      return ReplaceEagerly(node, invert ? jsgraph()->TrueConstant()
-                                         : jsgraph()->FalseConstant());
-    }
-  }
-  */
   if (r.OneInputIs(Type::Undefined())) {
     return r.ChangeToPureOperator(
         simplified()->ReferenceEqual(Type::Undefined()), invert);
=======================================
--- /trunk/src/compiler/machine-operator-reducer.cc Tue Oct 14 07:51:07 2014 UTC +++ /trunk/src/compiler/machine-operator-reducer.cc Wed Oct 15 13:35:30 2014 UTC
@@ -5,6 +5,7 @@
 #include "src/compiler/machine-operator-reducer.h"

 #include "src/base/bits.h"
+#include "src/base/division-by-constant.h"
 #include "src/codegen.h"
 #include "src/compiler/generic-node-inl.h"
 #include "src/compiler/graph.h"
@@ -40,6 +41,54 @@
 Node* MachineOperatorReducer::Int64Constant(int64_t value) {
   return graph()->NewNode(common()->Int64Constant(value));
 }
+
+
+Node* MachineOperatorReducer::Word32And(Node* lhs, uint32_t rhs) {
+ return graph()->NewNode(machine()->Word32And(), lhs, Uint32Constant(rhs));
+}
+
+
+Node* MachineOperatorReducer::Word32Sar(Node* lhs, uint32_t rhs) {
+ return graph()->NewNode(machine()->Word32Sar(), lhs, Uint32Constant(rhs));
+}
+
+
+Node* MachineOperatorReducer::Word32Shr(Node* lhs, uint32_t rhs) {
+ return graph()->NewNode(machine()->Word32Shr(), lhs, Uint32Constant(rhs));
+}
+
+
+Node* MachineOperatorReducer::Int32Add(Node* lhs, Node* rhs) {
+  return graph()->NewNode(machine()->Int32Add(), lhs, rhs);
+}
+
+
+Node* MachineOperatorReducer::Int32Sub(Node* lhs, Node* rhs) {
+  return graph()->NewNode(machine()->Int32Sub(), lhs, rhs);
+}
+
+
+Node* MachineOperatorReducer::Int32Mul(Node* lhs, Node* rhs) {
+  return graph()->NewNode(machine()->Int32Mul(), lhs, rhs);
+}
+
+
+Node* MachineOperatorReducer::TruncatingDiv(Node* dividend, int32_t divisor) {
+  DCHECK_NE(std::numeric_limits<int32_t>::min(), divisor);
+  base::MagicNumbersForDivision<uint32_t> const mag =
+      base::SignedDivisionByConstant(bit_cast<uint32_t>(divisor));
+  Node* quotient = graph()->NewNode(machine()->Int32MulHigh(), dividend,
+                                    Uint32Constant(mag.multiplier));
+  if (divisor > 0 && bit_cast<int32_t>(mag.multiplier) < 0) {
+    quotient = Int32Add(quotient, dividend);
+  } else if (divisor < 0 && bit_cast<int32_t>(mag.multiplier) > 0) {
+    quotient = Int32Sub(quotient, dividend);
+  }
+  if (mag.shift) {
+    quotient = Word32Sar(quotient, mag.shift);
+  }
+  return Int32Add(quotient, Word32Shr(dividend, 31));
+}


 // Perform constant folding and strength reduction on machine operators.
@@ -227,25 +276,8 @@
       }
       break;
     }
-    case IrOpcode::kInt32Div: {
-      Int32BinopMatcher m(node);
-      if (m.right().Is(1)) return Replace(m.left().node());  // x / 1 => x
-      // TODO(turbofan): if (m.left().Is(0))
-      // TODO(turbofan): if (m.right().IsPowerOf2())
-      // TODO(turbofan): if (m.right().Is(0))
-      // TODO(turbofan): if (m.LeftEqualsRight())
-      if (m.IsFoldable() && !m.right().Is(0)) {  // K / K => K
-        if (m.right().Is(-1)) return ReplaceInt32(-m.left().Value());
-        return ReplaceInt32(m.left().Value() / m.right().Value());
-      }
-      if (m.right().Is(-1)) {  // x / -1 => 0 - x
-        node->set_op(machine()->Int32Sub());
-        node->ReplaceInput(0, Int32Constant(0));
-        node->ReplaceInput(1, m.left().node());
-        return Changed(node);
-      }
-      break;
-    }
+    case IrOpcode::kInt32Div:
+      return ReduceInt32Div(node);
     case IrOpcode::kUint32Div: {
       Uint32BinopMatcher m(node);
       if (m.right().Is(1)) return Replace(m.left().node());  // x / 1 => x
@@ -499,7 +531,50 @@
 }


-Reduction MachineOperatorReducer::ReduceInt32Mod(Node* const node) {
+Reduction MachineOperatorReducer::ReduceInt32Div(Node* node) {
+  Int32BinopMatcher m(node);
+  if (m.right().Is(0)) return Replace(m.right().node());  // x / 0 => 0
+  if (m.right().Is(1)) return Replace(m.left().node());   // x / 1 => x
+  // TODO(turbofan): if (m.left().Is(0))
+  // TODO(turbofan): if (m.LeftEqualsRight())
+  if (m.IsFoldable() && !m.right().Is(0)) {  // K / K => K
+    if (m.right().Is(-1)) return ReplaceInt32(-m.left().Value());
+    return ReplaceInt32(m.left().Value() / m.right().Value());
+  }
+  if (m.right().Is(-1)) {  // x / -1 => 0 - x
+    node->set_op(machine()->Int32Sub());
+    node->ReplaceInput(0, Int32Constant(0));
+    node->ReplaceInput(1, m.left().node());
+    return Changed(node);
+  }
+  if (m.right().HasValue()) {
+    int32_t const divisor = m.right().Value();
+    Node* const dividend = m.left().node();
+    Node* quotient = dividend;
+    if (base::bits::IsPowerOfTwo32(Abs(divisor))) {
+      uint32_t const shift = WhichPowerOf2Abs(divisor);
+      DCHECK_NE(0, shift);
+      if (shift > 1) {
+        quotient = Word32Sar(quotient, 31);
+      }
+      quotient = Int32Add(Word32Shr(quotient, 32u - shift), dividend);
+      quotient = Word32Sar(quotient, shift);
+    } else {
+      quotient = TruncatingDiv(quotient, Abs(divisor));
+    }
+    if (divisor < 0) {
+      node->set_op(machine()->Int32Sub());
+      node->ReplaceInput(0, Int32Constant(0));
+      node->ReplaceInput(1, quotient);
+      return Changed(node);
+    }
+    return Replace(quotient);
+  }
+  return NoChange();
+}
+
+
+Reduction MachineOperatorReducer::ReduceInt32Mod(Node* node) {
   Int32BinopMatcher m(node);
   if (m.right().Is(1)) return ReplaceInt32(0);   // x % 1  => 0
   if (m.right().Is(-1)) return ReplaceInt32(0);  // x % -1 => 0
@@ -509,29 +584,35 @@
   if (m.IsFoldable() && !m.right().Is(0)) {  // K % K => K
     return ReplaceInt32(m.left().Value() % m.right().Value());
   }
-  if (m.right().IsPowerOf2()) {
-    int32_t const divisor = m.right().Value();
-    Node* zero = Int32Constant(0);
-    Node* mask = Int32Constant(divisor - 1);
-    Node* dividend = m.left().node();
+  if (m.right().HasValue()) {
+    Node* const dividend = m.left().node();
+    int32_t const divisor = Abs(m.right().Value());
+    if (base::bits::IsPowerOfTwo32(divisor)) {
+      uint32_t const mask = divisor - 1;
+      Node* const zero = Int32Constant(0);

- Node* check = graph()->NewNode(machine()->Int32LessThan(), dividend, zero);
-    Node* branch =
-        graph()->NewNode(common()->Branch(), check, graph()->start());
+      Node* check =
+          graph()->NewNode(machine()->Int32LessThan(), dividend, zero);
+      Node* branch =
+          graph()->NewNode(common()->Branch(), check, graph()->start());

-    Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
-    Node* neg = graph()->NewNode(
-        machine()->Int32Sub(), zero,
-        graph()->NewNode(
-            machine()->Word32And(),
- graph()->NewNode(machine()->Int32Sub(), zero, dividend), mask));
+      Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
+ Node* neg = Int32Sub(zero, Word32And(Int32Sub(zero, dividend), mask));

-    Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
-    Node* pos = graph()->NewNode(machine()->Word32And(), dividend, mask);
+      Node* if_false = graph()->NewNode(common()->IfFalse(), branch);
+      Node* pos = Word32And(dividend, mask);

-    Node* merge = graph()->NewNode(common()->Merge(2), if_true, if_false);
- Node* phi = graph()->NewNode(common()->Phi(kMachInt32, 2), neg, pos, merge);
-    return Replace(phi);
+ Node* merge = graph()->NewNode(common()->Merge(2), if_true, if_false);
+      Node* phi =
+          graph()->NewNode(common()->Phi(kMachInt32, 2), neg, pos, merge);
+      return Replace(phi);
+    } else {
+      Node* quotient = TruncatingDiv(dividend, divisor);
+      node->set_op(machine()->Int32Sub());
+      DCHECK_EQ(dividend, node->InputAt(0));
+      node->ReplaceInput(1, Int32Mul(quotient, Int32Constant(divisor)));
+      return Changed(node);
+    }
   }
   return NoChange();
 }
=======================================
--- /trunk/src/compiler/machine-operator-reducer.h Tue Oct 14 07:51:07 2014 UTC +++ /trunk/src/compiler/machine-operator-reducer.h Wed Oct 15 13:35:30 2014 UTC
@@ -34,6 +34,14 @@
   Node* Uint32Constant(uint32_t value) {
     return Int32Constant(bit_cast<uint32_t>(value));
   }
+  Node* Word32And(Node* lhs, uint32_t rhs);
+  Node* Word32Sar(Node* lhs, uint32_t rhs);
+  Node* Word32Shr(Node* lhs, uint32_t rhs);
+  Node* Int32Add(Node* lhs, Node* rhs);
+  Node* Int32Sub(Node* lhs, Node* rhs);
+  Node* Int32Mul(Node* lhs, Node* rhs);
+
+  Node* TruncatingDiv(Node* dividend, int32_t divisor);

   Reduction ReplaceBool(bool value) { return ReplaceInt32(value ? 1 : 0); }
   Reduction ReplaceFloat32(volatile float value) {
@@ -49,6 +57,7 @@
     return Replace(Int64Constant(value));
   }

+  Reduction ReduceInt32Div(Node* node);
   Reduction ReduceInt32Mod(Node* node);
   Reduction ReduceProjection(size_t index, Node* node);

=======================================
--- /trunk/src/compiler/machine-operator.cc     Fri Oct 10 00:05:16 2014 UTC
+++ /trunk/src/compiler/machine-operator.cc     Wed Oct 15 13:35:30 2014 UTC
@@ -75,6 +75,7 @@
V(Int32Sub, Operator::kNoProperties, 2, 1) \ V(Int32SubWithOverflow, Operator::kNoProperties, 2, 2) \ V(Int32Mul, Operator::kAssociative | Operator::kCommutative, 2, 1) \ + V(Int32MulHigh, Operator::kAssociative | Operator::kCommutative, 2, 1) \ V(Int32Div, Operator::kNoProperties, 2, 1) \ V(Int32Mod, Operator::kNoProperties, 2, 1) \ V(Int32LessThan, Operator::kNoProperties, 2, 1) \
=======================================
--- /trunk/src/compiler/machine-operator.h      Fri Oct 10 00:05:16 2014 UTC
+++ /trunk/src/compiler/machine-operator.h      Wed Oct 15 13:35:30 2014 UTC
@@ -82,6 +82,7 @@
   const Operator* Int32Sub();
   const Operator* Int32SubWithOverflow();
   const Operator* Int32Mul();
+  const Operator* Int32MulHigh();
   const Operator* Int32Div();
   const Operator* Int32Mod();
   const Operator* Int32LessThan();
=======================================
--- /trunk/src/compiler/mips/code-generator-mips.cc Wed Oct 15 00:05:09 2014 UTC +++ /trunk/src/compiler/mips/code-generator-mips.cc Wed Oct 15 13:35:30 2014 UTC
@@ -185,6 +185,9 @@
     case kMipsMul:
       __ Mul(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
       break;
+    case kMipsMulHigh:
+      __ Mulh(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
+      break;
     case kMipsDiv:
       __ Div(i.OutputRegister(), i.InputRegister(0), i.InputOperand(1));
       break;
=======================================
--- /trunk/src/compiler/mips/instruction-codes-mips.h Fri Oct 3 00:04:58 2014 UTC +++ /trunk/src/compiler/mips/instruction-codes-mips.h Wed Oct 15 13:35:30 2014 UTC
@@ -17,6 +17,7 @@
   V(MipsSub)                       \
   V(MipsSubOvf)                    \
   V(MipsMul)                       \
+  V(MipsMulHigh)                   \
   V(MipsDiv)                       \
   V(MipsDivU)                      \
   V(MipsMod)                       \
=======================================
--- /trunk/src/compiler/mips/instruction-selector-mips.cc Tue Oct 14 07:51:07 2014 UTC +++ /trunk/src/compiler/mips/instruction-selector-mips.cc Wed Oct 15 13:35:30 2014 UTC
@@ -298,6 +298,13 @@
   Emit(kMipsMul, g.DefineAsRegister(node), g.UseRegister(m.left().node()),
        g.UseRegister(m.right().node()));
 }
+
+
+void InstructionSelector::VisitInt32MulHigh(Node* node) {
+  MipsOperandGenerator g(this);
+ Emit(kMipsMulHigh, g.DefineAsRegister(node), g.UseRegister(node->InputAt(0)),
+       g.UseRegister(node->InputAt(1)));
+}


 void InstructionSelector::VisitInt32Div(Node* node) {
=======================================
--- /trunk/src/compiler/opcodes.h       Thu Oct  2 00:05:29 2014 UTC
+++ /trunk/src/compiler/opcodes.h       Wed Oct 15 13:35:30 2014 UTC
@@ -185,6 +185,7 @@
   V(Int32Sub)                 \
   V(Int32SubWithOverflow)     \
   V(Int32Mul)                 \
+  V(Int32MulHigh)             \
   V(Int32Div)                 \
   V(Int32Mod)                 \
   V(Int32LessThan)            \
=======================================
--- /trunk/src/compiler/raw-machine-assembler.h Wed Oct  8 00:05:11 2014 UTC
+++ /trunk/src/compiler/raw-machine-assembler.h Wed Oct 15 13:35:30 2014 UTC
@@ -225,6 +225,9 @@
   Node* Int32Mul(Node* a, Node* b) {
     return NewNode(machine()->Int32Mul(), a, b);
   }
+  Node* Int32MulHigh(Node* a, Node* b) {
+    return NewNode(machine()->Int32MulHigh(), a, b);
+  }
   Node* Int32Div(Node* a, Node* b) {
     return NewNode(machine()->Int32Div(), a, b);
   }
=======================================
--- /trunk/src/compiler/scheduler.cc    Tue Oct 14 07:51:07 2014 UTC
+++ /trunk/src/compiler/scheduler.cc    Wed Oct 15 13:35:30 2014 UTC
@@ -181,6 +181,7 @@
       data->is_connected_control_ = true;
     }
   }
+

   void BuildBlocks(Node* node) {
     switch (node->opcode()) {
@@ -395,6 +396,24 @@
       Trace("  Use count of #%d:%s (used by #%d:%s)++ = %d\n", to->id(),
             to->op()->mnemonic(), from->id(), from->op()->mnemonic(),
             scheduler_->GetData(to)->unscheduled_count_);
+      if (OperatorProperties::IsBasicBlockBegin(to->op()) &&
+          (from->opcode() == IrOpcode::kEffectPhi ||
+           from->opcode() == IrOpcode::kPhi) &&
+          scheduler_->GetData(to)->is_floating_control_ &&
+          !scheduler_->GetData(to)->is_connected_control_) {
+ for (InputIter i = from->inputs().begin(); i != from->inputs().end();
+             ++i) {
+          if (!NodeProperties::IsControlEdge(i.edge())) {
+            ++(scheduler_->GetData(*i)->unscheduled_count_);
+            Trace(
+ " Use count of #%d:%s (additional dependency of #%d:%s)++ = "
+                "%d\n",
+                (*i)->id(), (*i)->op()->mnemonic(), to->id(),
+                to->op()->mnemonic(),
+                scheduler_->GetData(*i)->unscheduled_count_);
+          }
+        }
+      }
     }
   }

@@ -505,6 +524,7 @@
     if (schedule_->IsScheduled(node)) {
       return GenericGraphVisit::CONTINUE;
     }
+
     Scheduler::SchedulerData* data = scheduler_->GetData(node);
     DCHECK_EQ(Scheduler::kSchedulable, data->placement_);

@@ -607,6 +627,29 @@
         }
       }
     }
+
+    for (UseIter i = node->uses().begin(); i != node->uses().end(); ++i) {
+      Node* use = *i;
+      if (use->opcode() == IrOpcode::kPhi ||
+          use->opcode() == IrOpcode::kEffectPhi) {
+        Node* control = NodeProperties::GetControlInput(use);
+        Scheduler::SchedulerData* data = scheduler_->GetData(control);
+        if (data->is_floating_control_ && !data->is_connected_control_) {
+          --data->unscheduled_count_;
+          if (FLAG_trace_turbo_scheduler) {
+            Trace(
+ " Use count for #%d:%s (additional dependency of #%d:%s)-- = "
+                "%d\n",
+                (*i)->id(), (*i)->op()->mnemonic(), node->id(),
+                node->op()->mnemonic(), data->unscheduled_count_);
+            if (data->unscheduled_count_ == 0) {
+              Trace("  newly eligible #%d:%s\n", (*i)->id(),
+                    (*i)->op()->mnemonic());
+            }
+          }
+        }
+      }
+    }
   }

   Scheduler* scheduler_;
@@ -665,16 +708,14 @@
     // TODO(titzer): we place at most one floating control structure per
     // basic block because scheduling currently can interleave phis from
     // one subgraph with the merges from another subgraph.
-    bool one_placed = false;
     for (size_t j = 0; j < block->NodeCount(); j++) {
       Node* node = block->NodeAt(block->NodeCount() - 1 - j);
       SchedulerData* data = GetData(node);
-      if (data->is_floating_control_ && !data->is_connected_control_ &&
-          !one_placed) {
+      if (data->is_floating_control_ && !data->is_connected_control_) {
Trace(" Floating control #%d:%s was scheduled in B%d\n", node->id(),
               node->op()->mnemonic(), block->id().ToInt());
         ConnectFloatingControlSubgraph(block, node);
-        one_placed = true;
+        break;
       }
     }
   }
=======================================
--- /trunk/src/compiler/typer.cc        Thu Oct  9 00:05:16 2014 UTC
+++ /trunk/src/compiler/typer.cc        Wed Oct 15 13:35:30 2014 UTC
@@ -17,6 +17,27 @@
 Typer::Typer(Zone* zone) : zone_(zone) {
   Factory* f = zone->isolate()->factory();

+  Handle<Object> zero = f->NewNumber(0);
+  Handle<Object> one = f->NewNumber(1);
+  Handle<Object> positive_infinity = f->NewNumber(+V8_INFINITY);
+  Handle<Object> negative_infinity = f->NewNumber(-V8_INFINITY);
+
+  negative_signed32 = Type::Union(
+      Type::SignedSmall(), Type::OtherSigned32(), zone);
+  non_negative_signed32 = Type::Union(
+      Type::UnsignedSmall(), Type::OtherUnsigned31(), zone);
+  undefined_or_null = Type::Union(Type::Undefined(), Type::Null(), zone);
+  singleton_false = Type::Constant(f->false_value(), zone);
+  singleton_true = Type::Constant(f->true_value(), zone);
+  singleton_zero = Type::Range(zero, zero, zone);
+  singleton_one = Type::Range(one, one, zone);
+  zero_or_one = Type::Union(singleton_zero, singleton_one, zone);
+  zeroish = Type::Union(
+ singleton_zero, Type::Union(Type::NaN(), Type::MinusZero(), zone), zone);
+  falsish = Type::Union(Type::Undetectable(),
+      Type::Union(zeroish, undefined_or_null, zone), zone);
+  integer = Type::Range(negative_infinity, positive_infinity, zone);
+
   Type* number = Type::Number();
   Type* signed32 = Type::Signed32();
   Type* unsigned32 = Type::Unsigned32();
@@ -24,8 +45,7 @@
   Type* object = Type::Object();
   Type* undefined = Type::Undefined();
   Type* weakint = Type::Union(
- Type::Range(f->NewNumber(-V8_INFINITY), f->NewNumber(+V8_INFINITY), zone),
-      Type::Union(Type::NaN(), Type::MinusZero(), zone), zone);
+      integer, Type::Union(Type::NaN(), Type::MinusZero(), zone), zone);

   number_fun0_ = Type::Function(number, zone);
   number_fun1_ = Type::Function(number, number, zone);
@@ -35,19 +55,27 @@
   random_fun_ = Type::Function(Type::Union(
       Type::UnsignedSmall(), Type::OtherNumber(), zone), zone);

+  Type* int8 = Type::Intersect(
+      Type::Range(f->NewNumber(-0x7F), f->NewNumber(0x7F-1), zone),
+      Type::UntaggedInt8(), zone);
+  Type* int16 = Type::Intersect(
+      Type::Range(f->NewNumber(-0x7FFF), f->NewNumber(0x7FFF-1), zone),
+      Type::UntaggedInt16(), zone);
+  Type* uint8 = Type::Intersect(
+      Type::Range(zero, f->NewNumber(0xFF-1), zone),
+      Type::UntaggedInt8(), zone);
+  Type* uint16 = Type::Intersect(
+      Type::Range(zero, f->NewNumber(0xFFFF-1), zone),
+      Type::UntaggedInt16(), zone);

 #define NATIVE_TYPE(sem, rep) \
-  Type::Intersect(Type::sem(zone), Type::rep(zone), zone)
-  // TODO(rossberg): Use range types for more precision, once we have them.
-  Type* int8 = NATIVE_TYPE(SignedSmall, UntaggedInt8);
-  Type* int16 = NATIVE_TYPE(SignedSmall, UntaggedInt16);
+    Type::Intersect(Type::sem(), Type::rep(), zone)
   Type* int32 = NATIVE_TYPE(Signed32, UntaggedInt32);
-  Type* uint8 = NATIVE_TYPE(UnsignedSmall, UntaggedInt8);
-  Type* uint16 = NATIVE_TYPE(UnsignedSmall, UntaggedInt16);
   Type* uint32 = NATIVE_TYPE(Unsigned32, UntaggedInt32);
   Type* float32 = NATIVE_TYPE(Number, UntaggedFloat32);
   Type* float64 = NATIVE_TYPE(Number, UntaggedFloat64);
 #undef NATIVE_TYPE
+
   Type* buffer = Type::Buffer(zone);
   Type* int8_array = Type::Array(int8, zone);
   Type* int16_array = Type::Array(int16, zone);
@@ -79,9 +107,21 @@

   Bounds TypeNode(Node* node) {
     switch (node->opcode()) {
+#define DECLARE_CASE(x) \
+      case IrOpcode::k##x: return TypeBinaryOp(node, x##Typer);
+      JS_SIMPLE_BINOP_LIST(DECLARE_CASE)
+#undef DECLARE_CASE
+
 #define DECLARE_CASE(x) case IrOpcode::k##x: return Type##x(node);
       DECLARE_CASE(Start)
-      VALUE_OP_LIST(DECLARE_CASE)
+      // VALUE_OP_LIST without JS_SIMPLE_BINOP_LIST:
+      COMMON_OP_LIST(DECLARE_CASE)
+      SIMPLIFIED_OP_LIST(DECLARE_CASE)
+      MACHINE_OP_LIST(DECLARE_CASE)
+      JS_SIMPLE_UNOP_LIST(DECLARE_CASE)
+      JS_OBJECT_OP_LIST(DECLARE_CASE)
+      JS_CONTEXT_OP_LIST(DECLARE_CASE)
+      JS_OTHER_OP_LIST(DECLARE_CASE)
 #undef DECLARE_CASE

 #define DECLARE_CASE(x) case IrOpcode::k##x:
@@ -102,11 +142,11 @@
   VALUE_OP_LIST(DECLARE_METHOD)
 #undef DECLARE_METHOD

-  Bounds OperandType(Node* node, int i) {
+  static Bounds OperandType(Node* node, int i) {
return NodeProperties::GetBounds(NodeProperties::GetValueInput(node, i));
   }

-  Type* ContextType(Node* node) {
+  static Type* ContextType(Node* node) {
     Bounds result =
         NodeProperties::GetBounds(NodeProperties::GetContextInput(node));
     DCHECK(result.upper->Maybe(Type::Internal()));
@@ -122,6 +162,37 @@
  private:
   Typer* typer_;
   MaybeHandle<Context> context_;
+
+  typedef Type* (*UnaryTyperFun)(Type*, Typer* t);
+  typedef Type* (*BinaryTyperFun)(Type*, Type*, Typer* t);
+
+  Bounds TypeUnaryOp(Node* node, UnaryTyperFun);
+  Bounds TypeBinaryOp(Node* node, BinaryTyperFun);
+
+  static Type* Invert(Type*, Typer*);
+  static Type* FalsifyUndefined(Type*, Typer*);
+
+  static Type* ToPrimitive(Type*, Typer*);
+  static Type* ToBoolean(Type*, Typer*);
+  static Type* ToNumber(Type*, Typer*);
+  static Type* ToString(Type*, Typer*);
+  static Type* NumberToInt32(Type*, Typer*);
+  static Type* NumberToUint32(Type*, Typer*);
+
+  static Type* JSAddRanger(Type::RangeType*, Type::RangeType*, Typer*);
+ static Type* JSSubtractRanger(Type::RangeType*, Type::RangeType*, Typer*); + static Type* JSMultiplyRanger(Type::RangeType*, Type::RangeType*, Typer*);
+  static Type* JSDivideRanger(Type::RangeType*, Type::RangeType*, Typer*);
+
+  static Type* JSCompareTyper(Type*, Type*, Typer*);
+
+#define DECLARE_METHOD(x) static Type* x##Typer(Type*, Type*, Typer*);
+  JS_SIMPLE_BINOP_LIST(DECLARE_METHOD)
+#undef DECLARE_METHOD
+
+  static Type* JSUnaryNotTyper(Type*, Typer*);
+  static Type* JSLoadPropertyTyper(Type*, Type*, Typer*);
+  static Type* JSCallFunctionTyper(Type*, Typer*);
 };


@@ -237,49 +308,160 @@

// -----------------------------------------------------------------------------

+// Helper functions that lift a function f on types to a function on bounds, +// and uses that to type the given node. Note that f is never called with None
+// as an argument.
+
+
+Bounds Typer::Visitor::TypeUnaryOp(Node* node, UnaryTyperFun f) {
+  Bounds input = OperandType(node, 0);
+  Type* upper = input.upper->Is(Type::None())
+      ? Type::None()
+      : f(input.upper, typer_);
+  Type* lower = input.lower->Is(Type::None())
+      ? Type::None()
+      : (input.lower == input.upper || upper->IsConstant())
+ ? upper // TODO(neis): Extend this to Range(x,x), NaN, MinusZero, ...?
+      : f(input.lower, typer_);
+  // TODO(neis): Figure out what to do with lower bound.
+  return Bounds(lower, upper);
+}
+
+
+Bounds Typer::Visitor::TypeBinaryOp(Node* node, BinaryTyperFun f) {
+  Bounds left = OperandType(node, 0);
+  Bounds right = OperandType(node, 1);
+ Type* upper = left.upper->Is(Type::None()) || right.upper->Is(Type::None())
+      ? Type::None()
+      : f(left.upper, right.upper, typer_);
+ Type* lower = left.lower->Is(Type::None()) || right.lower->Is(Type::None())
+      ? Type::None()
+      : ((left.lower == left.upper && right.lower == right.upper) ||
+         upper->IsConstant())
+      ? upper
+      : f(left.lower, right.lower, typer_);
+  // TODO(neis): Figure out what to do with lower bound.
+  return Bounds(lower, upper);
+}
+
+
+Type* Typer::Visitor::Invert(Type* type, Typer* t) {
+  if (type->Is(t->singleton_false)) return t->singleton_true;
+  if (type->Is(t->singleton_true)) return t->singleton_false;
+  return type;
+}
+
+
+Type* Typer::Visitor::FalsifyUndefined(Type* type, Typer* t) {
+  if (type->Is(Type::Undefined())) return t->singleton_false;
+  return type;
+}
+
+
+// Type conversion.
+
+
+Type* Typer::Visitor::ToPrimitive(Type* type, Typer* t) {
+  if (type->Is(Type::Primitive()) && !type->Maybe(Type::Receiver())) {
+    return type;
+  }
+  return Type::Primitive();
+}
+
+
+Type* Typer::Visitor::ToBoolean(Type* type, Typer* t) {
+  if (type->Is(Type::Boolean())) return type;
+  if (type->Is(t->falsish)) return t->singleton_false;
+  if (type->Is(Type::DetectableReceiver())) return t->singleton_true;
+ if (type->Is(Type::OrderedNumber()) && (type->Max() < 0 || 0 < type->Min())) {
+    return t->singleton_true;  // Ruled out nan, -0 and +0.
+  }
+  return Type::Boolean();
+}
+
+
+Type* Typer::Visitor::ToNumber(Type* type, Typer* t) {
+  if (type->Is(Type::Number())) return type;
+  if (type->Is(Type::Undefined())) return Type::NaN();
+  if (type->Is(t->singleton_false)) return t->singleton_zero;
+  if (type->Is(t->singleton_true)) return t->singleton_one;
+  if (type->Is(Type::Boolean())) return t->zero_or_one;
+  return Type::Number();
+}
+
+
+Type* Typer::Visitor::ToString(Type* type, Typer* t) {
+  if (type->Is(Type::String())) return type;
+  return Type::String();
+}
+
+
+Type* Typer::Visitor::NumberToInt32(Type* type, Typer* t) {
+  // TODO(neis): DCHECK(type->Is(Type::Number()));
+  if (type->Is(Type::Signed32())) return type;
+  if (type->Is(t->zeroish)) return t->singleton_zero;
+  return Type::Signed32();
+}
+
+
+Type* Typer::Visitor::NumberToUint32(Type* type, Typer* t) {
+  // TODO(neis): DCHECK(type->Is(Type::Number()));
+  if (type->Is(Type::Unsigned32())) return type;
+  if (type->Is(t->zeroish)) return t->singleton_zero;
+  return Type::Unsigned32();
+}
+
+
+// -----------------------------------------------------------------------------
+

 // Control operators.

+
 Bounds Typer::Visitor::TypeStart(Node* node) {
-  return Bounds(Type::Internal(zone()));
+  return Bounds(Type::Internal());
 }


 // Common operators.

+
 Bounds Typer::Visitor::TypeParameter(Node* node) {
   return Bounds::Unbounded(zone());
 }


 Bounds Typer::Visitor::TypeInt32Constant(Node* node) {
-  // TODO(titzer): only call Type::Of() if the type is not already known.
-  return Bounds(Type::Of(OpParameter<int32_t>(node), zone()));
+  Factory* f = zone()->isolate()->factory();
+  Handle<Object> number = f->NewNumber(OpParameter<int32_t>(node));
+  return Bounds(Type::Intersect(
+      Type::Range(number, number, zone()), Type::UntaggedInt32(), zone()));
 }


 Bounds Typer::Visitor::TypeInt64Constant(Node* node) {
-  // TODO(titzer): only call Type::Of() if the type is not already known.
-  return Bounds(
-      Type::Of(static_cast<double>(OpParameter<int64_t>(node)), zone()));
+ return Bounds(Type::Internal()); // TODO(rossberg): Add int64 bitset type?
 }


 Bounds Typer::Visitor::TypeFloat32Constant(Node* node) {
-  // TODO(titzer): only call Type::Of() if the type is not already known.
-  return Bounds(Type::Of(OpParameter<float>(node), zone()));
+  return Bounds(Type::Intersect(
+      Type::Of(OpParameter<float>(node), zone()),
+      Type::UntaggedFloat32(), zone()));
 }


 Bounds Typer::Visitor::TypeFloat64Constant(Node* node) {
-  // TODO(titzer): only call Type::Of() if the type is not already known.
-  return Bounds(Type::Of(OpParameter<double>(node), zone()));
+  return Bounds(Type::Intersect(
+      Type::Of(OpParameter<double>(node), zone()),
+      Type::UntaggedFloat64(), zone()));
 }


 Bounds Typer::Visitor::TypeNumberConstant(Node* node) {
-  // TODO(titzer): only call Type::Of() if the type is not already known.
-  return Bounds(Type::Of(OpParameter<double>(node), zone()));
+  Factory* f = zone()->isolate()->factory();
+  return Bounds(Type::Constant(
+      f->NewNumber(OpParameter<double>(node)), zone()));
 }


@@ -289,7 +471,7 @@


 Bounds Typer::Visitor::TypeExternalConstant(Node* node) {
-  return Bounds(Type::Internal(zone()));
+  return Bounds(Type::Internal());
 }


@@ -322,12 +504,12 @@

 Bounds Typer::Visitor::TypeFrameState(Node* node) {
   // TODO(rossberg): Ideally FrameState wouldn't have a value output.
-  return Bounds(Type::Internal(zone()));
+  return Bounds(Type::Internal());
 }


 Bounds Typer::Visitor::TypeStateValues(Node* node) {
-  return Bounds(Type::Internal(zone()));
+  return Bounds(Type::Internal());
 }


@@ -344,159 +526,339 @@

 // JS comparison operators.

-#define DEFINE_METHOD(x)                       \
-  Bounds Typer::Visitor::Type##x(Node* node) { \
-    return Bounds(Type::Boolean(zone()));      \
+
+Type* Typer::Visitor::JSEqualTyper(Type* lhs, Type* rhs, Typer* t) {
+ if (lhs->Is(Type::NaN()) || rhs->Is(Type::NaN())) return t->singleton_false;
+  if (lhs->Is(t->undefined_or_null) && rhs->Is(t->undefined_or_null)) {
+    return t->singleton_true;
+  }
+  if (lhs->Is(Type::Number()) && rhs->Is(Type::Number()) &&
+      (lhs->Max() < rhs->Min() || lhs->Min() > rhs->Max())) {
+      return t->singleton_false;
+  }
+  if (lhs->IsConstant() && rhs->Is(lhs)) {
+    // Types are equal and are inhabited only by a single semantic value,
+    // which is not nan due to the earlier check.
+    // TODO(neis): Extend this to Range(x,x), MinusZero, ...?
+    return t->singleton_true;
+  }
+  return Type::Boolean();
+}
+
+
+Type* Typer::Visitor::JSNotEqualTyper(Type* lhs, Type* rhs, Typer* t) {
+  return Invert(JSEqualTyper(lhs, rhs, t), t);
+}
+
+
+static Type* JSType(Type* type) {
+  if (type->Is(Type::Boolean())) return Type::Boolean();
+  if (type->Is(Type::String())) return Type::String();
+  if (type->Is(Type::Number())) return Type::Number();
+  if (type->Is(Type::Undefined())) return Type::Undefined();
+  if (type->Is(Type::Null())) return Type::Null();
+  if (type->Is(Type::Symbol())) return Type::Symbol();
+  if (type->Is(Type::Receiver())) return Type::Receiver();  // JS "Object"
+  return Type::Any();
+}
+
+
+Type* Typer::Visitor::JSStrictEqualTyper(Type* lhs, Type* rhs, Typer* t) {
+  if (!JSType(lhs)->Maybe(JSType(rhs))) return t->singleton_false;
+ if (lhs->Is(Type::NaN()) || rhs->Is(Type::NaN())) return t->singleton_false;
+  if (lhs->Is(Type::Number()) && rhs->Is(Type::Number()) &&
+      (lhs->Max() < rhs->Min() || lhs->Min() > rhs->Max())) {
+      return t->singleton_false;
   }
-JS_COMPARE_BINOP_LIST(DEFINE_METHOD)
-#undef DEFINE_METHOD
+  if (lhs->IsConstant() && rhs->Is(lhs)) {
+    // Types are equal and are inhabited only by a single semantic value,
+    // which is not nan due to the earlier check.
+    return t->singleton_true;
+  }
+  return Type::Boolean();
+}
+
+
+Type* Typer::Visitor::JSStrictNotEqualTyper(Type* lhs, Type* rhs, Typer* t) {
+  return Invert(JSStrictEqualTyper(lhs, rhs, t), t);
+}
+
+
+// The EcmaScript specification defines the four relational comparison operators +// (<, <=, >=, >) with the help of a single abstract one. It behaves like <
+// but returns undefined when the inputs cannot be compared.
+// We implement the typing analogously.
+Type* Typer::Visitor::JSCompareTyper(Type* lhs, Type* rhs, Typer* t) {
+  lhs = ToPrimitive(lhs, t);
+  rhs = ToPrimitive(rhs, t);
+  if (lhs->Maybe(Type::String()) && rhs->Maybe(Type::String())) {
+    return Type::Boolean();
+  }
+  lhs = ToNumber(lhs, t);
+  rhs = ToNumber(rhs, t);
+ if (lhs->Is(Type::NaN()) || rhs->Is(Type::NaN())) return Type::Undefined();
+  if (lhs->IsConstant() && rhs->Is(lhs)) {
+    // Types are equal and are inhabited only by a single semantic value,
+    // which is not NaN due to the previous check.
+    return t->singleton_false;
+  }
+  if (lhs->Min() >= rhs->Max()) return t->singleton_false;
+  if (lhs->Max() < rhs->Min() &&
+      !lhs->Maybe(Type::NaN()) && !rhs->Maybe(Type::NaN())) {
+    return t->singleton_true;
+  }
+  return Type::Boolean();
+}
+
+
+Type* Typer::Visitor::JSLessThanTyper(Type* lhs, Type* rhs, Typer* t) {
+  return FalsifyUndefined(JSCompareTyper(lhs, rhs, t), t);
+}
+
+
+Type* Typer::Visitor::JSGreaterThanTyper(Type* lhs, Type* rhs, Typer* t) {
+  return FalsifyUndefined(JSCompareTyper(rhs, lhs, t), t);
+}
+
+
+Type* Typer::Visitor::JSLessThanOrEqualTyper(Type* lhs, Type* rhs, Typer* t) {
+  return FalsifyUndefined(Invert(JSCompareTyper(rhs, lhs, t), t), t);
+}
+
+
+Type* Typer::Visitor::JSGreaterThanOrEqualTyper(
+    Type* lhs, Type* rhs, Typer* t) {
+  return FalsifyUndefined(Invert(JSCompareTyper(lhs, rhs, t), t), t);
+}


 // JS bitwise operators.

-Bounds Typer::Visitor::TypeJSBitwiseOr(Node* node) {
-  Bounds left = OperandType(node, 0);
-  Bounds right = OperandType(node, 1);
-  Type* upper = Type::Union(left.upper, right.upper, zone());
-  if (!upper->Is(Type::Signed32())) upper = Type::Signed32(zone());
-  Type* lower = Type::Intersect(Type::SignedSmall(zone()), upper, zone());
-  return Bounds(lower, upper);
+
+Type* Typer::Visitor::JSBitwiseOrTyper(Type* lhs, Type* rhs, Typer* t) {
+  Factory* f = t->zone()->isolate()->factory();
+  lhs = NumberToInt32(ToNumber(lhs, t), t);
+  rhs = NumberToInt32(ToNumber(rhs, t), t);
+  double lmin = lhs->Min();
+  double rmin = rhs->Min();
+  double lmax = lhs->Max();
+  double rmax = rhs->Max();
+ // Or-ing any two values results in a value no smaller than their minimum.
+  // Even no smaller than their maximum if both values are non-negative.
+  Handle<Object> min = f->NewNumber(
+ lmin >= 0 && rmin >= 0 ? std::max(lmin, rmin) : std::min(lmin, rmin));
+  if (lmax < 0 || rmax < 0) {
+ // Or-ing two values of which at least one is negative results in a negative
+    // value.
+    Handle<Object> max = f->NewNumber(-1);
+    return Type::Range(min, max, t->zone());
+  }
+  Handle<Object> max = f->NewNumber(Type::Signed32()->Max());
+  return Type::Range(min, max, t->zone());
+  // TODO(neis): Be precise for singleton inputs, here and elsewhere.
 }


-Bounds Typer::Visitor::TypeJSBitwiseAnd(Node* node) {
-  Bounds left = OperandType(node, 0);
-  Bounds right = OperandType(node, 1);
-  Type* upper = Type::Union(left.upper, right.upper, zone());
-  if (!upper->Is(Type::Signed32())) upper = Type::Signed32(zone());
-  Type* lower = Type::Intersect(Type::SignedSmall(zone()), upper, zone());
-  return Bounds(lower, upper);
+Type* Typer::Visitor::JSBitwiseAndTyper(Type* lhs, Type* rhs, Typer* t) {
+  Factory* f = t->zone()->isolate()->factory();
+  lhs = NumberToInt32(ToNumber(lhs, t), t);
+  rhs = NumberToInt32(ToNumber(rhs, t), t);
+  double lmin = lhs->Min();
+  double rmin = rhs->Min();
+  double lmax = lhs->Max();
+  double rmax = rhs->Max();
+ // And-ing any two values results in a value no larger than their maximum.
+  // Even no larger than their minimum if both values are non-negative.
+  Handle<Object> max = f->NewNumber(
+ lmin >= 0 && rmin >= 0 ? std::min(lmax, rmax) : std::max(lmax, rmax));
+  if (lmin >= 0 || rmin >= 0) {
+ // And-ing two values of which at least one is non-negative results in a
+    // non-negative value.
+    Handle<Object> min = f->NewNumber(0);
+    return Type::Range(min, max, t->zone());
+  }
+  Handle<Object> min = f->NewNumber(Type::Signed32()->Min());
+  return Type::Range(min, max, t->zone());
 }


-Bounds Typer::Visitor::TypeJSBitwiseXor(Node* node) {
-  return Bounds(Type::SignedSmall(zone()), Type::Signed32(zone()));
+Type* Typer::Visitor::JSBitwiseXorTyper(Type* lhs, Type* rhs, Typer* t) {
+  lhs = NumberToInt32(ToNumber(lhs, t), t);
+  rhs = NumberToInt32(ToNumber(rhs, t), t);
+  double lmin = lhs->Min();
+  double rmin = rhs->Min();
+  double lmax = lhs->Max();
+  double rmax = rhs->Max();
+  if ((lmin >= 0 && rmin >= 0) || (lmax < 0 && rmax < 0)) {
+ // Xor-ing negative or non-negative values results in a non-negative value.
+    return t->non_negative_signed32;
+  }
+  if ((lmax < 0 && rmin >= 0) || (lmin >= 0 && rmax < 0)) {
+ // Xor-ing a negative and a non-negative value results in a negative value.
+    return t->negative_signed32;
+  }
+  return Type::Signed32();
 }


-Bounds Typer::Visitor::TypeJSShiftLeft(Node* node) {
-  return Bounds(Type::SignedSmall(zone()), Type::Signed32(zone()));
+Type* Typer::Visitor::JSShiftLeftTyper(Type* lhs, Type* rhs, Typer* t) {
+  return Type::Signed32();
 }


-Bounds Typer::Visitor::TypeJSShiftRight(Node* node) {
-  return Bounds(Type::SignedSmall(zone()), Type::Signed32(zone()));
+Type* Typer::Visitor::JSShiftRightTyper(Type* lhs, Type* rhs, Typer* t) {
+  lhs = NumberToInt32(ToNumber(lhs, t), t);
+  Factory* f = t->zone()->isolate()->factory();
+  if (lhs->Min() >= 0) {
+ // Right-shifting a non-negative value cannot make it negative, nor larger.
+    Handle<Object> min = f->NewNumber(0);
+    Handle<Object> max = f->NewNumber(lhs->Max());
+    return Type::Range(min, max, t->zone());
+  }
+  if (lhs->Max() < 0) {
+ // Right-shifting a negative value cannot make it non-negative, nor smaller.
+    Handle<Object> min = f->NewNumber(lhs->Min());
+    Handle<Object> max = f->NewNumber(-1);
+    return Type::Range(min, max, t->zone());
+  }
+  return Type::Signed32();
 }


-Bounds Typer::Visitor::TypeJSShiftRightLogical(Node* node) {
-  return Bounds(Type::UnsignedSmall(zone()), Type::Unsigned32(zone()));
+Type* Typer::Visitor::JSShiftRightLogicalTyper(Type* lhs, Type* rhs, Typer* t) {
+  lhs = NumberToUint32(ToNumber(lhs, t), t);
+  Factory* f = t->zone()->isolate()->factory();
+  // Logical right-shifting any value cannot make it larger.
+  Handle<Object> min = f->NewNumber(0);
+  Handle<Object> max = f->NewNumber(lhs->Max());
+  return Type::Range(min, max, t->zone());
 }


 // JS arithmetic operators.

-Bounds Typer::Visitor::TypeJSAdd(Node* node) {
-  Bounds left = OperandType(node, 0);
-  Bounds right = OperandType(node, 1);
-  Type* lower =
-      left.lower->Is(Type::None()) || right.lower->Is(Type::None()) ?
-          Type::None(zone()) :
-      left.lower->Is(Type::Number()) && right.lower->Is(Type::Number()) ?
-          Type::SignedSmall(zone()) :
-      left.lower->Is(Type::String()) || right.lower->Is(Type::String()) ?
-          Type::String(zone()) : Type::None(zone());
-  Type* upper =
-      left.upper->Is(Type::None()) && right.upper->Is(Type::None()) ?
-          Type::None(zone()) :
-      left.upper->Is(Type::Number()) && right.upper->Is(Type::Number()) ?
-          Type::Number(zone()) :
-      left.upper->Is(Type::String()) || right.upper->Is(Type::String()) ?
-          Type::String(zone()) : Type::NumberOrString(zone());
-  return Bounds(lower, upper);
+
+Type* Typer::Visitor::JSAddTyper(Type* lhs, Type* rhs, Typer* t) {
+  lhs = ToPrimitive(lhs, t);
+  rhs = ToPrimitive(rhs, t);
+  if (lhs->Maybe(Type::String()) || rhs->Maybe(Type::String())) {
+    if (lhs->Is(Type::String()) || rhs->Is(Type::String())) {
+      return Type::String();
+    } else {
+      return Type::NumberOrString();
+    }
+  }
+  lhs = ToNumber(lhs, t);
+  rhs = ToNumber(rhs, t);
+  if (lhs->Is(Type::NaN()) || rhs->Is(Type::NaN())) return Type::NaN();
+  // TODO(neis): Do some analysis.
+  // TODO(neis): Deal with numeric bitsets here and elsewhere.
+  return Type::Number();
 }


-Bounds Typer::Visitor::TypeJSSubtract(Node* node) {
-  return Bounds(Type::SignedSmall(zone()), Type::Number(zone()));
+Type* Typer::Visitor::JSSubtractTyper(Type* lhs, Type* rhs, Typer* t) {
+  lhs = ToNumber(lhs, t);
+  rhs = ToNumber(rhs, t);
+  if (lhs->Is(Type::NaN()) || rhs->Is(Type::NaN())) return Type::NaN();
+  // TODO(neis): Do some analysis.
+  return Type::Number();
 }


-Bounds Typer::Visitor::TypeJSMultiply(Node* node) {
-  return Bounds(Type::SignedSmall(zone()), Type::Number(zone()));
+Type* Typer::Visitor::JSMultiplyTyper(Type* lhs, Type* rhs, Typer* t) {
+  lhs = ToNumber(lhs, t);
+  rhs = ToNumber(rhs, t);
+  if (lhs->Is(Type::NaN()) || rhs->Is(Type::NaN())) return Type::NaN();
+  // TODO(neis): Do some analysis.
+  return Type::Number();
 }


-Bounds Typer::Visitor::TypeJSDivide(Node* node) {
-  return Bounds(Type::SignedSmall(zone()), Type::Number(zone()));
+Type* Typer::Visitor::JSDivideTyper(Type* lhs, Type* rhs, Typer* t) {
+  lhs = ToNumber(lhs, t);
+  rhs = ToNumber(rhs, t);
+  if (lhs->Is(Type::NaN()) || rhs->Is(Type::NaN())) return Type::NaN();
+  // TODO(neis): Do some analysis.
+  return Type::Number();
 }


-Bounds Typer::Visitor::TypeJSModulus(Node* node) {
-  return Bounds(Type::SignedSmall(zone()), Type::Number(zone()));
+Type* Typer::Visitor::JSModulusTyper(Type* lhs, Type* rhs, Typer* t) {
+  lhs = ToNumber(lhs, t);
+  rhs = ToNumber(rhs, t);
+  if (lhs->Is(Type::NaN()) || rhs->Is(Type::NaN())) return Type::NaN();
+  // TODO(neis): Do some analysis.
+  return Type::Number();
 }


 // JS unary operators.

+
+Type* Typer::Visitor::JSUnaryNotTyper(Type* type, Typer* t) {
+  return Invert(ToBoolean(type, t), t);
+}
+
+
 Bounds Typer::Visitor::TypeJSUnaryNot(Node* node) {
-  return Bounds(Type::Boolean(zone()));
+  return TypeUnaryOp(node, JSUnaryNotTyper);
 }


 Bounds Typer::Visitor::TypeJSTypeOf(Node* node) {
-  return Bounds(Type::InternalizedString(zone()));
+  return Bounds(Type::InternalizedString());
 }


 // JS conversion operators.

+
 Bounds Typer::Visitor::TypeJSToBoolean(Node* node) {
-  return Bounds(Type::Boolean(zone()));
+  return TypeUnaryOp(node, ToBoolean);
 }


 Bounds Typer::Visitor::TypeJSToNumber(Node* node) {
-  return Bounds(Type::SignedSmall(zone()), Type::Number(zone()));
+  return TypeUnaryOp(node, ToNumber);
 }


 Bounds Typer::Visitor::TypeJSToString(Node* node) {
-  return Bounds(Type::None(zone()), Type::String(zone()));
+  return TypeUnaryOp(node, ToString);
 }


 Bounds Typer::Visitor::TypeJSToName(Node* node) {
-  return Bounds(Type::None(zone()), Type::Name(zone()));
+  return Bounds(Type::None(), Type::Name());
 }


 Bounds Typer::Visitor::TypeJSToObject(Node* node) {
-  return Bounds(Type::None(zone()), Type::Receiver(zone()));
+  return Bounds(Type::None(), Type::Receiver());
 }


 // JS object operators.

+
 Bounds Typer::Visitor::TypeJSCreate(Node* node) {
-  return Bounds(Type::None(zone()), Type::Object(zone()));
+  return Bounds(Type::None(), Type::Object());
 }


-Bounds Typer::Visitor::TypeJSLoadProperty(Node* node) {
-  Bounds object = OperandType(node, 0);
-  Bounds name = OperandType(node, 1);
-  Bounds result = Bounds::Unbounded(zone());
+Type* Typer::Visitor::JSLoadPropertyTyper(Type* object, Type* name, Typer* t) { // TODO(rossberg): Use range types and sized array types to filter undefined.
-  if (object.lower->IsArray() && name.lower->Is(Type::Integral32())) {
-    result.lower = Type::Union(
- object.lower->AsArray()->Element(), Type::Undefined(zone()), zone());
+  if (object->IsArray() && name->Is(Type::Integral32())) {
+    return Type::Union(
+        object->AsArray()->Element(), Type::Undefined(), t->zone());
   }
-  if (object.upper->IsArray() && name.upper->Is(Type::Integral32())) {
-    result.upper = Type::Union(
- object.upper->AsArray()->Element(), Type::Undefined(zone()), zone());
-  }
-  return result;
+  return Type::Any();
+}
+
+
+Bounds Typer::Visitor::TypeJSLoadProperty(Node* node) {
+  return TypeBinaryOp(node, JSLoadPropertyTyper);
 }


@@ -518,22 +880,23 @@


 Bounds Typer::Visitor::TypeJSDeleteProperty(Node* node) {
-  return Bounds(Type::Boolean(zone()));
+  return Bounds(Type::Boolean());
 }


 Bounds Typer::Visitor::TypeJSHasProperty(Node* node) {
-  return Bounds(Type::Boolean(zone()));
+  return Bounds(Type::Boolean());
 }


 Bounds Typer::Visitor::TypeJSInstanceOf(Node* node) {
-  return Bounds(Type::Boolean(zone()));
+  return Bounds(Type::Boolean());
 }


 // JS context operators.

+
 Bounds Typer::Visitor::TypeJSLoadContext(Node* node) {
   Bounds outer = OperandType(node, 0);
   DCHECK(outer.upper->Maybe(Type::Internal()));
@@ -568,7 +931,7 @@
handle(context.ToHandleChecked()->get(static_cast<int>(access.index())),
                isolate());
     Type* lower = TypeConstant(value);
-    return Bounds(lower, Type::Any(zone()));
+    return Bounds(lower, Type::Any());
   }
 }

@@ -618,23 +981,24 @@

 // JS other operators.

+
 Bounds Typer::Visitor::TypeJSYield(Node* node) {
   return Bounds::Unbounded(zone());
 }


 Bounds Typer::Visitor::TypeJSCallConstruct(Node* node) {
-  return Bounds(Type::None(zone()), Type::Receiver(zone()));
+  return Bounds(Type::None(), Type::Receiver());
+}
+
+
+Type* Typer::Visitor::JSCallFunctionTyper(Type* fun, Typer* t) {
+  return fun->IsFunction() ? fun->AsFunction()->Result() : Type::Any();
 }


 Bounds Typer::Visitor::TypeJSCallFunction(Node* node) {
-  Bounds fun = OperandType(node, 0);
-  Type* lower = fun.lower->IsFunction()
-      ? fun.lower->AsFunction()->Result() : Type::None(zone());
-  Type* upper = fun.upper->IsFunction()
-      ? fun.upper->AsFunction()->Result() : Type::Any(zone());
-  return Bounds(lower, upper);
+ return TypeUnaryOp(node, JSCallFunctionTyper); // We ignore argument types.
 }


@@ -650,143 +1014,172 @@

 // Simplified operators.

+
 Bounds Typer::Visitor::TypeBooleanNot(Node* node) {
-  return Bounds(Type::Boolean(zone()));
+  return Bounds(Type::Boolean());
 }


 Bounds Typer::Visitor::TypeBooleanToNumber(Node* node) {
-  return Bounds(Type::Number(zone()));
+  return Bounds(Type::Number());
 }


 Bounds Typer::Visitor::TypeNumberEqual(Node* node) {
-  return Bounds(Type::Boolean(zone()));
+  return Bounds(Type::Boolean());
 }


 Bounds Typer::Visitor::TypeNumberLessThan(Node* node) {
-  return Bounds(Type::Boolean(zone()));
+  return Bounds(Type::Boolean());
 }


 Bounds Typer::Visitor::TypeNumberLessThanOrEqual(Node* node) {
-  return Bounds(Type::Boolean(zone()));
+  return Bounds(Type::Boolean());
 }


 Bounds Typer::Visitor::TypeNumberAdd(Node* node) {
-  return Bounds(Type::Number(zone()));
+  return Bounds(Type::Number());
 }


 Bounds Typer::Visitor::TypeNumberSubtract(Node* node) {
-  return Bounds(Type::Number(zone()));
+  return Bounds(Type::Number());
 }


 Bounds Typer::Visitor::TypeNumberMultiply(Node* node) {
-  return Bounds(Type::Number(zone()));
+  return Bounds(Type::Number());
 }


 Bounds Typer::Visitor::TypeNumberDivide(Node* node) {
-  return Bounds(Type::Number(zone()));
+  return Bounds(Type::Number());
 }


 Bounds Typer::Visitor::TypeNumberModulus(Node* node) {
-  return Bounds(Type::Number(zone()));
+  return Bounds(Type::Number());
 }


 Bounds Typer::Visitor::TypeNumberToInt32(Node* node) {
-  Bounds arg = OperandType(node, 0);
-  Type* s32 = Type::Signed32(zone());
-  Type* lower = arg.lower->Is(s32) ? arg.lower : s32;
-  Type* upper = arg.upper->Is(s32) ? arg.upper : s32;
-  return Bounds(lower, upper);
+  return TypeUnaryOp(node, NumberToInt32);
 }


 Bounds Typer::Visitor::TypeNumberToUint32(Node* node) {
-  Bounds arg = OperandType(node, 0);
-  Type* u32 = Type::Unsigned32(zone());
-  Type* lower = arg.lower->Is(u32) ? arg.lower : u32;
-  Type* upper = arg.upper->Is(u32) ? arg.upper : u32;
-  return Bounds(lower, upper);
+  return TypeUnaryOp(node, NumberToUint32);
 }


 Bounds Typer::Visitor::TypeReferenceEqual(Node* node) {
-  return Bounds(Type::Boolean(zone()));
+  return Bounds(Type::Boolean());
 }


 Bounds Typer::Visitor::TypeStringEqual(Node* node) {
-  return Bounds(Type::Boolean(zone()));
+  return Bounds(Type::Boolean());
 }


 Bounds Typer::Visitor::TypeStringLessThan(Node* node) {
-  return Bounds(Type::Boolean(zone()));
+  return Bounds(Type::Boolean());
 }


 Bounds Typer::Visitor::TypeStringLessThanOrEqual(Node* node) {
-  return Bounds(Type::Boolean(zone()));
+  return Bounds(Type::Boolean());
 }


 Bounds Typer::Visitor::TypeStringAdd(Node* node) {
-  return Bounds(Type::String(zone()));
+  return Bounds(Type::String());
+}
+
+
+static Type* ChangeRepresentation(Type* type, Type* rep, Zone* zone) {
+  // TODO(neis): Enable when expressible.
+  /*
+  return Type::Union(
+      Type::Intersect(type, Type::Semantic(), zone),
+      Type::Intersect(rep, Type::Representation(), zone), zone);
+  */
+  return type;
 }


 Bounds Typer::Visitor::TypeChangeTaggedToInt32(Node* node) {
-  // TODO(titzer): type is type of input, representation is Word32.
-  return Bounds(Type::Integral32());
+  Bounds arg = OperandType(node, 0);
+  // TODO(neis): DCHECK(arg.upper->Is(Type::Signed32()));
+  return Bounds(
+      ChangeRepresentation(arg.lower, Type::UntaggedInt32(), zone()),
+      ChangeRepresentation(arg.upper, Type::UntaggedInt32(), zone()));
 }


 Bounds Typer::Visitor::TypeChangeTaggedToUint32(Node* node) {
-  return Bounds(Type::Integral32());  // TODO(titzer): add appropriate rep
+  Bounds arg = OperandType(node, 0);
+  // TODO(neis): DCHECK(arg.upper->Is(Type::Unsigned32()));
+  return Bounds(
+      ChangeRepresentation(arg.lower, Type::UntaggedInt32(), zone()),
+      ChangeRepresentation(arg.upper, Type::UntaggedInt32(), zone()));
 }


 Bounds Typer::Visitor::TypeChangeTaggedToFloat64(Node* node) {
-  // TODO(titzer): type is type of input, representation is Float64.
-  return Bounds(Type::Number());
+  Bounds arg = OperandType(node, 0);
+  // TODO(neis): DCHECK(arg.upper->Is(Type::Number()));
+  return Bounds(
+      ChangeRepresentation(arg.lower, Type::UntaggedFloat64(), zone()),
+      ChangeRepresentation(arg.upper, Type::UntaggedFloat64(), zone()));
 }


 Bounds Typer::Visitor::TypeChangeInt32ToTagged(Node* node) {
-  // TODO(titzer): type is type of input, representation is Tagged.
-  return Bounds(Type::Integral32());
+  Bounds arg = OperandType(node, 0);
+  // TODO(neis): DCHECK(arg.upper->Is(Type::Signed32()));
+  return Bounds(
+      ChangeRepresentation(arg.lower, Type::Tagged(), zone()),
+      ChangeRepresentation(arg.upper, Type::Tagged(), zone()));
 }


 Bounds Typer::Visitor::TypeChangeUint32ToTagged(Node* node) {
-  // TODO(titzer): type is type of input, representation is Tagged.
-  return Bounds(Type::Unsigned32());
+  Bounds arg = OperandType(node, 0);
+  // TODO(neis): DCHECK(arg.upper->Is(Type::Unsigned32()));
***The diff for this file has been truncated for email.***
=======================================
--- /trunk/src/compiler/typer.h Fri Sep 26 00:05:23 2014 UTC
+++ /trunk/src/compiler/typer.h Wed Oct 15 13:35:30 2014 UTC
@@ -36,6 +36,17 @@
   class WidenVisitor;

   Zone* zone_;
+  Type* negative_signed32;
+  Type* non_negative_signed32;
+  Type* undefined_or_null;
+  Type* singleton_false;
+  Type* singleton_true;
+  Type* singleton_zero;
+  Type* singleton_one;
+  Type* zero_or_one;
+  Type* zeroish;
+  Type* falsish;
+  Type* integer;
   Type* number_fun0_;
   Type* number_fun1_;
   Type* number_fun2_;
=======================================
--- /trunk/src/compiler/verifier.cc     Wed Oct  1 00:05:35 2014 UTC
+++ /trunk/src/compiler/verifier.cc     Wed Oct 15 13:35:30 2014 UTC
@@ -269,6 +269,19 @@
   }
   return false;
 }
+
+
+static bool Dominates(Schedule* schedule, Node* dominator, Node* dominatee) {
+  BasicBlock* dom = schedule->block(dominator);
+  BasicBlock* sub = schedule->block(dominatee);
+  while (sub != NULL) {
+    if (sub == dom) {
+      return true;
+    }
+    sub = sub->dominator();
+  }
+  return false;
+}


 static void CheckInputsDominate(Schedule* schedule, BasicBlock* block,
@@ -289,6 +302,19 @@
                input->id(), input->op()->mnemonic());
     }
   }
+  // Ensure that nodes are dominated by their control inputs;
+  // kEnd is an exception, as unreachable blocks resulting from kMerge
+  // are not in the RPO.
+  if (OperatorProperties::GetControlInputCount(node->op()) == 1 &&
+      node->opcode() != IrOpcode::kEnd) {
+    Node* ctl = NodeProperties::GetControlInput(node);
+    if (!Dominates(schedule, ctl, node)) {
+      V8_Fatal(__FILE__, __LINE__,
+ "Node #%d:%s in B%d is not dominated by control input #%d:%s",
+               node->id(), node->op()->mnemonic(), block->id(), ctl->id(),
+               ctl->op()->mnemonic());
+    }
+  }
 }


=======================================
--- /trunk/src/compiler/x64/code-generator-x64.cc Wed Oct 15 00:05:09 2014 UTC +++ /trunk/src/compiler/x64/code-generator-x64.cc Wed Oct 15 13:35:30 2014 UTC
@@ -283,6 +283,9 @@
     case kX64Imul:
       ASSEMBLE_MULT(imulq);
       break;
+    case kX64ImulHigh32:
+      __ imull(i.InputRegister(1));
+      break;
     case kX64Idiv32:
       __ cdq();
       __ idivl(i.InputRegister(1));
@@ -867,7 +870,7 @@
       switch (src.type()) {
         case Constant::kInt32:
           // TODO(dcarney): don't need scratch in this case.
-          __ movq(dst, Immediate(src.ToInt32()));
+          __ Set(dst, src.ToInt32());
           break;
         case Constant::kInt64:
           __ Set(dst, src.ToInt64());
=======================================
--- /trunk/src/compiler/x64/instruction-codes-x64.h Wed Oct 1 00:05:35 2014 UTC +++ /trunk/src/compiler/x64/instruction-codes-x64.h Wed Oct 15 13:35:30 2014 UTC
@@ -28,6 +28,7 @@
   V(X64Sub32)                      \
   V(X64Imul)                       \
   V(X64Imul32)                     \
+  V(X64ImulHigh32)                 \
   V(X64Idiv)                       \
   V(X64Idiv32)                     \
   V(X64Udiv)                       \
=======================================
--- /trunk/src/compiler/x64/instruction-selector-x64.cc Wed Oct 15 00:05:09 2014 UTC +++ /trunk/src/compiler/x64/instruction-selector-x64.cc Wed Oct 15 13:35:30 2014 UTC
@@ -240,7 +240,18 @@
   size_t output_count = 0;

   // TODO(turbofan): match complex addressing modes.
-  if (g.CanBeImmediate(right)) {
+  if (left == right) {
+ // If both inputs refer to the same operand, enforce allocating a register
+    // for both of them to ensure that we don't end up generating code like
+    // this:
+    //
+    //   mov rax, [rbp-0x10]
+    //   add rax, [rbp-0x10]
+    //   jo label
+    InstructionOperand* const input = g.UseRegister(left);
+    inputs[input_count++] = input;
+    inputs[input_count++] = input;
+  } else if (g.CanBeImmediate(right)) {
     inputs[input_count++] = g.UseRegister(left);
     inputs[input_count++] = g.UseImmediate(right);
   } else {
@@ -544,6 +555,16 @@
   if (TryEmitLeaMult(this, node, kX64Lea)) return;
   VisitMul(this, node, kX64Imul);
 }
+
+
+void InstructionSelector::VisitInt32MulHigh(Node* node) {
+  X64OperandGenerator g(this);
+  InstructionOperand* temps[] = {g.TempRegister(rax)};
+  size_t temp_count = arraysize(temps);
+  Emit(kX64ImulHigh32, g.DefineAsFixed(node, rdx),
+       g.UseFixed(node->InputAt(0), rax), g.UseRegister(node->InputAt(1)),
+       temp_count, temps);
+}


 static void VisitDiv(InstructionSelector* selector, Node* node,
@@ -784,13 +805,6 @@
VisitCompare(selector, opcode, g.UseRegister(left), g.Use(right), cont);
   }
 }
-
-
-static void VisitWordTest(InstructionSelector* selector, Node* node,
- InstructionCode opcode, FlagsContinuation* cont) {
-  X64OperandGenerator g(selector);
-  VisitCompare(selector, opcode, g.Use(node), g.TempImmediate(-1), cont);
-}


 static void VisitFloat64Compare(InstructionSelector* selector, Node* node,
@@ -805,7 +819,7 @@

 void InstructionSelector::VisitBranch(Node* branch, BasicBlock* tbranch,
                                       BasicBlock* fbranch) {
-  OperandGenerator g(this);
+  X64OperandGenerator g(this);
   Node* user = branch;
   Node* value = branch->InputAt(0);

@@ -908,15 +922,19 @@
         break;
       case IrOpcode::kInt32Sub:
         return VisitWordCompare(this, value, kX64Cmp32, &cont, false);
+      case IrOpcode::kInt64Sub:
+        return VisitWordCompare(this, value, kX64Cmp, &cont, false);
       case IrOpcode::kWord32And:
         return VisitWordCompare(this, value, kX64Test32, &cont, true);
+      case IrOpcode::kWord64And:
+        return VisitWordCompare(this, value, kX64Test, &cont, true);
       default:
         break;
     }
   }

   // Branch could not be combined with a compare, emit compare against 0.
-  VisitWordTest(this, value, kX64Test32, &cont);
+  VisitCompare(this, kX64Cmp32, g.Use(value), g.TempImmediate(0), &cont);
 }


@@ -935,7 +953,6 @@
         default:
           break;
       }
-      return VisitWordTest(this, value, kX64Test32, &cont);
     }
   }
   VisitWordCompare(this, node, kX64Cmp32, &cont, false);
@@ -981,7 +998,6 @@
         default:
           break;
       }
-      return VisitWordTest(this, value, kX64Test, &cont);
     }
   }
   VisitWordCompare(this, node, kX64Cmp, &cont, false);
=======================================
--- /trunk/src/counters.cc      Tue Jul 29 08:45:47 2014 UTC
+++ /trunk/src/counters.cc      Wed Oct 15 13:35:30 2014 UTC
@@ -7,6 +7,7 @@
 #include "src/base/platform/platform.h"
 #include "src/counters.h"
 #include "src/isolate.h"
+#include "src/log-inl.h"

 namespace v8 {
 namespace internal {
@@ -39,7 +40,7 @@
   if (Enabled()) {
     timer_.Start();
   }
-  isolate()->event_logger()(name(), Logger::START);
+  Logger::CallEventLogger(isolate(), name(), Logger::START, true);
 }


@@ -50,7 +51,7 @@
     AddSample(static_cast<int>(timer_.Elapsed().InMilliseconds()));
     timer_.Stop();
   }
-  isolate()->event_logger()(name(), Logger::END);
+  Logger::CallEventLogger(isolate(), name(), Logger::END, true);
 }


=======================================
--- /trunk/src/factory.cc       Mon Oct 13 00:05:20 2014 UTC
+++ /trunk/src/factory.cc       Wed Oct 15 13:35:30 2014 UTC
@@ -929,6 +929,13 @@
   PropertyCell::SetValueInferType(cell, value);
   return cell;
 }
+
+
+Handle<WeakCell> Factory::NewWeakCell(Handle<HeapObject> value) {
+  AllowDeferredHandleDereference convert_to_cell;
+ CALL_HEAP_FUNCTION(isolate(), isolate()->heap()->AllocateWeakCell(*value),
+                     WeakCell);
+}


 Handle<AllocationSite> Factory::NewAllocationSite() {
=======================================
--- /trunk/src/factory.h        Fri Oct  3 00:04:58 2014 UTC
+++ /trunk/src/factory.h        Wed Oct 15 13:35:30 2014 UTC
@@ -296,6 +296,8 @@

   Handle<PropertyCell> NewPropertyCell(Handle<Object> value);

+  Handle<WeakCell> NewWeakCell(Handle<HeapObject> value);
+
   // Allocate a tenured AllocationSite. It's payload is null.
   Handle<AllocationSite> NewAllocationSite();

=======================================
--- /trunk/src/harmony-array.js Thu Aug 21 00:04:56 2014 UTC
+++ /trunk/src/harmony-array.js Wed Oct 15 13:35:30 2014 UTC
@@ -26,16 +26,18 @@
     thisArg = %_Arguments(1);
   }

+  var needs_wrapper = false;
   if (IS_NULL_OR_UNDEFINED(thisArg)) {
     thisArg = %GetDefaultReceiver(predicate) || thisArg;
- } else if (!IS_SPEC_OBJECT(thisArg) && %IsSloppyModeFunction(predicate)) {
-    thisArg = ToObject(thisArg);
+  } else {
+    needs_wrapper = SHOULD_CREATE_WRAPPER(predicate, thisArg);
   }

   for (var i = 0; i < length; i++) {
     if (i in array) {
       var element = array[i];
-      if (%_CallFunction(thisArg, element, i, array, predicate)) {
+      var newThisArg = needs_wrapper ? ToObject(thisArg) : thisArg;
+      if (%_CallFunction(newThisArg, element, i, array, predicate)) {
         return element;
       }
     }
@@ -61,16 +63,18 @@
     thisArg = %_Arguments(1);
   }

+  var needs_wrapper = false;
   if (IS_NULL_OR_UNDEFINED(thisArg)) {
     thisArg = %GetDefaultReceiver(predicate) || thisArg;
- } else if (!IS_SPEC_OBJECT(thisArg) && %IsSloppyModeFunction(predicate)) {
-    thisArg = ToObject(thisArg);
+  } else {
+    needs_wrapper = SHOULD_CREATE_WRAPPER(predicate, thisArg);
   }

   for (var i = 0; i < length; i++) {
     if (i in array) {
       var element = array[i];
-      if (%_CallFunction(thisArg, element, i, array, predicate)) {
+      var newThisArg = needs_wrapper ? ToObject(thisArg) : thisArg;
+      if (%_CallFunction(newThisArg, element, i, array, predicate)) {
         return i;
       }
     }
=======================================
--- /trunk/src/heap/heap.cc     Tue Oct 14 07:51:07 2014 UTC
+++ /trunk/src/heap/heap.cc     Wed Oct 15 13:35:30 2014 UTC
@@ -150,6 +150,7 @@
   set_array_buffers_list(Smi::FromInt(0));
   set_allocation_sites_list(Smi::FromInt(0));
   set_encountered_weak_collections(Smi::FromInt(0));
+  set_encountered_weak_cells(Smi::FromInt(0));
   // Put a dummy entry in the remembered pages so we can find the list the
   // minidump even if there are no real unmapped pages.
   RememberUnmappedPage(NULL, false);
@@ -1509,6 +1510,8 @@

   // Copy objects reachable from the encountered weak collections list.
   scavenge_visitor.VisitPointer(&encountered_weak_collections_);
+  // Copy objects reachable from the encountered weak cells.
+  scavenge_visitor.VisitPointer(&encountered_weak_cells_);

   // Copy objects reachable from the code flushing candidates list.
   MarkCompactCollector* collector = mark_compact_collector();
@@ -2559,6 +2562,7 @@

     ALLOCATE_MAP(CELL_TYPE, Cell::kSize, cell)
ALLOCATE_MAP(PROPERTY_CELL_TYPE, PropertyCell::kSize, global_property_cell)
+    ALLOCATE_MAP(WEAK_CELL_TYPE, WeakCell::kSize, weak_cell)
     ALLOCATE_MAP(FILLER_TYPE, kPointerSize, one_pointer_filler)
     ALLOCATE_MAP(FILLER_TYPE, 2 * kPointerSize, two_pointer_filler)

@@ -2683,6 +2687,22 @@
   cell->set_type(HeapType::None());
   return result;
 }
+
+
+AllocationResult Heap::AllocateWeakCell(HeapObject* value) {
+  int size = WeakCell::kSize;
+  STATIC_ASSERT(WeakCell::kSize <= Page::kMaxRegularHeapObjectSize);
+  HeapObject* result;
+  {
+    AllocationResult allocation =
+        AllocateRaw(size, OLD_POINTER_SPACE, OLD_POINTER_SPACE);
+    if (!allocation.To(&result)) return allocation;
+  }
+  result->set_map_no_write_barrier(weak_cell_map());
+  WeakCell::cast(result)->initialize(value);
+  WeakCell::cast(result)->set_next(undefined_value(), SKIP_WRITE_BARRIER);
+  return result;
+}


 void Heap::CreateApiObjects() {
=======================================
--- /trunk/src/heap/heap.h      Tue Oct 14 07:51:07 2014 UTC
+++ /trunk/src/heap/heap.h      Wed Oct 15 13:35:30 2014 UTC
@@ -52,6 +52,7 @@
V(Map, fixed_cow_array_map, FixedCOWArrayMap) \ V(Map, fixed_double_array_map, FixedDoubleArrayMap) \ V(Map, constant_pool_array_map, ConstantPoolArrayMap) \ + V(Map, weak_cell_map, WeakCellMap) \ V(Oddball, no_interceptor_result_sentinel, NoInterceptorResultSentinel) \ V(Map, hash_table_map, HashTableMap) \ V(Map, ordered_hash_table_map, OrderedHashTableMap) \
@@ -223,6 +224,7 @@
   V(fixed_cow_array_map)                \
   V(fixed_double_array_map)             \
   V(constant_pool_array_map)            \
+  V(weak_cell_map)                      \
   V(no_interceptor_result_sentinel)     \
   V(hash_table_map)                     \
   V(ordered_hash_table_map)             \
@@ -828,6 +830,11 @@
   Object* encountered_weak_collections() const {
     return encountered_weak_collections_;
   }
+
+  void set_encountered_weak_cells(Object* weak_cell) {
+    encountered_weak_cells_ = weak_cell;
+  }
+ Object* encountered_weak_cells() const { return encountered_weak_cells_; }

   // Number of mark-sweeps.
   unsigned int ms_count() { return ms_count_; }
@@ -1559,6 +1566,8 @@
   // contains Smi(0) while marking is not active.
   Object* encountered_weak_collections_;

+  Object* encountered_weak_cells_;
+
   StoreBufferRebuilder store_buffer_rebuilder_;

   struct StringTypeTable {
@@ -1839,6 +1848,8 @@
   // Allocate a tenured JS global property cell initialized with the hole.
   MUST_USE_RESULT AllocationResult AllocatePropertyCell();

+  MUST_USE_RESULT AllocationResult AllocateWeakCell(HeapObject* value);
+
   // Allocates a new utility object in the old generation.
   MUST_USE_RESULT AllocationResult AllocateStruct(InstanceType type);

=======================================
***Additional files exist in this changeset.***

--
--
v8-dev mailing list
[email protected]
http://groups.google.com/group/v8-dev
--- You received this message because you are subscribed to the Google Groups "v8-dev" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
For more options, visit https://groups.google.com/d/optout.

Reply via email to