Revision: 24827
Author:   [email protected]
Date:     Thu Oct 23 08:44:45 2014 UTC
Log:      Version 3.30.17 (based on bleeding_edge revision r24817)

ARM64: Fix stack manipulation (Chromium issue 425585).

Speed up creation of Objects whose prototype has dictionary elements (Chromium issue 422754).

Enable libstdc++ debug mode in debug builds (issue 3638).

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

Added:
 /trunk/test/mjsunit/regress/regress-425551.js
 /trunk/test/mjsunit/regress/regress-crbug-425585.js
Modified:
 /trunk/ChangeLog
 /trunk/build/standalone.gypi
 /trunk/include/v8config.h
 /trunk/src/arm/full-codegen-arm.cc
 /trunk/src/arm64/assembler-arm64.cc
 /trunk/src/arm64/assembler-arm64.h
 /trunk/src/arm64/builtins-arm64.cc
 /trunk/src/arm64/full-codegen-arm64.cc
 /trunk/src/arm64/macro-assembler-arm64-inl.h
 /trunk/src/arm64/macro-assembler-arm64.h
 /trunk/src/arm64/simulator-arm64.cc
 /trunk/src/array.js
 /trunk/src/base/cpu.cc
 /trunk/src/compiler/ast-graph-builder.cc
 /trunk/src/compiler/change-lowering.cc
 /trunk/src/compiler/code-generator.cc
 /trunk/src/compiler/code-generator.h
 /trunk/src/compiler/common-operator.cc
 /trunk/src/compiler/common-operator.h
 /trunk/src/compiler/graph-visualizer.cc
 /trunk/src/compiler/instruction-selector.cc
 /trunk/src/compiler/instruction.cc
 /trunk/src/compiler/instruction.h
 /trunk/src/compiler/opcodes.h
 /trunk/src/compiler/operator-properties-inl.h
 /trunk/src/compiler/schedule.cc
 /trunk/src/compiler/schedule.h
 /trunk/src/compiler/scheduler.cc
 /trunk/src/compiler/simplified-lowering.cc
 /trunk/src/compiler/verifier.cc
 /trunk/src/conversions.cc
 /trunk/src/conversions.h
 /trunk/src/d8.cc
 /trunk/src/flag-definitions.h
 /trunk/src/harmony-tostring.js
 /trunk/src/heap/heap.cc
 /trunk/src/heap/heap.h
 /trunk/src/heap/spaces.cc
 /trunk/src/heap/spaces.h
 /trunk/src/hydrogen.cc
 /trunk/src/ia32/full-codegen-ia32.cc
 /trunk/src/lookup.cc
 /trunk/src/mips/full-codegen-mips.cc
 /trunk/src/mips64/full-codegen-mips64.cc
 /trunk/src/objects.cc
 /trunk/src/runtime/runtime-numbers.cc
 /trunk/src/sampler.cc
 /trunk/src/third_party/vtune/v8-vtune.h
 /trunk/src/third_party/vtune/vtune-jit.cc
 /trunk/src/version.cc
 /trunk/src/x64/full-codegen-x64.cc
 /trunk/src/x87/full-codegen-x87.cc
 /trunk/test/cctest/cctest.h
 /trunk/test/cctest/compiler/test-scheduler.cc
 /trunk/test/cctest/test-assembler-arm64.cc
 /trunk/test/cctest/test-disasm-arm64.cc
 /trunk/test/cctest/test-spaces.cc
 /trunk/test/js-perf-test/Classes/Classes.json
 /trunk/test/js-perf-test/Collections/Collections.json
 /trunk/test/js-perf-test/Iterators/Iterators.json
 /trunk/test/js-perf-test/Strings/Strings.json
 /trunk/test/js-perf-test/Strings/harmony-string.js
 /trunk/test/mjsunit/array-reduce.js
 /trunk/test/mjsunit/fast-prototype.js
 /trunk/test/mjsunit/getters-on-elements.js
 /trunk/test/mjsunit/setters-on-elements.js
 /trunk/test/unittests/compiler/common-operator-unittest.cc
 /trunk/test/webkit/webkit.status
 /trunk/tools/run-deopt-fuzzer.py
 /trunk/tools/run-tests.py
 /trunk/tools/whitespace.txt

=======================================
--- /dev/null
+++ /trunk/test/mjsunit/regress/regress-425551.js Thu Oct 23 08:44:45 2014 UTC
@@ -0,0 +1,7 @@
+// 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 array = new Int8Array(10);
+array[/\u007d\u00fc\u0043/] = 1.499
+assertEquals(1.499, array[/\u007d\u00fc\u0043/]);
=======================================
--- /dev/null
+++ /trunk/test/mjsunit/regress/regress-crbug-425585.js Thu Oct 23 08:44:45 2014 UTC
@@ -0,0 +1,48 @@
+// Copyright 2014 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+
+var correct_result = "This is the correct result.";
+
+function foo(recursion_depth) {
+   if (recursion_depth > 0) return foo(recursion_depth - 1);
+   return new String(correct_result, 1, 2, 3, 4, 5, 6);
+}
+
+// Roll our own non-strict assertEquals replacement.
+function test(i) {
+   var actual = foo(i);
+   if (correct_result != actual) {
+     var msg = "Expected \"" + correct_result + "\", found " + actual;
+     throw new MjsUnitAssertionError(msg);
+   }
+}
+
+test(1);
+test(1);
+test(10);
+test(100);
=======================================
--- /trunk/ChangeLog    Wed Oct 22 07:27:53 2014 UTC
+++ /trunk/ChangeLog    Thu Oct 23 08:44:45 2014 UTC
@@ -1,3 +1,15 @@
+2014-10-23: Version 3.30.17
+
+        ARM64: Fix stack manipulation (Chromium issue 425585).
+
+ Speed up creation of Objects whose prototype has dictionary elements
+        (Chromium issue 422754).
+
+        Enable libstdc++ debug mode in debug builds (issue 3638).
+
+        Performance and stability improvements on all platforms.
+
+
 2014-10-22: Version 3.30.16

         Remove v8stdint.h, it doesn't serve a purpose anymore.
=======================================
--- /trunk/build/standalone.gypi        Mon Oct 20 08:53:36 2014 UTC
+++ /trunk/build/standalone.gypi        Thu Oct 23 08:44:45 2014 UTC
@@ -136,6 +136,14 @@
     'configurations': {
       'DebugBaseCommon': {
         'cflags': [ '-g', '-O0' ],
+        'conditions': [
+          ['(v8_target_arch=="ia32" or v8_target_arch=="x87") and \
+            OS=="linux"', {
+            'defines': [
+              '_GLIBCXX_DEBUG'
+            ],
+          }],
+        ],
       },
       'Optdebug': {
         'inherit_from': [ 'DebugBaseCommon', 'DebugBase2' ],
=======================================
--- /trunk/include/v8config.h   Tue Oct 21 12:48:28 2014 UTC
+++ /trunk/include/v8config.h   Thu Oct 23 08:44:45 2014 UTC
@@ -120,7 +120,6 @@
 //  V8_LIBC_BIONIC  - Bionic libc
 //  V8_LIBC_BSD     - BSD libc derivate
 //  V8_LIBC_GLIBC   - GNU C library
-//  V8_LIBC_UCLIBC  - uClibc
 //
// Note that testing for libc must be done using #if not #ifdef. For example,
 // to test for the GNU C library, use:
@@ -133,8 +132,6 @@
 #elif defined(__BIONIC__)
 # define V8_LIBC_BIONIC 1
 # define V8_LIBC_BSD 1
-#elif defined(__UCLIBC__)
-# define V8_LIBC_UCLIBC 1
 #elif defined(__GLIBC__) || defined(__GNU_LIBRARY__)
 # define V8_LIBC_GLIBC 1
 #else
=======================================
--- /trunk/src/arm/full-codegen-arm.cc  Tue Oct 21 12:48:28 2014 UTC
+++ /trunk/src/arm/full-codegen-arm.cc  Thu Oct 23 08:44:45 2014 UTC
@@ -1726,6 +1726,8 @@
         DCHECK(!CompileTimeValue::IsCompileTimeValue(property->value()));
         // Fall through.
       case ObjectLiteral::Property::COMPUTED:
+        // It is safe to use [[Put]] here because the boilerplate already
+        // contains computed properties with an uninitialized value.
         if (key->value()->IsInternalizedString()) {
           if (property->emit_store()) {
             VisitForAccumulatorValue(value);
@@ -1758,7 +1760,7 @@
         __ push(r0);
         VisitForStackValue(value);
         if (property->emit_store()) {
-          __ CallRuntime(Runtime::kSetPrototype, 2);
+          __ CallRuntime(Runtime::kInternalSetPrototype, 2);
         } else {
           __ Drop(2);
         }
=======================================
--- /trunk/src/arm64/assembler-arm64.cc Fri Sep 12 00:05:16 2014 UTC
+++ /trunk/src/arm64/assembler-arm64.cc Thu Oct 23 08:44:45 2014 UTC
@@ -1934,6 +1934,12 @@
   DCHECK(fd.SizeInBits() == fn.SizeInBits());
   FPDataProcessing1Source(fd, fn, FRINTN);
 }
+
+
+void Assembler::frintp(const FPRegister& fd, const FPRegister& fn) {
+  DCHECK(fd.SizeInBits() == fn.SizeInBits());
+  FPDataProcessing1Source(fd, fn, FRINTP);
+}


 void Assembler::frintz(const FPRegister& fd,
=======================================
--- /trunk/src/arm64/assembler-arm64.h  Fri Sep 26 00:05:23 2014 UTC
+++ /trunk/src/arm64/assembler-arm64.h  Thu Oct 23 08:44:45 2014 UTC
@@ -1663,6 +1663,9 @@
   // FP round to integer (nearest with ties to even).
   void frintn(const FPRegister& fd, const FPRegister& fn);

+  // FP round to integer (towards plus infinity).
+  void frintp(const FPRegister& fd, const FPRegister& fn);
+
   // FP round to integer (towards zero.)
   void frintz(const FPRegister& fd, const FPRegister& fn);

=======================================
--- /trunk/src/arm64/builtins-arm64.cc  Fri Sep 26 00:05:23 2014 UTC
+++ /trunk/src/arm64/builtins-arm64.cc  Thu Oct 23 08:44:45 2014 UTC
@@ -156,7 +156,7 @@
   __ Cbz(argc, &no_arguments);
   // First args = sp[(argc - 1) * 8].
   __ Sub(argc, argc, 1);
-  __ Claim(argc, kXRegSize);
+  __ Drop(argc, kXRegSize);
   // jssp now point to args[0], load and drop args[0] + receiver.
   Register arg = argc;
   __ Ldr(arg, MemOperand(jssp, 2 * kPointerSize, PostIndex));
=======================================
--- /trunk/src/arm64/full-codegen-arm64.cc      Wed Oct 22 07:27:53 2014 UTC
+++ /trunk/src/arm64/full-codegen-arm64.cc      Thu Oct 23 08:44:45 2014 UTC
@@ -1706,6 +1706,8 @@
         DCHECK(!CompileTimeValue::IsCompileTimeValue(property->value()));
         // Fall through.
       case ObjectLiteral::Property::COMPUTED:
+        // It is safe to use [[Put]] here because the boilerplate already
+        // contains computed properties with an uninitialized value.
         if (key->value()->IsInternalizedString()) {
           if (property->emit_store()) {
             VisitForAccumulatorValue(value);
@@ -1739,7 +1741,7 @@
           __ Peek(x0, 0);
           __ Push(x0);
           VisitForStackValue(value);
-          __ CallRuntime(Runtime::kSetPrototype, 2);
+          __ CallRuntime(Runtime::kInternalSetPrototype, 2);
         } else {
           VisitForEffect(value);
         }
=======================================
--- /trunk/src/arm64/macro-assembler-arm64-inl.h Wed Sep 3 08:32:14 2014 UTC +++ /trunk/src/arm64/macro-assembler-arm64-inl.h Thu Oct 23 08:44:45 2014 UTC
@@ -823,6 +823,12 @@
   DCHECK(allow_macro_instructions_);
   frintn(fd, fn);
 }
+
+
+void MacroAssembler::Frintp(const FPRegister& fd, const FPRegister& fn) {
+  DCHECK(allow_macro_instructions_);
+  frintp(fd, fn);
+}


 void MacroAssembler::Frintz(const FPRegister& fd, const FPRegister& fn) {
=======================================
--- /trunk/src/arm64/macro-assembler-arm64.h    Tue Oct 14 07:51:07 2014 UTC
+++ /trunk/src/arm64/macro-assembler-arm64.h    Thu Oct 23 08:44:45 2014 UTC
@@ -422,6 +422,7 @@
   inline void Frinta(const FPRegister& fd, const FPRegister& fn);
   inline void Frintm(const FPRegister& fd, const FPRegister& fn);
   inline void Frintn(const FPRegister& fd, const FPRegister& fn);
+  inline void Frintp(const FPRegister& fd, const FPRegister& fn);
   inline void Frintz(const FPRegister& fd, const FPRegister& fn);
   inline void Fsqrt(const FPRegister& fd, const FPRegister& fn);
   inline void Fsub(const FPRegister& fd,
=======================================
--- /trunk/src/arm64/simulator-arm64.cc Wed Sep 24 00:05:07 2014 UTC
+++ /trunk/src/arm64/simulator-arm64.cc Thu Oct 23 08:44:45 2014 UTC
@@ -2463,6 +2463,12 @@
         set_sreg(fd, FPRoundInt(sreg(fn), FPNegativeInfinity)); break;
     case FRINTM_d:
         set_dreg(fd, FPRoundInt(dreg(fn), FPNegativeInfinity)); break;
+    case FRINTP_s:
+      set_sreg(fd, FPRoundInt(sreg(fn), FPPositiveInfinity));
+      break;
+    case FRINTP_d:
+      set_dreg(fd, FPRoundInt(dreg(fn), FPPositiveInfinity));
+      break;
     case FRINTN_s: set_sreg(fd, FPRoundInt(sreg(fn), FPTieEven)); break;
     case FRINTN_d: set_dreg(fd, FPRoundInt(dreg(fn), FPTieEven)); break;
     case FRINTZ_s: set_sreg(fd, FPRoundInt(sreg(fn), FPZero)); break;
@@ -2767,6 +2773,10 @@
       // We always use floor(value).
       break;
     }
+    case FPPositiveInfinity: {
+      int_result = ceil(value);
+      break;
+    }
     default: UNIMPLEMENTED();
   }
   return int_result;
=======================================
--- /trunk/src/array.js Wed Oct 22 07:27:53 2014 UTC
+++ /trunk/src/array.js Thu Oct 23 08:44:45 2014 UTC
@@ -1418,9 +1418,8 @@
   var i = 0;
   find_initial: if (%_ArgumentsLength() < 2) {
     for (; i < length; i++) {
-      current = array[i];
-      if (!IS_UNDEFINED(current) || i in array) {
-        i++;
+      if (i in array) {
+        current = array[i++];
         break find_initial;
       }
     }
@@ -1455,9 +1454,8 @@
   var i = length - 1;
   find_initial: if (%_ArgumentsLength() < 2) {
     for (; i >= 0; i--) {
-      current = array[i];
-      if (!IS_UNDEFINED(current) || i in array) {
-        i--;
+      if (i in array) {
+        current = array[i--];
         break find_initial;
       }
     }
=======================================
--- /trunk/src/base/cpu.cc      Fri Oct 10 00:05:16 2014 UTC
+++ /trunk/src/base/cpu.cc      Thu Oct 23 08:44:45 2014 UTC
@@ -7,12 +7,18 @@
 #if V8_LIBC_MSVCRT
 #include <intrin.h>  // __cpuid()
 #endif
-#if V8_OS_POSIX
-#include <unistd.h>  // sysconf()
+#if V8_OS_LINUX
+#include <linux/auxvec.h>  // AT_HWCAP
+#endif
+#if V8_GLIBC_PREREQ(2, 16)
+#include <sys/auxv.h>  // getauxval()
 #endif
 #if V8_OS_QNX
 #include <sys/syspage.h>  // cpuinfo
 #endif
+#if V8_OS_POSIX
+#include <unistd.h>  // sysconf()
+#endif

 #include <ctype.h>
 #include <limits.h>
@@ -92,11 +98,12 @@
 #define HWCAP_IDIV  (HWCAP_IDIVA | HWCAP_IDIVT)
 #define HWCAP_LPAE  (1 << 20)

-#define AT_HWCAP 16
-
-// Read the ELF HWCAP flags by parsing /proc/self/auxv.
 static uint32_t ReadELFHWCaps() {
   uint32_t result = 0;
+#if V8_GLIBC_PREREQ(2, 16)
+  result = static_cast<uint32_t>(getauxval(AT_HWCAP));
+#else
+  // Read the ELF HWCAP flags by parsing /proc/self/auxv.
   FILE* fp = fopen("/proc/self/auxv", "r");
   if (fp != NULL) {
     struct { uint32_t tag; uint32_t value; } entry;
@@ -112,6 +119,7 @@
     }
     fclose(fp);
   }
+#endif
   return result;
 }

@@ -310,7 +318,7 @@
              has_vfp3_d32_(false),
              is_fp64_mode_(false) {
   memcpy(vendor_, "Unknown", 8);
-#if defined(__pnacl__)
+#if V8_OS_NACL
 // Portable host shouldn't do feature detection.
 // TODO(jfb): Remove the hardcoded ARM simulator flags in the build, and
 // hardcode them here instead.
=======================================
--- /trunk/src/compiler/ast-graph-builder.cc    Wed Oct 22 07:27:53 2014 UTC
+++ /trunk/src/compiler/ast-graph-builder.cc    Thu Oct 23 08:44:45 2014 UTC
@@ -942,7 +942,7 @@
         Node* receiver = environment()->Pop();
         if (property->emit_store()) {
           const Operator* op =
-              javascript()->CallRuntime(Runtime::kSetPrototype, 2);
+              javascript()->CallRuntime(Runtime::kInternalSetPrototype, 2);
           NewNode(op, receiver, value);
         }
         break;
=======================================
--- /trunk/src/compiler/change-lowering.cc      Thu Oct  2 00:05:29 2014 UTC
+++ /trunk/src/compiler/change-lowering.cc      Thu Oct 23 08:44:45 2014 UTC
@@ -142,7 +142,8 @@
Node* add = graph()->NewNode(machine()->Int32AddWithOverflow(), val, val);
   Node* ovf = graph()->NewNode(common()->Projection(1), add);

-  Node* branch = graph()->NewNode(common()->Branch(), ovf, control);
+  Node* branch =
+      graph()->NewNode(common()->Branch(BranchHint::kTrue), ovf, control);

   Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
   Node* heap_number = AllocateHeapNumberWithValue(
@@ -215,7 +216,8 @@

   Node* cmp = graph()->NewNode(machine()->Uint32LessThanOrEqual(), val,
                                SmiMaxValueConstant());
-  Node* branch = graph()->NewNode(common()->Branch(), cmp, control);
+  Node* branch =
+      graph()->NewNode(common()->Branch(BranchHint::kTrue), cmp, control);

   Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
   Node* smi = graph()->NewNode(
=======================================
--- /trunk/src/compiler/code-generator.cc       Wed Oct 22 07:27:53 2014 UTC
+++ /trunk/src/compiler/code-generator.cc       Thu Oct 23 08:44:45 2014 UTC
@@ -44,10 +44,20 @@
   info->set_prologue_offset(masm()->pc_offset());
   AssemblePrologue();

-  // Assemble all instructions.
-  for (InstructionSequence::const_iterator i = code()->begin();
-       i != code()->end(); ++i) {
-    AssembleInstruction(*i);
+  // Assemble all non-deferred instructions.
+  for (auto const block : code()->instruction_blocks()) {
+    if (block->IsDeferred()) continue;
+    for (int i = block->code_start(); i < block->code_end(); ++i) {
+      AssembleInstruction(code()->InstructionAt(i));
+    }
+  }
+
+  // Assemble all deferred instructions.
+  for (auto const block : code()->instruction_blocks()) {
+    if (!block->IsDeferred()) continue;
+    for (int i = block->code_start(); i < block->code_end(); ++i) {
+      AssembleInstruction(code()->InstructionAt(i));
+    }
   }

   FinishCode(masm());
@@ -81,6 +91,12 @@

   return result;
 }
+
+
+bool CodeGenerator::IsNextInAssemblyOrder(BasicBlock::RpoNumber block) const {
+  return code()->InstructionBlockAt(current_block_)->ao_number().IsNext(
+      code()->InstructionBlockAt(block)->ao_number());
+}


void CodeGenerator::RecordSafepoint(PointerMap* pointers, Safepoint::Kind kind,
=======================================
--- /trunk/src/compiler/code-generator.h        Wed Oct 22 07:27:53 2014 UTC
+++ /trunk/src/compiler/code-generator.h        Thu Oct 23 08:44:45 2014 UTC
@@ -39,9 +39,7 @@

   // Checks if {block} will appear directly after {current_block_} when
   // assembling code, in which case, a fall-through can be used.
-  bool IsNextInAssemblyOrder(BasicBlock::RpoNumber block) const {
-    return current_block_.IsNext(block);
-  }
+  bool IsNextInAssemblyOrder(BasicBlock::RpoNumber block) const;

   // Record a safepoint with the given pointer map.
   void RecordSafepoint(PointerMap* pointers, Safepoint::Kind kind,
=======================================
--- /trunk/src/compiler/common-operator.cc      Wed Oct  8 13:44:16 2014 UTC
+++ /trunk/src/compiler/common-operator.cc      Thu Oct 23 08:44:45 2014 UTC
@@ -30,6 +30,26 @@
 }  // namespace


+std::ostream& operator<<(std::ostream& os, BranchHint hint) {
+  switch (hint) {
+    case BranchHint::kNone:
+      return os << "None";
+    case BranchHint::kTrue:
+      return os << "True";
+    case BranchHint::kFalse:
+      return os << "False";
+  }
+  UNREACHABLE();
+  return os;
+}
+
+
+BranchHint BranchHintOf(const Operator* const op) {
+  DCHECK_EQ(IrOpcode::kBranch, op->opcode());
+  return OpParameter<BranchHint>(op);
+}
+
+
 size_t hash_value(OutputFrameStateCombine const& sc) {
   return base::hash_combine(sc.kind_, sc.parameter_);
 }
@@ -74,7 +94,6 @@
 #define SHARED_OP_LIST(V)               \
   V(Dead, Operator::kFoldable, 0, 0)    \
   V(End, Operator::kFoldable, 0, 1)     \
-  V(Branch, Operator::kFoldable, 1, 1)  \
   V(IfTrue, Operator::kFoldable, 0, 1)  \
   V(IfFalse, Operator::kFoldable, 0, 1) \
   V(Throw, Operator::kFoldable, 1, 1)   \
@@ -110,6 +129,12 @@
 #undef SHARED


+const Operator* CommonOperatorBuilder::Branch(BranchHint hint) {
+  return new (zone()) Operator1<BranchHint>(
+      IrOpcode::kBranch, Operator::kFoldable, 1, 0, "Branch", hint);
+}
+
+
 const Operator* CommonOperatorBuilder::Start(int num_formal_parameters) {
   // Outputs are formal parameters, plus context, receiver, and JSFunction.
   const int value_output_count = num_formal_parameters + 3;
@@ -128,6 +153,13 @@
return new (zone()) ControlOperator(IrOpcode::kLoop, Operator::kFoldable, 0,
                                       0, controls, "Loop");
 }
+
+
+const Operator* CommonOperatorBuilder::Terminate(int effects) {
+  return new (zone()) Operator1<int>(IrOpcode::kTerminate,
+ Operator::kNoRead | Operator::kNoWrite, 0,
+                                     0, "Terminate", effects);
+}


 const Operator* CommonOperatorBuilder::Parameter(int index) {
=======================================
--- /trunk/src/compiler/common-operator.h       Wed Oct  8 00:05:11 2014 UTC
+++ /trunk/src/compiler/common-operator.h       Thu Oct 23 08:44:45 2014 UTC
@@ -23,6 +23,16 @@
 class Operator;


+// Prediction hint for branches.
+enum class BranchHint : uint8_t { kNone, kTrue, kFalse };
+
+inline size_t hash_value(BranchHint hint) { return static_cast<size_t>(hint); }
+
+std::ostream& operator<<(std::ostream&, BranchHint);
+
+BranchHint BranchHintOf(const Operator* const);
+
+
 // Flag that describes how to combine the current environment with
 // the output of a node to obtain a framestate for lazy bailout.
 class OutputFrameStateCombine {
@@ -123,10 +133,11 @@

   const Operator* Dead();
   const Operator* End();
-  const Operator* Branch();
+  const Operator* Branch(BranchHint = BranchHint::kNone);
   const Operator* IfTrue();
   const Operator* IfFalse();
   const Operator* Throw();
+  const Operator* Terminate(int effects);
   const Operator* Return();

   const Operator* Start(int num_formal_parameters);
=======================================
--- /trunk/src/compiler/graph-visualizer.cc     Tue Oct 21 12:48:28 2014 UTC
+++ /trunk/src/compiler/graph-visualizer.cc     Thu Oct 23 08:44:45 2014 UTC
@@ -562,6 +562,7 @@
     BasicBlock* current = (*rpo)[i];
     Tag block_tag(this, "block");
     PrintBlockProperty("name", current->id());
+ PrintStringProperty("deferred", current->deferred() ? "true" : "false");
     PrintIntProperty("from_bci", -1);
     PrintIntProperty("to_bci", -1);

=======================================
--- /trunk/src/compiler/instruction-selector.cc Wed Oct 22 07:27:53 2014 UTC
+++ /trunk/src/compiler/instruction-selector.cc Thu Oct 23 08:44:45 2014 UTC
@@ -147,7 +147,7 @@


bool InstructionSelector::IsNextInAssemblyOrder(const BasicBlock* block) const {
-  return current_block_->GetRpoNumber().IsNext(block->GetRpoNumber());
+  return current_block_->GetAoNumber().IsNext(block->GetAoNumber());
 }


@@ -457,6 +457,7 @@
     case IrOpcode::kIfFalse:
     case IrOpcode::kEffectPhi:
     case IrOpcode::kMerge:
+    case IrOpcode::kTerminate:
       // No code needed for these graph artifacts.
       return kMachNone;
     case IrOpcode::kFinish:
=======================================
--- /trunk/src/compiler/instruction.cc  Wed Oct 22 07:27:53 2014 UTC
+++ /trunk/src/compiler/instruction.cc  Thu Oct 23 08:44:45 2014 UTC
@@ -336,11 +336,13 @@
                     BasicBlock::RpoNumber::Invalid(), zone),
       phis_(zone),
       id_(block->id()),
+      ao_number_(block->GetAoNumber()),
       rpo_number_(block->GetRpoNumber()),
       loop_header_(GetRpo(block->loop_header())),
       loop_end_(GetLoopEndRpo(block)),
       code_start_(-1),
-      code_end_(-1) {
+      code_end_(-1),
+      deferred_(block->deferred()) {
   // Map successors and precessors
   size_t index = 0;
for (BasicBlock::Successors::const_iterator it = block->successors_begin();
@@ -604,7 +606,10 @@
     const InstructionBlock* block = code.InstructionBlockAt(rpo);
     CHECK(block->rpo_number() == rpo);

-    os << "RPO#" << block->rpo_number() << ": B" << block->id();
+    os << "RPO#" << block->rpo_number();
+    os << ": AO#" << block->ao_number();
+    os << ": B" << block->id();
+    if (block->IsDeferred()) os << " (deferred)";
     if (block->IsLoopHeader()) {
       os << " loop blocks: [" << block->rpo_number() << ", "
          << block->loop_end() << ")";
=======================================
--- /trunk/src/compiler/instruction.h   Wed Oct 22 07:27:53 2014 UTC
+++ /trunk/src/compiler/instruction.h   Thu Oct 23 08:44:45 2014 UTC
@@ -794,8 +794,11 @@

   int32_t code_end() const { return code_end_; }
   void set_code_end(int32_t end) { code_end_ = end; }
+
+  bool IsDeferred() const { return deferred_; }

   BasicBlock::Id id() const { return id_; }
+  BasicBlock::RpoNumber ao_number() const { return ao_number_; }
   BasicBlock::RpoNumber rpo_number() const { return rpo_number_; }
   BasicBlock::RpoNumber loop_header() const { return loop_header_; }
   BasicBlock::RpoNumber loop_end() const {
@@ -822,12 +825,14 @@
   Predecessors predecessors_;
   PhiInstructions phis_;
   BasicBlock::Id id_;
+  BasicBlock::RpoNumber ao_number_;  // Assembly order number.
   // TODO(dcarney): probably dont't need this.
   BasicBlock::RpoNumber rpo_number_;
   BasicBlock::RpoNumber loop_header_;
   BasicBlock::RpoNumber loop_end_;
-  int32_t code_start_;  // start index of arch-specific code.
-  int32_t code_end_;    // end index of arch-specific code.
+  int32_t code_start_;   // start index of arch-specific code.
+  int32_t code_end_;     // end index of arch-specific code.
+  const bool deferred_;  // Block contains deferred code.
 };

 typedef ZoneDeque<Constant> ConstantDeque;
@@ -853,6 +858,10 @@
   int VirtualRegisterCount() const { return next_virtual_register_; }

   int node_count() const { return static_cast<int>(node_map_.size()); }
+
+  const InstructionBlocks& instruction_blocks() const {
+    return instruction_blocks_;
+  }

   int InstructionBlockCount() const {
     return static_cast<int>(instruction_blocks_.size());
=======================================
--- /trunk/src/compiler/opcodes.h       Tue Oct 21 12:48:28 2014 UTC
+++ /trunk/src/compiler/opcodes.h       Thu Oct 23 08:44:45 2014 UTC
@@ -7,13 +7,14 @@

 // Opcodes for control operators.
 #define INNER_CONTROL_OP_LIST(V) \
-  V(Dead)                  \
-  V(Loop)                  \
-  V(Branch)                \
-  V(IfTrue)                \
-  V(IfFalse)               \
-  V(Merge)                 \
-  V(Return)                \
+  V(Dead)                        \
+  V(Loop)                        \
+  V(Branch)                      \
+  V(IfTrue)                      \
+  V(IfFalse)                     \
+  V(Merge)                       \
+  V(Return)                      \
+  V(Terminate)                   \
   V(Throw)

 #define CONTROL_OP_LIST(V) \
=======================================
--- /trunk/src/compiler/operator-properties-inl.h Wed Oct 15 00:05:09 2014 UTC +++ /trunk/src/compiler/operator-properties-inl.h Thu Oct 23 08:44:45 2014 UTC
@@ -104,7 +104,8 @@

 inline int OperatorProperties::GetEffectInputCount(const Operator* op) {
   if (op->opcode() == IrOpcode::kEffectPhi ||
-      op->opcode() == IrOpcode::kFinish) {
+      op->opcode() == IrOpcode::kFinish ||
+      op->opcode() == IrOpcode::kTerminate) {
     return OpParameter<int>(op);
   }
if (op->HasProperty(Operator::kNoRead) && op->HasProperty(Operator::kNoWrite))
@@ -123,6 +124,8 @@
 #define OPCODE_CASE(x) case IrOpcode::k##x:
       CONTROL_OP_LIST(OPCODE_CASE)
 #undef OPCODE_CASE
+      // Branch operator is special
+      if (op->opcode() == IrOpcode::kBranch) return 1;
       // Control operators are Operator1<int>.
       return OpParameter<int>(op);
     default:
@@ -152,7 +155,8 @@
 inline bool OperatorProperties::HasEffectOutput(const Operator* op) {
   return op->opcode() == IrOpcode::kStart ||
          op->opcode() == IrOpcode::kValueEffect ||
- (op->opcode() != IrOpcode::kFinish && GetEffectInputCount(op) > 0);
+         (op->opcode() != IrOpcode::kFinish &&
+ op->opcode() != IrOpcode::kTerminate && GetEffectInputCount(op)
0);
 }

 inline bool OperatorProperties::HasControlOutput(const Operator* op) {
=======================================
--- /trunk/src/compiler/schedule.cc     Tue Oct 21 12:48:28 2014 UTC
+++ /trunk/src/compiler/schedule.cc     Thu Oct 23 08:44:45 2014 UTC
@@ -13,7 +13,9 @@
 namespace compiler {

 BasicBlock::BasicBlock(Zone* zone, Id id)
-    : rpo_number_(-1),
+    : ao_number_(-1),
+      rpo_number_(-1),
+      deferred_(false),
       dominator_(NULL),
       loop_header_(NULL),
       loop_depth_(0),
@@ -194,10 +196,6 @@
   AddSuccessor(block, tblock);
   AddSuccessor(block, fblock);
   SetControlInput(block, branch);
-  if (branch->opcode() == IrOpcode::kBranch) {
-    // TODO(titzer): require a Branch node here. (sloppy tests).
-    SetBlockForNode(block, branch);
-  }
 }


@@ -205,13 +203,7 @@
   DCHECK(block->control() == BasicBlock::kNone);
   block->set_control(BasicBlock::kReturn);
   SetControlInput(block, input);
-  if (block != end()) {
-    AddSuccessor(block, end());
-  }
-  if (input->opcode() == IrOpcode::kReturn) {
-    // TODO(titzer): require a Return node here. (sloppy tests).
-    SetBlockForNode(block, input);
-  }
+  if (block != end()) AddSuccessor(block, end());
 }


@@ -250,6 +242,7 @@
   for (BasicBlockVectorIter i = rpo->begin(); i != rpo->end(); ++i) {
     BasicBlock* block = *i;
     os << "--- BLOCK B" << block->id();
+    if (block->deferred()) os << " (deferred)";
     if (block->PredecessorCount() != 0) os << " <- ";
     bool comma = false;
for (BasicBlock::Predecessors::iterator j = block->predecessors_begin();
=======================================
--- /trunk/src/compiler/schedule.h      Tue Oct 21 12:48:28 2014 UTC
+++ /trunk/src/compiler/schedule.h      Thu Oct 23 08:44:45 2014 UTC
@@ -139,6 +139,9 @@

   Node* control_input() const { return control_input_; }
   void set_control_input(Node* control_input);
+
+  bool deferred() const { return deferred_; }
+  void set_deferred(bool deferred) { deferred_ = deferred; }

   BasicBlock* dominator() const { return dominator_; }
   void set_dominator(BasicBlock* dominator);
@@ -151,6 +154,10 @@

   int32_t loop_end() const { return loop_end_; }
   void set_loop_end(int32_t loop_end);
+
+  RpoNumber GetAoNumber() const { return RpoNumber::FromInt(ao_number_); }
+  int32_t ao_number() const { return ao_number_; }
+  void set_ao_number(int32_t ao_number) { ao_number_ = ao_number; }

RpoNumber GetRpoNumber() const { return RpoNumber::FromInt(rpo_number_); }
   int32_t rpo_number() const { return rpo_number_; }
@@ -161,7 +168,9 @@
   bool LoopContains(BasicBlock* block) const;

  private:
+  int32_t ao_number_;        // assembly order number of the block.
   int32_t rpo_number_;       // special RPO number of the block.
+  bool deferred_;            // true if the block contains deferred code.
   BasicBlock* dominator_;    // Immediate dominator of the block.
BasicBlock* loop_header_; // Pointer to dominating loop header basic block, // NULL if none. For loop headers, this points to
=======================================
--- /trunk/src/compiler/scheduler.cc    Wed Oct 22 07:27:53 2014 UTC
+++ /trunk/src/compiler/scheduler.cc    Thu Oct 23 08:44:45 2014 UTC
@@ -277,6 +277,20 @@

     TraceConnect(branch, branch_block, successor_blocks[0]);
     TraceConnect(branch, branch_block, successor_blocks[1]);
+
+    // Consider branch hints.
+ // TODO(turbofan): Propagate the deferred flag to all blocks dominated by
+    // this IfTrue/IfFalse later.
+    switch (BranchHintOf(branch->op())) {
+      case BranchHint::kNone:
+        break;
+      case BranchHint::kTrue:
+        successor_blocks[1]->set_deferred(true);
+        break;
+      case BranchHint::kFalse:
+        successor_blocks[0]->set_deferred(true);
+        break;
+    }

     schedule_->AddBranch(branch_block, branch, successor_blocks[0],
                          successor_blocks[1]);
@@ -521,27 +535,42 @@
 // Phase 4: Schedule nodes late.


-class ScheduleLateNodeVisitor : public NullNodeVisitor {
+class ScheduleLateNodeVisitor {
  public:
-  explicit ScheduleLateNodeVisitor(Scheduler* scheduler)
-      : scheduler_(scheduler), schedule_(scheduler_->schedule_) {}
+  ScheduleLateNodeVisitor(Zone* zone, Scheduler* scheduler)
+ : scheduler_(scheduler), schedule_(scheduler_->schedule_), queue_(zone) {}
+
+  // Run the schedule late algorithm on a set of fixed root nodes.
+  void Run(NodeVector* roots) {
+    for (NodeVectorIter i = roots->begin(); i != roots->end(); ++i) {
+      ProcessQueue(*i);
+    }
+  }
+
+ private:
+  void ProcessQueue(Node* root) {
+ for (InputIter i = root->inputs().begin(); i != root->inputs().end(); ++i) {
+      if (scheduler_->GetData(*i)->unscheduled_count_ != 0) continue;
+      queue_.push(*i);
+      while (!queue_.empty()) {
+        VisitNode(queue_.front());
+        queue_.pop();
+      }
+    }
+  }
+
+  // Visits one node from the queue of schedulable nodes and determines its
+  // schedule late position. Also hoists nodes out of loops to find a more
+  // optimal scheduling position.
+  void VisitNode(Node* node) {
+    DCHECK(scheduler_->GetData(node)->unscheduled_count_ == 0);

-  GenericGraphVisit::Control Pre(Node* node) {
     // Don't schedule nodes that are already scheduled.
-    if (schedule_->IsScheduled(node)) {
-      return GenericGraphVisit::CONTINUE;
-    }
+    if (schedule_->IsScheduled(node)) return;

     Scheduler::SchedulerData* data = scheduler_->GetData(node);
     DCHECK_EQ(Scheduler::kSchedulable, data->placement_);

- // If all the uses of a node have been scheduled, then the node itself can
-    // be scheduled.
-    bool eligible = data->unscheduled_count_ == 0;
-    Trace("Testing for schedule eligibility for #%d:%s = %s\n", node->id(),
-          node->op()->mnemonic(), eligible ? "true" : "false");
-    if (!eligible) return GenericGraphVisit::DEFER;
-
// Determine the dominating block for all of the uses of this node. It is
     // the latest block that this node can be scheduled in.
     BasicBlock* block = NULL;
@@ -586,11 +615,8 @@
     }

     ScheduleNode(block, node);
-
-    return GenericGraphVisit::CONTINUE;
   }

- private:
   BasicBlock* GetBlockForUse(Node::Edge edge) {
     Node* use = edge.from();
     IrOpcode::Value opcode = use->opcode();
@@ -619,7 +645,8 @@
     scheduler_->scheduled_nodes_[block->id().ToSize()].push_back(node);

     // Reduce the use count of the node's inputs to potentially make them
-    // schedulable.
+ // schedulable. If all the uses of a node have been scheduled, then the node
+    // itself can be scheduled.
for (InputIter i = node->inputs().begin(); i != node->inputs().end(); ++i) {
       Scheduler::SchedulerData* data = scheduler_->GetData(*i);
       DCHECK(data->unscheduled_count_ > 0);
@@ -628,10 +655,10 @@
Trace(" Use count for #%d:%s (used by #%d:%s)-- = %d\n", (*i)->id(),
               (*i)->op()->mnemonic(), i.edge().from()->id(),
               i.edge().from()->op()->mnemonic(), data->unscheduled_count_);
-        if (data->unscheduled_count_ == 0) {
-          Trace("  newly eligible #%d:%s\n", (*i)->id(),
-                (*i)->op()->mnemonic());
-        }
+      }
+      if (data->unscheduled_count_ == 0) {
+ Trace(" newly eligible #%d:%s\n", (*i)->id(), (*i)->op()->mnemonic());
+        queue_.push(*i);
       }
     }

@@ -649,10 +676,11 @@
                 "%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());
-            }
+          }
+          if (data->unscheduled_count_ == 0) {
+            Trace("  newly eligible #%d:%s\n", (*i)->id(),
+                  (*i)->op()->mnemonic());
+            queue_.push(*i);
           }
         }
       }
@@ -661,6 +689,7 @@

   Scheduler* scheduler_;
   Schedule* schedule_;
+  ZoneQueue<Node*> queue_;
 };


@@ -676,15 +705,10 @@
   }

   // Schedule: Places nodes in dominator block of all their uses.
-  ScheduleLateNodeVisitor schedule_late_visitor(this);
-
   {
     ZonePool::Scope zone_scope(zone_pool_);
-    Zone* zone = zone_scope.zone();
-    GenericGraphVisit::Visit<ScheduleLateNodeVisitor,
-                             NodeInputIterationTraits<Node> >(
- graph_, zone, schedule_root_nodes_.begin(), schedule_root_nodes_.end(),
-        &schedule_late_visitor);
+    ScheduleLateNodeVisitor schedule_late_visitor(zone_scope.zone(), this);
+    schedule_late_visitor.Run(&schedule_root_nodes_);
   }

// Add collected nodes for basic blocks to their blocks in the right order.
@@ -1194,6 +1218,18 @@
             current->loop_header()->id().ToInt(), current->loop_depth());
     }
   }
+
+  // Compute the assembly order (non-deferred code first, deferred code
+  // afterwards).
+  int32_t number = 0;
+  for (auto block : *final_order) {
+    if (block->deferred()) continue;
+    block->set_ao_number(number++);
+  }
+  for (auto block : *final_order) {
+    if (!block->deferred()) continue;
+    block->set_ao_number(number++);
+  }

 #if DEBUG
   if (FLAG_trace_turbo_scheduler) PrintRPO(num_loops, loops, final_order);
=======================================
--- /trunk/src/compiler/simplified-lowering.cc  Tue Oct 21 12:48:28 2014 UTC
+++ /trunk/src/compiler/simplified-lowering.cc  Thu Oct 23 08:44:45 2014 UTC
@@ -1027,7 +1027,8 @@
     Node* control = node->InputAt(4);

Node* check = graph()->NewNode(machine()->Uint32LessThan(), key, length);
-    Node* branch = graph()->NewNode(common()->Branch(), check, control);
+    Node* branch =
+ graph()->NewNode(common()->Branch(BranchHint::kTrue), check, control);

     Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
     Node* load = graph()->NewNode(op, base, index, effect, if_true);
@@ -1098,7 +1099,8 @@
     Node* control = node->InputAt(5);

Node* check = graph()->NewNode(machine()->Uint32LessThan(), key, length);
-    Node* branch = graph()->NewNode(common()->Branch(), check, control);
+    Node* branch =
+ graph()->NewNode(common()->Branch(BranchHint::kTrue), check, control);

     Node* if_true = graph()->NewNode(common()->IfTrue(), branch);
Node* store = graph()->NewNode(op, base, index, value, effect, if_true);
=======================================
--- /trunk/src/compiler/verifier.cc     Tue Oct 21 12:48:28 2014 UTC
+++ /trunk/src/compiler/verifier.cc     Thu Oct 23 08:44:45 2014 UTC
@@ -6,6 +6,8 @@

 #include <deque>
 #include <queue>
+#include <sstream>
+#include <string>

 #include "src/compiler/generic-algorithm.h"
 #include "src/compiler/generic-node-inl.h"
@@ -20,6 +22,7 @@
 #include "src/compiler/schedule.h"
 #include "src/compiler/simplified-operator.h"
 #include "src/data-flow.h"
+#include "src/ostreams.h"

 namespace v8 {
 namespace internal {
@@ -56,10 +59,8 @@

  private:
   // TODO(rossberg): Get rid of these once we got rid of NodeProperties.
-  Bounds bounds(Node* node) {
-    return NodeProperties::GetBounds(node);
-  }
-  Node* Operand(Node* node, int i = 0) {
+  Bounds bounds(Node* node) { return NodeProperties::GetBounds(node); }
+  Node* ValueInput(Node* node, int i = 0) {
     return NodeProperties::GetValueInput(node, i);
   }
   FieldAccess Field(Node* node) {
@@ -72,6 +73,50 @@
            node->opcode() == IrOpcode::kStoreElement);
     return OpParameter<ElementAccess>(node);
   }
+  void CheckNotTyped(Node* node) {
+    if (NodeProperties::IsTyped(node)) {
+      std::ostringstream str;
+      str << "TypeError: node #" << node->opcode() << ":"
+          << node->op()->mnemonic() << " should never have a type";
+      V8_Fatal(__FILE__, __LINE__, str.str().c_str());
+    }
+  }
+  void CheckUpperIs(Node* node, Type* type) {
+    if (typing == TYPED && !bounds(node).upper->Is(type)) {
+      std::ostringstream str;
+      str << "TypeError: node #" << node->opcode() << ":"
+          << node->op()->mnemonic() << " upper bound ";
+      bounds(node).upper->PrintTo(str);
+      str << " is not ";
+      type->PrintTo(str);
+      V8_Fatal(__FILE__, __LINE__, str.str().c_str());
+    }
+  }
+  void CheckUpperMaybe(Node* node, Type* type) {
+    if (typing == TYPED && !bounds(node).upper->Maybe(type)) {
+      std::ostringstream str;
+      str << "TypeError: node #" << node->opcode() << ":"
+          << node->op()->mnemonic() << " upper bound ";
+      bounds(node).upper->PrintTo(str);
+      str << " must intersect ";
+      type->PrintTo(str);
+      V8_Fatal(__FILE__, __LINE__, str.str().c_str());
+    }
+  }
+  void CheckValueInputIs(Node* node, int i, Type* type) {
+    Node* input = ValueInput(node, i);
+    if (typing == TYPED && !bounds(input).upper->Is(type)) {
+      std::ostringstream str;
+      str << "TypeError: node #" << node->opcode() << ":"
+          << node->op()->mnemonic() << "(input @" << i << " = "
+          << input->opcode() << ":" << input->op()->mnemonic()
+          << ") upper bound ";
+      bounds(input).upper->PrintTo(str);
+      str << " is not ";
+      type->PrintTo(str);
+      V8_Fatal(__FILE__, __LINE__, str.str().c_str());
+    }
+  }
 };


@@ -141,527 +186,538 @@
     }
   }

-  if (typing == TYPED) {
-    switch (node->opcode()) {
-      // Control operators
-      // -----------------
-      case IrOpcode::kStart:
-        // Start has no inputs.
-        CHECK_EQ(0, input_count);
-        // Type is a tuple.
- // TODO(rossberg): Multiple outputs are currently typed as Internal.
-        CHECK(bounds(node).upper->Is(Type::Internal()));
-        break;
-      case IrOpcode::kEnd:
-        // End has no outputs.
-        CHECK(!OperatorProperties::HasValueOutput(node->op()));
-        CHECK(!OperatorProperties::HasEffectOutput(node->op()));
-        CHECK(!OperatorProperties::HasControlOutput(node->op()));
-        // Type is empty.
-        CHECK(!NodeProperties::IsTyped(node));
-        break;
-      case IrOpcode::kDead:
-        // Dead is never connected to the graph.
-        UNREACHABLE();
-      case IrOpcode::kBranch: {
-        // Branch uses are IfTrue and IfFalse.
-        Node::Uses uses = node->uses();
-        int count_true = 0, count_false = 0;
- for (Node::Uses::iterator it = uses.begin(); it != uses.end(); ++it) {
-          CHECK((*it)->opcode() == IrOpcode::kIfTrue ||
-                (*it)->opcode() == IrOpcode::kIfFalse);
-          if ((*it)->opcode() == IrOpcode::kIfTrue) ++count_true;
-          if ((*it)->opcode() == IrOpcode::kIfFalse) ++count_false;
-        }
-        CHECK(count_true == 1 && count_false == 1);
-        // Type is empty.
-        CHECK(!NodeProperties::IsTyped(node));
-        break;
+  switch (node->opcode()) {
+    case IrOpcode::kStart:
+      // Start has no inputs.
+      CHECK_EQ(0, input_count);
+      // Type is a tuple.
+      // TODO(rossberg): Multiple outputs are currently typed as Internal.
+      CheckUpperIs(node, Type::Internal());
+      break;
+    case IrOpcode::kEnd:
+      // End has no outputs.
+      CHECK(!OperatorProperties::HasValueOutput(node->op()));
+      CHECK(!OperatorProperties::HasEffectOutput(node->op()));
+      CHECK(!OperatorProperties::HasControlOutput(node->op()));
+      // Type is empty.
+      CheckNotTyped(node);
+      break;
+    case IrOpcode::kDead:
+      // Dead is never connected to the graph.
+      UNREACHABLE();
+    case IrOpcode::kBranch: {
+      // Branch uses are IfTrue and IfFalse.
+      Node::Uses uses = node->uses();
+      int count_true = 0, count_false = 0;
+ for (Node::Uses::iterator it = uses.begin(); it != uses.end(); ++it) {
+        CHECK((*it)->opcode() == IrOpcode::kIfTrue ||
+              (*it)->opcode() == IrOpcode::kIfFalse);
+        if ((*it)->opcode() == IrOpcode::kIfTrue) ++count_true;
+        if ((*it)->opcode() == IrOpcode::kIfFalse) ++count_false;
       }
-      case IrOpcode::kIfTrue:
-      case IrOpcode::kIfFalse:
-        CHECK_EQ(IrOpcode::kBranch,
-                 NodeProperties::GetControlInput(node, 0)->opcode());
-        // Type is empty.
-        CHECK(!NodeProperties::IsTyped(node));
-        break;
-      case IrOpcode::kLoop:
-      case IrOpcode::kMerge:
-        // Type is empty.
-        CHECK(!NodeProperties::IsTyped(node));
-        break;
-      case IrOpcode::kReturn:
-        // TODO(rossberg): check successor is End
-        // Type is empty.
-        CHECK(!NodeProperties::IsTyped(node));
-        break;
-      case IrOpcode::kThrow:
-        // TODO(rossberg): what are the constraints on these?
-        // Type is empty.
-        CHECK(!NodeProperties::IsTyped(node));
-        break;
+      CHECK(count_true == 1 && count_false == 1);
+      // Type is empty.
+      CheckNotTyped(node);
+      break;
+    }
+    case IrOpcode::kIfTrue:
+    case IrOpcode::kIfFalse:
+      CHECK_EQ(IrOpcode::kBranch,
+               NodeProperties::GetControlInput(node, 0)->opcode());
+      // Type is empty.
+      CheckNotTyped(node);
+      break;
+    case IrOpcode::kLoop:
+    case IrOpcode::kMerge:
+      CHECK_EQ(control_count, input_count);
+      // Type is empty.
+      CheckNotTyped(node);
+      break;
+    case IrOpcode::kReturn:
+      // TODO(rossberg): check successor is End
+      // Type is empty.
+      CheckNotTyped(node);
+      break;
+    case IrOpcode::kThrow:
+      // TODO(rossberg): what are the constraints on these?
+      // Type is empty.
+      CheckNotTyped(node);
+      break;
+    case IrOpcode::kTerminate:
+      // Type is empty.
+      CheckNotTyped(node);
+      CHECK_EQ(1, control_count);
+      CHECK_EQ(input_count, 1 + effect_count);
+      break;

-      // Common operators
-      // ----------------
-      case IrOpcode::kParameter: {
-        // Parameters have the start node as inputs.
-        CHECK_EQ(1, input_count);
-        CHECK_EQ(IrOpcode::kStart,
-                 NodeProperties::GetValueInput(node, 0)->opcode());
-        // Parameter has an input that produces enough values.
-        int index = OpParameter<int>(node);
-        Node* input = NodeProperties::GetValueInput(node, 0);
-        // Currently, parameter indices start at -1 instead of 0.
-        CHECK_GT(
- OperatorProperties::GetValueOutputCount(input->op()), index + 1);
-        // Type can be anything.
-        CHECK(bounds(node).upper->Is(Type::Any()));
-        break;
+    // Common operators
+    // ----------------
+    case IrOpcode::kParameter: {
+      // Parameters have the start node as inputs.
+      CHECK_EQ(1, input_count);
+      CHECK_EQ(IrOpcode::kStart,
+               NodeProperties::GetValueInput(node, 0)->opcode());
+      // Parameter has an input that produces enough values.
+      int index = OpParameter<int>(node);
+      Node* input = NodeProperties::GetValueInput(node, 0);
+      // Currently, parameter indices start at -1 instead of 0.
+ CHECK_GT(OperatorProperties::GetValueOutputCount(input->op()), index + 1);
+      // Type can be anything.
+      CheckUpperIs(node, Type::Any());
+      break;
+    }
+ case IrOpcode::kInt32Constant: // TODO(rossberg): rename Word32Constant?
+      // Constants have no inputs.
+      CHECK_EQ(0, input_count);
+      // Type is a 32 bit integer, signed or unsigned.
+      CheckUpperIs(node, Type::Integral32());
+      break;
+    case IrOpcode::kInt64Constant:
+      // Constants have no inputs.
+      CHECK_EQ(0, input_count);
+      // Type is internal.
+      // TODO(rossberg): Introduce proper Int64 type.
+      CheckUpperIs(node, Type::Internal());
+      break;
+    case IrOpcode::kFloat32Constant:
+    case IrOpcode::kFloat64Constant:
+    case IrOpcode::kNumberConstant:
+      // Constants have no inputs.
+      CHECK_EQ(0, input_count);
+      // Type is a number.
+      CheckUpperIs(node, Type::Number());
+      break;
+    case IrOpcode::kHeapConstant:
+      // Constants have no inputs.
+      CHECK_EQ(0, input_count);
+      // Type can be anything represented as a heap pointer.
+      CheckUpperIs(node, Type::TaggedPtr());
+      break;
+    case IrOpcode::kExternalConstant:
+      // Constants have no inputs.
+      CHECK_EQ(0, input_count);
+      // Type is considered internal.
+      CheckUpperIs(node, Type::Internal());
+      break;
+    case IrOpcode::kProjection: {
+      // Projection has an input that produces enough values.
+      int index = OpParameter<int>(node->op());
+      Node* input = NodeProperties::GetValueInput(node, 0);
+ CHECK_GT(OperatorProperties::GetValueOutputCount(input->op()), index);
+      // Type can be anything.
+      // TODO(rossberg): Introduce tuple types for this.
+      // TODO(titzer): Convince rossberg not to.
+      CheckUpperIs(node, Type::Any());
+      break;
+    }
+    case IrOpcode::kPhi: {
+      // Phi input count matches parent control node.
+      CHECK_EQ(0, effect_count);
+      CHECK_EQ(1, control_count);
+      Node* control = NodeProperties::GetControlInput(node, 0);
+      CHECK_EQ(value_count,
+               OperatorProperties::GetControlInputCount(control->op()));
+      CHECK_EQ(input_count, 1 + value_count);
+      // Type must be subsumed by all input types.
+      // TODO(rossberg): for now at least, narrowing does not really hold.
+      /*
+      for (int i = 0; i < value_count; ++i) {
+        // TODO(rossberg, jarin): Figure out what to do about lower bounds.
+ // CHECK(bounds(node).lower->Is(bounds(ValueInput(node, i)).lower));
+        CHECK(bounds(ValueInput(node, i)).upper->Is(bounds(node).upper));
       }
- case IrOpcode::kInt32Constant: // TODO(rossberg): rename Word32Constant?
-        // Constants have no inputs.
-        CHECK_EQ(0, input_count);
-        // Type is a 32 bit integer, signed or unsigned.
-        CHECK(bounds(node).upper->Is(Type::Integral32()));
-        break;
-      case IrOpcode::kInt64Constant:
-        // Constants have no inputs.
-        CHECK_EQ(0, input_count);
-        // Type is internal.
-        // TODO(rossberg): Introduce proper Int64 type.
-        CHECK(bounds(node).upper->Is(Type::Internal()));
-        break;
-      case IrOpcode::kFloat32Constant:
-      case IrOpcode::kFloat64Constant:
-      case IrOpcode::kNumberConstant:
-        // Constants have no inputs.
-        CHECK_EQ(0, input_count);
-        // Type is a number.
-        CHECK(bounds(node).upper->Is(Type::Number()));
-        break;
-      case IrOpcode::kHeapConstant:
-        // Constants have no inputs.
-        CHECK_EQ(0, input_count);
-        // Type can be anything represented as a heap pointer.
-        CHECK(bounds(node).upper->Is(Type::TaggedPtr()));
-        break;
-      case IrOpcode::kExternalConstant:
-        // Constants have no inputs.
-        CHECK_EQ(0, input_count);
-        // Type is considered internal.
-        CHECK(bounds(node).upper->Is(Type::Internal()));
-        break;
-      case IrOpcode::kProjection: {
-        // Projection has an input that produces enough values.
-        int index = OpParameter<int>(node->op());
-        Node* input = NodeProperties::GetValueInput(node, 0);
- CHECK_GT(OperatorProperties::GetValueOutputCount(input->op()), index);
-        // Type can be anything.
-        // TODO(rossberg): Introduce tuple types for this.
-        CHECK(bounds(node).upper->Is(Type::Any()));
-        break;
+      */
+      break;
+    }
+    case IrOpcode::kEffectPhi: {
+      // EffectPhi input count matches parent control node.
+      CHECK_EQ(0, value_count);
+      CHECK_EQ(1, control_count);
+      Node* control = NodeProperties::GetControlInput(node, 0);
+      CHECK_EQ(effect_count,
+               OperatorProperties::GetControlInputCount(control->op()));
+      CHECK_EQ(input_count, 1 + effect_count);
+      break;
+    }
+    case IrOpcode::kValueEffect:
+      // TODO(rossberg): what are the constraints on these?
+      break;
+    case IrOpcode::kFinish: {
+      // TODO(rossberg): what are the constraints on these?
+      // Type must be subsumed by input type.
+      if (typing == TYPED) {
+        CHECK(bounds(ValueInput(node)).lower->Is(bounds(node).lower));
+        CHECK(bounds(ValueInput(node)).upper->Is(bounds(node).upper));
       }
-      case IrOpcode::kPhi: {
-        // Phi input count matches parent control node.
-        CHECK_EQ(1, control_count);
-        Node* control = NodeProperties::GetControlInput(node, 0);
-        CHECK_EQ(value_count,
-                 OperatorProperties::GetControlInputCount(control->op()));
-        // Type must be subsumed by all input types.
- // TODO(rossberg): for now at least, narrowing does not really hold.
-        /*
-        for (int i = 0; i < value_count; ++i) {
- // TODO(rossberg, jarin): Figure out what to do about lower bounds.
-          // CHECK(bounds(node).lower->Is(bounds(Operand(node, i)).lower));
-          CHECK(bounds(Operand(node, i)).upper->Is(bounds(node).upper));
-        }
-        */
-        break;
-      }
-      case IrOpcode::kEffectPhi: {
-        // EffectPhi input count matches parent control node.
-        CHECK_EQ(1, control_count);
-        Node* control = NodeProperties::GetControlInput(node, 0);
-        CHECK_EQ(effect_count,
-                 OperatorProperties::GetControlInputCount(control->op()));
-        break;
-      }
-      case IrOpcode::kValueEffect:
-        // TODO(rossberg): what are the constraints on these?
-        break;
-      case IrOpcode::kFinish: {
-        // TODO(rossberg): what are the constraints on these?
-        // Type must be subsumed by input type.
-        CHECK(bounds(Operand(node)).lower->Is(bounds(node).lower));
-        CHECK(bounds(Operand(node)).upper->Is(bounds(node).upper));
-        break;
-      }
-      case IrOpcode::kFrameState:
-        // TODO(jarin): what are the constraints on these?
-        break;
-      case IrOpcode::kStateValues:
-        // TODO(jarin): what are the constraints on these?
-        break;
-      case IrOpcode::kCall:
-        // TODO(rossberg): what are the constraints on these?
-        break;
+      break;
+    }
+    case IrOpcode::kFrameState:
+      // TODO(jarin): what are the constraints on these?
+      break;
+    case IrOpcode::kStateValues:
+      // TODO(jarin): what are the constraints on these?
+      break;
+    case IrOpcode::kCall:
+      // TODO(rossberg): what are the constraints on these?
+      break;

-      // JavaScript operators
-      // --------------------
-      case IrOpcode::kJSEqual:
-      case IrOpcode::kJSNotEqual:
-      case IrOpcode::kJSStrictEqual:
-      case IrOpcode::kJSStrictNotEqual:
-      case IrOpcode::kJSLessThan:
-      case IrOpcode::kJSGreaterThan:
-      case IrOpcode::kJSLessThanOrEqual:
-      case IrOpcode::kJSGreaterThanOrEqual:
-      case IrOpcode::kJSUnaryNot:
-        // Type is Boolean.
-        CHECK(bounds(node).upper->Is(Type::Boolean()));
-        break;
+    // JavaScript operators
+    // --------------------
+    case IrOpcode::kJSEqual:
+    case IrOpcode::kJSNotEqual:
+    case IrOpcode::kJSStrictEqual:
+    case IrOpcode::kJSStrictNotEqual:
+    case IrOpcode::kJSLessThan:
+    case IrOpcode::kJSGreaterThan:
+    case IrOpcode::kJSLessThanOrEqual:
+    case IrOpcode::kJSGreaterThanOrEqual:
+    case IrOpcode::kJSUnaryNot:
+      // Type is Boolean.
+      CheckUpperIs(node, Type::Boolean());
+      break;

-      case IrOpcode::kJSBitwiseOr:
-      case IrOpcode::kJSBitwiseXor:
-      case IrOpcode::kJSBitwiseAnd:
-      case IrOpcode::kJSShiftLeft:
-      case IrOpcode::kJSShiftRight:
-      case IrOpcode::kJSShiftRightLogical:
-        // Type is 32 bit integral.
-        CHECK(bounds(node).upper->Is(Type::Integral32()));
-        break;
-      case IrOpcode::kJSAdd:
-        // Type is Number or String.
-        CHECK(bounds(node).upper->Is(Type::NumberOrString()));
-        break;
-      case IrOpcode::kJSSubtract:
-      case IrOpcode::kJSMultiply:
-      case IrOpcode::kJSDivide:
-      case IrOpcode::kJSModulus:
-        // Type is Number.
-        CHECK(bounds(node).upper->Is(Type::Number()));
-        break;
+    case IrOpcode::kJSBitwiseOr:
+    case IrOpcode::kJSBitwiseXor:
+    case IrOpcode::kJSBitwiseAnd:
+    case IrOpcode::kJSShiftLeft:
+    case IrOpcode::kJSShiftRight:
+    case IrOpcode::kJSShiftRightLogical:
+      // Type is 32 bit integral.
+      CheckUpperIs(node, Type::Integral32());
+      break;
+    case IrOpcode::kJSAdd:
+      // Type is Number or String.
+      CheckUpperIs(node, Type::NumberOrString());
+      break;
+    case IrOpcode::kJSSubtract:
+    case IrOpcode::kJSMultiply:
+    case IrOpcode::kJSDivide:
+    case IrOpcode::kJSModulus:
+      // Type is Number.
+      CheckUpperIs(node, Type::Number());
+      break;

-      case IrOpcode::kJSToBoolean:
-        // Type is Boolean.
-        CHECK(bounds(node).upper->Is(Type::Boolean()));
-        break;
-      case IrOpcode::kJSToNumber:
-        // Type is Number.
-        CHECK(bounds(node).upper->Is(Type::Number()));
-        break;
-      case IrOpcode::kJSToString:
-        // Type is String.
-        CHECK(bounds(node).upper->Is(Type::String()));
-        break;
-      case IrOpcode::kJSToName:
-        // Type is Name.
-        CHECK(bounds(node).upper->Is(Type::Name()));
-        break;
-      case IrOpcode::kJSToObject:
-        // Type is Receiver.
-        CHECK(bounds(node).upper->Is(Type::Receiver()));
-        break;
+    case IrOpcode::kJSToBoolean:
+      // Type is Boolean.
+      CheckUpperIs(node, Type::Boolean());
+      break;
+    case IrOpcode::kJSToNumber:
+      // Type is Number.
+      CheckUpperIs(node, Type::Number());
+      break;
+    case IrOpcode::kJSToString:
+      // Type is String.
+      CheckUpperIs(node, Type::String());
+      break;
+    case IrOpcode::kJSToName:
+      // Type is Name.
+      CheckUpperIs(node, Type::Name());
+      break;
+    case IrOpcode::kJSToObject:
+      // Type is Receiver.
+      CheckUpperIs(node, Type::Receiver());
+      break;

-      case IrOpcode::kJSCreate:
-        // Type is Object.
-        CHECK(bounds(node).upper->Is(Type::Object()));
-        break;
-      case IrOpcode::kJSLoadProperty:
-      case IrOpcode::kJSLoadNamed:
-        // Type can be anything.
-        CHECK(bounds(node).upper->Is(Type::Any()));
-        break;
-      case IrOpcode::kJSStoreProperty:
-      case IrOpcode::kJSStoreNamed:
-        // Type is empty.
-        CHECK(!NodeProperties::IsTyped(node));
-        break;
-      case IrOpcode::kJSDeleteProperty:
-      case IrOpcode::kJSHasProperty:
-      case IrOpcode::kJSInstanceOf:
-        // Type is Boolean.
-        CHECK(bounds(node).upper->Is(Type::Boolean()));
-        break;
-      case IrOpcode::kJSTypeOf:
-        // Type is String.
-        CHECK(bounds(node).upper->Is(Type::String()));
-        break;
+    case IrOpcode::kJSCreate:
+      // Type is Object.
+      CheckUpperIs(node, Type::Object());
+      break;
+    case IrOpcode::kJSLoadProperty:
+    case IrOpcode::kJSLoadNamed:
+      // Type can be anything.
+      CheckUpperIs(node, Type::Any());
+      break;
+    case IrOpcode::kJSStoreProperty:
+    case IrOpcode::kJSStoreNamed:
+      // Type is empty.
+      CheckNotTyped(node);
+      break;
+    case IrOpcode::kJSDeleteProperty:
+    case IrOpcode::kJSHasProperty:
+    case IrOpcode::kJSInstanceOf:
+      // Type is Boolean.
+      CheckUpperIs(node, Type::Boolean());
+      break;
+    case IrOpcode::kJSTypeOf:
+      // Type is String.
+      CheckUpperIs(node, Type::String());
+      break;

-      case IrOpcode::kJSLoadContext:
-        // Type can be anything.
-        CHECK(bounds(node).upper->Is(Type::Any()));
-        break;
-      case IrOpcode::kJSStoreContext:
-        // Type is empty.
-        CHECK(!NodeProperties::IsTyped(node));
-        break;
-      case IrOpcode::kJSCreateFunctionContext:
-      case IrOpcode::kJSCreateCatchContext:
-      case IrOpcode::kJSCreateWithContext:
-      case IrOpcode::kJSCreateBlockContext:
-      case IrOpcode::kJSCreateModuleContext:
-      case IrOpcode::kJSCreateGlobalContext: {
-        // Type is Context, and operand is Internal.
-        Bounds outer = bounds(NodeProperties::GetContextInput(node));
- // TODO(rossberg): This should really be Is(Internal), but the typer
-        // currently can't do backwards propagation.
-        CHECK(outer.upper->Maybe(Type::Internal()));
-        CHECK(bounds(node).upper->IsContext());
-        break;
-      }
+    case IrOpcode::kJSLoadContext:
+      // Type can be anything.
+      CheckUpperIs(node, Type::Any());
+      break;
+    case IrOpcode::kJSStoreContext:
+      // Type is empty.
+      CheckNotTyped(node);
+      break;
+    case IrOpcode::kJSCreateFunctionContext:
+    case IrOpcode::kJSCreateCatchContext:
+    case IrOpcode::kJSCreateWithContext:
+    case IrOpcode::kJSCreateBlockContext:
+    case IrOpcode::kJSCreateModuleContext:
+    case IrOpcode::kJSCreateGlobalContext: {
+      // Type is Context, and operand is Internal.
+      Node* context = NodeProperties::GetContextInput(node);
+      // TODO(rossberg): This should really be Is(Internal), but the typer
+      // currently can't do backwards propagation.
+      CheckUpperMaybe(context, Type::Internal());
+      if (typing == TYPED) CHECK(bounds(node).upper->IsContext());
+      break;
+    }

-      case IrOpcode::kJSCallConstruct:
-        // Type is Receiver.
-        CHECK(bounds(node).upper->Is(Type::Receiver()));
-        break;
-      case IrOpcode::kJSCallFunction:
-      case IrOpcode::kJSCallRuntime:
-      case IrOpcode::kJSYield:
-      case IrOpcode::kJSDebugger:
-        // Type can be anything.
-        CHECK(bounds(node).upper->Is(Type::Any()));
-        break;
+    case IrOpcode::kJSCallConstruct:
+      // Type is Receiver.
+      CheckUpperIs(node, Type::Receiver());
+      break;
+    case IrOpcode::kJSCallFunction:
+    case IrOpcode::kJSCallRuntime:
+    case IrOpcode::kJSYield:
+    case IrOpcode::kJSDebugger:
+      // Type can be anything.
+      CheckUpperIs(node, Type::Any());
+      break;

-      // Simplified operators
-      // -------------------------------
-      case IrOpcode::kBooleanNot:
-        // Boolean -> Boolean
-        CHECK(bounds(Operand(node)).upper->Is(Type::Boolean()));
-        CHECK(bounds(node).upper->Is(Type::Boolean()));
-        break;
-      case IrOpcode::kBooleanToNumber:
-        // Boolean -> Number
-        CHECK(bounds(Operand(node)).upper->Is(Type::Boolean()));
-        CHECK(bounds(node).upper->Is(Type::Number()));
-        break;
-      case IrOpcode::kNumberEqual:
-      case IrOpcode::kNumberLessThan:
-      case IrOpcode::kNumberLessThanOrEqual:
-        // (Number, Number) -> Boolean
-        CHECK(bounds(Operand(node, 0)).upper->Is(Type::Number()));
-        CHECK(bounds(Operand(node, 1)).upper->Is(Type::Number()));
-        CHECK(bounds(node).upper->Is(Type::Boolean()));
-        break;
-      case IrOpcode::kNumberAdd:
-      case IrOpcode::kNumberSubtract:
-      case IrOpcode::kNumberMultiply:
-      case IrOpcode::kNumberDivide:
-      case IrOpcode::kNumberModulus:
-        // (Number, Number) -> Number
-        CHECK(bounds(Operand(node, 0)).upper->Is(Type::Number()));
-        CHECK(bounds(Operand(node, 1)).upper->Is(Type::Number()));
-        // TODO(rossberg): activate once we retype after opcode changes.
-        // CHECK(bounds(node).upper->Is(Type::Number()));
-        break;
-      case IrOpcode::kNumberToInt32:
-        // Number -> Signed32
-        CHECK(bounds(Operand(node)).upper->Is(Type::Number()));
-        CHECK(bounds(node).upper->Is(Type::Signed32()));
-        break;
-      case IrOpcode::kNumberToUint32:
-        // Number -> Unsigned32
-        CHECK(bounds(Operand(node)).upper->Is(Type::Number()));
-        CHECK(bounds(node).upper->Is(Type::Unsigned32()));
-        break;
-      case IrOpcode::kStringEqual:
-      case IrOpcode::kStringLessThan:
-      case IrOpcode::kStringLessThanOrEqual:
-        // (String, String) -> Boolean
-        CHECK(bounds(Operand(node, 0)).upper->Is(Type::String()));
-        CHECK(bounds(Operand(node, 1)).upper->Is(Type::String()));
-        CHECK(bounds(node).upper->Is(Type::Boolean()));
-        break;
-      case IrOpcode::kStringAdd:
-        // (String, String) -> String
-        CHECK(bounds(Operand(node, 0)).upper->Is(Type::String()));
-        CHECK(bounds(Operand(node, 1)).upper->Is(Type::String()));
-        CHECK(bounds(node).upper->Is(Type::String()));
-        break;
-      case IrOpcode::kReferenceEqual: {
-        // (Unique, Any) -> Boolean  and
-        // (Any, Unique) -> Boolean
-        CHECK(bounds(Operand(node, 0)).upper->Is(Type::Unique()) ||
-              bounds(Operand(node, 1)).upper->Is(Type::Unique()));
-        CHECK(bounds(node).upper->Is(Type::Boolean()));
-        break;
+    // Simplified operators
+    // -------------------------------
+    case IrOpcode::kBooleanNot:
+      // Boolean -> Boolean
+      CheckValueInputIs(node, 0, Type::Boolean());
+      CheckUpperIs(node, Type::Boolean());
+      break;
+    case IrOpcode::kBooleanToNumber:
+      // Boolean -> Number
+      CheckValueInputIs(node, 0, Type::Boolean());
+      CheckUpperIs(node, Type::Number());
+      break;
+    case IrOpcode::kNumberEqual:
+    case IrOpcode::kNumberLessThan:
+    case IrOpcode::kNumberLessThanOrEqual:
+      // (Number, Number) -> Boolean
+      CheckValueInputIs(node, 0, Type::Number());
+      CheckValueInputIs(node, 1, Type::Number());
+      CheckUpperIs(node, Type::Boolean());
+      break;
+    case IrOpcode::kNumberAdd:
+    case IrOpcode::kNumberSubtract:
+    case IrOpcode::kNumberMultiply:
+    case IrOpcode::kNumberDivide:
+    case IrOpcode::kNumberModulus:
+      // (Number, Number) -> Number
+      CheckValueInputIs(node, 0, Type::Number());
+      CheckValueInputIs(node, 1, Type::Number());
+      // TODO(rossberg): activate once we retype after opcode changes.
+      // CheckUpperIs(node, Type::Number());
+      break;
+    case IrOpcode::kNumberToInt32:
+      // Number -> Signed32
+      CheckValueInputIs(node, 0, Type::Number());
+      CheckUpperIs(node, Type::Signed32());
+      break;
+    case IrOpcode::kNumberToUint32:
+      // Number -> Unsigned32
+      CheckValueInputIs(node, 0, Type::Number());
+      CheckUpperIs(node, Type::Unsigned32());
+      break;
+    case IrOpcode::kStringEqual:
+    case IrOpcode::kStringLessThan:
+    case IrOpcode::kStringLessThanOrEqual:
+      // (String, String) -> Boolean
+      CheckValueInputIs(node, 0, Type::String());
+      CheckValueInputIs(node, 1, Type::String());
+      CheckUpperIs(node, Type::Boolean());
+      break;
+    case IrOpcode::kStringAdd:
+      // (String, String) -> String
+      CheckValueInputIs(node, 0, Type::String());
+      CheckValueInputIs(node, 1, Type::String());
+      CheckUpperIs(node, Type::String());
+      break;
+    case IrOpcode::kReferenceEqual: {
+      // (Unique, Any) -> Boolean  and
+      // (Any, Unique) -> Boolean
+      if (typing == TYPED) {
+        CHECK(bounds(ValueInput(node, 0)).upper->Is(Type::Unique()) ||
+              bounds(ValueInput(node, 1)).upper->Is(Type::Unique()));
       }
-      case IrOpcode::kObjectIsSmi:
-        CHECK(bounds(Operand(node)).upper->Is(Type::Any()));
-        CHECK(bounds(node).upper->Is(Type::Boolean()));
-        break;
-      case IrOpcode::kObjectIsNonNegativeSmi:
-        CHECK(bounds(Operand(node)).upper->Is(Type::Any()));
-        CHECK(bounds(node).upper->Is(Type::Boolean()));
-        break;
+      CheckUpperIs(node, Type::Boolean());
+      break;
+    }
+    case IrOpcode::kObjectIsSmi:
+      CheckValueInputIs(node, 0, Type::Any());
+      CheckUpperIs(node, Type::Boolean());
+      break;
+    case IrOpcode::kObjectIsNonNegativeSmi:
+      CheckValueInputIs(node, 0, Type::Any());
+      CheckUpperIs(node, Type::Boolean());
+      break;

-      case IrOpcode::kChangeTaggedToInt32: {
-        // Signed32 /\ Tagged -> Signed32 /\ UntaggedInt32
-        // TODO(neis): Activate once ChangeRepresentation works in typer.
-        // Type* from = Type::Intersect(Type::Signed32(), Type::Tagged());
- // Type* to = Type::Intersect(Type::Signed32(), Type::UntaggedInt32());
-        // CHECK(bounds(Operand(node)).upper->Is(from));
-        // CHECK(bounds(node).upper->Is(to));
-        break;
-      }
-      case IrOpcode::kChangeTaggedToUint32: {
-        // Unsigned32 /\ Tagged -> Unsigned32 /\ UntaggedInt32
-        // TODO(neis): Activate once ChangeRepresentation works in typer.
- // Type* from = Type::Intersect(Type::Unsigned32(), Type::Tagged()); - // Type* to =Type::Intersect(Type::Unsigned32(), Type::UntaggedInt32());
-        // CHECK(bounds(Operand(node)).upper->Is(from));
-        // CHECK(bounds(node).upper->Is(to));
-        break;
-      }
-      case IrOpcode::kChangeTaggedToFloat64: {
-        // Number /\ Tagged -> Number /\ UntaggedFloat64
-        // TODO(neis): Activate once ChangeRepresentation works in typer.
-        // Type* from = Type::Intersect(Type::Number(), Type::Tagged());
- // Type* to = Type::Intersect(Type::Number(), Type::UntaggedFloat64());
-        // CHECK(bounds(Operand(node)).upper->Is(from));
-        // CHECK(bounds(node).upper->Is(to));
-        break;
-      }
-      case IrOpcode::kChangeInt32ToTagged: {
-        // Signed32 /\ UntaggedInt32 -> Signed32 /\ Tagged
-        // TODO(neis): Activate once ChangeRepresentation works in typer.
- // Type* from =Type::Intersect(Type::Signed32(), Type::UntaggedInt32());
-        // Type* to = Type::Intersect(Type::Signed32(), Type::Tagged());
-        // CHECK(bounds(Operand(node)).upper->Is(from));
-        // CHECK(bounds(node).upper->Is(to));
-        break;
-      }
-      case IrOpcode::kChangeUint32ToTagged: {
-        // Unsigned32 /\ UntaggedInt32 -> Unsigned32 /\ Tagged
-        // TODO(neis): Activate once ChangeRepresentation works in typer.
- // Type* from=Type::Intersect(Type::Unsigned32(),Type::UntaggedInt32());
-        // Type* to = Type::Intersect(Type::Unsigned32(), Type::Tagged());
-        // CHECK(bounds(Operand(node)).upper->Is(from));
-        // CHECK(bounds(node).upper->Is(to));
-        break;
-      }
-      case IrOpcode::kChangeFloat64ToTagged: {
-        // Number /\ UntaggedFloat64 -> Number /\ Tagged
-        // TODO(neis): Activate once ChangeRepresentation works in typer.
- // Type* from =Type::Intersect(Type::Number(), Type::UntaggedFloat64());
-        // Type* to = Type::Intersect(Type::Number(), Type::Tagged());
-        // CHECK(bounds(Operand(node)).upper->Is(from));
-        // CHECK(bounds(node).upper->Is(to));
-        break;
-      }
-      case IrOpcode::kChangeBoolToBit: {
-        // Boolean /\ TaggedPtr -> Boolean /\ UntaggedInt1
-        // TODO(neis): Activate once ChangeRepresentation works in typer.
- // Type* from = Type::Intersect(Type::Boolean(), Type::TaggedPtr()); - // Type* to = Type::Intersect(Type::Boolean(), Type::UntaggedInt1());
-        // CHECK(bounds(Operand(node)).upper->Is(from));
-        // CHECK(bounds(node).upper->Is(to));
-        break;
-      }
-      case IrOpcode::kChangeBitToBool: {
-        // Boolean /\ UntaggedInt1 -> Boolean /\ TaggedPtr
-        // TODO(neis): Activate once ChangeRepresentation works in typer.
- // Type* from = Type::Intersect(Type::Boolean(), Type::UntaggedInt1());
-        // Type* to = Type::Intersect(Type::Boolean(), Type::TaggedPtr());
-        // CHECK(bounds(Operand(node)).upper->Is(from));
-        // CHECK(bounds(node).upper->Is(to));
-        break;
-      }
+    case IrOpcode::kChangeTaggedToInt32: {
+      // Signed32 /\ Tagged -> Signed32 /\ UntaggedInt32
+      // TODO(neis): Activate once ChangeRepresentation works in typer.
+      // Type* from = Type::Intersect(Type::Signed32(), Type::Tagged());
+ // Type* to = Type::Intersect(Type::Signed32(), Type::UntaggedInt32());
+      // CheckValueInputIs(node, 0, from));
+      // CheckUpperIs(node, to));
+      break;
+    }
+    case IrOpcode::kChangeTaggedToUint32: {
+      // Unsigned32 /\ Tagged -> Unsigned32 /\ UntaggedInt32
+      // TODO(neis): Activate once ChangeRepresentation works in typer.
+      // Type* from = Type::Intersect(Type::Unsigned32(), Type::Tagged());
+ // Type* to =Type::Intersect(Type::Unsigned32(), Type::UntaggedInt32());
+      // CheckValueInputIs(node, 0, from));
+      // CheckUpperIs(node, to));
+      break;
+    }
+    case IrOpcode::kChangeTaggedToFloat64: {
+      // Number /\ Tagged -> Number /\ UntaggedFloat64
+      // TODO(neis): Activate once ChangeRepresentation works in typer.
+      // Type* from = Type::Intersect(Type::Number(), Type::Tagged());
+ // Type* to = Type::Intersect(Type::Number(), Type::UntaggedFloat64());
+      // CheckValueInputIs(node, 0, from));
+      // CheckUpperIs(node, to));
+      break;
+    }
+    case IrOpcode::kChangeInt32ToTagged: {
+      // Signed32 /\ UntaggedInt32 -> Signed32 /\ Tagged
+      // TODO(neis): Activate once ChangeRepresentation works in typer.
+ // Type* from =Type::Intersect(Type::Signed32(), Type::UntaggedInt32());
+      // Type* to = Type::Intersect(Type::Signed32(), Type::Tagged());
+      // CheckValueInputIs(node, 0, from));
+      // CheckUpperIs(node, to));
+      break;
+    }
+    case IrOpcode::kChangeUint32ToTagged: {
+      // Unsigned32 /\ UntaggedInt32 -> Unsigned32 /\ Tagged
+      // TODO(neis): Activate once ChangeRepresentation works in typer.
+ // Type* from=Type::Intersect(Type::Unsigned32(),Type::UntaggedInt32());
+      // Type* to = Type::Intersect(Type::Unsigned32(), Type::Tagged());
+      // CheckValueInputIs(node, 0, from));
+      // CheckUpperIs(node, to));
+      break;
+    }
+    case IrOpcode::kChangeFloat64ToTagged: {
+      // Number /\ UntaggedFloat64 -> Number /\ Tagged
+      // TODO(neis): Activate once ChangeRepresentation works in typer.
+ // Type* from =Type::Intersect(Type::Number(), Type::UntaggedFloat64());
+      // Type* to = Type::Intersect(Type::Number(), Type::Tagged());
+      // CheckValueInputIs(node, 0, from));
+      // CheckUpperIs(node, to));
+      break;
+    }
+    case IrOpcode::kChangeBoolToBit: {
+      // Boolean /\ TaggedPtr -> Boolean /\ UntaggedInt1
+      // TODO(neis): Activate once ChangeRepresentation works in typer.
+      // Type* from = Type::Intersect(Type::Boolean(), Type::TaggedPtr());
+      // Type* to = Type::Intersect(Type::Boolean(), Type::UntaggedInt1());
+      // CheckValueInputIs(node, 0, from));
+      // CheckUpperIs(node, to));
+      break;
+    }
+    case IrOpcode::kChangeBitToBool: {
+      // Boolean /\ UntaggedInt1 -> Boolean /\ TaggedPtr
+      // TODO(neis): Activate once ChangeRepresentation works in typer.
+ // Type* from = Type::Intersect(Type::Boolean(), Type::UntaggedInt1());
+      // Type* to = Type::Intersect(Type::Boolean(), Type::TaggedPtr());
+      // CheckValueInputIs(node, 0, from));
+      // CheckUpperIs(node, to));
+      break;
+    }

-      case IrOpcode::kLoadField:
-        // Object -> fieldtype
-        // TODO(rossberg): activate once machine ops are typed.
-        // CHECK(bounds(Operand(node)).upper->Is(Type::Object()));
-        // CHECK(bounds(node).upper->Is(Field(node).type));
-        break;
-      case IrOpcode::kLoadElement:
-        // Object -> elementtype
-        // TODO(rossberg): activate once machine ops are typed.
-        // CHECK(bounds(Operand(node)).upper->Is(Type::Object()));
-        // CHECK(bounds(node).upper->Is(Element(node).type));
-        break;
-      case IrOpcode::kStoreField:
-        // (Object, fieldtype) -> _|_
-        // TODO(rossberg): activate once machine ops are typed.
-        // CHECK(bounds(Operand(node, 0)).upper->Is(Type::Object()));
-        // CHECK(bounds(Operand(node, 1)).upper->Is(Field(node).type));
-        CHECK(!NodeProperties::IsTyped(node));
-        break;
-      case IrOpcode::kStoreElement:
-        // (Object, elementtype) -> _|_
-        // TODO(rossberg): activate once machine ops are typed.
-        // CHECK(bounds(Operand(node, 0)).upper->Is(Type::Object()));
-        // CHECK(bounds(Operand(node, 1)).upper->Is(Element(node).type));
-        CHECK(!NodeProperties::IsTyped(node));
-        break;
+    case IrOpcode::kLoadField:
+      // Object -> fieldtype
+      // TODO(rossberg): activate once machine ops are typed.
+      // CheckValueInputIs(node, 0, Type::Object());
+      // CheckUpperIs(node, Field(node).type));
+      break;
+    case IrOpcode::kLoadElement:
+      // Object -> elementtype
+      // TODO(rossberg): activate once machine ops are typed.
+      // CheckValueInputIs(node, 0, Type::Object());
+      // CheckUpperIs(node, Element(node).type));
+      break;
+    case IrOpcode::kStoreField:
+      // (Object, fieldtype) -> _|_
+      // TODO(rossberg): activate once machine ops are typed.
+      // CheckValueInputIs(node, 0, Type::Object());
+      // CheckValueInputIs(node, 1, Field(node).type));
+      CheckNotTyped(node);
+      break;
+    case IrOpcode::kStoreElement:
+      // (Object, elementtype) -> _|_
+      // TODO(rossberg): activate once machine ops are typed.
+      // CheckValueInputIs(node, 0, Type::Object());
+      // CheckValueInputIs(node, 1, Element(node).type));
+      CheckNotTyped(node);
+      break;

-      // Machine operators
-      // -----------------------
-      case IrOpcode::kLoad:
-      case IrOpcode::kStore:
-      case IrOpcode::kWord32And:
-      case IrOpcode::kWord32Or:
-      case IrOpcode::kWord32Xor:
-      case IrOpcode::kWord32Shl:
-      case IrOpcode::kWord32Shr:
***The diff for this file has been truncated for email.***
=======================================
--- /trunk/src/conversions.cc   Thu Sep 11 00:05:22 2014 UTC
+++ /trunk/src/conversions.cc   Thu Oct 23 08:44:45 2014 UTC
@@ -483,19 +483,21 @@
 }


-double StringToDouble(UnicodeCache* unicode_cache,
-                      String* string,
-                      int flags,
-                      double empty_string_val) {
-  DisallowHeapAllocation no_gc;
-  String::FlatContent flat = string->GetFlatContent();
-  // ECMA-262 section 15.1.2.3, empty string is NaN
-  if (flat.IsOneByte()) {
-    return StringToDouble(
-        unicode_cache, flat.ToOneByteVector(), flags, empty_string_val);
-  } else {
-    return StringToDouble(
-        unicode_cache, flat.ToUC16Vector(), flags, empty_string_val);
+double StringToDouble(UnicodeCache* unicode_cache, Handle<String> string,
+                      int flags, double empty_string_val) {
+  Handle<String> flattened = String::Flatten(string);
+  {
+    DisallowHeapAllocation no_gc;
+    String::FlatContent flat = flattened->GetFlatContent();
+    DCHECK(flat.IsFlat());
+    // ECMA-262 section 15.1.2.3, empty string is NaN
+    if (flat.IsOneByte()) {
+      return StringToDouble(unicode_cache, flat.ToOneByteVector(), flags,
+                            empty_string_val);
+    } else {
+      return StringToDouble(unicode_cache, flat.ToUC16Vector(), flags,
+                            empty_string_val);
+    }
   }
 }

=======================================
--- /trunk/src/conversions.h    Wed Sep 24 00:05:07 2014 UTC
+++ /trunk/src/conversions.h    Thu Oct 23 08:44:45 2014 UTC
@@ -198,10 +198,8 @@
 }


-double StringToDouble(UnicodeCache* unicode_cache,
-                      String* string,
-                      int flags,
-                      double empty_string_val = 0.0);
+double StringToDouble(UnicodeCache* unicode_cache, Handle<String> string,
+                      int flags, double empty_string_val = 0.0);


 inline bool TryNumberToSize(Isolate* isolate,
=======================================
--- /trunk/src/d8.cc    Wed Oct 22 07:27:53 2014 UTC
+++ /trunk/src/d8.cc    Thu Oct 23 08:44:45 2014 UTC
@@ -1686,7 +1686,7 @@
   }
 #endif
 #ifdef ENABLE_VTUNE_JIT_INTERFACE
-  vTune::InitializeVtuneForV8(create_params);
+  create_params.code_event_handler = vTune::GetVtuneCodeEventHandler();
 #endif
 #ifndef V8_SHARED
   create_params.constraints.ConfigureDefaults(
=======================================
--- /trunk/src/flag-definitions.h       Wed Oct 22 07:27:53 2014 UTC
+++ /trunk/src/flag-definitions.h       Thu Oct 23 08:44:45 2014 UTC
@@ -157,7 +157,6 @@
 #define HARMONY_FEATURES(V)                                       \
   V(harmony_scoping, "harmony block scoping")                     \
   V(harmony_modules, "harmony modules (implies block scoping)")   \
-  V(harmony_strings, "harmony strings")                           \
   V(harmony_arrays, "harmony arrays")                             \
   V(harmony_classes, "harmony classes")                           \
   V(harmony_object_literals, "harmony object literal extensions") \
@@ -165,7 +164,8 @@
   V(harmony_arrow_functions, "harmony arrow functions")           \
   V(harmony_tostring, "harmony Symbol.toStringTag")

-#define STAGED_FEATURES(V) \
+#define STAGED_FEATURES(V)              \
+  V(harmony_strings, "harmony strings") \
   V(harmony_numeric_literals, "harmony numeric literals (0o77, 0b11)")

 #define SHIPPING_FEATURES(V)
@@ -509,6 +509,8 @@
 DEFINE_INT(min_semi_space_size, 0,
"min size of a semi-space (in MBytes), the new space consists of two"
            "semi-spaces")
+DEFINE_INT(target_semi_space_size, 0,
+ "target size of a semi-space (in MBytes) before triggering a GC")
 DEFINE_INT(max_semi_space_size, 0,
"max size of a semi-space (in MBytes), the new space consists of two"
            "semi-spaces")
=======================================
--- /trunk/src/harmony-tostring.js      Wed Oct 22 07:27:53 2014 UTC
+++ /trunk/src/harmony-tostring.js      Thu Oct 23 08:44:45 2014 UTC
@@ -56,11 +56,19 @@
 function HarmonyToStringExtendObjectPrototype() {
   %CheckIsBootstrapping();

+  // Can't use InstallFunctions() because will fail in Debug mode.
+  // Emulate InstallFunctions() here.
+  %FunctionSetName(ObjectToStringHarmony, "toString");
+  %FunctionRemovePrototype(ObjectToStringHarmony);
+  %SetNativeFlag(ObjectToStringHarmony);
+
   // Set up the non-enumerable functions on the Array prototype object.
   var desc = ToPropertyDescriptor({
     value: ObjectToStringHarmony
   });
   DefineOwnProperty($Object.prototype, "toString", desc, false);
+
+  %ToFastProperties($Object.prototype);
 }

 HarmonyToStringExtendObjectPrototype();
=======================================
--- /trunk/src/heap/heap.cc     Tue Oct 21 12:48:28 2014 UTC
+++ /trunk/src/heap/heap.cc     Thu Oct 23 08:44:45 2014 UTC
@@ -61,6 +61,7 @@
       reserved_semispace_size_(8 * (kPointerSize / 4) * MB),
       max_semi_space_size_(8 * (kPointerSize / 4) * MB),
       initial_semispace_size_(Page::kPageSize),
+      target_semispace_size_(Page::kPageSize),
       max_old_generation_size_(700ul * (kPointerSize / 4) * MB),
       max_executable_size_(256ul * (kPointerSize / 4) * MB),
       // Variables set based on semispace_size_ and old_generation_size_ in
@@ -4944,9 +4945,9 @@
       initial_semispace_size_ = max_semi_space_size_;
       if (FLAG_trace_gc) {
         PrintPID(
-            "Min semi-space size cannot be more than the maximum"
+            "Min semi-space size cannot be more than the maximum "
             "semi-space size of %d MB\n",
-            max_semi_space_size_);
+            max_semi_space_size_ / MB);
       }
     } else {
       initial_semispace_size_ = initial_semispace_size;
@@ -4955,6 +4956,31 @@

initial_semispace_size_ = Min(initial_semispace_size_, max_semi_space_size_);

+  if (FLAG_target_semi_space_size > 0) {
+    int target_semispace_size = FLAG_target_semi_space_size * MB;
+    if (target_semispace_size < initial_semispace_size_) {
+      target_semispace_size_ = initial_semispace_size_;
+      if (FLAG_trace_gc) {
+        PrintPID(
+            "Target semi-space size cannot be less than the minimum "
+            "semi-space size of %d MB\n",
+            initial_semispace_size_ / MB);
+      }
+    } else if (target_semispace_size > max_semi_space_size_) {
+      target_semispace_size_ = max_semi_space_size_;
+      if (FLAG_trace_gc) {
+        PrintPID(
+            "Target semi-space size cannot be less than the maximum "
+            "semi-space size of %d MB\n",
+            max_semi_space_size_ / MB);
+      }
+    } else {
+      target_semispace_size_ = target_semispace_size;
+    }
+  }
+
+ target_semispace_size_ = Max(initial_semispace_size_, target_semispace_size_);
+
// The old generation is paged and needs at least one page for each space.
   int paged_space_count = LAST_PAGED_SPACE - FIRST_PAGED_SPACE + 1;
   max_old_generation_size_ =
=======================================
--- /trunk/src/heap/heap.h      Wed Oct 22 07:27:53 2014 UTC
+++ /trunk/src/heap/heap.h      Thu Oct 23 08:44:45 2014 UTC
@@ -570,6 +570,7 @@
   int MaxSemiSpaceSize() { return max_semi_space_size_; }
   int ReservedSemiSpaceSize() { return reserved_semispace_size_; }
   int InitialSemiSpaceSize() { return initial_semispace_size_; }
+  int TargetSemiSpaceSize() { return target_semispace_size_; }
   intptr_t MaxOldGenerationSize() { return max_old_generation_size_; }
   intptr_t MaxExecutableSize() { return max_executable_size_; }

@@ -1472,6 +1473,7 @@
   int reserved_semispace_size_;
   int max_semi_space_size_;
   int initial_semispace_size_;
+  int target_semispace_size_;
   intptr_t max_old_generation_size_;
   intptr_t max_executable_size_;
   intptr_t maximum_committed_;
=======================================
--- /trunk/src/heap/spaces.cc   Wed Oct 15 00:05:09 2014 UTC
+++ /trunk/src/heap/spaces.cc   Thu Oct 23 08:44:45 2014 UTC
@@ -1195,6 +1195,8 @@
   // this chunk must be a power of two and it must be aligned to its size.
   int initial_semispace_capacity = heap()->InitialSemiSpaceSize();

+  int target_semispace_capacity = heap()->TargetSemiSpaceSize();
+
   size_t size = 2 * reserved_semispace_capacity;
Address base = heap()->isolate()->memory_allocator()->ReserveAlignedMemory(
       size, size, &reservation_);
@@ -1223,9 +1225,10 @@
DCHECK(IsAddressAligned(chunk_base_, 2 * reserved_semispace_capacity, 0));

   to_space_.SetUp(chunk_base_, initial_semispace_capacity,
-                  maximum_semispace_capacity);
+                  target_semispace_capacity, maximum_semispace_capacity);
   from_space_.SetUp(chunk_base_ + reserved_semispace_capacity,
- initial_semispace_capacity, maximum_semispace_capacity);
+                    initial_semispace_capacity, target_semispace_capacity,
+                    maximum_semispace_capacity);
   if (!to_space_.Commit()) {
     return false;
   }
@@ -1285,12 +1288,42 @@
       if (!to_space_.ShrinkTo(from_space_.TotalCapacity())) {
         // We are in an inconsistent state because we could not
         // commit/uncommit memory from new space.
-        V8::FatalProcessOutOfMemory("Failed to grow new space.");
+        CHECK(false);
       }
     }
   }
   DCHECK_SEMISPACE_ALLOCATION_INFO(allocation_info_, to_space_);
 }
+
+
+bool NewSpace::GrowOnePage() {
+  if (TotalCapacity() == MaximumCapacity()) return false;
+  int new_capacity = static_cast<int>(TotalCapacity()) + Page::kPageSize;
+  if (to_space_.GrowTo(new_capacity)) {
+ // Only grow from space if we managed to grow to-space and the from space
+    // is actually committed.
+    if (from_space_.is_committed()) {
+      if (!from_space_.GrowTo(new_capacity)) {
+        // If we managed to grow to-space but couldn't grow from-space,
+        // attempt to shrink to-space.
+        if (!to_space_.ShrinkTo(from_space_.TotalCapacity())) {
+          // We are in an inconsistent state because we could not
+          // commit/uncommit memory from new space.
+          CHECK(false);
+        }
+        return false;
+      }
+    } else {
+      if (!from_space_.SetTotalCapacity(new_capacity)) {
+        // Can't really happen, but better safe than sorry.
+        CHECK(false);
+      }
+    }
+    DCHECK_SEMISPACE_ALLOCATION_INFO(allocation_info_, to_space_);
+    return true;
+  }
+  return false;
+}


 void NewSpace::Shrink() {
@@ -1306,7 +1339,7 @@
       if (!to_space_.GrowTo(from_space_.TotalCapacity())) {
         // We are in an inconsistent state because we could not
         // commit/uncommit memory from new space.
-        V8::FatalProcessOutOfMemory("Failed to shrink new space.");
+        CHECK(false);
       }
     }
   }
@@ -1367,8 +1400,19 @@
     return false;
   }
   if (!to_space_.AdvancePage()) {
-    // Failed to get a new page in to-space.
-    return false;
+ // Check if we reached the target capacity yet. If not, try to commit a page
+    // and continue.
+    if ((to_space_.TotalCapacity() < to_space_.TargetCapacity()) &&
+        GrowOnePage()) {
+      if (!to_space_.AdvancePage()) {
+ // It doesn't make sense that we managed to commit a page, but can't use
+        // it.
+        CHECK(false);
+      }
+    } else {
+      // Failed to get a new page in to-space.
+      return false;
+    }
   }

   // Clear remainder of current page.
@@ -1472,7 +1516,7 @@
// -----------------------------------------------------------------------------
 // SemiSpace implementation

-void SemiSpace::SetUp(Address start, int initial_capacity,
+void SemiSpace::SetUp(Address start, int initial_capacity, int target_capacity,
                       int maximum_capacity) {
   // Creates a space in the young generation. The constructor does not
// allocate memory from the OS. A SemiSpace is given a contiguous chunk of
@@ -1481,8 +1525,11 @@
   // space is used as the marking stack. It requires contiguous memory
   // addresses.
   DCHECK(maximum_capacity >= Page::kPageSize);
+  DCHECK(initial_capacity <= target_capacity);
+  DCHECK(target_capacity <= maximum_capacity);
   initial_total_capacity_ = RoundDown(initial_capacity, Page::kPageSize);
   total_capacity_ = initial_capacity;
+  target_capacity_ = RoundDown(target_capacity, Page::kPageSize);
   maximum_total_capacity_ = RoundDown(maximum_capacity, Page::kPageSize);
   maximum_committed_ = 0;
   committed_ = false;
@@ -1609,6 +1656,17 @@

   return true;
 }
+
+
+bool SemiSpace::SetTotalCapacity(int new_capacity) {
+  CHECK(!is_committed());
+  if (new_capacity >= initial_total_capacity_ &&
+      new_capacity <= maximum_total_capacity_) {
+    total_capacity_ = new_capacity;
+    return true;
+  }
+  return false;
+}


 void SemiSpace::FlipPages(intptr_t flags, intptr_t mask) {
=======================================
--- /trunk/src/heap/spaces.h    Tue Sep 30 00:05:10 2014 UTC
+++ /trunk/src/heap/spaces.h    Thu Oct 23 08:44:45 2014 UTC
@@ -2075,7 +2075,8 @@
         current_page_(NULL) {}

   // Sets up the semispace using the given chunk.
-  void SetUp(Address start, int initial_capacity, int maximum_capacity);
+  void SetUp(Address start, int initial_capacity, int target_capacity,
+             int maximum_capacity);

// Tear down the space. Heap memory was not allocated by the space, so it
   // is not deallocated here.
@@ -2094,6 +2095,9 @@
   // semispace and less than the current capacity.
   bool ShrinkTo(int new_capacity);

+ // Sets the total capacity. Only possible when the space is not committed.
+  bool SetTotalCapacity(int new_capacity);
+
   // Returns the start address of the first page of the space.
   Address space_start() {
     DCHECK(anchor_.next_page() != &anchor_);
@@ -2167,6 +2171,9 @@

   // Returns the current total capacity of the semispace.
   int TotalCapacity() { return total_capacity_; }
+
+  // Returns the target for total capacity of the semispace.
+  int TargetCapacity() { return target_capacity_; }

   // Returns the maximum total capacity of the semispace.
   int MaximumTotalCapacity() { return maximum_total_capacity_; }
@@ -2196,6 +2203,7 @@

   // The current and maximum total capacity of the space.
   int total_capacity_;
+  int target_capacity_;
   int maximum_total_capacity_;
   int initial_total_capacity_;

@@ -2341,6 +2349,9 @@
   // their maximum capacity.
   void Grow();

+  // Grow the capacity of the semispaces by one page.
+  bool GrowOnePage();
+
   // Shrink the capacity of the semispaces.
   void Shrink();

=======================================
--- /trunk/src/hydrogen.cc      Wed Oct 22 07:27:53 2014 UTC
+++ /trunk/src/hydrogen.cc      Thu Oct 23 08:44:45 2014 UTC
@@ -5621,6 +5621,8 @@
         DCHECK(!CompileTimeValue::IsCompileTimeValue(value));
         // Fall through.
       case ObjectLiteral::Property::COMPUTED:
+        // It is safe to use [[Put]] here because the boilerplate already
+        // contains computed properties with an uninitialized value.
         if (key->value()->IsInternalizedString()) {
           if (property->emit_store()) {
             CHECK_ALIVE(VisitForValue(value));
=======================================
--- /trunk/src/ia32/full-codegen-ia32.cc        Tue Oct 21 12:48:28 2014 UTC
+++ /trunk/src/ia32/full-codegen-ia32.cc        Thu Oct 23 08:44:45 2014 UTC
@@ -1657,6 +1657,8 @@
         DCHECK(!CompileTimeValue::IsCompileTimeValue(value));
         // Fall through.
       case ObjectLiteral::Property::COMPUTED:
+        // It is safe to use [[Put]] here because the boilerplate already
+        // contains computed properties with an uninitialized value.
         if (key->value()->IsInternalizedString()) {
           if (property->emit_store()) {
             VisitForAccumulatorValue(value);
@@ -1684,7 +1686,7 @@
         __ push(Operand(esp, 0));  // Duplicate receiver.
         VisitForStackValue(value);
         if (property->emit_store()) {
-          __ CallRuntime(Runtime::kSetPrototype, 2);
+          __ CallRuntime(Runtime::kInternalSetPrototype, 2);
         } else {
           __ Drop(2);
         }
=======================================
--- /trunk/src/lookup.cc        Wed Oct 22 07:27:53 2014 UTC
+++ /trunk/src/lookup.cc        Thu Oct 23 08:44:45 2014 UTC
@@ -314,7 +314,7 @@
     Handle<String> name_string = Handle<String>::cast(name());
     if (name_string->length() > 0) {
       double d =
- StringToDouble(isolate()->unicode_cache(), *name_string, NO_FLAGS); + StringToDouble(isolate()->unicode_cache(), name_string, NO_FLAGS);
       if (!std::isnan(d)) {
         if (String::Equals(isolate()->factory()->minus_zero_string(),
                            name_string))
=======================================
--- /trunk/src/mips/full-codegen-mips.cc        Tue Oct 21 12:48:28 2014 UTC
+++ /trunk/src/mips/full-codegen-mips.cc        Thu Oct 23 08:44:45 2014 UTC
@@ -1711,6 +1711,8 @@
         DCHECK(!CompileTimeValue::IsCompileTimeValue(property->value()));
         // Fall through.
       case ObjectLiteral::Property::COMPUTED:
+        // It is safe to use [[Put]] here because the boilerplate already
+        // contains computed properties with an uninitialized value.
         if (key->value()->IsInternalizedString()) {
           if (property->emit_store()) {
             VisitForAccumulatorValue(value);
@@ -1744,7 +1746,7 @@
         __ push(a0);
         VisitForStackValue(value);
         if (property->emit_store()) {
-          __ CallRuntime(Runtime::kSetPrototype, 2);
+          __ CallRuntime(Runtime::kInternalSetPrototype, 2);
         } else {
           __ Drop(2);
         }
=======================================
--- /trunk/src/mips64/full-codegen-mips64.cc    Tue Oct 21 12:48:28 2014 UTC
+++ /trunk/src/mips64/full-codegen-mips64.cc    Thu Oct 23 08:44:45 2014 UTC
@@ -1708,6 +1708,8 @@
         DCHECK(!CompileTimeValue::IsCompileTimeValue(property->value()));
         // Fall through.
       case ObjectLiteral::Property::COMPUTED:
+        // It is safe to use [[Put]] here because the boilerplate already
+        // contains computed properties with an uninitialized value.
         if (key->value()->IsInternalizedString()) {
           if (property->emit_store()) {
             VisitForAccumulatorValue(value);
@@ -1741,7 +1743,7 @@
         __ push(a0);
         VisitForStackValue(value);
         if (property->emit_store()) {
-          __ CallRuntime(Runtime::kSetPrototype, 2);
+          __ CallRuntime(Runtime::kInternalSetPrototype, 2);
         } else {
           __ Drop(2);
         }
=======================================
--- /trunk/src/objects.cc       Wed Oct 22 07:27:53 2014 UTC
+++ /trunk/src/objects.cc       Thu Oct 23 08:44:45 2014 UTC
@@ -11796,7 +11796,7 @@
   DCHECK(new_map->prototype() == *value);
   JSObject::MigrateToMap(real_receiver, new_map);

-  if (!dictionary_elements_in_chain &&
+  if (from_javascript && !dictionary_elements_in_chain &&
       new_map->DictionaryElementsInPrototypeChainOnly()) {
// If the prototype chain didn't previously have element callbacks, then
     // KeyedStoreICs need to be cleared to ensure any that involve this
=======================================
--- /trunk/src/runtime/runtime-numbers.cc       Tue Oct 21 12:48:28 2014 UTC
+++ /trunk/src/runtime/runtime-numbers.cc       Thu Oct 23 08:44:45 2014 UTC
@@ -193,7 +193,7 @@
   }

   return *isolate->factory()->NewNumber(
-      StringToDouble(isolate->unicode_cache(), *subject, flags));
+      StringToDouble(isolate->unicode_cache(), subject, flags));
 }


@@ -229,8 +229,7 @@
   DCHECK(args.length() == 1);
   CONVERT_ARG_HANDLE_CHECKED(String, subject, 0);

-  subject = String::Flatten(subject);
-  double value = StringToDouble(isolate->unicode_cache(), *subject,
+  double value = StringToDouble(isolate->unicode_cache(), subject,
ALLOW_TRAILING_JUNK, base::OS::nan_value());

   return *isolate->factory()->NewNumber(value);
=======================================
--- /trunk/src/sampler.cc       Fri Oct 17 20:38:26 2014 UTC
+++ /trunk/src/sampler.cc       Thu Oct 23 08:44:45 2014 UTC
@@ -374,8 +374,7 @@
   state.sp = reinterpret_cast<Address>(mcontext.gregs[REG_RSP]);
   state.fp = reinterpret_cast<Address>(mcontext.gregs[REG_RBP]);
 #elif V8_HOST_ARCH_ARM
-#if defined(__GLIBC__) && !defined(__UCLIBC__) && \
-    (__GLIBC__ < 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ <= 3))
+#if V8_LIBC_GLIBC && !V8_GLIBC_PREREQ(2, 4)
   // Old GLibc ARM versions used a gregs[] array to access the register
   // values from mcontext_t.
   state.pc = reinterpret_cast<Address>(mcontext.gregs[R15]);
@@ -385,8 +384,7 @@
   state.pc = reinterpret_cast<Address>(mcontext.arm_pc);
   state.sp = reinterpret_cast<Address>(mcontext.arm_sp);
   state.fp = reinterpret_cast<Address>(mcontext.arm_fp);
-#endif  // defined(__GLIBC__) && !defined(__UCLIBC__) &&
-        // (__GLIBC__ < 2 || (__GLIBC__ == 2 && __GLIBC_MINOR__ <= 3))
+#endif  // V8_LIBC_GLIBC && !V8_GLIBC_PREREQ(2, 4)
 #elif V8_HOST_ARCH_ARM64
   state.pc = reinterpret_cast<Address>(mcontext.pc);
   state.sp = reinterpret_cast<Address>(mcontext.sp);
=======================================
--- /trunk/src/third_party/vtune/v8-vtune.h     Tue Sep 16 07:50:38 2014 UTC
+++ /trunk/src/third_party/vtune/v8-vtune.h     Thu Oct 23 08:44:45 2014 UTC
@@ -62,7 +62,7 @@

 namespace vTune {

-void InitializeVtuneForV8(v8::Isolate::CreateParams& params);
+v8::JitCodeEventHandler GetVtuneCodeEventHandler();

 }  // namespace vTune

=======================================
***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