Update V8 to version 4.1.0.21

This is a cherry-pick of all commits up to and including the
4.1.0.21 cherry-pick in Chromium.

Original commit message:

Version 4.1.0.21 (cherry-pick)

Merged 206e9136bde0f2b5ae8cb77afbb1e7833e5bd412

Unlink pages from the space page list after evacuation.

BUG=430201
LOG=N
R=jkummerow@chromium.org

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

Cr-Commit-Position: refs/branch-heads/4.1@{#22}
Cr-Branched-From: 2e08d2a7aa9d65d269d8c57aba82eb38a8cb0a18-refs/heads/candidates@{#25353}

---

FPIIM-449

Change-Id: I8c23c7bbb70772b4858fe8a47b64fa97ee0d1f8c
diff --git a/test/cctest/cctest.cc b/test/cctest/cctest.cc
index f03710a..170aa5a 100644
--- a/test/cctest/cctest.cc
+++ b/test/cctest/cctest.cc
@@ -34,12 +34,12 @@
 #include "test/cctest/profiler-extension.h"
 #include "test/cctest/trace-extension.h"
 
-#if (defined(_WIN32) || defined(_WIN64))
+#if V8_OS_WIN
 #include <windows.h>  // NOLINT
-#if defined(_MSC_VER)
+#if V8_CC_MSVC
 #include <crtdbg.h>
-#endif  // defined(_MSC_VER)
-#endif  // defined(_WIN32) || defined(_WIN64)
+#endif
+#endif
 
 enum InitializationState {kUnset, kUnintialized, kInitialized};
 static InitializationState initialization_state_  = kUnset;
@@ -47,7 +47,7 @@
 
 CcTest* CcTest::last_ = NULL;
 bool CcTest::initialize_called_ = false;
-bool CcTest::isolate_used_ = false;
+v8::base::Atomic32 CcTest::isolate_used_ = 0;
 v8::Isolate* CcTest::isolate_ = NULL;
 
 
@@ -145,12 +145,12 @@
 
 
 int main(int argc, char* argv[]) {
-#if (defined(_WIN32) || defined(_WIN64))
+#if V8_OS_WIN
   UINT new_flags =
       SEM_FAILCRITICALERRORS | SEM_NOGPFAULTERRORBOX | SEM_NOOPENFILEERRORBOX;
   UINT existing_flags = SetErrorMode(new_flags);
   SetErrorMode(existing_flags | new_flags);
-#if defined(_MSC_VER)
+#if V8_CC_MSVC
   _CrtSetReportMode(_CRT_WARN, _CRTDBG_MODE_DEBUG | _CRTDBG_MODE_FILE);
   _CrtSetReportFile(_CRT_WARN, _CRTDBG_FILE_STDERR);
   _CrtSetReportMode(_CRT_ASSERT, _CRTDBG_MODE_DEBUG | _CRTDBG_MODE_FILE);
@@ -158,8 +158,8 @@
   _CrtSetReportMode(_CRT_ERROR, _CRTDBG_MODE_DEBUG | _CRTDBG_MODE_FILE);
   _CrtSetReportFile(_CRT_ERROR, _CRTDBG_FILE_STDERR);
   _set_error_mode(_OUT_TO_STDERR);
-#endif  // _MSC_VER
-#endif  // defined(_WIN32) || defined(_WIN64)
+#endif  // V8_CC_MSVC
+#endif  // V8_OS_WIN
 
   v8::V8::InitializeICU();
   v8::Platform* platform = v8::platform::CreateDefaultPlatform();
diff --git a/test/cctest/cctest.gyp b/test/cctest/cctest.gyp
index 6a57763..4d1c467 100644
--- a/test/cctest/cctest.gyp
+++ b/test/cctest/cctest.gyp
@@ -53,22 +53,27 @@
         'compiler/graph-tester.h',
         'compiler/simplified-graph-builder.cc',
         'compiler/simplified-graph-builder.h',
+        'compiler/test-basic-block-profiler.cc',
         'compiler/test-branch-combine.cc',
         'compiler/test-changes-lowering.cc',
         'compiler/test-codegen-deopt.cc',
+        'compiler/test-control-reducer.cc',
         'compiler/test-gap-resolver.cc',
         'compiler/test-graph-reducer.cc',
+        'compiler/test-graph-visualizer.cc',
         'compiler/test-instruction.cc',
         'compiler/test-js-context-specialization.cc',
         'compiler/test-js-constant-cache.cc',
         'compiler/test-js-typed-lowering.cc',
+        'compiler/test-jump-threading.cc',
         'compiler/test-linkage.cc',
+        'compiler/test-loop-assignment-analysis.cc',
+        'compiler/test-loop-analysis.cc',
         'compiler/test-machine-operator-reducer.cc',
         'compiler/test-node-algorithm.cc',
         'compiler/test-node-cache.cc',
         'compiler/test-node.cc',
         'compiler/test-operator.cc',
-        'compiler/test-phi-reducer.cc',
         'compiler/test-pipeline.cc',
         'compiler/test-representation-change.cc',
         'compiler/test-run-deopt.cc',
@@ -80,10 +85,12 @@
         'compiler/test-run-jsops.cc',
         'compiler/test-run-machops.cc',
         'compiler/test-run-properties.cc',
+        'compiler/test-run-stackcheck.cc',
         'compiler/test-run-variables.cc',
         'compiler/test-schedule.cc',
         'compiler/test-scheduler.cc',
         'compiler/test-simplified-lowering.cc',
+        'compiler/test-typer.cc',
         'cctest.cc',
         'gay-fixed.cc',
         'gay-precision.cc',
@@ -97,13 +104,13 @@
         'test-atomicops.cc',
         'test-bignum.cc',
         'test-bignum-dtoa.cc',
+        'test-bit-vector.cc',
         'test-checks.cc',
         'test-circular-queue.cc',
         'test-compiler.cc',
         'test-constantpool.cc',
         'test-conversions.cc',
         'test-cpu-profiler.cc',
-        'test-dataflow.cc',
         'test-date.cc',
         'test-debug.cc',
         'test-declarative-accessors.cc',
@@ -114,6 +121,7 @@
         'test-double.cc',
         'test-dtoa.cc',
         'test-fast-dtoa.cc',
+        'test-feedback-vector.cc',
         'test-fixed-dtoa.cc',
         'test-flags.cc',
         'test-func-name-inference.cc',
@@ -134,7 +142,6 @@
         'test-mementos.cc',
         'test-object-observe.cc',
         'test-ordered-hash-table.cc',
-        'test-ostreams.cc',
         'test-parsing.cc',
         'test-platform.cc',
         'test-profile-generator.cc',
@@ -142,6 +149,7 @@
         'test-regexp.cc',
         'test-reloc-info.cc',
         'test-representation.cc',
+        'test-sampler-api.cc',
         'test-serialize.cc',
         'test-spaces.cc',
         'test-strings.cc',
@@ -149,8 +157,10 @@
         'test-strtod.cc',
         'test-thread-termination.cc',
         'test-threads.cc',
+        'test-transitions.cc',
         'test-types.cc',
         'test-unbound-queue.cc',
+        'test-unboxed-doubles.cc',
         'test-unique.cc',
         'test-unscopables-hidden-prototype.cc',
         'test-utils.cc',
@@ -250,13 +260,14 @@
           # cctest can't be built against a shared library, so we need to
           # depend on the underlying static target in that case.
           'conditions': [
-            ['v8_use_snapshot=="true"', {
+            ['v8_use_snapshot=="true" and v8_use_external_startup_data==0', {
               'dependencies': ['../../tools/gyp/v8.gyp:v8_snapshot'],
-            },
-            {
-              'dependencies': [
-                '../../tools/gyp/v8.gyp:v8_nosnapshot',
-              ],
+            }],
+            ['v8_use_snapshot=="true" and v8_use_external_startup_data==1', {
+              'dependencies': ['../../tools/gyp/v8.gyp:v8_external_snapshot'],
+            }],
+            ['v8_use_snapshot!="true"', {
+              'dependencies': ['../../tools/gyp/v8.gyp:v8_nosnapshot'],
             }],
           ],
         }, {
@@ -294,7 +305,6 @@
             '../../tools/js2c.py',
             '<@(_outputs)',
             'TEST',  # type
-            'off',  # compression
             '<@(file_list)',
           ],
         }
diff --git a/test/cctest/cctest.h b/test/cctest/cctest.h
index 6d27074..a8239d2 100644
--- a/test/cctest/cctest.h
+++ b/test/cctest/cctest.h
@@ -117,7 +117,7 @@
 
   static v8::Isolate* isolate() {
     CHECK(isolate_ != NULL);
-    isolate_used_ = true;
+    v8::base::NoBarrier_Store(&isolate_used_, 1);
     return isolate_;
   }
 
@@ -149,7 +149,7 @@
   // TODO(dcarney): Remove.
   // This must be called first in a test.
   static void InitializeVM() {
-    CHECK(!isolate_used_);
+    CHECK(!v8::base::NoBarrier_Load(&isolate_used_));
     CHECK(!initialize_called_);
     initialize_called_ = true;
     v8::HandleScope handle_scope(CcTest::isolate());
@@ -181,7 +181,7 @@
   static CcTest* last_;
   static v8::Isolate* isolate_;
   static bool initialize_called_;
-  static bool isolate_used_;
+  static v8::base::Atomic32 isolate_used_;
 };
 
 // Switches between all the Api tests using the threading support.
@@ -481,15 +481,31 @@
 
 
 // Helper function that simulates a full new-space in the heap.
-static inline void SimulateFullSpace(v8::internal::NewSpace* space) {
-  int new_linear_size = static_cast<int>(
-      *space->allocation_limit_address() - *space->allocation_top_address());
-  if (new_linear_size == 0) return;
+static inline bool FillUpOnePage(v8::internal::NewSpace* space) {
   v8::internal::AllocationResult allocation =
-      space->AllocateRaw(new_linear_size);
+      space->AllocateRaw(v8::internal::Page::kMaxRegularHeapObjectSize);
+  if (allocation.IsRetry()) return false;
   v8::internal::FreeListNode* node =
       v8::internal::FreeListNode::cast(allocation.ToObjectChecked());
-  node->set_size(space->heap(), new_linear_size);
+  node->set_size(space->heap(), v8::internal::Page::kMaxRegularHeapObjectSize);
+  return true;
+}
+
+
+static inline void SimulateFullSpace(v8::internal::NewSpace* space) {
+  int new_linear_size = static_cast<int>(*space->allocation_limit_address() -
+                                         *space->allocation_top_address());
+  if (new_linear_size > 0) {
+    // Fill up the current page.
+    v8::internal::AllocationResult allocation =
+        space->AllocateRaw(new_linear_size);
+    v8::internal::FreeListNode* node =
+        v8::internal::FreeListNode::cast(allocation.ToObjectChecked());
+    node->set_size(space->heap(), new_linear_size);
+  }
+  // Fill up all remaining pages.
+  while (FillUpOnePage(space))
+    ;
 }
 
 
diff --git a/test/cctest/cctest.status b/test/cctest/cctest.status
index 5198af6..cc5414d 100644
--- a/test/cctest/cctest.status
+++ b/test/cctest/cctest.status
@@ -29,6 +29,7 @@
 [ALWAYS, {
   # All tests prefixed with 'Bug' are expected to fail.
   'test-api/Bug*': [FAIL],
+  'test-serialize/Bug*': [FAIL],
 
   ##############################################################################
 
@@ -80,58 +81,14 @@
   ##############################################################################
   # TurboFan compiler failures.
 
-  # TODO(sigurds): The schedule is borked with multiple inlinees,
-  # and cannot handle free-floating loops yet
-  'test-run-inlining/InlineTwiceDependentDiamond': [SKIP],
-  'test-run-inlining/InlineTwiceDependentDiamondDifferent': [SKIP],
-  'test-run-inlining/InlineLoop': [SKIP],
-
   # Some tests are just too slow to run for now.
   'test-api/Threading*': [PASS, NO_VARIANTS],
   'test-heap/IncrementalMarkingStepMakesBigProgressWithLargeObjects': [PASS, NO_VARIANTS],
   'test-heap-profiler/ManyLocalsInSharedContext': [PASS, NO_VARIANTS],
   'test-debug/ThreadedDebugging': [PASS, NO_VARIANTS],
   'test-debug/DebugBreakLoop': [PASS, NO_VARIANTS],
-
-  # Support for breakpoints requires using LoadICs and StoreICs.
-  'test-debug/BreakPointICStore': [PASS, NO_VARIANTS],
-  'test-debug/BreakPointICLoad': [PASS, NO_VARIANTS],
-  'test-debug/BreakPointICCall': [PASS, NO_VARIANTS],
-  'test-debug/BreakPointICCallWithGC': [PASS, NO_VARIANTS],
-  'test-debug/BreakPointConstructCallWithGC': [PASS, NO_VARIANTS],
-  'test-debug/BreakPointReturn': [PASS, NO_VARIANTS],
-  'test-debug/BreakPointThroughJavaScript': [PASS, NO_VARIANTS],
-  'test-debug/ScriptBreakPointByNameThroughJavaScript': [PASS, NO_VARIANTS],
-  'test-debug/ScriptBreakPointByIdThroughJavaScript': [PASS, NO_VARIANTS],
-  'test-debug/DebugStepLinear': [PASS, NO_VARIANTS],
-  'test-debug/DebugStepKeyedLoadLoop': [PASS, NO_VARIANTS],
-  'test-debug/DebugStepKeyedStoreLoop': [PASS, NO_VARIANTS],
-  'test-debug/DebugStepNamedLoadLoop': [PASS, NO_VARIANTS],
-  'test-debug/DebugStepNamedStoreLoop': [PASS, NO_VARIANTS],
-  'test-debug/DebugStepLinearMixedICs': [PASS, NO_VARIANTS],
-  'test-debug/DebugStepDeclarations': [PASS, NO_VARIANTS],
-  'test-debug/DebugStepLocals': [PASS, NO_VARIANTS],
-  'test-debug/DebugStepIf': [PASS, NO_VARIANTS],
-  'test-debug/DebugStepSwitch': [PASS, NO_VARIANTS],
-  'test-debug/DebugStepWhile': [PASS, NO_VARIANTS],
-  'test-debug/DebugStepDoWhile': [PASS, NO_VARIANTS],
-  'test-debug/DebugStepFor': [PASS, NO_VARIANTS],
-  'test-debug/DebugStepForContinue': [PASS, NO_VARIANTS],
-  'test-debug/DebugStepForBreak': [PASS, NO_VARIANTS],
-  'test-debug/DebugStepForIn': [PASS, NO_VARIANTS],
-  'test-debug/DebugStepWith': [PASS, NO_VARIANTS],
-  'test-debug/DebugConditional': [PASS, NO_VARIANTS],
-  'test-debug/StepInOutSimple': [PASS, NO_VARIANTS],
-  'test-debug/StepInOutTree': [PASS, NO_VARIANTS],
-  'test-debug/StepInOutBranch': [PASS, NO_VARIANTS],
-  'test-debug/DebugBreak': [PASS, NO_VARIANTS],
-  'test-debug/DebugBreakStackInspection': [PASS, NO_VARIANTS],
-  'test-debug/BreakMessageWhenMessageHandlerIsReset': [PASS, NO_VARIANTS],
-  'test-debug/NoDebugBreakInAfterCompileMessageHandler': [PASS, NO_VARIANTS],
-  'test-debug/DisableBreak': [PASS, NO_VARIANTS],
-  'test-debug/RegExpDebugBreak': [PASS, NO_VARIANTS],
-  'test-debug/DebugBreakFunctionApply': [PASS, NO_VARIANTS],
-  'test-debug/DeoptimizeDuringDebugBreak': [PASS, NO_VARIANTS],
+  # BUG(3742).
+  'test-mark-compact/MarkCompactCollector': [PASS, ['arch==arm', NO_VARIANTS]],
 
   # Support for %GetFrameDetails is missing and requires checkpoints.
   'test-api/Regress385349': [PASS, NO_VARIANTS],
@@ -148,6 +105,17 @@
   'test-debug/CallingContextIsNotDebugContext': [PASS, NO_VARIANTS],
   'test-debug/DebugEventContext': [PASS, NO_VARIANTS],
   'test-debug/DebugBreakInline': [PASS, NO_VARIANTS],
+  'test-debug/BreakMessageWhenMessageHandlerIsReset': [PASS, NO_VARIANTS],
+  'test-debug/DebugBreak': [PASS, NO_VARIANTS],
+  'test-debug/DebugBreakFunctionApply': [PASS, NO_VARIANTS],
+  'test-debug/DebugBreakStackInspection': [PASS, NO_VARIANTS],
+  'test-debug/DeoptimizeDuringDebugBreak': [PASS, NO_VARIANTS],
+  'test-debug/DisableBreak': [PASS, NO_VARIANTS],
+  'test-debug/NoDebugBreakInAfterCompileMessageHandler': [PASS, NO_VARIANTS],
+  'test-debug/RegExpDebugBreak': [PASS, NO_VARIANTS],
+
+  # TODO(titzer): Triggers bug in late control reduction.
+  'test-run-inlining/InlineLoopGuardedEmpty': [SKIP],
 
   ############################################################################
   # Slow tests.
@@ -298,6 +266,19 @@
 }],  # 'arch == mipsel or arch == mips'
 
 ##############################################################################
+['arch == mips', {
+  # Too slow with TF.
+  'test-api/ExternalArrays': [PASS, NO_VARIANTS],
+
+  # TODO(mips-team): Currently fails on mips board.
+  'test-simplified-lowering/RunNumberMultiply_TruncatingToUint32': [SKIP],
+  'test-parsing/TooManyArguments': [SKIP],
+  'test-api/Threading3': [SKIP],
+  'test-api/RequestInterruptTestWithNativeAccessor': [SKIP],
+  'test-api/RequestInterruptTestWithAccessor': [SKIP],
+}],  # 'arch == mips'
+
+##############################################################################
 ['arch == mips64el', {
 
   # BUG(2657): Test sometimes times out on MIPS simulator.
@@ -334,12 +315,6 @@
   'test-log/LogAccessorCallbacks': [SKIP],
   'test-log/LogCallbacks': [SKIP],
   'test-log/ProfLazyMode': [SKIP],
-
-  # platform-tls.h does not contain an ANDROID-related header.
-  'test-platform-tls/FastTLS': [SKIP],
-
-  # This test times out.
-  'test-threads/ThreadJoinSelf': [SKIP],
 }],  # 'arch == android_arm or arch == android_ia32'
 
 ##############################################################################
diff --git a/test/cctest/compiler/call-tester.h b/test/cctest/compiler/call-tester.h
index e864160..cad171e 100644
--- a/test/cctest/compiler/call-tester.h
+++ b/test/cctest/compiler/call-tester.h
@@ -207,7 +207,43 @@
         Simulator::CallArgument::End()};
     return ReturnValueTraits<R>::Cast(CallSimulator(FUNCTION_ADDR(f), args));
   }
-#elif USE_SIMULATOR && V8_TARGET_ARCH_ARM
+#elif USE_SIMULATOR && V8_TARGET_ARCH_MIPS64
+  uintptr_t CallSimulator(byte* f, int64_t p1 = 0, int64_t p2 = 0,
+                          int64_t p3 = 0, int64_t p4 = 0) {
+    Simulator* simulator = Simulator::current(isolate_);
+    return static_cast<uintptr_t>(simulator->Call(f, 4, p1, p2, p3, p4));
+  }
+
+  template <typename R, typename F>
+  R DoCall(F* f) {
+    return ReturnValueTraits<R>::Cast(CallSimulator(FUNCTION_ADDR(f)));
+  }
+  template <typename R, typename F, typename P1>
+  R DoCall(F* f, P1 p1) {
+    return ReturnValueTraits<R>::Cast(
+        CallSimulator(FUNCTION_ADDR(f), ParameterTraits<P1>::Cast(p1)));
+  }
+  template <typename R, typename F, typename P1, typename P2>
+  R DoCall(F* f, P1 p1, P2 p2) {
+    return ReturnValueTraits<R>::Cast(
+        CallSimulator(FUNCTION_ADDR(f), ParameterTraits<P1>::Cast(p1),
+                      ParameterTraits<P2>::Cast(p2)));
+  }
+  template <typename R, typename F, typename P1, typename P2, typename P3>
+  R DoCall(F* f, P1 p1, P2 p2, P3 p3) {
+    return ReturnValueTraits<R>::Cast(CallSimulator(
+        FUNCTION_ADDR(f), ParameterTraits<P1>::Cast(p1),
+        ParameterTraits<P2>::Cast(p2), ParameterTraits<P3>::Cast(p3)));
+  }
+  template <typename R, typename F, typename P1, typename P2, typename P3,
+            typename P4>
+  R DoCall(F* f, P1 p1, P2 p2, P3 p3, P4 p4) {
+    return ReturnValueTraits<R>::Cast(CallSimulator(
+        FUNCTION_ADDR(f), ParameterTraits<P1>::Cast(p1),
+        ParameterTraits<P2>::Cast(p2), ParameterTraits<P3>::Cast(p3),
+        ParameterTraits<P4>::Cast(p4)));
+  }
+#elif USE_SIMULATOR && (V8_TARGET_ARCH_ARM || V8_TARGET_ARCH_MIPS)
   uintptr_t CallSimulator(byte* f, int32_t p1 = 0, int32_t p2 = 0,
                           int32_t p3 = 0, int32_t p4 = 0) {
     Simulator* simulator = Simulator::current(isolate_);
diff --git a/test/cctest/compiler/codegen-tester.cc b/test/cctest/compiler/codegen-tester.cc
index b1874f5..5311001 100644
--- a/test/cctest/compiler/codegen-tester.cc
+++ b/test/cctest/compiler/codegen-tester.cc
@@ -14,7 +14,6 @@
 TEST(CompareWrapper) {
   // Who tests the testers?
   // If CompareWrapper is broken, then test expectations will be broken.
-  RawMachineAssemblerTester<int32_t> m;
   CompareWrapper wWord32Equal(IrOpcode::kWord32Equal);
   CompareWrapper wInt32LessThan(IrOpcode::kInt32LessThan);
   CompareWrapper wInt32LessThanOrEqual(IrOpcode::kInt32LessThanOrEqual);
@@ -477,10 +476,10 @@
 
 
 TEST(RunHeapNumberConstant) {
-  RawMachineAssemblerTester<Object*> m;
-  Handle<Object> number = m.isolate()->factory()->NewHeapNumber(100.5);
+  RawMachineAssemblerTester<HeapObject*> m;
+  Handle<HeapObject> number = m.isolate()->factory()->NewHeapNumber(100.5);
   m.Return(m.HeapConstant(number));
-  Object* result = m.Call();
+  HeapObject* result = m.Call();
   CHECK_EQ(result, *number);
 }
 
diff --git a/test/cctest/compiler/codegen-tester.h b/test/cctest/compiler/codegen-tester.h
index 6aa5bae..283d533 100644
--- a/test/cctest/compiler/codegen-tester.h
+++ b/test/cctest/compiler/codegen-tester.h
@@ -7,6 +7,7 @@
 
 #include "src/v8.h"
 
+#include "src/compiler/instruction-selector.h"
 #include "src/compiler/pipeline.h"
 #include "src/compiler/raw-machine-assembler.h"
 #include "src/simulator.h"
@@ -23,7 +24,9 @@
  public:
   MachineAssemblerTester(MachineType return_type, MachineType p0,
                          MachineType p1, MachineType p2, MachineType p3,
-                         MachineType p4)
+                         MachineType p4,
+                         MachineOperatorBuilder::Flags flags =
+                             MachineOperatorBuilder::Flag::kNoFlags)
       : HandleAndZoneScope(),
         CallHelper(
             main_isolate(),
@@ -31,7 +34,7 @@
         MachineAssembler(
             new (main_zone()) Graph(main_zone()),
             MakeMachineSignature(main_zone(), return_type, p0, p1, p2, p3, p4),
-            kMachPtr) {}
+            kMachPtr, flags) {}
 
   Node* LoadFromPointer(void* address, MachineType rep, int32_t offset = 0) {
     return this->Load(rep, this->PointerConstant(address),
@@ -65,10 +68,8 @@
       Schedule* schedule = this->Export();
       CallDescriptor* call_descriptor = this->call_descriptor();
       Graph* graph = this->graph();
-      CompilationInfo info(graph->zone()->isolate(), graph->zone());
-      Linkage linkage(&info, call_descriptor);
-      Pipeline pipeline(&info);
-      code_ = pipeline.GenerateCodeForMachineGraph(&linkage, graph, schedule);
+      code_ =
+          Pipeline::GenerateCodeForTesting(call_descriptor, graph, schedule);
     }
     return this->code_.ToHandleChecked()->entry();
   }
@@ -89,8 +90,8 @@
                             MachineType p3 = kMachNone,
                             MachineType p4 = kMachNone)
       : MachineAssemblerTester<RawMachineAssembler>(
-            ReturnValueTraits<ReturnType>::Representation(), p0, p1, p2, p3,
-            p4) {}
+            ReturnValueTraits<ReturnType>::Representation(), p0, p1, p2, p3, p4,
+            InstructionSelector::SupportedMachineOperatorFlags()) {}
 
   template <typename Ci, typename Fn>
   void Run(const Ci& ci, const Fn& fn) {
diff --git a/test/cctest/compiler/function-tester.h b/test/cctest/compiler/function-tester.h
index c869f00..7e16eea 100644
--- a/test/cctest/compiler/function-tester.h
+++ b/test/cctest/compiler/function-tester.h
@@ -8,7 +8,9 @@
 #include "src/v8.h"
 #include "test/cctest/cctest.h"
 
+#include "src/ast-numbering.h"
 #include "src/compiler.h"
+#include "src/compiler/linkage.h"
 #include "src/compiler/pipeline.h"
 #include "src/execution.h"
 #include "src/full-codegen.h"
@@ -37,52 +39,16 @@
     CHECK_EQ(0, flags_ & ~supported_flags);
   }
 
+  explicit FunctionTester(Graph* graph)
+      : isolate(main_isolate()),
+        function(NewFunction("(function(a,b){})")),
+        flags_(0) {
+    CompileGraph(graph);
+  }
+
   Isolate* isolate;
   Handle<JSFunction> function;
 
-  Handle<JSFunction> Compile(Handle<JSFunction> function) {
-#if V8_TURBOFAN_TARGET
-    CompilationInfoWithZone info(function);
-
-    CHECK(Parser::Parse(&info));
-    info.SetOptimizing(BailoutId::None(), Handle<Code>(function->code()));
-    if (flags_ & CompilationInfo::kContextSpecializing) {
-      info.MarkAsContextSpecializing();
-    }
-    if (flags_ & CompilationInfo::kInliningEnabled) {
-      info.MarkAsInliningEnabled();
-    }
-    if (flags_ & CompilationInfo::kTypingEnabled) {
-      info.MarkAsTypingEnabled();
-    }
-    CHECK(Rewriter::Rewrite(&info));
-    CHECK(Scope::Analyze(&info));
-    CHECK(Compiler::EnsureDeoptimizationSupport(&info));
-
-    Pipeline pipeline(&info);
-    Handle<Code> code = pipeline.GenerateCode();
-    if (FLAG_turbo_deoptimization) {
-      info.context()->native_context()->AddOptimizedCode(*code);
-    }
-
-    CHECK(!code.is_null());
-    function->ReplaceCode(*code);
-#elif USE_CRANKSHAFT
-    Handle<Code> unoptimized = Handle<Code>(function->code());
-    Handle<Code> code = Compiler::GetOptimizedCode(function, unoptimized,
-                                                   Compiler::NOT_CONCURRENT);
-    CHECK(!code.is_null());
-#if ENABLE_DISASSEMBLER
-    if (FLAG_print_opt_code) {
-      CodeTracer::Scope tracing_scope(isolate->GetCodeTracer());
-      code->Disassemble("test code", tracing_scope.file());
-    }
-#endif
-    function->ReplaceCode(*code);
-#endif
-    return function;
-  }
-
   MaybeHandle<Object> Call(Handle<Object> a, Handle<Object> b) {
     Handle<Object> args[] = {a, b};
     return Execution::Call(isolate, function, undefined(), 2, args, false);
@@ -183,8 +149,78 @@
 
   Handle<Object> false_value() { return isolate->factory()->false_value(); }
 
+  Handle<JSFunction> Compile(Handle<JSFunction> function) {
+// TODO(titzer): make this method private.
+#if V8_TURBOFAN_TARGET
+    CompilationInfoWithZone info(function);
+
+    CHECK(Parser::Parse(&info));
+    info.SetOptimizing(BailoutId::None(), Handle<Code>(function->code()));
+    if (flags_ & CompilationInfo::kContextSpecializing) {
+      info.MarkAsContextSpecializing();
+    }
+    if (flags_ & CompilationInfo::kInliningEnabled) {
+      info.MarkAsInliningEnabled();
+    }
+    if (flags_ & CompilationInfo::kTypingEnabled) {
+      info.MarkAsTypingEnabled();
+    }
+    CHECK(Compiler::Analyze(&info));
+    CHECK(Compiler::EnsureDeoptimizationSupport(&info));
+
+    Pipeline pipeline(&info);
+    Handle<Code> code = pipeline.GenerateCode();
+    if (FLAG_turbo_deoptimization) {
+      info.context()->native_context()->AddOptimizedCode(*code);
+    }
+
+    CHECK(!code.is_null());
+    function->ReplaceCode(*code);
+#elif USE_CRANKSHAFT
+    Handle<Code> unoptimized = Handle<Code>(function->code());
+    Handle<Code> code = Compiler::GetOptimizedCode(function, unoptimized,
+                                                   Compiler::NOT_CONCURRENT);
+    CHECK(!code.is_null());
+#if ENABLE_DISASSEMBLER
+    if (FLAG_print_opt_code) {
+      CodeTracer::Scope tracing_scope(isolate->GetCodeTracer());
+      code->Disassemble("test code", tracing_scope.file());
+    }
+#endif
+    function->ReplaceCode(*code);
+#endif
+    return function;
+  }
+
+  static Handle<JSFunction> ForMachineGraph(Graph* graph) {
+    JSFunction* p = NULL;
+    {  // because of the implicit handle scope of FunctionTester.
+      FunctionTester f(graph);
+      p = *f.function;
+    }
+    return Handle<JSFunction>(p);  // allocated in outer handle scope.
+  }
+
  private:
   uint32_t flags_;
+
+  // Compile the given machine graph instead of the source of the function
+  // and replace the JSFunction's code with the result.
+  Handle<JSFunction> CompileGraph(Graph* graph) {
+    CHECK(Pipeline::SupportedTarget());
+    CompilationInfoWithZone info(function);
+
+    CHECK(Parser::Parse(&info));
+    info.SetOptimizing(BailoutId::None(),
+                       Handle<Code>(function->shared()->code()));
+    CHECK(Compiler::Analyze(&info));
+    CHECK(Compiler::EnsureDeoptimizationSupport(&info));
+
+    Handle<Code> code = Pipeline::GenerateCodeForTesting(&info, graph);
+    CHECK(!code.is_null());
+    function->ReplaceCode(*code);
+    return function;
+  }
 };
 }
 }
diff --git a/test/cctest/compiler/graph-builder-tester.cc b/test/cctest/compiler/graph-builder-tester.cc
index bfa8226..b0f470b 100644
--- a/test/cctest/compiler/graph-builder-tester.cc
+++ b/test/cctest/compiler/graph-builder-tester.cc
@@ -35,11 +35,9 @@
   if (!Pipeline::SupportedBackend()) return NULL;
   if (code_.is_null()) {
     Zone* zone = graph_->zone();
-    CompilationInfo info(zone->isolate(), zone);
-    Linkage linkage(&info,
-                    Linkage::GetSimplifiedCDescriptor(zone, machine_sig_));
-    Pipeline pipeline(&info);
-    code_ = pipeline.GenerateCodeForMachineGraph(&linkage, graph_);
+    CallDescriptor* desc =
+        Linkage::GetSimplifiedCDescriptor(zone, machine_sig_);
+    code_ = Pipeline::GenerateCodeForTesting(desc, graph_);
   }
   return code_.ToHandleChecked()->entry();
 }
diff --git a/test/cctest/compiler/graph-builder-tester.h b/test/cctest/compiler/graph-builder-tester.h
index df79250..772de4d 100644
--- a/test/cctest/compiler/graph-builder-tester.h
+++ b/test/cctest/compiler/graph-builder-tester.h
@@ -27,8 +27,8 @@
 
  protected:
   virtual Node* MakeNode(const Operator* op, int value_input_count,
-                         Node** value_inputs) FINAL {
-    return graph()->NewNode(op, value_input_count, value_inputs);
+                         Node** value_inputs, bool incomplete) FINAL {
+    return graph()->NewNode(op, value_input_count, value_inputs, incomplete);
   }
 };
 
@@ -61,6 +61,7 @@
   explicit GraphAndBuilders(Zone* zone)
       : main_graph_(new (zone) Graph(zone)),
         main_common_(zone),
+        main_machine_(zone),
         main_simplified_(zone) {}
 
  protected:
diff --git a/test/cctest/compiler/simplified-graph-builder.cc b/test/cctest/compiler/simplified-graph-builder.cc
index c44d5ed..baa03fb 100644
--- a/test/cctest/compiler/simplified-graph-builder.cc
+++ b/test/cctest/compiler/simplified-graph-builder.cc
@@ -5,7 +5,6 @@
 #include "test/cctest/compiler/simplified-graph-builder.h"
 
 #include "src/compiler/operator-properties.h"
-#include "src/compiler/operator-properties-inl.h"
 
 namespace v8 {
 namespace internal {
@@ -45,20 +44,20 @@
 
 Node* SimplifiedGraphBuilder::MakeNode(const Operator* op,
                                        int value_input_count,
-                                       Node** value_inputs) {
-  DCHECK(op->InputCount() == value_input_count);
+                                       Node** value_inputs, bool incomplete) {
+  DCHECK(op->ValueInputCount() == value_input_count);
 
   DCHECK(!OperatorProperties::HasContextInput(op));
   DCHECK(!OperatorProperties::HasFrameStateInput(op));
-  bool has_control = OperatorProperties::GetControlInputCount(op) == 1;
-  bool has_effect = OperatorProperties::GetEffectInputCount(op) == 1;
+  bool has_control = op->ControlInputCount() == 1;
+  bool has_effect = op->EffectInputCount() == 1;
 
-  DCHECK(OperatorProperties::GetControlInputCount(op) < 2);
-  DCHECK(OperatorProperties::GetEffectInputCount(op) < 2);
+  DCHECK(op->ControlInputCount() < 2);
+  DCHECK(op->EffectInputCount() < 2);
 
   Node* result = NULL;
   if (!has_control && !has_effect) {
-    result = graph()->NewNode(op, value_input_count, value_inputs);
+    result = graph()->NewNode(op, value_input_count, value_inputs, incomplete);
   } else {
     int input_count_with_deps = value_input_count;
     if (has_control) ++input_count_with_deps;
@@ -72,14 +71,12 @@
     if (has_control) {
       *current_input++ = graph()->start();
     }
-    result = graph()->NewNode(op, input_count_with_deps, buffer);
+    result = graph()->NewNode(op, input_count_with_deps, buffer, incomplete);
     if (has_effect) {
       effect_ = result;
     }
-    if (OperatorProperties::HasControlOutput(result->op())) {
-      // This graph builder does not support control flow.
-      UNREACHABLE();
-    }
+    // This graph builder does not support control flow.
+    CHECK_EQ(0, op->ControlOutputCount());
   }
 
   return result;
diff --git a/test/cctest/compiler/simplified-graph-builder.h b/test/cctest/compiler/simplified-graph-builder.h
index 1b637b7..537094a 100644
--- a/test/cctest/compiler/simplified-graph-builder.h
+++ b/test/cctest/compiler/simplified-graph-builder.h
@@ -45,8 +45,8 @@
   Node* Int32Constant(int32_t value) {
     return NewNode(common()->Int32Constant(value));
   }
-  Node* HeapConstant(Handle<Object> object) {
-    Unique<Object> val = Unique<Object>::CreateUninitialized(object);
+  Node* HeapConstant(Handle<HeapObject> object) {
+    Unique<HeapObject> val = Unique<HeapObject>::CreateUninitialized(object);
     return NewNode(common()->HeapConstant(val));
   }
 
@@ -127,19 +127,17 @@
   Node* StoreField(const FieldAccess& access, Node* object, Node* value) {
     return NewNode(simplified()->StoreField(access), object, value);
   }
-  Node* LoadElement(const ElementAccess& access, Node* object, Node* index,
-                    Node* length) {
-    return NewNode(simplified()->LoadElement(access), object, index, length);
+  Node* LoadElement(const ElementAccess& access, Node* object, Node* index) {
+    return NewNode(simplified()->LoadElement(access), object, index);
   }
   Node* StoreElement(const ElementAccess& access, Node* object, Node* index,
-                     Node* length, Node* value) {
-    return NewNode(simplified()->StoreElement(access), object, index, length,
-                   value);
+                     Node* value) {
+    return NewNode(simplified()->StoreElement(access), object, index, value);
   }
 
  protected:
   virtual Node* MakeNode(const Operator* op, int value_input_count,
-                         Node** value_inputs) FINAL;
+                         Node** value_inputs, bool incomplete) FINAL;
 
  private:
   Node* effect_;
diff --git a/test/cctest/compiler/test-basic-block-profiler.cc b/test/cctest/compiler/test-basic-block-profiler.cc
new file mode 100644
index 0000000..703fc17
--- /dev/null
+++ b/test/cctest/compiler/test-basic-block-profiler.cc
@@ -0,0 +1,114 @@
+// 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.
+
+#include "src/v8.h"
+
+#include "src/basic-block-profiler.h"
+#include "test/cctest/cctest.h"
+#include "test/cctest/compiler/codegen-tester.h"
+
+#if V8_TURBOFAN_TARGET
+
+using namespace v8::internal;
+using namespace v8::internal::compiler;
+
+typedef RawMachineAssembler::Label MLabel;
+
+class BasicBlockProfilerTest : public RawMachineAssemblerTester<int32_t> {
+ public:
+  BasicBlockProfilerTest() : RawMachineAssemblerTester<int32_t>(kMachInt32) {
+    FLAG_turbo_profiling = true;
+  }
+
+  void ResetCounts() { isolate()->basic_block_profiler()->ResetCounts(); }
+
+  void Expect(size_t size, uint32_t* expected) {
+    CHECK_NE(NULL, isolate()->basic_block_profiler());
+    const BasicBlockProfiler::DataList* l =
+        isolate()->basic_block_profiler()->data_list();
+    CHECK_NE(0, static_cast<int>(l->size()));
+    const BasicBlockProfiler::Data* data = l->back();
+    CHECK_EQ(static_cast<int>(size), static_cast<int>(data->n_blocks()));
+    const uint32_t* counts = data->counts();
+    for (size_t i = 0; i < size; ++i) {
+      CHECK_EQ(static_cast<int>(expected[i]), static_cast<int>(counts[i]));
+    }
+  }
+};
+
+
+TEST(ProfileDiamond) {
+  BasicBlockProfilerTest m;
+
+  MLabel blocka, blockb, end;
+  m.Branch(m.Parameter(0), &blocka, &blockb);
+  m.Bind(&blocka);
+  m.Goto(&end);
+  m.Bind(&blockb);
+  m.Goto(&end);
+  m.Bind(&end);
+  m.Return(m.Int32Constant(0));
+
+  m.GenerateCode();
+  {
+    uint32_t expected[] = {0, 0, 0, 0};
+    m.Expect(arraysize(expected), expected);
+  }
+
+  m.Call(0);
+  {
+    uint32_t expected[] = {1, 1, 0, 1};
+    m.Expect(arraysize(expected), expected);
+  }
+
+  m.ResetCounts();
+
+  m.Call(1);
+  {
+    uint32_t expected[] = {1, 0, 1, 1};
+    m.Expect(arraysize(expected), expected);
+  }
+
+  m.Call(0);
+  {
+    uint32_t expected[] = {2, 1, 1, 2};
+    m.Expect(arraysize(expected), expected);
+  }
+}
+
+
+TEST(ProfileLoop) {
+  BasicBlockProfilerTest m;
+
+  MLabel header, body, end;
+  Node* one = m.Int32Constant(1);
+  m.Goto(&header);
+
+  m.Bind(&header);
+  Node* count = m.Phi(kMachInt32, m.Parameter(0), one);
+  m.Branch(count, &body, &end);
+
+  m.Bind(&body);
+  count->ReplaceInput(1, m.Int32Sub(count, one));
+  m.Goto(&header);
+
+  m.Bind(&end);
+  m.Return(one);
+
+  m.GenerateCode();
+  {
+    uint32_t expected[] = {0, 0, 0, 0};
+    m.Expect(arraysize(expected), expected);
+  }
+
+  uint32_t runs[] = {0, 1, 500, 10000};
+  for (size_t i = 0; i < arraysize(runs); i++) {
+    m.ResetCounts();
+    CHECK_EQ(1, m.Call(static_cast<int>(runs[i])));
+    uint32_t expected[] = {1, runs[i] + 1, runs[i], 1};
+    m.Expect(arraysize(expected), expected);
+  }
+}
+
+#endif  // V8_TURBOFAN_TARGET
diff --git a/test/cctest/compiler/test-changes-lowering.cc b/test/cctest/compiler/test-changes-lowering.cc
index 06308a0..5795754 100644
--- a/test/cctest/compiler/test-changes-lowering.cc
+++ b/test/cctest/compiler/test-changes-lowering.cc
@@ -6,10 +6,11 @@
 
 #include "src/compiler/change-lowering.h"
 #include "src/compiler/control-builders.h"
-#include "src/compiler/generic-node-inl.h"
 #include "src/compiler/js-graph.h"
 #include "src/compiler/node-properties-inl.h"
 #include "src/compiler/pipeline.h"
+#include "src/compiler/select-lowering.h"
+#include "src/compiler/simplified-lowering.h"
 #include "src/compiler/typer.h"
 #include "src/compiler/verifier.h"
 #include "src/execution.h"
@@ -19,6 +20,7 @@
 #include "src/scopes.h"
 #include "test/cctest/cctest.h"
 #include "test/cctest/compiler/codegen-tester.h"
+#include "test/cctest/compiler/function-tester.h"
 #include "test/cctest/compiler/graph-builder-tester.h"
 #include "test/cctest/compiler/value-helper.h"
 
@@ -30,13 +32,10 @@
  public:
   explicit ChangesLoweringTester(MachineType p0 = kMachNone)
       : GraphBuilderTester<ReturnType>(p0),
-        typer(this->zone()),
         javascript(this->zone()),
-        jsgraph(this->graph(), this->common(), &javascript, &typer,
-                this->machine()),
+        jsgraph(this->graph(), this->common(), &javascript, this->machine()),
         function(Handle<JSFunction>::null()) {}
 
-  Typer typer;
   JSOperatorBuilder javascript;
   JSGraph jsgraph;
   Handle<JSFunction> function;
@@ -45,29 +44,10 @@
 
   template <typename T>
   T* CallWithPotentialGC() {
-    // TODO(titzer): we need to wrap the code in a JSFunction and call it via
-    // Execution::Call() so that the GC knows about the frame, can walk it,
-    // relocate the code object if necessary, etc.
-    // This is pretty ugly and at the least should be moved up to helpers.
+    // TODO(titzer): we wrap the code in a JSFunction here to reuse the
+    // JSEntryStub; that could be done with a special prologue or other stub.
     if (function.is_null()) {
-      function =
-          v8::Utils::OpenHandle(*v8::Handle<v8::Function>::Cast(CompileRun(
-              "(function() { 'use strict'; return 2.7123; })")));
-      CompilationInfoWithZone info(function);
-      CHECK(Parser::Parse(&info));
-      info.SetOptimizing(BailoutId::None(), Handle<Code>(function->code()));
-      CHECK(Rewriter::Rewrite(&info));
-      CHECK(Scope::Analyze(&info));
-      CHECK_NE(NULL, info.scope());
-      Handle<ScopeInfo> scope_info =
-          ScopeInfo::Create(info.scope(), info.zone());
-      info.shared_info()->set_scope_info(*scope_info);
-      Pipeline pipeline(&info);
-      Linkage linkage(&info);
-      Handle<Code> code =
-          pipeline.GenerateCodeForMachineGraph(&linkage, this->graph());
-      CHECK(!code.is_null());
-      function->ReplaceCode(*code);
+      function = FunctionTester::ForMachineGraph(this->graph());
     }
     Handle<Object>* args = NULL;
     MaybeHandle<Object> result =
@@ -132,9 +112,9 @@
                          void* location) {
     // We build a graph by hand here, because the raw machine assembler
     // does not add the correct control and effect nodes.
-    Node* load =
-        this->graph()->NewNode(load_op, this->PointerConstant(location),
-                               this->Int32Constant(0), this->start());
+    Node* load = this->graph()->NewNode(
+        load_op, this->PointerConstant(location), this->Int32Constant(0),
+        this->start(), this->start());
     Node* change = this->graph()->NewNode(op, load);
     Node* ret = this->graph()->NewNode(this->common()->Return(), change,
                                        this->start(), this->start());
@@ -146,12 +126,16 @@
   void LowerChange(Node* change) {
     // Run the graph reducer with changes lowering on a single node.
     CompilationInfo info(this->isolate(), this->zone());
-    Linkage linkage(&info);
-    ChangeLowering lowering(&jsgraph, &linkage);
-    GraphReducer reducer(this->graph());
-    reducer.AddReducer(&lowering);
+    Linkage linkage(this->zone(), &info);
+    Typer typer(this->graph(), info.context());
+    typer.Run();
+    ChangeLowering change_lowering(&jsgraph, &linkage);
+    SelectLowering select_lowering(this->graph(), this->common());
+    GraphReducer reducer(this->graph(), this->zone());
+    reducer.AddReducer(&change_lowering);
+    reducer.AddReducer(&select_lowering);
     reducer.ReduceNode(change);
-    Verifier::Run(this->graph());
+    Verifier::Run(this->graph(), Verifier::UNTYPED);
   }
 
   Factory* factory() { return this->isolate()->factory(); }
diff --git a/test/cctest/compiler/test-codegen-deopt.cc b/test/cctest/compiler/test-codegen-deopt.cc
index 8217229..56afe7b 100644
--- a/test/cctest/compiler/test-codegen-deopt.cc
+++ b/test/cctest/compiler/test-codegen-deopt.cc
@@ -16,6 +16,7 @@
 #include "src/compiler/register-allocator.h"
 #include "src/compiler/schedule.h"
 
+#include "src/ast-numbering.h"
 #include "src/full-codegen.h"
 #include "src/parser.h"
 #include "src/rewriter.h"
@@ -30,6 +31,7 @@
 #if V8_TURBOFAN_TARGET
 
 typedef RawMachineAssembler::Label MLabel;
+typedef v8::internal::compiler::InstructionSequence TestInstrSeq;
 
 static Handle<JSFunction> NewFunction(const char* source) {
   return v8::Utils::OpenHandle(
@@ -46,8 +48,7 @@
         bailout_id(-1) {
     CHECK(Parser::Parse(&info));
     info.SetOptimizing(BailoutId::None(), Handle<Code>(function->code()));
-    CHECK(Rewriter::Rewrite(&info));
-    CHECK(Scope::Analyze(&info));
+    CHECK(Compiler::Analyze(&info));
     CHECK(Compiler::EnsureDeoptimizationSupport(&info));
 
     DCHECK(info.shared_info()->has_deoptimization_support());
@@ -55,38 +56,14 @@
     graph = new (scope_->main_zone()) Graph(scope_->main_zone());
   }
 
-  virtual ~DeoptCodegenTester() { delete code; }
+  virtual ~DeoptCodegenTester() {}
 
   void GenerateCodeFromSchedule(Schedule* schedule) {
     OFStream os(stdout);
     if (FLAG_trace_turbo) {
       os << *schedule;
     }
-
-    // Initialize the codegen and generate code.
-    Linkage* linkage = new (scope_->main_zone()) Linkage(&info);
-    code = new v8::internal::compiler::InstructionSequence(linkage, graph,
-                                                           schedule);
-    SourcePositionTable source_positions(graph);
-    InstructionSelector selector(code, &source_positions);
-    selector.SelectInstructions();
-
-    if (FLAG_trace_turbo) {
-      os << "----- Instruction sequence before register allocation -----\n"
-         << *code;
-    }
-
-    RegisterAllocator allocator(code);
-    CHECK(allocator.Allocate());
-
-    if (FLAG_trace_turbo) {
-      os << "----- Instruction sequence after register allocation -----\n"
-         << *code;
-    }
-
-    compiler::CodeGenerator generator(code);
-    result_code = generator.GenerateCode();
-
+    result_code = Pipeline::GenerateCodeForTesting(&info, graph, schedule);
 #ifdef OBJECT_PRINT
     if (FLAG_print_opt_code || FLAG_trace_turbo) {
       result_code->Print();
@@ -101,7 +78,7 @@
   CompilationInfo info;
   BailoutId bailout_id;
   Handle<Code> result_code;
-  v8::internal::compiler::InstructionSequence* code;
+  TestInstrSeq* code;
   Graph* graph;
 };
 
@@ -129,13 +106,13 @@
 
     Handle<JSFunction> deopt_function =
         NewFunction("function deopt() { %DeoptimizeFunction(foo); }; deopt");
-    Unique<Object> deopt_fun_constant =
-        Unique<Object>::CreateUninitialized(deopt_function);
+    Unique<JSFunction> deopt_fun_constant =
+        Unique<JSFunction>::CreateUninitialized(deopt_function);
     Node* deopt_fun_node = m.NewNode(common.HeapConstant(deopt_fun_constant));
 
     Handle<Context> caller_context(function->context(), CcTest::i_isolate());
-    Unique<Object> caller_context_constant =
-        Unique<Object>::CreateUninitialized(caller_context);
+    Unique<Context> caller_context_constant =
+        Unique<Context>::CreateUninitialized(caller_context);
     Node* caller_context_node =
         m.NewNode(common.HeapConstant(caller_context_constant));
 
@@ -145,12 +122,13 @@
     Node* stack = m.NewNode(common.StateValues(0));
 
     Node* state_node = m.NewNode(
-        common.FrameState(JS_FRAME, bailout_id, kIgnoreOutput), parameters,
-        locals, stack, caller_context_node, m.UndefinedConstant());
+        common.FrameState(JS_FRAME, bailout_id,
+                          OutputFrameStateCombine::Ignore()),
+        parameters, locals, stack, caller_context_node, m.UndefinedConstant());
 
     Handle<Context> context(deopt_function->context(), CcTest::i_isolate());
-    Unique<Object> context_constant =
-        Unique<Object>::CreateUninitialized(context);
+    Unique<Context> context_constant =
+        Unique<Context>::CreateUninitialized(context);
     Node* context_node = m.NewNode(common.HeapConstant(context_constant));
 
     m.CallJS0(deopt_fun_node, m.UndefinedConstant(), context_node, state_node);
@@ -244,13 +222,13 @@
     CSignature1<Object*, Object*> sig;
     RawMachineAssembler m(graph, &sig);
 
-    Unique<Object> this_fun_constant =
-        Unique<Object>::CreateUninitialized(function);
+    Unique<HeapObject> this_fun_constant =
+        Unique<HeapObject>::CreateUninitialized(function);
     Node* this_fun_node = m.NewNode(common.HeapConstant(this_fun_constant));
 
     Handle<Context> context(function->context(), CcTest::i_isolate());
-    Unique<Object> context_constant =
-        Unique<Object>::CreateUninitialized(context);
+    Unique<HeapObject> context_constant =
+        Unique<HeapObject>::CreateUninitialized(context);
     Node* context_node = m.NewNode(common.HeapConstant(context_constant));
 
     bailout_id = GetCallBailoutId();
@@ -259,8 +237,9 @@
     Node* stack = m.NewNode(common.StateValues(0));
 
     Node* state_node = m.NewNode(
-        common.FrameState(JS_FRAME, bailout_id, kIgnoreOutput), parameters,
-        locals, stack, context_node, m.UndefinedConstant());
+        common.FrameState(JS_FRAME, bailout_id,
+                          OutputFrameStateCombine::Ignore()),
+        parameters, locals, stack, context_node, m.UndefinedConstant());
 
     m.CallRuntime1(Runtime::kDeoptimizeFunction, this_fun_node, context_node,
                    state_node);
diff --git a/test/cctest/compiler/test-control-reducer.cc b/test/cctest/compiler/test-control-reducer.cc
new file mode 100644
index 0000000..03aa50b
--- /dev/null
+++ b/test/cctest/compiler/test-control-reducer.cc
@@ -0,0 +1,1678 @@
+// 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.
+
+#include "src/v8.h"
+#include "test/cctest/cctest.h"
+
+#include "src/base/bits.h"
+#include "src/compiler/common-operator.h"
+#include "src/compiler/control-reducer.h"
+#include "src/compiler/graph-inl.h"
+#include "src/compiler/js-graph.h"
+#include "src/compiler/node-properties-inl.h"
+
+using namespace v8::internal;
+using namespace v8::internal::compiler;
+
+static const size_t kNumLeafs = 4;
+
+// TODO(titzer): convert this whole file into unit tests.
+
+static int CheckInputs(Node* node, Node* i0 = NULL, Node* i1 = NULL,
+                       Node* i2 = NULL) {
+  int count = 3;
+  if (i2 == NULL) count = 2;
+  if (i1 == NULL) count = 1;
+  if (i0 == NULL) count = 0;
+  CHECK_EQ(count, node->InputCount());
+  if (i0 != NULL) CHECK_EQ(i0, node->InputAt(0));
+  if (i1 != NULL) CHECK_EQ(i1, node->InputAt(1));
+  if (i2 != NULL) CHECK_EQ(i2, node->InputAt(2));
+  return count;
+}
+
+
+static int CheckMerge(Node* node, Node* i0 = NULL, Node* i1 = NULL,
+                      Node* i2 = NULL) {
+  CHECK_EQ(IrOpcode::kMerge, node->opcode());
+  int count = CheckInputs(node, i0, i1, i2);
+  CHECK_EQ(count, node->op()->ControlInputCount());
+  return count;
+}
+
+
+static int CheckLoop(Node* node, Node* i0 = NULL, Node* i1 = NULL,
+                     Node* i2 = NULL) {
+  CHECK_EQ(IrOpcode::kLoop, node->opcode());
+  int count = CheckInputs(node, i0, i1, i2);
+  CHECK_EQ(count, node->op()->ControlInputCount());
+  return count;
+}
+
+
+bool IsUsedBy(Node* a, Node* b) {
+  for (UseIter i = a->uses().begin(); i != a->uses().end(); ++i) {
+    if (b == *i) return true;
+  }
+  return false;
+}
+
+
+// A helper for all tests dealing with ControlTester.
+class ControlReducerTester : HandleAndZoneScope {
+ public:
+  ControlReducerTester()
+      : isolate(main_isolate()),
+        common(main_zone()),
+        graph(main_zone()),
+        jsgraph(&graph, &common, NULL, NULL),
+        start(graph.NewNode(common.Start(1))),
+        end(graph.NewNode(common.End(), start)),
+        p0(graph.NewNode(common.Parameter(0), start)),
+        zero(jsgraph.Int32Constant(0)),
+        one(jsgraph.OneConstant()),
+        half(jsgraph.Constant(0.5)),
+        self(graph.NewNode(common.Int32Constant(0xaabbccdd))),
+        dead(graph.NewNode(common.Dead())) {
+    graph.SetEnd(end);
+    graph.SetStart(start);
+    leaf[0] = zero;
+    leaf[1] = one;
+    leaf[2] = half;
+    leaf[3] = p0;
+  }
+
+  Isolate* isolate;
+  CommonOperatorBuilder common;
+  Graph graph;
+  JSGraph jsgraph;
+  Node* start;
+  Node* end;
+  Node* p0;
+  Node* zero;
+  Node* one;
+  Node* half;
+  Node* self;
+  Node* dead;
+  Node* leaf[kNumLeafs];
+
+  Node* Phi(Node* a) {
+    return SetSelfReferences(graph.NewNode(op(1, false), a, start));
+  }
+
+  Node* Phi(Node* a, Node* b) {
+    return SetSelfReferences(graph.NewNode(op(2, false), a, b, start));
+  }
+
+  Node* Phi(Node* a, Node* b, Node* c) {
+    return SetSelfReferences(graph.NewNode(op(3, false), a, b, c, start));
+  }
+
+  Node* Phi(Node* a, Node* b, Node* c, Node* d) {
+    return SetSelfReferences(graph.NewNode(op(4, false), a, b, c, d, start));
+  }
+
+  Node* EffectPhi(Node* a) {
+    return SetSelfReferences(graph.NewNode(op(1, true), a, start));
+  }
+
+  Node* EffectPhi(Node* a, Node* b) {
+    return SetSelfReferences(graph.NewNode(op(2, true), a, b, start));
+  }
+
+  Node* EffectPhi(Node* a, Node* b, Node* c) {
+    return SetSelfReferences(graph.NewNode(op(3, true), a, b, c, start));
+  }
+
+  Node* EffectPhi(Node* a, Node* b, Node* c, Node* d) {
+    return SetSelfReferences(graph.NewNode(op(4, true), a, b, c, d, start));
+  }
+
+  Node* SetSelfReferences(Node* node) {
+    for (Edge edge : node->input_edges()) {
+      if (edge.to() == self) node->ReplaceInput(edge.index(), node);
+    }
+    return node;
+  }
+
+  const Operator* op(int count, bool effect) {
+    return effect ? common.EffectPhi(count) : common.Phi(kMachAnyTagged, count);
+  }
+
+  void Trim() { ControlReducer::TrimGraph(main_zone(), &jsgraph); }
+
+  void ReduceGraph() {
+    ControlReducer::ReduceGraph(main_zone(), &jsgraph, &common);
+  }
+
+  // Checks one-step reduction of a phi.
+  void ReducePhi(Node* expect, Node* phi) {
+    Node* result = ControlReducer::ReducePhiForTesting(&jsgraph, &common, phi);
+    CHECK_EQ(expect, result);
+    ReducePhiIterative(expect, phi);  // iterative should give the same result.
+  }
+
+  void ReducePhiIterative(Node* expect, Node* phi) {
+    p0->ReplaceInput(0, start);  // hack: parameters may be trimmed.
+    Node* ret = graph.NewNode(common.Return(), phi, start, start);
+    Node* end = graph.NewNode(common.End(), ret);
+    graph.SetEnd(end);
+    ControlReducer::ReduceGraph(main_zone(), &jsgraph, &common);
+    CheckInputs(end, ret);
+    CheckInputs(ret, expect, start, start);
+  }
+
+  void ReduceMerge(Node* expect, Node* merge) {
+    Node* result =
+        ControlReducer::ReduceMergeForTesting(&jsgraph, &common, merge);
+    CHECK_EQ(expect, result);
+  }
+
+  void ReduceMergeIterative(Node* expect, Node* merge) {
+    p0->ReplaceInput(0, start);  // hack: parameters may be trimmed.
+    Node* end = graph.NewNode(common.End(), merge);
+    graph.SetEnd(end);
+    ReduceGraph();
+    CheckInputs(end, expect);
+  }
+
+  void ReduceBranch(Node* expect, Node* branch) {
+    Node* result =
+        ControlReducer::ReduceBranchForTesting(&jsgraph, &common, branch);
+    CHECK_EQ(expect, result);
+  }
+
+  Node* Return(Node* val, Node* effect, Node* control) {
+    Node* ret = graph.NewNode(common.Return(), val, effect, control);
+    end->ReplaceInput(0, ret);
+    return ret;
+  }
+};
+
+
+TEST(Trim1_live) {
+  ControlReducerTester T;
+  CHECK(IsUsedBy(T.start, T.p0));
+  T.graph.SetEnd(T.p0);
+  T.Trim();
+  CHECK(IsUsedBy(T.start, T.p0));
+  CheckInputs(T.p0, T.start);
+}
+
+
+TEST(Trim1_dead) {
+  ControlReducerTester T;
+  CHECK(IsUsedBy(T.start, T.p0));
+  T.Trim();
+  CHECK(!IsUsedBy(T.start, T.p0));
+  CHECK_EQ(NULL, T.p0->InputAt(0));
+}
+
+
+TEST(Trim2_live) {
+  ControlReducerTester T;
+  Node* phi =
+      T.graph.NewNode(T.common.Phi(kMachAnyTagged, 2), T.one, T.half, T.start);
+  CHECK(IsUsedBy(T.one, phi));
+  CHECK(IsUsedBy(T.half, phi));
+  CHECK(IsUsedBy(T.start, phi));
+  T.graph.SetEnd(phi);
+  T.Trim();
+  CHECK(IsUsedBy(T.one, phi));
+  CHECK(IsUsedBy(T.half, phi));
+  CHECK(IsUsedBy(T.start, phi));
+  CheckInputs(phi, T.one, T.half, T.start);
+}
+
+
+TEST(Trim2_dead) {
+  ControlReducerTester T;
+  Node* phi =
+      T.graph.NewNode(T.common.Phi(kMachAnyTagged, 2), T.one, T.half, T.start);
+  CHECK(IsUsedBy(T.one, phi));
+  CHECK(IsUsedBy(T.half, phi));
+  CHECK(IsUsedBy(T.start, phi));
+  T.Trim();
+  CHECK(!IsUsedBy(T.one, phi));
+  CHECK(!IsUsedBy(T.half, phi));
+  CHECK(!IsUsedBy(T.start, phi));
+  CHECK_EQ(NULL, phi->InputAt(0));
+  CHECK_EQ(NULL, phi->InputAt(1));
+  CHECK_EQ(NULL, phi->InputAt(2));
+}
+
+
+TEST(Trim_chain1) {
+  ControlReducerTester T;
+  const int kDepth = 15;
+  Node* live[kDepth];
+  Node* dead[kDepth];
+  Node* end = T.start;
+  for (int i = 0; i < kDepth; i++) {
+    live[i] = end = T.graph.NewNode(T.common.Merge(1), end);
+    dead[i] = T.graph.NewNode(T.common.Merge(1), end);
+  }
+  // end         -> live[last] ->  live[last-1] -> ... -> start
+  //     dead[last] ^ dead[last-1] ^ ...                  ^
+  T.graph.SetEnd(end);
+  T.Trim();
+  for (int i = 0; i < kDepth; i++) {
+    CHECK(!IsUsedBy(live[i], dead[i]));
+    CHECK_EQ(NULL, dead[i]->InputAt(0));
+    CHECK_EQ(i == 0 ? T.start : live[i - 1], live[i]->InputAt(0));
+  }
+}
+
+
+TEST(Trim_chain2) {
+  ControlReducerTester T;
+  const int kDepth = 15;
+  Node* live[kDepth];
+  Node* dead[kDepth];
+  Node* l = T.start;
+  Node* d = T.start;
+  for (int i = 0; i < kDepth; i++) {
+    live[i] = l = T.graph.NewNode(T.common.Merge(1), l);
+    dead[i] = d = T.graph.NewNode(T.common.Merge(1), d);
+  }
+  // end -> live[last] -> live[last-1] -> ... -> start
+  //        dead[last] -> dead[last-1] -> ... -> start
+  T.graph.SetEnd(l);
+  T.Trim();
+  CHECK(!IsUsedBy(T.start, dead[0]));
+  for (int i = 0; i < kDepth; i++) {
+    CHECK_EQ(i == 0 ? NULL : dead[i - 1], dead[i]->InputAt(0));
+    CHECK_EQ(i == 0 ? T.start : live[i - 1], live[i]->InputAt(0));
+  }
+}
+
+
+TEST(Trim_cycle1) {
+  ControlReducerTester T;
+  Node* loop = T.graph.NewNode(T.common.Loop(1), T.start, T.start);
+  loop->ReplaceInput(1, loop);
+  Node* end = T.graph.NewNode(T.common.End(), loop);
+  T.graph.SetEnd(end);
+
+  CHECK(IsUsedBy(T.start, loop));
+  CHECK(IsUsedBy(loop, end));
+  CHECK(IsUsedBy(loop, loop));
+
+  T.Trim();
+
+  // nothing should have happened to the loop itself.
+  CHECK(IsUsedBy(T.start, loop));
+  CHECK(IsUsedBy(loop, end));
+  CHECK(IsUsedBy(loop, loop));
+  CheckInputs(loop, T.start, loop);
+  CheckInputs(end, loop);
+}
+
+
+TEST(Trim_cycle2) {
+  ControlReducerTester T;
+  Node* loop = T.graph.NewNode(T.common.Loop(2), T.start, T.start);
+  loop->ReplaceInput(1, loop);
+  Node* end = T.graph.NewNode(T.common.End(), loop);
+  Node* phi =
+      T.graph.NewNode(T.common.Phi(kMachAnyTagged, 2), T.one, T.half, loop);
+  T.graph.SetEnd(end);
+
+  CHECK(IsUsedBy(T.start, loop));
+  CHECK(IsUsedBy(loop, end));
+  CHECK(IsUsedBy(loop, loop));
+  CHECK(IsUsedBy(loop, phi));
+  CHECK(IsUsedBy(T.one, phi));
+  CHECK(IsUsedBy(T.half, phi));
+
+  T.Trim();
+
+  // nothing should have happened to the loop itself.
+  CHECK(IsUsedBy(T.start, loop));
+  CHECK(IsUsedBy(loop, end));
+  CHECK(IsUsedBy(loop, loop));
+  CheckInputs(loop, T.start, loop);
+  CheckInputs(end, loop);
+
+  // phi should have been trimmed away.
+  CHECK(!IsUsedBy(loop, phi));
+  CHECK(!IsUsedBy(T.one, phi));
+  CHECK(!IsUsedBy(T.half, phi));
+  CHECK_EQ(NULL, phi->InputAt(0));
+  CHECK_EQ(NULL, phi->InputAt(1));
+  CHECK_EQ(NULL, phi->InputAt(2));
+}
+
+
+void CheckTrimConstant(ControlReducerTester* T, Node* k) {
+  Node* phi = T->graph.NewNode(T->common.Phi(kMachInt32, 1), k, T->start);
+  CHECK(IsUsedBy(k, phi));
+  T->Trim();
+  CHECK(!IsUsedBy(k, phi));
+  CHECK_EQ(NULL, phi->InputAt(0));
+  CHECK_EQ(NULL, phi->InputAt(1));
+}
+
+
+TEST(Trim_constants) {
+  ControlReducerTester T;
+  int32_t int32_constants[] = {
+      0, -1,  -2,  2,  2,  3,  3,  4,  4,  5,  5,  4,  5,  6, 6, 7, 8, 7, 8, 9,
+      0, -11, -12, 12, 12, 13, 13, 14, 14, 15, 15, 14, 15, 6, 6, 7, 8, 7, 8, 9};
+
+  for (size_t i = 0; i < arraysize(int32_constants); i++) {
+    CheckTrimConstant(&T, T.jsgraph.Int32Constant(int32_constants[i]));
+    CheckTrimConstant(&T, T.jsgraph.Float64Constant(int32_constants[i]));
+    CheckTrimConstant(&T, T.jsgraph.Constant(int32_constants[i]));
+  }
+
+  Node* other_constants[] = {
+      T.jsgraph.UndefinedConstant(), T.jsgraph.TheHoleConstant(),
+      T.jsgraph.TrueConstant(),      T.jsgraph.FalseConstant(),
+      T.jsgraph.NullConstant(),      T.jsgraph.ZeroConstant(),
+      T.jsgraph.OneConstant(),       T.jsgraph.NaNConstant(),
+      T.jsgraph.Constant(21),        T.jsgraph.Constant(22.2)};
+
+  for (size_t i = 0; i < arraysize(other_constants); i++) {
+    CheckTrimConstant(&T, other_constants[i]);
+  }
+}
+
+
+TEST(CReducePhi1) {
+  ControlReducerTester R;
+
+  R.ReducePhi(R.leaf[0], R.Phi(R.leaf[0]));
+  R.ReducePhi(R.leaf[1], R.Phi(R.leaf[1]));
+  R.ReducePhi(R.leaf[2], R.Phi(R.leaf[2]));
+  R.ReducePhi(R.leaf[3], R.Phi(R.leaf[3]));
+}
+
+
+TEST(CReducePhi1_dead) {
+  ControlReducerTester R;
+
+  R.ReducePhi(R.leaf[0], R.Phi(R.leaf[0], R.dead));
+  R.ReducePhi(R.leaf[1], R.Phi(R.leaf[1], R.dead));
+  R.ReducePhi(R.leaf[2], R.Phi(R.leaf[2], R.dead));
+  R.ReducePhi(R.leaf[3], R.Phi(R.leaf[3], R.dead));
+
+  R.ReducePhi(R.leaf[0], R.Phi(R.dead, R.leaf[0]));
+  R.ReducePhi(R.leaf[1], R.Phi(R.dead, R.leaf[1]));
+  R.ReducePhi(R.leaf[2], R.Phi(R.dead, R.leaf[2]));
+  R.ReducePhi(R.leaf[3], R.Phi(R.dead, R.leaf[3]));
+}
+
+
+TEST(CReducePhi1_dead2) {
+  ControlReducerTester R;
+
+  R.ReducePhi(R.leaf[0], R.Phi(R.leaf[0], R.dead, R.dead));
+  R.ReducePhi(R.leaf[0], R.Phi(R.dead, R.leaf[0], R.dead));
+  R.ReducePhi(R.leaf[0], R.Phi(R.dead, R.dead, R.leaf[0]));
+}
+
+
+TEST(CReducePhi2a) {
+  ControlReducerTester R;
+
+  for (size_t i = 0; i < kNumLeafs; i++) {
+    Node* a = R.leaf[i];
+    R.ReducePhi(a, R.Phi(a, a));
+  }
+}
+
+
+TEST(CReducePhi2b) {
+  ControlReducerTester R;
+
+  for (size_t i = 0; i < kNumLeafs; i++) {
+    Node* a = R.leaf[i];
+    R.ReducePhi(a, R.Phi(R.self, a));
+    R.ReducePhi(a, R.Phi(a, R.self));
+  }
+}
+
+
+TEST(CReducePhi2c) {
+  ControlReducerTester R;
+
+  for (size_t i = 1; i < kNumLeafs; i++) {
+    Node* a = R.leaf[i], *b = R.leaf[0];
+    Node* phi1 = R.Phi(b, a);
+    R.ReducePhi(phi1, phi1);
+
+    Node* phi2 = R.Phi(a, b);
+    R.ReducePhi(phi2, phi2);
+  }
+}
+
+
+TEST(CReducePhi2_dead) {
+  ControlReducerTester R;
+
+  for (size_t i = 0; i < kNumLeafs; i++) {
+    Node* a = R.leaf[i];
+    R.ReducePhi(a, R.Phi(a, a, R.dead));
+    R.ReducePhi(a, R.Phi(a, R.dead, a));
+    R.ReducePhi(a, R.Phi(R.dead, a, a));
+  }
+
+  for (size_t i = 0; i < kNumLeafs; i++) {
+    Node* a = R.leaf[i];
+    R.ReducePhi(a, R.Phi(R.self, a));
+    R.ReducePhi(a, R.Phi(a, R.self));
+    R.ReducePhi(a, R.Phi(R.self, a, R.dead));
+    R.ReducePhi(a, R.Phi(a, R.self, R.dead));
+  }
+
+  for (size_t i = 1; i < kNumLeafs; i++) {
+    Node* a = R.leaf[i], *b = R.leaf[0];
+    Node* phi1 = R.Phi(b, a, R.dead);
+    R.ReducePhi(phi1, phi1);
+
+    Node* phi2 = R.Phi(a, b, R.dead);
+    R.ReducePhi(phi2, phi2);
+  }
+}
+
+
+TEST(CReducePhi3) {
+  ControlReducerTester R;
+
+  for (size_t i = 0; i < kNumLeafs; i++) {
+    Node* a = R.leaf[i];
+    R.ReducePhi(a, R.Phi(a, a, a));
+  }
+
+  for (size_t i = 0; i < kNumLeafs; i++) {
+    Node* a = R.leaf[i];
+    R.ReducePhi(a, R.Phi(R.self, a, a));
+    R.ReducePhi(a, R.Phi(a, R.self, a));
+    R.ReducePhi(a, R.Phi(a, a, R.self));
+  }
+
+  for (size_t i = 1; i < kNumLeafs; i++) {
+    Node* a = R.leaf[i], *b = R.leaf[0];
+    Node* phi1 = R.Phi(b, a, a);
+    R.ReducePhi(phi1, phi1);
+
+    Node* phi2 = R.Phi(a, b, a);
+    R.ReducePhi(phi2, phi2);
+
+    Node* phi3 = R.Phi(a, a, b);
+    R.ReducePhi(phi3, phi3);
+  }
+}
+
+
+TEST(CReducePhi4) {
+  ControlReducerTester R;
+
+  for (size_t i = 0; i < kNumLeafs; i++) {
+    Node* a = R.leaf[i];
+    R.ReducePhi(a, R.Phi(a, a, a, a));
+  }
+
+  for (size_t i = 0; i < kNumLeafs; i++) {
+    Node* a = R.leaf[i];
+    R.ReducePhi(a, R.Phi(R.self, a, a, a));
+    R.ReducePhi(a, R.Phi(a, R.self, a, a));
+    R.ReducePhi(a, R.Phi(a, a, R.self, a));
+    R.ReducePhi(a, R.Phi(a, a, a, R.self));
+
+    R.ReducePhi(a, R.Phi(R.self, R.self, a, a));
+    R.ReducePhi(a, R.Phi(a, R.self, R.self, a));
+    R.ReducePhi(a, R.Phi(a, a, R.self, R.self));
+    R.ReducePhi(a, R.Phi(R.self, a, a, R.self));
+  }
+
+  for (size_t i = 1; i < kNumLeafs; i++) {
+    Node* a = R.leaf[i], *b = R.leaf[0];
+    Node* phi1 = R.Phi(b, a, a, a);
+    R.ReducePhi(phi1, phi1);
+
+    Node* phi2 = R.Phi(a, b, a, a);
+    R.ReducePhi(phi2, phi2);
+
+    Node* phi3 = R.Phi(a, a, b, a);
+    R.ReducePhi(phi3, phi3);
+
+    Node* phi4 = R.Phi(a, a, a, b);
+    R.ReducePhi(phi4, phi4);
+  }
+}
+
+
+TEST(CReducePhi_iterative1) {
+  ControlReducerTester R;
+
+  R.ReducePhiIterative(R.leaf[0], R.Phi(R.leaf[0], R.Phi(R.leaf[0])));
+  R.ReducePhiIterative(R.leaf[0], R.Phi(R.Phi(R.leaf[0]), R.leaf[0]));
+}
+
+
+TEST(CReducePhi_iterative2) {
+  ControlReducerTester R;
+
+  R.ReducePhiIterative(R.leaf[0], R.Phi(R.Phi(R.leaf[0]), R.Phi(R.leaf[0])));
+}
+
+
+TEST(CReducePhi_iterative3) {
+  ControlReducerTester R;
+
+  R.ReducePhiIterative(R.leaf[0],
+                       R.Phi(R.leaf[0], R.Phi(R.leaf[0], R.leaf[0])));
+  R.ReducePhiIterative(R.leaf[0],
+                       R.Phi(R.Phi(R.leaf[0], R.leaf[0]), R.leaf[0]));
+}
+
+
+TEST(CReducePhi_iterative4) {
+  ControlReducerTester R;
+
+  R.ReducePhiIterative(R.leaf[0], R.Phi(R.Phi(R.leaf[0], R.leaf[0]),
+                                        R.Phi(R.leaf[0], R.leaf[0])));
+
+  Node* p1 = R.Phi(R.leaf[0], R.leaf[0]);
+  R.ReducePhiIterative(R.leaf[0], R.Phi(p1, p1));
+
+  Node* p2 = R.Phi(R.leaf[0], R.leaf[0], R.leaf[0]);
+  R.ReducePhiIterative(R.leaf[0], R.Phi(p2, p2, p2));
+
+  Node* p3 = R.Phi(R.leaf[0], R.leaf[0], R.leaf[0]);
+  R.ReducePhiIterative(R.leaf[0], R.Phi(p3, p3, R.leaf[0]));
+}
+
+
+TEST(CReducePhi_iterative_self1) {
+  ControlReducerTester R;
+
+  R.ReducePhiIterative(R.leaf[0], R.Phi(R.leaf[0], R.Phi(R.leaf[0], R.self)));
+  R.ReducePhiIterative(R.leaf[0], R.Phi(R.Phi(R.leaf[0], R.self), R.leaf[0]));
+}
+
+
+TEST(CReducePhi_iterative_self2) {
+  ControlReducerTester R;
+
+  R.ReducePhiIterative(
+      R.leaf[0], R.Phi(R.Phi(R.leaf[0], R.self), R.Phi(R.leaf[0], R.self)));
+  R.ReducePhiIterative(
+      R.leaf[0], R.Phi(R.Phi(R.self, R.leaf[0]), R.Phi(R.self, R.leaf[0])));
+
+  Node* p1 = R.Phi(R.leaf[0], R.self);
+  R.ReducePhiIterative(R.leaf[0], R.Phi(p1, p1));
+
+  Node* p2 = R.Phi(R.self, R.leaf[0]);
+  R.ReducePhiIterative(R.leaf[0], R.Phi(p2, p2));
+}
+
+
+TEST(EReducePhi1) {
+  ControlReducerTester R;
+
+  R.ReducePhi(R.leaf[0], R.EffectPhi(R.leaf[0]));
+  R.ReducePhi(R.leaf[1], R.EffectPhi(R.leaf[1]));
+  R.ReducePhi(R.leaf[2], R.EffectPhi(R.leaf[2]));
+  R.ReducePhi(R.leaf[3], R.EffectPhi(R.leaf[3]));
+}
+
+
+TEST(EReducePhi1_dead) {
+  ControlReducerTester R;
+
+  R.ReducePhi(R.leaf[0], R.EffectPhi(R.leaf[0], R.dead));
+  R.ReducePhi(R.leaf[1], R.EffectPhi(R.leaf[1], R.dead));
+  R.ReducePhi(R.leaf[2], R.EffectPhi(R.leaf[2], R.dead));
+  R.ReducePhi(R.leaf[3], R.EffectPhi(R.leaf[3], R.dead));
+
+  R.ReducePhi(R.leaf[0], R.EffectPhi(R.dead, R.leaf[0]));
+  R.ReducePhi(R.leaf[1], R.EffectPhi(R.dead, R.leaf[1]));
+  R.ReducePhi(R.leaf[2], R.EffectPhi(R.dead, R.leaf[2]));
+  R.ReducePhi(R.leaf[3], R.EffectPhi(R.dead, R.leaf[3]));
+}
+
+
+TEST(EReducePhi1_dead2) {
+  ControlReducerTester R;
+
+  R.ReducePhi(R.leaf[0], R.EffectPhi(R.leaf[0], R.dead, R.dead));
+  R.ReducePhi(R.leaf[0], R.EffectPhi(R.dead, R.leaf[0], R.dead));
+  R.ReducePhi(R.leaf[0], R.EffectPhi(R.dead, R.dead, R.leaf[0]));
+}
+
+
+TEST(CMergeReduce_simple1) {
+  ControlReducerTester R;
+
+  Node* merge = R.graph.NewNode(R.common.Merge(1), R.start);
+  R.ReduceMerge(R.start, merge);
+}
+
+
+TEST(CMergeReduce_simple2) {
+  ControlReducerTester R;
+
+  Node* merge1 = R.graph.NewNode(R.common.Merge(1), R.start);
+  Node* merge2 = R.graph.NewNode(R.common.Merge(1), merge1);
+  R.ReduceMerge(merge1, merge2);
+  R.ReduceMergeIterative(R.start, merge2);
+}
+
+
+TEST(CMergeReduce_none1) {
+  ControlReducerTester R;
+
+  Node* merge = R.graph.NewNode(R.common.Merge(2), R.start, R.start);
+  R.ReduceMerge(merge, merge);
+}
+
+
+TEST(CMergeReduce_none2) {
+  ControlReducerTester R;
+
+  Node* t = R.graph.NewNode(R.common.IfTrue(), R.start);
+  Node* f = R.graph.NewNode(R.common.IfFalse(), R.start);
+  Node* merge = R.graph.NewNode(R.common.Merge(2), t, f);
+  R.ReduceMerge(merge, merge);
+}
+
+
+TEST(CMergeReduce_self3) {
+  ControlReducerTester R;
+
+  Node* merge =
+      R.SetSelfReferences(R.graph.NewNode(R.common.Merge(2), R.start, R.self));
+  R.ReduceMerge(merge, merge);
+}
+
+
+TEST(CMergeReduce_dead1) {
+  ControlReducerTester R;
+
+  Node* merge = R.graph.NewNode(R.common.Merge(2), R.start, R.dead);
+  R.ReduceMerge(R.start, merge);
+}
+
+
+TEST(CMergeReduce_dead2) {
+  ControlReducerTester R;
+
+  Node* merge1 = R.graph.NewNode(R.common.Merge(1), R.start);
+  Node* merge2 = R.graph.NewNode(R.common.Merge(2), merge1, R.dead);
+  R.ReduceMerge(merge1, merge2);
+  R.ReduceMergeIterative(R.start, merge2);
+}
+
+
+TEST(CMergeReduce_dead_rm1a) {
+  ControlReducerTester R;
+
+  for (int i = 0; i < 3; i++) {
+    Node* merge = R.graph.NewNode(R.common.Merge(3), R.start, R.start, R.start);
+    merge->ReplaceInput(i, R.dead);
+    R.ReduceMerge(merge, merge);
+    CheckMerge(merge, R.start, R.start);
+  }
+}
+
+
+TEST(CMergeReduce_dead_rm1b) {
+  ControlReducerTester R;
+
+  Node* t = R.graph.NewNode(R.common.IfTrue(), R.start);
+  Node* f = R.graph.NewNode(R.common.IfFalse(), R.start);
+  for (int i = 0; i < 2; i++) {
+    Node* merge = R.graph.NewNode(R.common.Merge(3), R.dead, R.dead, R.dead);
+    for (int j = i + 1; j < 3; j++) {
+      merge->ReplaceInput(i, t);
+      merge->ReplaceInput(j, f);
+      R.ReduceMerge(merge, merge);
+      CheckMerge(merge, t, f);
+    }
+  }
+}
+
+
+TEST(CMergeReduce_dead_rm2) {
+  ControlReducerTester R;
+
+  for (int i = 0; i < 3; i++) {
+    Node* merge = R.graph.NewNode(R.common.Merge(3), R.dead, R.dead, R.dead);
+    merge->ReplaceInput(i, R.start);
+    R.ReduceMerge(R.start, merge);
+  }
+}
+
+
+TEST(CLoopReduce_dead_rm1) {
+  ControlReducerTester R;
+
+  for (int i = 0; i < 3; i++) {
+    Node* loop = R.graph.NewNode(R.common.Loop(3), R.dead, R.start, R.start);
+    R.ReduceMerge(loop, loop);
+    CheckLoop(loop, R.start, R.start);
+  }
+}
+
+
+TEST(CMergeReduce_edit_phi1) {
+  ControlReducerTester R;
+
+  for (int i = 0; i < 3; i++) {
+    Node* merge = R.graph.NewNode(R.common.Merge(3), R.start, R.start, R.start);
+    merge->ReplaceInput(i, R.dead);
+    Node* phi = R.graph.NewNode(R.common.Phi(kMachAnyTagged, 3), R.leaf[0],
+                                R.leaf[1], R.leaf[2], merge);
+    R.ReduceMerge(merge, merge);
+    CHECK_EQ(IrOpcode::kPhi, phi->opcode());
+    CHECK_EQ(2, phi->op()->ValueInputCount());
+    CHECK_EQ(3, phi->InputCount());
+    CHECK_EQ(R.leaf[i < 1 ? 1 : 0], phi->InputAt(0));
+    CHECK_EQ(R.leaf[i < 2 ? 2 : 1], phi->InputAt(1));
+    CHECK_EQ(merge, phi->InputAt(2));
+  }
+}
+
+
+TEST(CMergeReduce_edit_effect_phi1) {
+  ControlReducerTester R;
+
+  for (int i = 0; i < 3; i++) {
+    Node* merge = R.graph.NewNode(R.common.Merge(3), R.start, R.start, R.start);
+    merge->ReplaceInput(i, R.dead);
+    Node* phi = R.graph.NewNode(R.common.EffectPhi(3), R.leaf[0], R.leaf[1],
+                                R.leaf[2], merge);
+    R.ReduceMerge(merge, merge);
+    CHECK_EQ(IrOpcode::kEffectPhi, phi->opcode());
+    CHECK_EQ(0, phi->op()->ValueInputCount());
+    CHECK_EQ(2, phi->op()->EffectInputCount());
+    CHECK_EQ(3, phi->InputCount());
+    CHECK_EQ(R.leaf[i < 1 ? 1 : 0], phi->InputAt(0));
+    CHECK_EQ(R.leaf[i < 2 ? 2 : 1], phi->InputAt(1));
+    CHECK_EQ(merge, phi->InputAt(2));
+  }
+}
+
+
+static const int kSelectorSize = 4;
+
+// Helper to select K of N nodes according to a mask, useful for the test below.
+struct Selector {
+  int mask;
+  int count;
+  explicit Selector(int m) {
+    mask = m;
+    count = v8::base::bits::CountPopulation32(m);
+  }
+  bool is_selected(int i) { return (mask & (1 << i)) != 0; }
+  void CheckNode(Node* node, IrOpcode::Value opcode, Node** inputs,
+                 Node* control) {
+    CHECK_EQ(opcode, node->opcode());
+    CHECK_EQ(count + (control != NULL ? 1 : 0), node->InputCount());
+    int index = 0;
+    for (int i = 0; i < kSelectorSize; i++) {
+      if (mask & (1 << i)) {
+        CHECK_EQ(inputs[i], node->InputAt(index++));
+      }
+    }
+    CHECK_EQ(count, index);
+    if (control != NULL) CHECK_EQ(control, node->InputAt(index++));
+  }
+  int single_index() {
+    CHECK_EQ(1, count);
+    return WhichPowerOf2(mask);
+  }
+};
+
+
+TEST(CMergeReduce_exhaustive_4) {
+  ControlReducerTester R;
+  Node* controls[] = {
+      R.graph.NewNode(R.common.Start(1)), R.graph.NewNode(R.common.Start(2)),
+      R.graph.NewNode(R.common.Start(3)), R.graph.NewNode(R.common.Start(4))};
+  Node* values[] = {R.jsgraph.Int32Constant(11), R.jsgraph.Int32Constant(22),
+                    R.jsgraph.Int32Constant(33), R.jsgraph.Int32Constant(44)};
+  Node* effects[] = {
+      R.jsgraph.Float64Constant(123.4), R.jsgraph.Float64Constant(223.4),
+      R.jsgraph.Float64Constant(323.4), R.jsgraph.Float64Constant(423.4)};
+
+  for (int mask = 0; mask < (1 << (kSelectorSize - 1)); mask++) {
+    // Reduce a single merge with a given mask.
+    Node* merge = R.graph.NewNode(R.common.Merge(4), controls[0], controls[1],
+                                  controls[2], controls[3]);
+    Node* phi = R.graph.NewNode(R.common.Phi(kMachAnyTagged, 4), values[0],
+                                values[1], values[2], values[3], merge);
+    Node* ephi = R.graph.NewNode(R.common.EffectPhi(4), effects[0], effects[1],
+                                 effects[2], effects[3], merge);
+
+    Node* phi_use =
+        R.graph.NewNode(R.common.Phi(kMachAnyTagged, 1), phi, R.start);
+    Node* ephi_use = R.graph.NewNode(R.common.EffectPhi(1), ephi, R.start);
+
+    Selector selector(mask);
+
+    for (int i = 0; i < kSelectorSize; i++) {  // set up dead merge inputs.
+      if (!selector.is_selected(i)) merge->ReplaceInput(i, R.dead);
+    }
+
+    Node* result =
+        ControlReducer::ReduceMergeForTesting(&R.jsgraph, &R.common, merge);
+
+    int count = selector.count;
+    if (count == 0) {
+      // result should be dead.
+      CHECK_EQ(IrOpcode::kDead, result->opcode());
+    } else if (count == 1) {
+      // merge should be replaced with one of the controls.
+      CHECK_EQ(controls[selector.single_index()], result);
+      // Phis should have been directly replaced.
+      CHECK_EQ(values[selector.single_index()], phi_use->InputAt(0));
+      CHECK_EQ(effects[selector.single_index()], ephi_use->InputAt(0));
+    } else {
+      // Otherwise, nodes should be edited in place.
+      CHECK_EQ(merge, result);
+      selector.CheckNode(merge, IrOpcode::kMerge, controls, NULL);
+      selector.CheckNode(phi, IrOpcode::kPhi, values, merge);
+      selector.CheckNode(ephi, IrOpcode::kEffectPhi, effects, merge);
+      CHECK_EQ(phi, phi_use->InputAt(0));
+      CHECK_EQ(ephi, ephi_use->InputAt(0));
+      CHECK_EQ(count, phi->op()->ValueInputCount());
+      CHECK_EQ(count + 1, phi->InputCount());
+      CHECK_EQ(count, ephi->op()->EffectInputCount());
+      CHECK_EQ(count + 1, ephi->InputCount());
+    }
+  }
+}
+
+
+TEST(CMergeReduce_edit_many_phis1) {
+  ControlReducerTester R;
+
+  const int kPhiCount = 10;
+  Node* phis[kPhiCount];
+
+  for (int i = 0; i < 3; i++) {
+    Node* merge = R.graph.NewNode(R.common.Merge(3), R.start, R.start, R.start);
+    merge->ReplaceInput(i, R.dead);
+    for (int j = 0; j < kPhiCount; j++) {
+      phis[j] = R.graph.NewNode(R.common.Phi(kMachAnyTagged, 3), R.leaf[0],
+                                R.leaf[1], R.leaf[2], merge);
+    }
+    R.ReduceMerge(merge, merge);
+    for (int j = 0; j < kPhiCount; j++) {
+      Node* phi = phis[j];
+      CHECK_EQ(IrOpcode::kPhi, phi->opcode());
+      CHECK_EQ(2, phi->op()->ValueInputCount());
+      CHECK_EQ(3, phi->InputCount());
+      CHECK_EQ(R.leaf[i < 1 ? 1 : 0], phi->InputAt(0));
+      CHECK_EQ(R.leaf[i < 2 ? 2 : 1], phi->InputAt(1));
+      CHECK_EQ(merge, phi->InputAt(2));
+    }
+  }
+}
+
+
+TEST(CMergeReduce_simple_chain1) {
+  ControlReducerTester R;
+  for (int i = 0; i < 5; i++) {
+    Node* merge = R.graph.NewNode(R.common.Merge(1), R.start);
+    for (int j = 0; j < i; j++) {
+      merge = R.graph.NewNode(R.common.Merge(1), merge);
+    }
+    R.ReduceMergeIterative(R.start, merge);
+  }
+}
+
+
+TEST(CMergeReduce_dead_chain1) {
+  ControlReducerTester R;
+  for (int i = 0; i < 5; i++) {
+    Node* merge = R.graph.NewNode(R.common.Merge(1), R.dead);
+    for (int j = 0; j < i; j++) {
+      merge = R.graph.NewNode(R.common.Merge(1), merge);
+    }
+    Node* end = R.graph.NewNode(R.common.End(), merge);
+    R.graph.SetEnd(end);
+    R.ReduceGraph();
+    CHECK(merge->IsDead());
+    CHECK_EQ(NULL, end->InputAt(0));  // end dies.
+  }
+}
+
+
+TEST(CMergeReduce_dead_chain2) {
+  ControlReducerTester R;
+  for (int i = 0; i < 5; i++) {
+    Node* merge = R.graph.NewNode(R.common.Merge(1), R.start);
+    for (int j = 0; j < i; j++) {
+      merge = R.graph.NewNode(R.common.Merge(2), merge, R.dead);
+    }
+    R.ReduceMergeIterative(R.start, merge);
+  }
+}
+
+
+struct Branch {
+  Node* branch;
+  Node* if_true;
+  Node* if_false;
+
+  Branch(ControlReducerTester& R, Node* cond, Node* control = NULL) {
+    if (control == NULL) control = R.start;
+    branch = R.graph.NewNode(R.common.Branch(), cond, control);
+    if_true = R.graph.NewNode(R.common.IfTrue(), branch);
+    if_false = R.graph.NewNode(R.common.IfFalse(), branch);
+  }
+};
+
+
+// TODO(titzer): use the diamonds from src/compiler/diamond.h here.
+struct Diamond {
+  Node* branch;
+  Node* if_true;
+  Node* if_false;
+  Node* merge;
+  Node* phi;
+
+  Diamond(ControlReducerTester& R, Node* cond) {
+    branch = R.graph.NewNode(R.common.Branch(), cond, R.start);
+    if_true = R.graph.NewNode(R.common.IfTrue(), branch);
+    if_false = R.graph.NewNode(R.common.IfFalse(), branch);
+    merge = R.graph.NewNode(R.common.Merge(2), if_true, if_false);
+    phi = NULL;
+  }
+
+  Diamond(ControlReducerTester& R, Node* cond, Node* tv, Node* fv) {
+    branch = R.graph.NewNode(R.common.Branch(), cond, R.start);
+    if_true = R.graph.NewNode(R.common.IfTrue(), branch);
+    if_false = R.graph.NewNode(R.common.IfFalse(), branch);
+    merge = R.graph.NewNode(R.common.Merge(2), if_true, if_false);
+    phi = R.graph.NewNode(R.common.Phi(kMachAnyTagged, 2), tv, fv, merge);
+  }
+
+  void chain(Diamond& that) { branch->ReplaceInput(1, that.merge); }
+
+  // Nest {this} into either the if_true or if_false branch of {that}.
+  void nest(Diamond& that, bool if_true) {
+    if (if_true) {
+      branch->ReplaceInput(1, that.if_true);
+      that.merge->ReplaceInput(0, merge);
+    } else {
+      branch->ReplaceInput(1, that.if_false);
+      that.merge->ReplaceInput(1, merge);
+    }
+  }
+};
+
+
+struct While {
+  Node* branch;
+  Node* if_true;
+  Node* exit;
+  Node* loop;
+
+  While(ControlReducerTester& R, Node* cond) {
+    loop = R.graph.NewNode(R.common.Loop(2), R.start, R.start);
+    branch = R.graph.NewNode(R.common.Branch(), cond, loop);
+    if_true = R.graph.NewNode(R.common.IfTrue(), branch);
+    exit = R.graph.NewNode(R.common.IfFalse(), branch);
+    loop->ReplaceInput(1, if_true);
+  }
+
+  void chain(Node* control) { loop->ReplaceInput(0, control); }
+};
+
+
+TEST(CBranchReduce_none1) {
+  ControlReducerTester R;
+  Diamond d(R, R.p0);
+  R.ReduceBranch(d.branch, d.branch);
+}
+
+
+TEST(CBranchReduce_none2) {
+  ControlReducerTester R;
+  Diamond d1(R, R.p0);
+  Diamond d2(R, R.p0);
+  d2.chain(d1);
+  R.ReduceBranch(d2.branch, d2.branch);
+}
+
+
+TEST(CBranchReduce_true) {
+  ControlReducerTester R;
+  Node* true_values[] = {
+      R.one,                               R.jsgraph.Int32Constant(2),
+      R.jsgraph.Int32Constant(0x7fffffff), R.jsgraph.Constant(1.0),
+      R.jsgraph.Constant(22.1),            R.jsgraph.TrueConstant()};
+
+  for (size_t i = 0; i < arraysize(true_values); i++) {
+    Diamond d(R, true_values[i]);
+    Node* true_use = R.graph.NewNode(R.common.Merge(1), d.if_true);
+    Node* false_use = R.graph.NewNode(R.common.Merge(1), d.if_false);
+    R.ReduceBranch(R.start, d.branch);
+    CHECK_EQ(R.start, true_use->InputAt(0));
+    CHECK_EQ(IrOpcode::kDead, false_use->InputAt(0)->opcode());
+    CHECK(d.if_true->IsDead());   // replaced
+    CHECK(d.if_false->IsDead());  // replaced
+  }
+}
+
+
+TEST(CBranchReduce_false) {
+  ControlReducerTester R;
+  Node* false_values[] = {R.zero, R.jsgraph.Constant(0.0),
+                          R.jsgraph.Constant(-0.0), R.jsgraph.FalseConstant()};
+
+  for (size_t i = 0; i < arraysize(false_values); i++) {
+    Diamond d(R, false_values[i]);
+    Node* true_use = R.graph.NewNode(R.common.Merge(1), d.if_true);
+    Node* false_use = R.graph.NewNode(R.common.Merge(1), d.if_false);
+    R.ReduceBranch(R.start, d.branch);
+    CHECK_EQ(R.start, false_use->InputAt(0));
+    CHECK_EQ(IrOpcode::kDead, true_use->InputAt(0)->opcode());
+    CHECK(d.if_true->IsDead());   // replaced
+    CHECK(d.if_false->IsDead());  // replaced
+  }
+}
+
+
+TEST(CDiamondReduce_true) {
+  ControlReducerTester R;
+  Diamond d1(R, R.one);
+  R.ReduceMergeIterative(R.start, d1.merge);
+}
+
+
+TEST(CDiamondReduce_false) {
+  ControlReducerTester R;
+  Diamond d2(R, R.zero);
+  R.ReduceMergeIterative(R.start, d2.merge);
+}
+
+
+TEST(CChainedDiamondsReduce_true_false) {
+  ControlReducerTester R;
+  Diamond d1(R, R.one);
+  Diamond d2(R, R.zero);
+  d2.chain(d1);
+
+  R.ReduceMergeIterative(R.start, d2.merge);
+}
+
+
+TEST(CChainedDiamondsReduce_x_false) {
+  ControlReducerTester R;
+  Diamond d1(R, R.p0);
+  Diamond d2(R, R.zero);
+  d2.chain(d1);
+
+  R.ReduceMergeIterative(d1.merge, d2.merge);
+}
+
+
+TEST(CChainedDiamondsReduce_false_x) {
+  ControlReducerTester R;
+  Diamond d1(R, R.zero);
+  Diamond d2(R, R.p0);
+  d2.chain(d1);
+
+  R.ReduceMergeIterative(d2.merge, d2.merge);
+  CheckInputs(d2.branch, R.p0, R.start);
+}
+
+
+TEST(CChainedDiamondsReduce_phi1) {
+  ControlReducerTester R;
+  Diamond d1(R, R.zero, R.one, R.zero);  // foldable branch, phi.
+  Diamond d2(R, d1.phi);
+  d2.chain(d1);
+
+  R.ReduceMergeIterative(R.start, d2.merge);
+}
+
+
+TEST(CChainedDiamondsReduce_phi2) {
+  ControlReducerTester R;
+  Diamond d1(R, R.p0, R.one, R.one);  // redundant phi.
+  Diamond d2(R, d1.phi);
+  d2.chain(d1);
+
+  R.ReduceMergeIterative(d1.merge, d2.merge);
+}
+
+
+TEST(CNestedDiamondsReduce_true_true_false) {
+  ControlReducerTester R;
+  Diamond d1(R, R.one);
+  Diamond d2(R, R.zero);
+  d2.nest(d1, true);
+
+  R.ReduceMergeIterative(R.start, d1.merge);
+}
+
+
+TEST(CNestedDiamondsReduce_false_true_false) {
+  ControlReducerTester R;
+  Diamond d1(R, R.one);
+  Diamond d2(R, R.zero);
+  d2.nest(d1, false);
+
+  R.ReduceMergeIterative(R.start, d1.merge);
+}
+
+
+TEST(CNestedDiamonds_xyz) {
+  ControlReducerTester R;
+
+  for (int a = 0; a < 2; a++) {
+    for (int b = 0; b < 2; b++) {
+      for (int c = 0; c < 2; c++) {
+        Diamond d1(R, R.jsgraph.Int32Constant(a));
+        Diamond d2(R, R.jsgraph.Int32Constant(b));
+        d2.nest(d1, c);
+
+        R.ReduceMergeIterative(R.start, d1.merge);
+      }
+    }
+  }
+}
+
+
+TEST(CDeadLoop1) {
+  ControlReducerTester R;
+
+  Node* loop = R.graph.NewNode(R.common.Loop(1), R.start);
+  Branch b(R, R.p0, loop);
+  loop->ReplaceInput(0, b.if_true);  // loop is not connected to start.
+  Node* merge = R.graph.NewNode(R.common.Merge(2), R.start, b.if_false);
+  R.ReduceMergeIterative(R.start, merge);
+  CHECK(b.if_true->IsDead());
+  CHECK(b.if_false->IsDead());
+}
+
+
+TEST(CDeadLoop2) {
+  ControlReducerTester R;
+
+  While w(R, R.p0);
+  Diamond d(R, R.zero);
+  // if (0) { while (p0) ; } else { }
+  w.branch->ReplaceInput(1, d.if_true);
+  d.merge->ReplaceInput(0, w.exit);
+
+  R.ReduceMergeIterative(R.start, d.merge);
+  CHECK(d.if_true->IsDead());
+  CHECK(d.if_false->IsDead());
+}
+
+
+TEST(CNonTermLoop1) {
+  ControlReducerTester R;
+  Node* loop =
+      R.SetSelfReferences(R.graph.NewNode(R.common.Loop(2), R.start, R.self));
+  R.ReduceGraph();
+  Node* end = R.graph.end();
+  CheckLoop(loop, R.start, loop);
+  Node* merge = end->InputAt(0);
+  CheckMerge(merge, R.start, loop);
+}
+
+
+TEST(CNonTermLoop2) {
+  ControlReducerTester R;
+  Diamond d(R, R.p0);
+  Node* loop = R.SetSelfReferences(
+      R.graph.NewNode(R.common.Loop(2), d.if_false, R.self));
+  d.merge->ReplaceInput(1, R.dead);
+  Node* end = R.graph.end();
+  end->ReplaceInput(0, d.merge);
+  R.ReduceGraph();
+  CHECK_EQ(end, R.graph.end());
+  CheckLoop(loop, d.if_false, loop);
+  Node* merge = end->InputAt(0);
+  CheckMerge(merge, d.if_true, loop);
+}
+
+
+TEST(NonTermLoop3) {
+  ControlReducerTester R;
+  Node* loop = R.graph.NewNode(R.common.Loop(2), R.start, R.start);
+  Branch b(R, R.one, loop);
+  loop->ReplaceInput(1, b.if_true);
+  Node* end = R.graph.end();
+  end->ReplaceInput(0, b.if_false);
+
+  R.ReduceGraph();
+
+  CHECK_EQ(end, R.graph.end());
+  CheckInputs(end, loop);
+  CheckInputs(loop, R.start, loop);
+}
+
+
+TEST(CNonTermLoop_terminate1) {
+  ControlReducerTester R;
+  Node* loop = R.graph.NewNode(R.common.Loop(2), R.start, R.start);
+  Node* effect = R.SetSelfReferences(
+      R.graph.NewNode(R.common.EffectPhi(2), R.start, R.self, loop));
+  Branch b(R, R.one, loop);
+  loop->ReplaceInput(1, b.if_true);
+  Node* end = R.graph.end();
+  end->ReplaceInput(0, b.if_false);
+
+  R.ReduceGraph();
+
+  CHECK_EQ(end, R.graph.end());
+  CheckLoop(loop, R.start, loop);
+  Node* terminate = end->InputAt(0);
+  CHECK_EQ(IrOpcode::kTerminate, terminate->opcode());
+  CHECK_EQ(2, terminate->InputCount());
+  CHECK_EQ(1, terminate->op()->EffectInputCount());
+  CHECK_EQ(1, terminate->op()->ControlInputCount());
+  CheckInputs(terminate, effect, loop);
+}
+
+
+TEST(CNonTermLoop_terminate2) {
+  ControlReducerTester R;
+  Node* loop = R.graph.NewNode(R.common.Loop(2), R.start, R.start);
+  Node* effect1 = R.SetSelfReferences(
+      R.graph.NewNode(R.common.EffectPhi(2), R.start, R.self, loop));
+  Node* effect2 = R.SetSelfReferences(
+      R.graph.NewNode(R.common.EffectPhi(2), R.start, R.self, loop));
+  Branch b(R, R.one, loop);
+  loop->ReplaceInput(1, b.if_true);
+  Node* end = R.graph.end();
+  end->ReplaceInput(0, b.if_false);
+
+  R.ReduceGraph();
+
+  CheckLoop(loop, R.start, loop);
+  CHECK_EQ(end, R.graph.end());
+  Node* terminate = end->InputAt(0);
+  CHECK_EQ(IrOpcode::kTerminate, terminate->opcode());
+  CHECK_EQ(3, terminate->InputCount());
+  CHECK_EQ(2, terminate->op()->EffectInputCount());
+  CHECK_EQ(1, terminate->op()->ControlInputCount());
+  Node* e0 = terminate->InputAt(0);
+  Node* e1 = terminate->InputAt(1);
+  CHECK(e0 == effect1 || e1 == effect1);
+  CHECK(e0 == effect2 || e1 == effect2);
+  CHECK_EQ(loop, terminate->InputAt(2));
+}
+
+
+TEST(CNonTermLoop_terminate_m1) {
+  ControlReducerTester R;
+  Node* loop =
+      R.SetSelfReferences(R.graph.NewNode(R.common.Loop(2), R.start, R.self));
+  Node* effect = R.SetSelfReferences(
+      R.graph.NewNode(R.common.EffectPhi(2), R.start, R.self, loop));
+  R.ReduceGraph();
+  Node* end = R.graph.end();
+  CHECK_EQ(R.start, loop->InputAt(0));
+  CHECK_EQ(loop, loop->InputAt(1));
+  Node* merge = end->InputAt(0);
+  CHECK_EQ(IrOpcode::kMerge, merge->opcode());
+  CHECK_EQ(2, merge->InputCount());
+  CHECK_EQ(2, merge->op()->ControlInputCount());
+  CHECK_EQ(R.start, merge->InputAt(0));
+
+  Node* terminate = merge->InputAt(1);
+  CHECK_EQ(IrOpcode::kTerminate, terminate->opcode());
+  CHECK_EQ(2, terminate->InputCount());
+  CHECK_EQ(1, terminate->op()->EffectInputCount());
+  CHECK_EQ(1, terminate->op()->ControlInputCount());
+  CHECK_EQ(effect, terminate->InputAt(0));
+  CHECK_EQ(loop, terminate->InputAt(1));
+}
+
+
+TEST(CNonTermLoop_big1) {
+  ControlReducerTester R;
+  Branch b1(R, R.p0);
+  Node* rt = R.graph.NewNode(R.common.Return(), R.one, R.start, b1.if_true);
+
+  Branch b2(R, R.p0, b1.if_false);
+  Node* rf = R.graph.NewNode(R.common.Return(), R.zero, R.start, b2.if_true);
+  Node* loop = R.SetSelfReferences(
+      R.graph.NewNode(R.common.Loop(2), b2.if_false, R.self));
+  Node* merge = R.graph.NewNode(R.common.Merge(2), rt, rf);
+  R.end->ReplaceInput(0, merge);
+
+  R.ReduceGraph();
+
+  CheckInputs(R.end, merge);
+  CheckInputs(merge, rt, rf, loop);
+  CheckInputs(loop, b2.if_false, loop);
+}
+
+
+TEST(CNonTermLoop_big2) {
+  ControlReducerTester R;
+  Branch b1(R, R.p0);
+  Node* rt = R.graph.NewNode(R.common.Return(), R.one, R.start, b1.if_true);
+
+  Branch b2(R, R.zero, b1.if_false);
+  Node* rf = R.graph.NewNode(R.common.Return(), R.zero, R.start, b2.if_true);
+  Node* loop = R.SetSelfReferences(
+      R.graph.NewNode(R.common.Loop(2), b2.if_false, R.self));
+  Node* merge = R.graph.NewNode(R.common.Merge(2), rt, rf);
+  R.end->ReplaceInput(0, merge);
+
+  R.ReduceGraph();
+
+  Node* new_merge = R.end->InputAt(0);  // old merge was reduced.
+  CHECK_NE(merge, new_merge);
+  CheckInputs(new_merge, rt, loop);
+  CheckInputs(loop, b1.if_false, loop);
+  CHECK(merge->IsDead());
+  CHECK(rf->IsDead());
+  CHECK(b2.if_true->IsDead());
+}
+
+
+TEST(Return1) {
+  ControlReducerTester R;
+  Node* ret = R.Return(R.one, R.start, R.start);
+  R.ReduceGraph();
+  CheckInputs(R.graph.end(), ret);
+  CheckInputs(ret, R.one, R.start, R.start);
+}
+
+
+TEST(Return2) {
+  ControlReducerTester R;
+  Diamond d(R, R.one);
+  Node* ret = R.Return(R.half, R.start, d.merge);
+  R.ReduceGraph();
+  CHECK(d.branch->IsDead());
+  CHECK(d.if_true->IsDead());
+  CHECK(d.if_false->IsDead());
+  CHECK(d.merge->IsDead());
+
+  CheckInputs(R.graph.end(), ret);
+  CheckInputs(ret, R.half, R.start, R.start);
+}
+
+
+TEST(Return_true1) {
+  ControlReducerTester R;
+  Diamond d(R, R.one, R.half, R.zero);
+  Node* ret = R.Return(d.phi, R.start, d.merge);
+  R.ReduceGraph();
+  CHECK(d.branch->IsDead());
+  CHECK(d.if_true->IsDead());
+  CHECK(d.if_false->IsDead());
+  CHECK(d.merge->IsDead());
+  CHECK(d.phi->IsDead());
+
+  CheckInputs(R.graph.end(), ret);
+  CheckInputs(ret, R.half, R.start, R.start);
+}
+
+
+TEST(Return_false1) {
+  ControlReducerTester R;
+  Diamond d(R, R.zero, R.one, R.half);
+  Node* ret = R.Return(d.phi, R.start, d.merge);
+  R.ReduceGraph();
+  CHECK(d.branch->IsDead());
+  CHECK(d.if_true->IsDead());
+  CHECK(d.if_false->IsDead());
+  CHECK(d.merge->IsDead());
+  CHECK(d.phi->IsDead());
+
+  CheckInputs(R.graph.end(), ret);
+  CheckInputs(ret, R.half, R.start, R.start);
+}
+
+
+void CheckDeadDiamond(Diamond& d) {
+  CHECK(d.branch->IsDead());
+  CHECK(d.if_true->IsDead());
+  CHECK(d.if_false->IsDead());
+  CHECK(d.merge->IsDead());
+  if (d.phi != NULL) CHECK(d.phi->IsDead());
+}
+
+
+void CheckLiveDiamond(Diamond& d, bool live_phi = true) {
+  CheckInputs(d.merge, d.if_true, d.if_false);
+  CheckInputs(d.if_true, d.branch);
+  CheckInputs(d.if_false, d.branch);
+  if (d.phi != NULL) {
+    if (live_phi) {
+      CHECK_EQ(3, d.phi->InputCount());
+      CHECK_EQ(d.merge, d.phi->InputAt(2));
+    } else {
+      CHECK(d.phi->IsDead());
+    }
+  }
+}
+
+
+TEST(Return_effect1) {
+  ControlReducerTester R;
+  Diamond d(R, R.one);
+  Node* e1 = R.jsgraph.Float64Constant(-100.1);
+  Node* e2 = R.jsgraph.Float64Constant(+100.1);
+  Node* effect = R.graph.NewNode(R.common.EffectPhi(2), e1, e2, d.merge);
+  Node* ret = R.Return(R.p0, effect, d.merge);
+  R.ReduceGraph();
+  CheckDeadDiamond(d);
+  CHECK(effect->IsDead());
+
+  CheckInputs(R.graph.end(), ret);
+  CheckInputs(ret, R.p0, e1, R.start);
+}
+
+
+TEST(Return_nested_diamonds1) {
+  ControlReducerTester R;
+  Diamond d1(R, R.p0, R.one, R.zero);
+  Diamond d2(R, R.p0);
+  Diamond d3(R, R.p0);
+
+  d2.nest(d1, true);
+  d3.nest(d1, false);
+
+  Node* ret = R.Return(d1.phi, R.start, d1.merge);
+
+  R.ReduceGraph();  // nothing should happen.
+
+  CheckInputs(ret, d1.phi, R.start, d1.merge);
+  CheckInputs(d1.phi, R.one, R.zero, d1.merge);
+  CheckInputs(d1.merge, d2.merge, d3.merge);
+  CheckLiveDiamond(d2);
+  CheckLiveDiamond(d3);
+}
+
+
+TEST(Return_nested_diamonds_true1) {
+  ControlReducerTester R;
+  Diamond d1(R, R.one, R.one, R.zero);
+  Diamond d2(R, R.p0);
+  Diamond d3(R, R.p0);
+
+  d2.nest(d1, true);
+  d3.nest(d1, false);
+
+  Node* ret = R.Return(d1.phi, R.start, d1.merge);
+
+  R.ReduceGraph();  // d1 gets folded true.
+
+  CheckInputs(ret, R.one, R.start, d2.merge);
+  CheckInputs(d2.branch, R.p0, R.start);
+  CheckDeadDiamond(d1);
+  CheckLiveDiamond(d2);
+  CheckDeadDiamond(d3);
+}
+
+
+TEST(Return_nested_diamonds_false1) {
+  ControlReducerTester R;
+  Diamond d1(R, R.zero, R.one, R.zero);
+  Diamond d2(R, R.p0);
+  Diamond d3(R, R.p0);
+
+  d2.nest(d1, true);
+  d3.nest(d1, false);
+
+  Node* ret = R.Return(d1.phi, R.start, d1.merge);
+
+  R.ReduceGraph();  // d1 gets folded false.
+
+  CheckInputs(ret, R.zero, R.start, d3.merge);
+  CheckInputs(d3.branch, R.p0, R.start);
+  CheckDeadDiamond(d1);
+  CheckDeadDiamond(d2);
+  CheckLiveDiamond(d3);
+}
+
+
+TEST(Return_nested_diamonds_true_true1) {
+  ControlReducerTester R;
+  Diamond d1(R, R.one, R.one, R.zero);
+  Diamond d2(R, R.one);
+  Diamond d3(R, R.p0);
+
+  d2.nest(d1, true);
+  d3.nest(d1, false);
+
+  Node* ret = R.Return(d1.phi, R.start, d1.merge);
+
+  R.ReduceGraph();  // d1 and d2 both get folded true.
+
+  CheckInputs(ret, R.one, R.start, R.start);
+  CheckDeadDiamond(d1);
+  CheckDeadDiamond(d2);
+  CheckDeadDiamond(d3);
+}
+
+
+TEST(Return_nested_diamonds_true_false1) {
+  ControlReducerTester R;
+  Diamond d1(R, R.one, R.one, R.zero);
+  Diamond d2(R, R.zero);
+  Diamond d3(R, R.p0);
+
+  d2.nest(d1, true);
+  d3.nest(d1, false);
+
+  Node* ret = R.Return(d1.phi, R.start, d1.merge);
+
+  R.ReduceGraph();  // d1 gets folded true and d2 gets folded false.
+
+  CheckInputs(ret, R.one, R.start, R.start);
+  CheckDeadDiamond(d1);
+  CheckDeadDiamond(d2);
+  CheckDeadDiamond(d3);
+}
+
+
+TEST(Return_nested_diamonds2) {
+  ControlReducerTester R;
+  Node* x2 = R.jsgraph.Float64Constant(11.1);
+  Node* y2 = R.jsgraph.Float64Constant(22.2);
+  Node* x3 = R.jsgraph.Float64Constant(33.3);
+  Node* y3 = R.jsgraph.Float64Constant(44.4);
+
+  Diamond d2(R, R.p0, x2, y2);
+  Diamond d3(R, R.p0, x3, y3);
+  Diamond d1(R, R.p0, d2.phi, d3.phi);
+
+  d2.nest(d1, true);
+  d3.nest(d1, false);
+
+  Node* ret = R.Return(d1.phi, R.start, d1.merge);
+
+  R.ReduceGraph();  // nothing should happen.
+
+  CheckInputs(ret, d1.phi, R.start, d1.merge);
+  CheckInputs(d1.phi, d2.phi, d3.phi, d1.merge);
+  CheckInputs(d1.merge, d2.merge, d3.merge);
+  CheckLiveDiamond(d2);
+  CheckLiveDiamond(d3);
+}
+
+
+TEST(Return_nested_diamonds_true2) {
+  ControlReducerTester R;
+  Node* x2 = R.jsgraph.Float64Constant(11.1);
+  Node* y2 = R.jsgraph.Float64Constant(22.2);
+  Node* x3 = R.jsgraph.Float64Constant(33.3);
+  Node* y3 = R.jsgraph.Float64Constant(44.4);
+
+  Diamond d2(R, R.p0, x2, y2);
+  Diamond d3(R, R.p0, x3, y3);
+  Diamond d1(R, R.one, d2.phi, d3.phi);
+
+  d2.nest(d1, true);
+  d3.nest(d1, false);
+
+  Node* ret = R.Return(d1.phi, R.start, d1.merge);
+
+  R.ReduceGraph();  // d1 gets folded true.
+
+  CheckInputs(ret, d2.phi, R.start, d2.merge);
+  CheckInputs(d2.branch, R.p0, R.start);
+  CheckDeadDiamond(d1);
+  CheckLiveDiamond(d2);
+  CheckDeadDiamond(d3);
+}
+
+
+TEST(Return_nested_diamonds_true_true2) {
+  ControlReducerTester R;
+  Node* x2 = R.jsgraph.Float64Constant(11.1);
+  Node* y2 = R.jsgraph.Float64Constant(22.2);
+  Node* x3 = R.jsgraph.Float64Constant(33.3);
+  Node* y3 = R.jsgraph.Float64Constant(44.4);
+
+  Diamond d2(R, R.one, x2, y2);
+  Diamond d3(R, R.p0, x3, y3);
+  Diamond d1(R, R.one, d2.phi, d3.phi);
+
+  d2.nest(d1, true);
+  d3.nest(d1, false);
+
+  Node* ret = R.Return(d1.phi, R.start, d1.merge);
+
+  R.ReduceGraph();  // d1 gets folded true.
+
+  CheckInputs(ret, x2, R.start, R.start);
+  CheckDeadDiamond(d1);
+  CheckDeadDiamond(d2);
+  CheckDeadDiamond(d3);
+}
+
+
+TEST(Return_nested_diamonds_true_false2) {
+  ControlReducerTester R;
+  Node* x2 = R.jsgraph.Float64Constant(11.1);
+  Node* y2 = R.jsgraph.Float64Constant(22.2);
+  Node* x3 = R.jsgraph.Float64Constant(33.3);
+  Node* y3 = R.jsgraph.Float64Constant(44.4);
+
+  Diamond d2(R, R.zero, x2, y2);
+  Diamond d3(R, R.p0, x3, y3);
+  Diamond d1(R, R.one, d2.phi, d3.phi);
+
+  d2.nest(d1, true);
+  d3.nest(d1, false);
+
+  Node* ret = R.Return(d1.phi, R.start, d1.merge);
+
+  R.ReduceGraph();  // d1 gets folded true.
+
+  CheckInputs(ret, y2, R.start, R.start);
+  CheckDeadDiamond(d1);
+  CheckDeadDiamond(d2);
+  CheckDeadDiamond(d3);
+}
diff --git a/test/cctest/compiler/test-gap-resolver.cc b/test/cctest/compiler/test-gap-resolver.cc
index 6239f2a..ea6f4ee 100644
--- a/test/cctest/compiler/test-gap-resolver.cc
+++ b/test/cctest/compiler/test-gap-resolver.cc
@@ -58,13 +58,16 @@
     return Value(op->kind(), op->index());
   }
 
-  friend OStream& operator<<(OStream& os, const InterpreterState& is) {
+  friend std::ostream& operator<<(std::ostream& os,
+                                  const InterpreterState& is) {
     for (OperandMap::const_iterator it = is.values_.begin();
          it != is.values_.end(); ++it) {
       if (it != is.values_.begin()) os << " ";
       InstructionOperand source(it->first.first, it->first.second);
       InstructionOperand destination(it->second.first, it->second.second);
-      os << MoveOperands(&source, &destination);
+      MoveOperands mo(&source, &destination);
+      PrintableMoveOperands pmo = {RegisterConfiguration::ArchDefault(), &mo};
+      os << pmo;
     }
     return os;
   }
diff --git a/test/cctest/compiler/test-graph-reducer.cc b/test/cctest/compiler/test-graph-reducer.cc
index eabfd22..70b57b9 100644
--- a/test/cctest/compiler/test-graph-reducer.cc
+++ b/test/cctest/compiler/test-graph-reducer.cc
@@ -5,7 +5,6 @@
 #include "src/v8.h"
 
 #include "graph-tester.h"
-#include "src/compiler/generic-node-inl.h"
 #include "src/compiler/graph-reducer.h"
 
 using namespace v8::internal;
@@ -21,15 +20,15 @@
 const uint8_t OPCODE_C1 = 31;
 const uint8_t OPCODE_C2 = 32;
 
-static SimpleOperator OPA0(OPCODE_A0, Operator::kNoWrite, 0, 0, "opa0");
-static SimpleOperator OPA1(OPCODE_A1, Operator::kNoWrite, 1, 0, "opa1");
-static SimpleOperator OPA2(OPCODE_A2, Operator::kNoWrite, 2, 0, "opa2");
-static SimpleOperator OPB0(OPCODE_B0, Operator::kNoWrite, 0, 0, "opa0");
-static SimpleOperator OPB1(OPCODE_B1, Operator::kNoWrite, 1, 0, "opa1");
-static SimpleOperator OPB2(OPCODE_B2, Operator::kNoWrite, 2, 0, "opa2");
-static SimpleOperator OPC0(OPCODE_C0, Operator::kNoWrite, 0, 0, "opc0");
-static SimpleOperator OPC1(OPCODE_C1, Operator::kNoWrite, 1, 0, "opc1");
-static SimpleOperator OPC2(OPCODE_C2, Operator::kNoWrite, 2, 0, "opc2");
+static Operator OPA0(OPCODE_A0, Operator::kNoWrite, "opa0", 0, 0, 0, 0, 0, 0);
+static Operator OPA1(OPCODE_A1, Operator::kNoWrite, "opa1", 1, 0, 0, 0, 0, 0);
+static Operator OPA2(OPCODE_A2, Operator::kNoWrite, "opa2", 2, 0, 0, 0, 0, 0);
+static Operator OPB0(OPCODE_B0, Operator::kNoWrite, "opa0", 0, 0, 0, 0, 0, 0);
+static Operator OPB1(OPCODE_B1, Operator::kNoWrite, "opa1", 1, 0, 0, 0, 0, 0);
+static Operator OPB2(OPCODE_B2, Operator::kNoWrite, "opa2", 2, 0, 0, 0, 0, 0);
+static Operator OPC0(OPCODE_C0, Operator::kNoWrite, "opc0", 0, 0, 0, 0, 0, 0);
+static Operator OPC1(OPCODE_C1, Operator::kNoWrite, "opc1", 1, 0, 0, 0, 0, 0);
+static Operator OPC2(OPCODE_C2, Operator::kNoWrite, "opc2", 2, 0, 0, 0, 0, 0);
 
 
 // Replaces all "A" operators with "B" operators without creating new nodes.
@@ -202,7 +201,7 @@
   Node* end = graph.NewNode(&OPA1, n1);
   graph.SetEnd(end);
 
-  GraphReducer reducer(&graph);
+  GraphReducer reducer(&graph, graph.zone());
   ReducerRecorder recorder(graph.zone());
   reducer.AddReducer(&recorder);
   reducer.ReduceGraph();
@@ -220,7 +219,7 @@
   Node* end = graph.NewNode(&OPA2, n2, n3);
   graph.SetEnd(end);
 
-  GraphReducer reducer(&graph);
+  GraphReducer reducer(&graph, graph.zone());
   ReducerRecorder recorder(graph.zone());
   reducer.AddReducer(&recorder);
   reducer.ReduceGraph();
@@ -238,7 +237,7 @@
   Node* end = graph.NewNode(&OPA1, n1);
   graph.SetEnd(end);
 
-  GraphReducer reducer(&graph);
+  GraphReducer reducer(&graph, graph.zone());
   InPlaceABReducer r;
   reducer.AddReducer(&r);
 
@@ -263,7 +262,7 @@
   Node* end = graph.NewNode(&OPA2, n2, n3);
   graph.SetEnd(end);
 
-  GraphReducer reducer(&graph);
+  GraphReducer reducer(&graph, graph.zone());
   InPlaceABReducer r;
   reducer.AddReducer(&r);
 
@@ -293,7 +292,7 @@
   Node* end = graph.NewNode(&OPA2, n2, n3);
   graph.SetEnd(end);
 
-  GraphReducer reducer(&graph);
+  GraphReducer reducer(&graph, graph.zone());
   NewABReducer r(&graph);
   reducer.AddReducer(&r);
 
@@ -330,7 +329,7 @@
   graph.SetEnd(end);
   CHECK_EQ(1, graph.NodeCount());
 
-  GraphReducer reducer(&graph);
+  GraphReducer reducer(&graph, graph.zone());
   A0Wrapper r(&graph);
   reducer.AddReducer(&r);
 
@@ -352,7 +351,7 @@
   graph.SetEnd(end);
   CHECK_EQ(1, graph.NodeCount());
 
-  GraphReducer reducer(&graph);
+  GraphReducer reducer(&graph, graph.zone());
   B0Wrapper r(&graph);
   reducer.AddReducer(&r);
 
@@ -379,7 +378,7 @@
   Node* end = graph.NewNode(&OPA1, n1);
   graph.SetEnd(end);
 
-  GraphReducer reducer(&graph);
+  GraphReducer reducer(&graph, graph.zone());
   A1Forwarder r;
   reducer.AddReducer(&r);
 
@@ -403,7 +402,7 @@
   Node* end = graph.NewNode(&OPA2, n2, n3);
   graph.SetEnd(end);
 
-  GraphReducer reducer(&graph);
+  GraphReducer reducer(&graph, graph.zone());
   A1Forwarder r;
   reducer.AddReducer(&r);
 
@@ -434,7 +433,7 @@
     }
     graph.SetEnd(end);
 
-    GraphReducer reducer(&graph);
+    GraphReducer reducer(&graph, graph.zone());
     A1Forwarder r;
     reducer.AddReducer(&r);
 
@@ -458,7 +457,7 @@
   Node* end = graph.NewNode(&OPA2, n2, n3);
   graph.SetEnd(end);
 
-  GraphReducer reducer(&graph);
+  GraphReducer reducer(&graph, graph.zone());
   InPlaceABReducer r;
   B1Forwarder f;
   reducer.AddReducer(&r);
@@ -501,7 +500,7 @@
 
     graph.SetEnd(end);
 
-    GraphReducer reducer(&graph);
+    GraphReducer reducer(&graph, graph.zone());
     reducer.AddReducer(&r);
 
     int before = graph.NodeCount();
@@ -560,7 +559,7 @@
 
         GenDAG(&graph, p3, p2, p1);
 
-        GraphReducer reducer(&graph);
+        GraphReducer reducer(&graph, graph.zone());
         AB2Sorter r1;
         A1Forwarder r2;
         InPlaceABReducer r3;
@@ -599,7 +598,7 @@
     Node* end = graph.NewNode(&OPA1, n1);
     graph.SetEnd(end);
 
-    GraphReducer reducer(&graph);
+    GraphReducer reducer(&graph, graph.zone());
     InPlaceABReducer abr;
     InPlaceBCReducer bcr;
     if (i == 0) {
@@ -621,41 +620,3 @@
     }
   }
 }
-
-
-// Tests that a reducer is only applied once.
-class OneTimeReducer : public Reducer {
- public:
-  OneTimeReducer(Reducer* reducer, Zone* zone)
-      : reducer_(reducer),
-        nodes_(NodeSet::key_compare(), NodeSet::allocator_type(zone)) {}
-  virtual Reduction Reduce(Node* node) {
-    CHECK_EQ(0, static_cast<int>(nodes_.count(node)));
-    nodes_.insert(node);
-    return reducer_->Reduce(node);
-  }
-  Reducer* reducer_;
-  NodeSet nodes_;
-};
-
-
-TEST(OneTimeReduce1) {
-  GraphTester graph;
-
-  Node* n1 = graph.NewNode(&OPA0);
-  Node* end = graph.NewNode(&OPA1, n1);
-  graph.SetEnd(end);
-
-  GraphReducer reducer(&graph);
-  InPlaceABReducer r;
-  OneTimeReducer once(&r, graph.zone());
-  reducer.AddReducer(&once);
-
-  // Tests A* => B* with in-place updates. Should only be applied once.
-  int before = graph.NodeCount();
-  reducer.ReduceGraph();
-  CHECK_EQ(before, graph.NodeCount());
-  CHECK_EQ(&OPB0, n1->op());
-  CHECK_EQ(&OPB1, end->op());
-  CHECK_EQ(n1, end->InputAt(0));
-}
diff --git a/test/cctest/compiler/test-graph-visualizer.cc b/test/cctest/compiler/test-graph-visualizer.cc
new file mode 100644
index 0000000..ce3e6b7
--- /dev/null
+++ b/test/cctest/compiler/test-graph-visualizer.cc
@@ -0,0 +1,90 @@
+// 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.
+
+#include "src/v8.h"
+#include "test/cctest/cctest.h"
+
+#include "src/compiler/common-operator.h"
+#include "src/compiler/graph.h"
+#include "src/compiler/graph-visualizer.h"
+#include "src/compiler/js-operator.h"
+#include "src/compiler/machine-operator.h"
+#include "src/compiler/node.h"
+#include "src/compiler/operator.h"
+#include "src/compiler/schedule.h"
+#include "src/compiler/scheduler.h"
+#include "src/compiler/verifier.h"
+
+using namespace v8::internal;
+using namespace v8::internal::compiler;
+
+TEST(NodeWithNullInputReachableFromEnd) {
+  HandleAndZoneScope scope;
+  Graph graph(scope.main_zone());
+  CommonOperatorBuilder common(scope.main_zone());
+
+  Node* start = graph.NewNode(common.Start(0));
+  graph.SetStart(start);
+  Node* k = graph.NewNode(common.Int32Constant(0));
+  Node* phi = graph.NewNode(common.Phi(kMachAnyTagged, 1), k, start);
+  phi->ReplaceInput(0, NULL);
+  graph.SetEnd(phi);
+
+  OFStream os(stdout);
+  os << AsDOT(graph);
+  os << AsJSON(graph);
+}
+
+
+TEST(NodeWithNullControlReachableFromEnd) {
+  HandleAndZoneScope scope;
+  Graph graph(scope.main_zone());
+  CommonOperatorBuilder common(scope.main_zone());
+
+  Node* start = graph.NewNode(common.Start(0));
+  graph.SetStart(start);
+  Node* k = graph.NewNode(common.Int32Constant(0));
+  Node* phi = graph.NewNode(common.Phi(kMachAnyTagged, 1), k, start);
+  phi->ReplaceInput(1, NULL);
+  graph.SetEnd(phi);
+
+  OFStream os(stdout);
+  os << AsDOT(graph);
+  os << AsJSON(graph);
+}
+
+
+TEST(NodeWithNullInputReachableFromStart) {
+  HandleAndZoneScope scope;
+  Graph graph(scope.main_zone());
+  CommonOperatorBuilder common(scope.main_zone());
+
+  Node* start = graph.NewNode(common.Start(0));
+  graph.SetStart(start);
+  Node* k = graph.NewNode(common.Int32Constant(0));
+  Node* phi = graph.NewNode(common.Phi(kMachAnyTagged, 1), k, start);
+  phi->ReplaceInput(0, NULL);
+  graph.SetEnd(start);
+
+  OFStream os(stdout);
+  os << AsDOT(graph);
+  os << AsJSON(graph);
+}
+
+
+TEST(NodeWithNullControlReachableFromStart) {
+  HandleAndZoneScope scope;
+  Graph graph(scope.main_zone());
+  CommonOperatorBuilder common(scope.main_zone());
+
+  Node* start = graph.NewNode(common.Start(0));
+  graph.SetStart(start);
+  Node* merge = graph.NewNode(common.Merge(2), start, start);
+  merge->ReplaceInput(1, NULL);
+  graph.SetEnd(merge);
+
+  OFStream os(stdout);
+  os << AsDOT(graph);
+  os << AsJSON(graph);
+}
diff --git a/test/cctest/compiler/test-instruction.cc b/test/cctest/compiler/test-instruction.cc
index a9feaac..294812f 100644
--- a/test/cctest/compiler/test-instruction.cc
+++ b/test/cctest/compiler/test-instruction.cc
@@ -31,12 +31,11 @@
         graph(zone()),
         schedule(zone()),
         info(static_cast<HydrogenCodeStub*>(NULL), main_isolate()),
-        linkage(&info),
+        linkage(zone(), &info),
         common(zone()),
+        machine(zone()),
         code(NULL) {}
 
-  ~InstructionTester() { delete code; }
-
   Isolate* isolate;
   Graph graph;
   Schedule schedule;
@@ -51,10 +50,12 @@
   void allocCode() {
     if (schedule.rpo_order()->size() == 0) {
       // Compute the RPO order.
-      Scheduler::ComputeSpecialRPO(&schedule);
+      Scheduler::ComputeSpecialRPO(main_zone(), &schedule);
       DCHECK(schedule.rpo_order()->size() > 0);
     }
-    code = new TestInstrSeq(&linkage, &graph, &schedule);
+    InstructionBlocks* instruction_blocks =
+        TestInstrSeq::InstructionBlocksFor(main_zone(), &schedule);
+    code = new (main_zone()) TestInstrSeq(main_zone(), instruction_blocks);
   }
 
   Node* Int32Constant(int32_t val) {
@@ -81,10 +82,10 @@
     return node;
   }
 
-  int NewInstr(BasicBlock* block) {
+  int NewInstr() {
     InstructionCode opcode = static_cast<InstructionCode>(110);
     TestInstr* instr = TestInstr::New(zone(), opcode);
-    return code->AddInstruction(instr, block);
+    return code->AddInstruction(instr);
   }
 
   UnallocatedOperand* NewUnallocated(int vreg) {
@@ -93,6 +94,21 @@
     unallocated->set_virtual_register(vreg);
     return unallocated;
   }
+
+  InstructionBlock* BlockAt(BasicBlock* block) {
+    return code->InstructionBlockAt(block->GetRpoNumber());
+  }
+  BasicBlock* GetBasicBlock(int instruction_index) {
+    const InstructionBlock* block =
+        code->GetInstructionBlock(instruction_index);
+    return schedule.rpo_order()->at(block->rpo_number().ToSize());
+  }
+  int first_instruction_index(BasicBlock* block) {
+    return BlockAt(block)->first_instruction_index();
+  }
+  int last_instruction_index(BasicBlock* block) {
+    return BlockAt(block)->last_instruction_index();
+  }
 };
 
 
@@ -112,17 +128,16 @@
 
   R.allocCode();
 
-  CHECK_EQ(R.graph.NodeCount(), R.code->ValueCount());
-
   BasicBlockVector* blocks = R.schedule.rpo_order();
-  CHECK_EQ(static_cast<int>(blocks->size()), R.code->BasicBlockCount());
+  CHECK_EQ(static_cast<int>(blocks->size()), R.code->InstructionBlockCount());
 
   int index = 0;
   for (BasicBlockVectorIter i = blocks->begin(); i != blocks->end();
        i++, index++) {
     BasicBlock* block = *i;
-    CHECK_EQ(block, R.code->BlockAt(index));
-    CHECK_EQ(-1, R.code->GetLoopEnd(block));
+    CHECK_EQ(block->rpo_number(), R.BlockAt(block)->rpo_number().ToInt());
+    CHECK_EQ(block->id().ToInt(), R.BlockAt(block)->id().ToInt());
+    CHECK_EQ(NULL, block->loop_end());
   }
 }
 
@@ -141,47 +156,47 @@
 
   R.allocCode();
 
-  R.code->StartBlock(b0);
-  int i0 = R.NewInstr(b0);
-  int i1 = R.NewInstr(b0);
-  R.code->EndBlock(b0);
-  R.code->StartBlock(b1);
-  int i2 = R.NewInstr(b1);
-  int i3 = R.NewInstr(b1);
-  int i4 = R.NewInstr(b1);
-  int i5 = R.NewInstr(b1);
-  R.code->EndBlock(b1);
-  R.code->StartBlock(b2);
-  int i6 = R.NewInstr(b2);
-  int i7 = R.NewInstr(b2);
-  int i8 = R.NewInstr(b2);
-  R.code->EndBlock(b2);
-  R.code->StartBlock(b3);
-  R.code->EndBlock(b3);
+  R.code->StartBlock(b0->GetRpoNumber());
+  int i0 = R.NewInstr();
+  int i1 = R.NewInstr();
+  R.code->EndBlock(b0->GetRpoNumber());
+  R.code->StartBlock(b1->GetRpoNumber());
+  int i2 = R.NewInstr();
+  int i3 = R.NewInstr();
+  int i4 = R.NewInstr();
+  int i5 = R.NewInstr();
+  R.code->EndBlock(b1->GetRpoNumber());
+  R.code->StartBlock(b2->GetRpoNumber());
+  int i6 = R.NewInstr();
+  int i7 = R.NewInstr();
+  int i8 = R.NewInstr();
+  R.code->EndBlock(b2->GetRpoNumber());
+  R.code->StartBlock(b3->GetRpoNumber());
+  R.code->EndBlock(b3->GetRpoNumber());
 
-  CHECK_EQ(b0, R.code->GetBasicBlock(i0));
-  CHECK_EQ(b0, R.code->GetBasicBlock(i1));
+  CHECK_EQ(b0, R.GetBasicBlock(i0));
+  CHECK_EQ(b0, R.GetBasicBlock(i1));
 
-  CHECK_EQ(b1, R.code->GetBasicBlock(i2));
-  CHECK_EQ(b1, R.code->GetBasicBlock(i3));
-  CHECK_EQ(b1, R.code->GetBasicBlock(i4));
-  CHECK_EQ(b1, R.code->GetBasicBlock(i5));
+  CHECK_EQ(b1, R.GetBasicBlock(i2));
+  CHECK_EQ(b1, R.GetBasicBlock(i3));
+  CHECK_EQ(b1, R.GetBasicBlock(i4));
+  CHECK_EQ(b1, R.GetBasicBlock(i5));
 
-  CHECK_EQ(b2, R.code->GetBasicBlock(i6));
-  CHECK_EQ(b2, R.code->GetBasicBlock(i7));
-  CHECK_EQ(b2, R.code->GetBasicBlock(i8));
+  CHECK_EQ(b2, R.GetBasicBlock(i6));
+  CHECK_EQ(b2, R.GetBasicBlock(i7));
+  CHECK_EQ(b2, R.GetBasicBlock(i8));
 
-  CHECK_EQ(b0, R.code->GetBasicBlock(b0->first_instruction_index()));
-  CHECK_EQ(b0, R.code->GetBasicBlock(b0->last_instruction_index()));
+  CHECK_EQ(b0, R.GetBasicBlock(R.first_instruction_index(b0)));
+  CHECK_EQ(b0, R.GetBasicBlock(R.last_instruction_index(b0)));
 
-  CHECK_EQ(b1, R.code->GetBasicBlock(b1->first_instruction_index()));
-  CHECK_EQ(b1, R.code->GetBasicBlock(b1->last_instruction_index()));
+  CHECK_EQ(b1, R.GetBasicBlock(R.first_instruction_index(b1)));
+  CHECK_EQ(b1, R.GetBasicBlock(R.last_instruction_index(b1)));
 
-  CHECK_EQ(b2, R.code->GetBasicBlock(b2->first_instruction_index()));
-  CHECK_EQ(b2, R.code->GetBasicBlock(b2->last_instruction_index()));
+  CHECK_EQ(b2, R.GetBasicBlock(R.first_instruction_index(b2)));
+  CHECK_EQ(b2, R.GetBasicBlock(R.last_instruction_index(b2)));
 
-  CHECK_EQ(b3, R.code->GetBasicBlock(b3->first_instruction_index()));
-  CHECK_EQ(b3, R.code->GetBasicBlock(b3->last_instruction_index()));
+  CHECK_EQ(b3, R.GetBasicBlock(R.first_instruction_index(b3)));
+  CHECK_EQ(b3, R.GetBasicBlock(R.last_instruction_index(b3)));
 }
 
 
@@ -194,10 +209,10 @@
   R.allocCode();
   TestInstr* i0 = TestInstr::New(R.zone(), 100);
   TestInstr* g = TestInstr::New(R.zone(), 103)->MarkAsControl();
-  R.code->StartBlock(b0);
-  R.code->AddInstruction(i0, b0);
-  R.code->AddInstruction(g, b0);
-  R.code->EndBlock(b0);
+  R.code->StartBlock(b0->GetRpoNumber());
+  R.code->AddInstruction(i0);
+  R.code->AddInstruction(g);
+  R.code->EndBlock(b0->GetRpoNumber());
 
   CHECK_EQ(true, R.code->InstructionAt(0)->IsBlockStart());
 
@@ -221,17 +236,17 @@
   R.allocCode();
   TestInstr* i0 = TestInstr::New(R.zone(), 100);
   TestInstr* g = TestInstr::New(R.zone(), 103)->MarkAsControl();
-  R.code->StartBlock(b0);
-  R.code->AddInstruction(i0, b0);
-  R.code->AddInstruction(g, b0);
-  R.code->EndBlock(b0);
+  R.code->StartBlock(b0->GetRpoNumber());
+  R.code->AddInstruction(i0);
+  R.code->AddInstruction(g);
+  R.code->EndBlock(b0->GetRpoNumber());
 
   TestInstr* i1 = TestInstr::New(R.zone(), 102);
   TestInstr* g1 = TestInstr::New(R.zone(), 104)->MarkAsControl();
-  R.code->StartBlock(b1);
-  R.code->AddInstruction(i1, b1);
-  R.code->AddInstruction(g1, b1);
-  R.code->EndBlock(b1);
+  R.code->StartBlock(b1->GetRpoNumber());
+  R.code->AddInstruction(i1);
+  R.code->AddInstruction(g1);
+  R.code->EndBlock(b1->GetRpoNumber());
 
   CHECK_EQ(true, R.code->InstructionAt(0)->IsBlockStart());
 
@@ -262,10 +277,10 @@
   R.allocCode();
   TestInstr* i0 = TestInstr::New(R.zone(), 100);
   TestInstr* g = TestInstr::New(R.zone(), 103)->MarkAsControl();
-  R.code->StartBlock(b0);
-  R.code->AddInstruction(i0, b0);
-  R.code->AddInstruction(g, b0);
-  R.code->EndBlock(b0);
+  R.code->StartBlock(b0->GetRpoNumber());
+  R.code->AddInstruction(i0);
+  R.code->AddInstruction(g);
+  R.code->EndBlock(b0->GetRpoNumber());
 
   CHECK_EQ(true, R.code->InstructionAt(0)->IsBlockStart());
 
diff --git a/test/cctest/compiler/test-js-constant-cache.cc b/test/cctest/compiler/test-js-constant-cache.cc
index eb0975e..8588f66 100644
--- a/test/cctest/compiler/test-js-constant-cache.cc
+++ b/test/cctest/compiler/test-js-constant-cache.cc
@@ -4,6 +4,7 @@
 
 #include "src/v8.h"
 
+#include "src/assembler.h"
 #include "src/compiler/js-graph.h"
 #include "src/compiler/node-properties-inl.h"
 #include "src/compiler/typer.h"
@@ -20,8 +21,8 @@
       : main_graph_(zone),
         main_common_(zone),
         main_javascript_(zone),
-        main_typer_(zone),
-        main_machine_() {}
+        main_typer_(&main_graph_, MaybeHandle<Context>()),
+        main_machine_(zone) {}
   Graph main_graph_;
   CommonOperatorBuilder main_common_;
   JSOperatorBuilder main_javascript_;
@@ -30,14 +31,19 @@
 };
 
 
+// TODO(dcarney): JSConstantCacheTester inherits from JSGraph???
 class JSConstantCacheTester : public HandleAndZoneScope,
                               public JSCacheTesterHelper,
                               public JSGraph {
  public:
   JSConstantCacheTester()
       : JSCacheTesterHelper(main_zone()),
-        JSGraph(&main_graph_, &main_common_, &main_javascript_, &main_typer_,
-                &main_machine_) {}
+        JSGraph(&main_graph_, &main_common_, &main_javascript_,
+                &main_machine_) {
+    main_graph_.SetStart(main_graph_.NewNode(common()->Start(0)));
+    main_graph_.SetEnd(main_graph_.NewNode(common()->End()));
+    main_typer_.Run();
+  }
 
   Type* upper(Node* node) { return NodeProperties::GetBounds(node).upper; }
 
@@ -227,7 +233,7 @@
   FOR_FLOAT64_INPUTS(i) {
     double value = *i;
     Node* node = T.Constant(value);
-    CHECK(T.upper(node)->Equals(Type::Of(value, T.main_zone())));
+    CHECK(T.upper(node)->Is(Type::Of(value, T.main_zone())));
   }
 }
 
@@ -289,3 +295,180 @@
 TEST(ExternalReferences) {
   // TODO(titzer): test canonicalization of external references.
 }
+
+
+static bool Contains(NodeVector* nodes, Node* n) {
+  for (size_t i = 0; i < nodes->size(); i++) {
+    if (nodes->at(i) == n) return true;
+  }
+  return false;
+}
+
+
+static void CheckGetCachedNodesContains(JSConstantCacheTester* T, Node* n) {
+  NodeVector nodes(T->main_zone());
+  T->GetCachedNodes(&nodes);
+  CHECK(Contains(&nodes, n));
+}
+
+
+TEST(JSGraph_GetCachedNodes1) {
+  JSConstantCacheTester T;
+  CheckGetCachedNodesContains(&T, T.TrueConstant());
+  CheckGetCachedNodesContains(&T, T.UndefinedConstant());
+  CheckGetCachedNodesContains(&T, T.TheHoleConstant());
+  CheckGetCachedNodesContains(&T, T.TrueConstant());
+  CheckGetCachedNodesContains(&T, T.FalseConstant());
+  CheckGetCachedNodesContains(&T, T.NullConstant());
+  CheckGetCachedNodesContains(&T, T.ZeroConstant());
+  CheckGetCachedNodesContains(&T, T.OneConstant());
+  CheckGetCachedNodesContains(&T, T.NaNConstant());
+}
+
+
+TEST(JSGraph_GetCachedNodes_int32) {
+  JSConstantCacheTester T;
+
+  int32_t constants[] = {0,  1,  1,   1,   1,   2,   3,   4,  11, 12, 13,
+                         14, 55, -55, -44, -33, -22, -11, 16, 16, 17, 17,
+                         18, 18, 19,  19,  20,  20,  21,  21, 22, 23, 24,
+                         25, 15, 30,  31,  45,  46,  47,  48};
+
+  for (size_t i = 0; i < arraysize(constants); i++) {
+    int count_before = T.graph()->NodeCount();
+    NodeVector nodes_before(T.main_zone());
+    T.GetCachedNodes(&nodes_before);
+    Node* n = T.Int32Constant(constants[i]);
+    if (n->id() < count_before) {
+      // An old ID indicates a cached node. It should have been in the set.
+      CHECK(Contains(&nodes_before, n));
+    }
+    // Old or new, it should be in the cached set afterwards.
+    CheckGetCachedNodesContains(&T, n);
+  }
+}
+
+
+TEST(JSGraph_GetCachedNodes_float64) {
+  JSConstantCacheTester T;
+
+  double constants[] = {0,   11.1, 12.2,  13,    14,   55.5, -55.5, -44.4,
+                        -33, -22,  -11,   0,     11.1, 11.1, 12.3,  12.3,
+                        11,  11,   -33.3, -33.3, -22,  -11};
+
+  for (size_t i = 0; i < arraysize(constants); i++) {
+    int count_before = T.graph()->NodeCount();
+    NodeVector nodes_before(T.main_zone());
+    T.GetCachedNodes(&nodes_before);
+    Node* n = T.Float64Constant(constants[i]);
+    if (n->id() < count_before) {
+      // An old ID indicates a cached node. It should have been in the set.
+      CHECK(Contains(&nodes_before, n));
+    }
+    // Old or new, it should be in the cached set afterwards.
+    CheckGetCachedNodesContains(&T, n);
+  }
+}
+
+
+TEST(JSGraph_GetCachedNodes_int64) {
+  JSConstantCacheTester T;
+
+  int32_t constants[] = {0,   11,  12, 13, 14, 55, -55, -44, -33,
+                         -22, -11, 16, 16, 17, 17, 18,  18,  19,
+                         19,  20,  20, 21, 21, 22, 23,  24,  25};
+
+  for (size_t i = 0; i < arraysize(constants); i++) {
+    int count_before = T.graph()->NodeCount();
+    NodeVector nodes_before(T.main_zone());
+    T.GetCachedNodes(&nodes_before);
+    Node* n = T.Int64Constant(constants[i]);
+    if (n->id() < count_before) {
+      // An old ID indicates a cached node. It should have been in the set.
+      CHECK(Contains(&nodes_before, n));
+    }
+    // Old or new, it should be in the cached set afterwards.
+    CheckGetCachedNodesContains(&T, n);
+  }
+}
+
+
+TEST(JSGraph_GetCachedNodes_number) {
+  JSConstantCacheTester T;
+
+  double constants[] = {0,   11.1, 12.2,  13,    14,   55.5, -55.5, -44.4,
+                        -33, -22,  -11,   0,     11.1, 11.1, 12.3,  12.3,
+                        11,  11,   -33.3, -33.3, -22,  -11};
+
+  for (size_t i = 0; i < arraysize(constants); i++) {
+    int count_before = T.graph()->NodeCount();
+    NodeVector nodes_before(T.main_zone());
+    T.GetCachedNodes(&nodes_before);
+    Node* n = T.Constant(constants[i]);
+    if (n->id() < count_before) {
+      // An old ID indicates a cached node. It should have been in the set.
+      CHECK(Contains(&nodes_before, n));
+    }
+    // Old or new, it should be in the cached set afterwards.
+    CheckGetCachedNodesContains(&T, n);
+  }
+}
+
+
+TEST(JSGraph_GetCachedNodes_external) {
+  JSConstantCacheTester T;
+
+  ExternalReference constants[] = {ExternalReference::address_of_min_int(),
+                                   ExternalReference::address_of_min_int(),
+                                   ExternalReference::address_of_min_int(),
+                                   ExternalReference::address_of_one_half(),
+                                   ExternalReference::address_of_one_half(),
+                                   ExternalReference::address_of_min_int(),
+                                   ExternalReference::address_of_the_hole_nan(),
+                                   ExternalReference::address_of_one_half()};
+
+  for (size_t i = 0; i < arraysize(constants); i++) {
+    int count_before = T.graph()->NodeCount();
+    NodeVector nodes_before(T.main_zone());
+    T.GetCachedNodes(&nodes_before);
+    Node* n = T.ExternalConstant(constants[i]);
+    if (n->id() < count_before) {
+      // An old ID indicates a cached node. It should have been in the set.
+      CHECK(Contains(&nodes_before, n));
+    }
+    // Old or new, it should be in the cached set afterwards.
+    CheckGetCachedNodesContains(&T, n);
+  }
+}
+
+
+TEST(JSGraph_GetCachedNodes_together) {
+  JSConstantCacheTester T;
+
+  Node* constants[] = {
+      T.TrueConstant(),
+      T.UndefinedConstant(),
+      T.TheHoleConstant(),
+      T.TrueConstant(),
+      T.FalseConstant(),
+      T.NullConstant(),
+      T.ZeroConstant(),
+      T.OneConstant(),
+      T.NaNConstant(),
+      T.Int32Constant(0),
+      T.Int32Constant(1),
+      T.Int64Constant(-2),
+      T.Int64Constant(-4),
+      T.Float64Constant(0.9),
+      T.Float64Constant(V8_INFINITY),
+      T.Constant(0.99),
+      T.Constant(1.11),
+      T.ExternalConstant(ExternalReference::address_of_one_half())};
+
+  NodeVector nodes(T.main_zone());
+  T.GetCachedNodes(&nodes);
+
+  for (size_t i = 0; i < arraysize(constants); i++) {
+    CHECK(Contains(&nodes, constants[i]));
+  }
+}
diff --git a/test/cctest/compiler/test-js-context-specialization.cc b/test/cctest/compiler/test-js-context-specialization.cc
index 47c660a..fb7bd94 100644
--- a/test/cctest/compiler/test-js-context-specialization.cc
+++ b/test/cctest/compiler/test-js-context-specialization.cc
@@ -7,7 +7,6 @@
 #include "src/compiler/node-matchers.h"
 #include "src/compiler/node-properties-inl.h"
 #include "src/compiler/source-position.h"
-#include "src/compiler/typer.h"
 #include "test/cctest/cctest.h"
 #include "test/cctest/compiler/function-tester.h"
 #include "test/cctest/compiler/graph-builder-tester.h"
@@ -22,10 +21,9 @@
       : DirectGraphBuilder(new (main_zone()) Graph(main_zone())),
         common_(main_zone()),
         javascript_(main_zone()),
-        machine_(),
+        machine_(main_zone()),
         simplified_(main_zone()),
-        typer_(main_zone()),
-        jsgraph_(graph(), common(), &javascript_, &typer_, &machine_),
+        jsgraph_(graph(), common(), &javascript_, &machine_),
         info_(main_isolate(), main_zone()) {}
 
   Factory* factory() { return main_isolate()->factory(); }
@@ -40,7 +38,6 @@
   JSOperatorBuilder javascript_;
   MachineOperatorBuilder machine_;
   SimplifiedOperatorBuilder simplified_;
-  Typer typer_;
   JSGraph jsgraph_;
   CompilationInfo info_;
 };
@@ -95,8 +92,8 @@
     HeapObjectMatcher<Context> match(new_context_input);
     CHECK_EQ(*native, *match.Value().handle());
     ContextAccess access = OpParameter<ContextAccess>(r.replacement());
-    CHECK_EQ(Context::GLOBAL_EVAL_FUN_INDEX, access.index());
-    CHECK_EQ(0, access.depth());
+    CHECK_EQ(Context::GLOBAL_EVAL_FUN_INDEX, static_cast<int>(access.index()));
+    CHECK_EQ(0, static_cast<int>(access.depth()));
     CHECK_EQ(false, access.immutable());
   }
 
@@ -175,8 +172,8 @@
     HeapObjectMatcher<Context> match(new_context_input);
     CHECK_EQ(*native, *match.Value().handle());
     ContextAccess access = OpParameter<ContextAccess>(r.replacement());
-    CHECK_EQ(Context::GLOBAL_EVAL_FUN_INDEX, access.index());
-    CHECK_EQ(0, access.depth());
+    CHECK_EQ(Context::GLOBAL_EVAL_FUN_INDEX, static_cast<int>(access.index()));
+    CHECK_EQ(0, static_cast<int>(access.depth()));
     CHECK_EQ(false, access.immutable());
   }
 }
@@ -206,7 +203,7 @@
   JSContextSpecializer spec(t.info(), t.jsgraph(), const_context);
 
   {
-    // Check that SpecializeToContext() replaces values and forwards effects
+    // Check that specialization replaces values and forwards effects
     // correctly, and folds values from constant and non-constant contexts
     Node* effect_in = start;
     Node* load = t.NewNode(t.javascript()->LoadContext(0, slot, true),
@@ -232,8 +229,10 @@
     CheckEffectInput(effect_in, load);
     CheckEffectInput(load, effect_use);
 
-    // Perform the substitution on the entire graph.
-    spec.SpecializeToContext();
+    // Perform the reduction on the entire graph.
+    GraphReducer graph_reducer(t.graph(), t.main_zone());
+    graph_reducer.AddReducer(&spec);
+    graph_reducer.ReduceGraph();
 
     // Effects should have been forwarded (not replaced with a value).
     CheckEffectInput(effect_in, effect_use);
diff --git a/test/cctest/compiler/test-js-typed-lowering.cc b/test/cctest/compiler/test-js-typed-lowering.cc
index cf126c2..3023837 100644
--- a/test/cctest/compiler/test-js-typed-lowering.cc
+++ b/test/cctest/compiler/test-js-typed-lowering.cc
@@ -2,14 +2,14 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "src/v8.h"
-#include "test/cctest/cctest.h"
-
 #include "src/compiler/graph-inl.h"
+#include "src/compiler/js-graph.h"
 #include "src/compiler/js-typed-lowering.h"
+#include "src/compiler/machine-operator.h"
 #include "src/compiler/node-properties-inl.h"
 #include "src/compiler/opcodes.h"
 #include "src/compiler/typer.h"
+#include "test/cctest/cctest.h"
 
 using namespace v8::internal;
 using namespace v8::internal::compiler;
@@ -21,14 +21,15 @@
         binop(NULL),
         unop(NULL),
         javascript(main_zone()),
+        machine(main_zone()),
         simplified(main_zone()),
         common(main_zone()),
         graph(main_zone()),
-        typer(main_zone()),
+        typer(&graph, MaybeHandle<Context>()),
         context_node(NULL) {
-    typer.DecorateGraph(&graph);
-    Node* s = graph.NewNode(common.Start(num_parameters));
-    graph.SetStart(s);
+    graph.SetStart(graph.NewNode(common.Start(num_parameters)));
+    graph.SetEnd(graph.NewNode(common.End()));
+    typer.Run();
   }
 
   Isolate* isolate;
@@ -49,13 +50,14 @@
   }
 
   Node* UndefinedConstant() {
-    Unique<Object> unique =
-        Unique<Object>::CreateImmovable(isolate->factory()->undefined_value());
+    Unique<HeapObject> unique = Unique<HeapObject>::CreateImmovable(
+        isolate->factory()->undefined_value());
     return graph.NewNode(common.HeapConstant(unique));
   }
 
-  Node* HeapConstant(Handle<Object> constant) {
-    Unique<Object> unique = Unique<Object>::CreateUninitialized(constant);
+  Node* HeapConstant(Handle<HeapObject> constant) {
+    Unique<HeapObject> unique =
+        Unique<HeapObject>::CreateUninitialized(constant);
     return graph.NewNode(common.HeapConstant(unique));
   }
 
@@ -65,15 +67,16 @@
     Node* stack = graph.NewNode(common.StateValues(0));
 
     Node* state_node =
-        graph.NewNode(common.FrameState(JS_FRAME, BailoutId(0), kIgnoreOutput),
+        graph.NewNode(common.FrameState(JS_FRAME, BailoutId(0),
+                                        OutputFrameStateCombine::Ignore()),
                       parameters, locals, stack, context, UndefinedConstant());
 
     return state_node;
   }
 
   Node* reduce(Node* node) {
-    JSGraph jsgraph(&graph, &common, &javascript, &typer, &machine);
-    JSTypedLowering reducer(&jsgraph);
+    JSGraph jsgraph(&graph, &common, &javascript, &machine);
+    JSTypedLowering reducer(&jsgraph, main_zone());
     Reduction reduction = reducer.Reduce(node);
     if (reduction.Changed()) return reduction.replacement();
     return node;
@@ -164,17 +167,19 @@
 
 
 static Type* kInt32Types[] = {
-    Type::UnsignedSmall(),   Type::OtherSignedSmall(), Type::OtherUnsigned31(),
-    Type::OtherUnsigned32(), Type::OtherSigned32(),    Type::SignedSmall(),
-    Type::Signed32(),        Type::Unsigned32(),       Type::Integral32()};
+    Type::UnsignedSmall(),       Type::NegativeSigned32(),
+    Type::NonNegativeSigned32(), Type::SignedSmall(),
+    Type::Signed32(),            Type::Unsigned32(),
+    Type::Integral32()};
 
 
 static Type* kNumberTypes[] = {
-    Type::UnsignedSmall(),   Type::OtherSignedSmall(), Type::OtherUnsigned31(),
-    Type::OtherUnsigned32(), Type::OtherSigned32(),    Type::SignedSmall(),
-    Type::Signed32(),        Type::Unsigned32(),       Type::Integral32(),
-    Type::MinusZero(),       Type::NaN(),              Type::OtherNumber(),
-    Type::OrderedNumber(),   Type::Number()};
+    Type::UnsignedSmall(),       Type::NegativeSigned32(),
+    Type::NonNegativeSigned32(), Type::SignedSmall(),
+    Type::Signed32(),            Type::Unsigned32(),
+    Type::Integral32(),          Type::MinusZero(),
+    Type::NaN(),                 Type::OrderedNumber(),
+    Type::PlainNumber(),         Type::Number()};
 
 
 static Type* kJSTypes[] = {Type::Undefined(), Type::Null(),   Type::Boolean(),
@@ -260,16 +265,15 @@
 
 static void CheckToI32(Node* old_input, Node* new_input, bool is_signed) {
   Type* old_type = NodeProperties::GetBounds(old_input).upper;
+  Type* new_type = NodeProperties::GetBounds(new_input).upper;
   Type* expected_type = I32Type(is_signed);
+  CHECK(new_type->Is(expected_type));
   if (old_type->Is(expected_type)) {
     CHECK_EQ(old_input, new_input);
   } else if (new_input->opcode() == IrOpcode::kNumberConstant) {
-    CHECK(NodeProperties::GetBounds(new_input).upper->Is(expected_type));
     double v = OpParameter<double>(new_input);
     double e = static_cast<double>(is_signed ? FastD2I(v) : FastD2UI(v));
     CHECK_EQ(e, v);
-  } else {
-    CHECK_EQ(NumberToI32(is_signed), new_input->opcode());
   }
 }
 
@@ -302,12 +306,13 @@
 TEST(Int32BitwiseShifts) {
   JSBitwiseShiftTypedLoweringTester R;
 
-  Type* types[] = {
-      Type::SignedSmall(), Type::UnsignedSmall(), Type::OtherSigned32(),
-      Type::Unsigned32(),  Type::Signed32(),      Type::MinusZero(),
-      Type::NaN(),         Type::OtherNumber(),   Type::Undefined(),
-      Type::Null(),        Type::Boolean(),       Type::Number(),
-      Type::String(),      Type::Object()};
+  Type* types[] = {Type::SignedSmall(),      Type::UnsignedSmall(),
+                   Type::NegativeSigned32(), Type::NonNegativeSigned32(),
+                   Type::Unsigned32(),       Type::Signed32(),
+                   Type::MinusZero(),        Type::NaN(),
+                   Type::Undefined(),        Type::Null(),
+                   Type::Boolean(),          Type::Number(),
+                   Type::PlainNumber(),      Type::String()};
 
   for (size_t i = 0; i < arraysize(types); ++i) {
     Node* p0 = R.Parameter(types[i], 0);
@@ -325,9 +330,13 @@
 
         CheckToI32(p0, r0, R.signedness[k]);
 
-        R.CheckPureBinop(IrOpcode::kWord32And, r1);
-        CheckToI32(p1, r1->InputAt(0), R.signedness[k + 1]);
-        R.CheckInt32Constant(0x1F, r1->InputAt(1));
+        if (r1->opcode() == IrOpcode::kWord32And) {
+          R.CheckPureBinop(IrOpcode::kWord32And, r1);
+          CheckToI32(p1, r1->InputAt(0), R.signedness[k + 1]);
+          R.CheckInt32Constant(0x1F, r1->InputAt(1));
+        } else {
+          CheckToI32(p1, r1, R.signedness[k]);
+        }
       }
     }
   }
@@ -363,11 +372,11 @@
   JSBitwiseTypedLoweringTester R;
 
   Type* types[] = {
-      Type::SignedSmall(), Type::UnsignedSmall(), Type::OtherSigned32(),
-      Type::Unsigned32(),  Type::Signed32(),      Type::MinusZero(),
-      Type::NaN(),         Type::OtherNumber(),   Type::Undefined(),
-      Type::Null(),        Type::Boolean(),       Type::Number(),
-      Type::String(),      Type::Object()};
+      Type::SignedSmall(),   Type::UnsignedSmall(), Type::Unsigned32(),
+      Type::Signed32(),      Type::MinusZero(),     Type::NaN(),
+      Type::OrderedNumber(), Type::PlainNumber(),   Type::Undefined(),
+      Type::Null(),          Type::Boolean(),       Type::Number(),
+      Type::String()};
 
   for (size_t i = 0; i < arraysize(types); ++i) {
     Node* p0 = R.Parameter(types[i], 0);
@@ -498,20 +507,6 @@
     CHECK_EQ(IrOpcode::kParameter, r->opcode());
   }
 
-  {  // ToBoolean(ordered-number)
-    Node* r = R.ReduceUnop(op, Type::OrderedNumber());
-    CHECK_EQ(IrOpcode::kBooleanNot, r->opcode());
-    Node* i = r->InputAt(0);
-    CHECK_EQ(IrOpcode::kNumberEqual, i->opcode());
-    // ToBoolean(x:ordered-number) => BooleanNot(NumberEqual(x, #0))
-  }
-
-  {  // ToBoolean(string)
-    Node* r = R.ReduceUnop(op, Type::String());
-    // TODO(titzer): test will break with better js-typed-lowering
-    CHECK_EQ(IrOpcode::kJSToBoolean, r->opcode());
-  }
-
   {  // ToBoolean(object)
     Node* r = R.ReduceUnop(op, Type::DetectableObject());
     R.CheckTrue(r);
@@ -524,39 +519,7 @@
 
   {  // ToBoolean(object)
     Node* r = R.ReduceUnop(op, Type::Object());
-    CHECK_EQ(IrOpcode::kJSToBoolean, r->opcode());
-  }
-}
-
-
-TEST(JSToBoolean_replacement) {
-  JSTypedLoweringTester R;
-
-  Type* types[] = {Type::Null(),             Type::Undefined(),
-                   Type::Boolean(),          Type::OrderedNumber(),
-                   Type::DetectableObject(), Type::Undetectable()};
-
-  for (size_t i = 0; i < arraysize(types); i++) {
-    Node* n = R.Parameter(types[i]);
-    Node* c = R.graph.NewNode(R.javascript.ToBoolean(), n, R.context(),
-                              R.start(), R.start());
-    Node* effect_use = R.UseForEffect(c);
-    Node* add = R.graph.NewNode(R.simplified.ReferenceEqual(Type::Any()), n, c);
-
-    R.CheckEffectInput(c, effect_use);
-    Node* r = R.reduce(c);
-
-    if (types[i]->Is(Type::Boolean())) {
-      CHECK_EQ(n, r);
-    } else if (types[i]->Is(Type::OrderedNumber())) {
-      CHECK_EQ(IrOpcode::kBooleanNot, r->opcode());
-    } else {
-      CHECK_EQ(IrOpcode::kHeapConstant, r->opcode());
-    }
-
-    CHECK_EQ(n, add->InputAt(0));
-    CHECK_EQ(r, add->InputAt(1));
-    R.CheckEffectInput(R.start(), effect_use);
+    CHECK_EQ(IrOpcode::kAnyToBoolean, r->opcode());
   }
 }
 
@@ -690,33 +653,22 @@
       R.javascript.GreaterThan(),        R.simplified.NumberLessThan(),
       R.javascript.GreaterThanOrEqual(), R.simplified.NumberLessThanOrEqual()};
 
-  for (size_t i = 0; i < arraysize(kJSTypes); i++) {
-    Type* t0 = kJSTypes[i];
-    // Skip Type::String and Type::Receiver which might coerce into a string.
-    if (t0->Is(Type::String()) || t0->Is(Type::Receiver())) continue;
-    Node* p0 = R.Parameter(t0, 0);
+  Node* const p0 = R.Parameter(Type::Number(), 0);
+  Node* const p1 = R.Parameter(Type::Number(), 1);
 
-    for (size_t j = 0; j < arraysize(kJSTypes); j++) {
-      Type* t1 = kJSTypes[j];
-      // Skip Type::String and Type::Receiver which might coerce into a string.
-      if (t1->Is(Type::String()) || t0->Is(Type::Receiver())) continue;
-      Node* p1 = R.Parameter(t1, 1);
+  for (size_t k = 0; k < arraysize(ops); k += 2) {
+    Node* cmp = R.Binop(ops[k], p0, p1);
+    Node* r = R.reduce(cmp);
 
-      for (size_t k = 0; k < arraysize(ops); k += 2) {
-        Node* cmp = R.Binop(ops[k], p0, p1);
-        Node* r = R.reduce(cmp);
-
-        R.CheckPureBinop(ops[k + 1], r);
-        if (k >= 4) {
-          // GreaterThan and GreaterThanOrEqual commute the inputs
-          // and use the LessThan and LessThanOrEqual operators.
-          CheckIsConvertedToNumber(p1, r->InputAt(0));
-          CheckIsConvertedToNumber(p0, r->InputAt(1));
-        } else {
-          CheckIsConvertedToNumber(p0, r->InputAt(0));
-          CheckIsConvertedToNumber(p1, r->InputAt(1));
-        }
-      }
+    R.CheckPureBinop(ops[k + 1], r);
+    if (k >= 4) {
+      // GreaterThan and GreaterThanOrEqual commute the inputs
+      // and use the LessThan and LessThanOrEqual operators.
+      CheckIsConvertedToNumber(p1, r->InputAt(0));
+      CheckIsConvertedToNumber(p0, r->InputAt(1));
+    } else {
+      CheckIsConvertedToNumber(p0, r->InputAt(0));
+      CheckIsConvertedToNumber(p1, r->InputAt(1));
     }
   }
 }
@@ -753,51 +705,18 @@
 }
 
 
-TEST(ObjectComparison) {
-  JSTypedLoweringTester R;
-
-  Node* p0 = R.Parameter(Type::Number(), 0);
-  Node* p1 = R.Parameter(Type::Object(), 1);
-
-  Node* cmp = R.Binop(R.javascript.LessThan(), p0, p1);
-  Node* effect_use = R.UseForEffect(cmp);
-
-  R.CheckEffectInput(R.start(), cmp);
-  R.CheckEffectInput(cmp, effect_use);
-
-  Node* r = R.reduce(cmp);
-
-  R.CheckPureBinop(R.simplified.NumberLessThan(), r);
-
-  Node* i0 = r->InputAt(0);
-  Node* i1 = r->InputAt(1);
-
-  CHECK_EQ(p0, i0);
-  CHECK_NE(p1, i1);
-  CHECK_EQ(IrOpcode::kParameter, i0->opcode());
-  CHECK_EQ(IrOpcode::kJSToNumber, i1->opcode());
-
-  // Check effect chain is correct.
-  R.CheckEffectInput(R.start(), i1);
-  R.CheckEffectInput(i1, effect_use);
-}
-
-
 TEST(UnaryNot) {
   JSTypedLoweringTester R;
   const Operator* opnot = R.javascript.UnaryNot();
 
   for (size_t i = 0; i < arraysize(kJSTypes); i++) {
     Node* orig = R.Unop(opnot, R.Parameter(kJSTypes[i]));
-    Node* use = R.graph.NewNode(R.common.Return(), orig);
     Node* r = R.reduce(orig);
-    // TODO(titzer): test will break if/when js-typed-lowering constant folds.
-    CHECK_EQ(IrOpcode::kBooleanNot, use->InputAt(0)->opcode());
 
     if (r == orig && orig->opcode() == IrOpcode::kJSToBoolean) {
       // The original node was turned into a ToBoolean.
       CHECK_EQ(IrOpcode::kJSToBoolean, r->opcode());
-    } else {
+    } else if (r->opcode() != IrOpcode::kHeapConstant) {
       CHECK_EQ(IrOpcode::kBooleanNot, r->opcode());
     }
   }
@@ -852,7 +771,7 @@
     if (effect_use != NULL) {
       R.CheckEffectInput(R.start(), effect_use);
       // Check that value uses of ToNumber() do not go to start().
-      for (int i = 0; i < effect_use->op()->InputCount(); i++) {
+      for (int i = 0; i < effect_use->op()->ValueInputCount(); i++) {
         CHECK_NE(R.start(), effect_use->InputAt(i));
       }
     }
@@ -904,9 +823,9 @@
   Node* CheckConverted(IrOpcode::Value opcode, Node* node, bool effects) {
     CHECK_EQ(opcode, node->opcode());
     if (effects) {
-      CHECK_LT(0, OperatorProperties::GetEffectInputCount(node->op()));
+      CHECK_LT(0, node->op()->EffectInputCount());
     } else {
-      CHECK_EQ(0, OperatorProperties::GetEffectInputCount(node->op()));
+      CHECK_EQ(0, node->op()->EffectInputCount());
     }
     return node;
   }
@@ -1030,7 +949,7 @@
   };
 
   for (size_t j = 0; j < arraysize(ops); j += 2) {
-    BinopEffectsTester B(ops[j], Type::Object(), Type::String());
+    BinopEffectsTester B(ops[j], Type::Symbol(), Type::Symbol());
     CHECK_EQ(ops[j + 1]->opcode(), B.result->op()->opcode());
 
     Node* i0 = B.CheckConvertedInput(IrOpcode::kJSToNumber, 0, true);
@@ -1103,8 +1022,8 @@
     CHECK_EQ(B.p1, i0->InputAt(0));
     CHECK_EQ(B.p0, i1->InputAt(0));
 
-    // But effects should be ordered start -> i1 -> i0 -> effect_use
-    B.CheckEffectOrdering(i1, i0);
+    // But effects should be ordered start -> i1 -> effect_use
+    B.CheckEffectOrdering(i1);
   }
 
   for (size_t j = 0; j < arraysize(ops); j += 2) {
@@ -1166,7 +1085,7 @@
 
   for (int j = 0; j < R.kNumberOps; j += 2) {
     bool signed_left = R.signedness[j], signed_right = R.signedness[j + 1];
-    BinopEffectsTester B(R.ops[j], Type::Number(), Type::Object());
+    BinopEffectsTester B(R.ops[j], Type::Number(), Type::Primitive());
 
     B.R.CheckPureBinop(B.result->opcode(), B.result);
 
@@ -1183,7 +1102,7 @@
 
   for (int j = 0; j < R.kNumberOps; j += 2) {
     bool signed_left = R.signedness[j], signed_right = R.signedness[j + 1];
-    BinopEffectsTester B(R.ops[j], Type::Object(), Type::Number());
+    BinopEffectsTester B(R.ops[j], Type::Primitive(), Type::Number());
 
     B.R.CheckPureBinop(B.result->opcode(), B.result);
 
@@ -1200,7 +1119,7 @@
 
   for (int j = 0; j < R.kNumberOps; j += 2) {
     bool signed_left = R.signedness[j], signed_right = R.signedness[j + 1];
-    BinopEffectsTester B(R.ops[j], Type::Object(), Type::Object());
+    BinopEffectsTester B(R.ops[j], Type::Primitive(), Type::Primitive());
 
     B.R.CheckPureBinop(B.result->opcode(), B.result);
 
@@ -1218,33 +1137,6 @@
 }
 
 
-TEST(UnaryNotEffects) {
-  JSTypedLoweringTester R;
-  const Operator* opnot = R.javascript.UnaryNot();
-
-  for (size_t i = 0; i < arraysize(kJSTypes); i++) {
-    Node* p0 = R.Parameter(kJSTypes[i], 0);
-    Node* orig = R.Unop(opnot, p0);
-    Node* effect_use = R.UseForEffect(orig);
-    Node* value_use = R.graph.NewNode(R.common.Return(), orig);
-    Node* r = R.reduce(orig);
-    // TODO(titzer): test will break if/when js-typed-lowering constant folds.
-    CHECK_EQ(IrOpcode::kBooleanNot, value_use->InputAt(0)->opcode());
-
-    if (r == orig && orig->opcode() == IrOpcode::kJSToBoolean) {
-      // The original node was turned into a ToBoolean, which has an effect.
-      CHECK_EQ(IrOpcode::kJSToBoolean, r->opcode());
-      R.CheckEffectInput(R.start(), orig);
-      R.CheckEffectInput(orig, effect_use);
-    } else {
-      // effect should have been removed from this node.
-      CHECK_EQ(IrOpcode::kBooleanNot, r->opcode());
-      R.CheckEffectInput(R.start(), effect_use);
-    }
-  }
-}
-
-
 TEST(Int32AddNarrowing) {
   {
     JSBitwiseTypedLoweringTester R;
@@ -1263,11 +1155,7 @@
             Node* r = R.reduce(or_node);
 
             CHECK_EQ(R.ops[o + 1]->opcode(), r->op()->opcode());
-            CHECK_EQ(IrOpcode::kInt32Add, add_node->opcode());
-            bool is_signed = l ? R.signedness[o] : R.signedness[o + 1];
-
-            Type* add_type = NodeProperties::GetBounds(add_node).upper;
-            CHECK(add_type->Is(I32Type(is_signed)));
+            CHECK_EQ(IrOpcode::kNumberAdd, add_node->opcode());
           }
         }
       }
@@ -1290,40 +1178,33 @@
             Node* r = R.reduce(or_node);
 
             CHECK_EQ(R.ops[o + 1]->opcode(), r->op()->opcode());
-            CHECK_EQ(IrOpcode::kInt32Add, add_node->opcode());
-            bool is_signed = l ? R.signedness[o] : R.signedness[o + 1];
-
-            Type* add_type = NodeProperties::GetBounds(add_node).upper;
-            CHECK(add_type->Is(I32Type(is_signed)));
+            CHECK_EQ(IrOpcode::kNumberAdd, add_node->opcode());
           }
         }
       }
     }
   }
-}
+  {
+    JSBitwiseTypedLoweringTester R;
 
+    for (int o = 0; o < R.kNumberOps; o += 2) {
+      Node* n0 = R.Parameter(I32Type(R.signedness[o]));
+      Node* n1 = R.Parameter(I32Type(R.signedness[o + 1]));
+      Node* one = R.graph.NewNode(R.common.NumberConstant(1));
 
-TEST(Int32AddNarrowingNotOwned) {
-  JSBitwiseTypedLoweringTester R;
-
-  for (int o = 0; o < R.kNumberOps; o += 2) {
-    Node* n0 = R.Parameter(I32Type(R.signedness[o]));
-    Node* n1 = R.Parameter(I32Type(R.signedness[o + 1]));
-    Node* one = R.graph.NewNode(R.common.NumberConstant(1));
-
-    Node* add_node = R.Binop(R.simplified.NumberAdd(), n0, n1);
-    Node* or_node = R.Binop(R.ops[o], add_node, one);
-    Node* other_use = R.Binop(R.simplified.NumberAdd(), add_node, one);
-    Node* r = R.reduce(or_node);
-    CHECK_EQ(R.ops[o + 1]->opcode(), r->op()->opcode());
-    // Should not be reduced to Int32Add because of the other number add.
-    CHECK_EQ(IrOpcode::kNumberAdd, add_node->opcode());
-    // Conversion to int32 should be done.
-    CheckToI32(add_node, r->InputAt(0), R.signedness[o]);
-    CheckToI32(one, r->InputAt(1), R.signedness[o + 1]);
-    // The other use should also not be touched.
-    CHECK_EQ(add_node, other_use->InputAt(0));
-    CHECK_EQ(one, other_use->InputAt(1));
+      Node* add_node = R.Binop(R.simplified.NumberAdd(), n0, n1);
+      Node* or_node = R.Binop(R.ops[o], add_node, one);
+      Node* other_use = R.Binop(R.simplified.NumberAdd(), add_node, one);
+      Node* r = R.reduce(or_node);
+      CHECK_EQ(R.ops[o + 1]->opcode(), r->op()->opcode());
+      CHECK_EQ(IrOpcode::kNumberAdd, add_node->opcode());
+      // Conversion to int32 should be done.
+      CheckToI32(add_node, r->InputAt(0), R.signedness[o]);
+      CheckToI32(one, r->InputAt(1), R.signedness[o + 1]);
+      // The other use should also not be touched.
+      CHECK_EQ(add_node, other_use->InputAt(0));
+      CHECK_EQ(one, other_use->InputAt(1));
+    }
   }
 }
 
diff --git a/test/cctest/compiler/test-jump-threading.cc b/test/cctest/compiler/test-jump-threading.cc
new file mode 100644
index 0000000..74bf43d
--- /dev/null
+++ b/test/cctest/compiler/test-jump-threading.cc
@@ -0,0 +1,764 @@
+// 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.
+
+#include "src/v8.h"
+#include "test/cctest/cctest.h"
+
+#include "src/compiler/instruction.h"
+#include "src/compiler/instruction-codes.h"
+#include "src/compiler/jump-threading.h"
+
+namespace v8 {
+namespace internal {
+namespace compiler {
+
+typedef BasicBlock::RpoNumber RpoNumber;
+
+class TestCode : public HandleAndZoneScope {
+ public:
+  TestCode()
+      : HandleAndZoneScope(),
+        blocks_(main_zone()),
+        sequence_(main_zone(), &blocks_),
+        rpo_number_(RpoNumber::FromInt(0)),
+        current_(NULL) {}
+
+  ZoneVector<InstructionBlock*> blocks_;
+  InstructionSequence sequence_;
+  RpoNumber rpo_number_;
+  InstructionBlock* current_;
+
+  int Jump(int target) {
+    Start();
+    InstructionOperand* ops[] = {UseRpo(target)};
+    sequence_.AddInstruction(Instruction::New(main_zone(), kArchJmp, 0, NULL, 1,
+                                              ops, 0, NULL)->MarkAsControl());
+    int pos = static_cast<int>(sequence_.instructions().size() - 1);
+    End();
+    return pos;
+  }
+  void Fallthru() {
+    Start();
+    End();
+  }
+  int Branch(int ttarget, int ftarget) {
+    Start();
+    InstructionOperand* ops[] = {UseRpo(ttarget), UseRpo(ftarget)};
+    InstructionCode code = 119 | FlagsModeField::encode(kFlags_branch) |
+                           FlagsConditionField::encode(kEqual);
+    sequence_.AddInstruction(Instruction::New(main_zone(), code, 0, NULL, 2,
+                                              ops, 0, NULL)->MarkAsControl());
+    int pos = static_cast<int>(sequence_.instructions().size() - 1);
+    End();
+    return pos;
+  }
+  void Nop() {
+    Start();
+    sequence_.AddInstruction(Instruction::New(main_zone(), kArchNop));
+  }
+  void RedundantMoves() {
+    Start();
+    sequence_.AddInstruction(Instruction::New(main_zone(), kArchNop));
+    int index = static_cast<int>(sequence_.instructions().size()) - 1;
+    sequence_.AddGapMove(index, RegisterOperand::Create(13, main_zone()),
+                         RegisterOperand::Create(13, main_zone()));
+  }
+  void NonRedundantMoves() {
+    Start();
+    sequence_.AddInstruction(Instruction::New(main_zone(), kArchNop));
+    int index = static_cast<int>(sequence_.instructions().size()) - 1;
+    sequence_.AddGapMove(index, ImmediateOperand::Create(11, main_zone()),
+                         RegisterOperand::Create(11, main_zone()));
+  }
+  void Other() {
+    Start();
+    sequence_.AddInstruction(Instruction::New(main_zone(), 155));
+  }
+  void End() {
+    Start();
+    sequence_.EndBlock(current_->rpo_number());
+    current_ = NULL;
+    rpo_number_ = RpoNumber::FromInt(rpo_number_.ToInt() + 1);
+  }
+  InstructionOperand* UseRpo(int num) {
+    int index = sequence_.AddImmediate(Constant(RpoNumber::FromInt(num)));
+    return ImmediateOperand::Create(index, main_zone());
+  }
+  void Start(bool deferred = false) {
+    if (current_ == NULL) {
+      current_ = new (main_zone()) InstructionBlock(
+          main_zone(), BasicBlock::Id::FromInt(rpo_number_.ToInt()),
+          rpo_number_, RpoNumber::Invalid(), RpoNumber::Invalid(), deferred);
+      blocks_.push_back(current_);
+      sequence_.StartBlock(rpo_number_);
+    }
+  }
+  void Defer() {
+    CHECK(current_ == NULL);
+    Start(true);
+  }
+};
+
+
+void VerifyForwarding(TestCode& code, int count, int* expected) {
+  Zone local_zone(code.main_isolate());
+  ZoneVector<RpoNumber> result(&local_zone);
+  JumpThreading::ComputeForwarding(&local_zone, result, &code.sequence_);
+
+  CHECK(count == static_cast<int>(result.size()));
+  for (int i = 0; i < count; i++) {
+    CHECK(expected[i] == result[i].ToInt());
+  }
+}
+
+
+TEST(FwEmpty1) {
+  TestCode code;
+
+  // B0
+  code.Jump(1);
+  // B1
+  code.Jump(2);
+  // B2
+  code.End();
+
+  static int expected[] = {2, 2, 2};
+  VerifyForwarding(code, 3, expected);
+}
+
+
+TEST(FwEmptyN) {
+  for (int i = 0; i < 9; i++) {
+    TestCode code;
+
+    // B0
+    code.Jump(1);
+    // B1
+    for (int j = 0; j < i; j++) code.Nop();
+    code.Jump(2);
+    // B2
+    code.End();
+
+    static int expected[] = {2, 2, 2};
+    VerifyForwarding(code, 3, expected);
+  }
+}
+
+
+TEST(FwNone1) {
+  TestCode code;
+
+  // B0
+  code.End();
+
+  static int expected[] = {0};
+  VerifyForwarding(code, 1, expected);
+}
+
+
+TEST(FwMoves1) {
+  TestCode code;
+
+  // B0
+  code.RedundantMoves();
+  code.End();
+
+  static int expected[] = {0};
+  VerifyForwarding(code, 1, expected);
+}
+
+
+TEST(FwMoves2) {
+  TestCode code;
+
+  // B0
+  code.RedundantMoves();
+  code.Fallthru();
+  // B1
+  code.End();
+
+  static int expected[] = {1, 1};
+  VerifyForwarding(code, 2, expected);
+}
+
+
+TEST(FwMoves2b) {
+  TestCode code;
+
+  // B0
+  code.NonRedundantMoves();
+  code.Fallthru();
+  // B1
+  code.End();
+
+  static int expected[] = {0, 1};
+  VerifyForwarding(code, 2, expected);
+}
+
+
+TEST(FwOther2) {
+  TestCode code;
+
+  // B0
+  code.Other();
+  code.Fallthru();
+  // B1
+  code.End();
+
+  static int expected[] = {0, 1};
+  VerifyForwarding(code, 2, expected);
+}
+
+
+TEST(FwNone2a) {
+  TestCode code;
+
+  // B0
+  code.Fallthru();
+  // B1
+  code.End();
+
+  static int expected[] = {1, 1};
+  VerifyForwarding(code, 2, expected);
+}
+
+
+TEST(FwNone2b) {
+  TestCode code;
+
+  // B0
+  code.Jump(1);
+  // B1
+  code.End();
+
+  static int expected[] = {1, 1};
+  VerifyForwarding(code, 2, expected);
+}
+
+
+TEST(FwLoop1) {
+  TestCode code;
+
+  // B0
+  code.Jump(0);
+
+  static int expected[] = {0};
+  VerifyForwarding(code, 1, expected);
+}
+
+
+TEST(FwLoop2) {
+  TestCode code;
+
+  // B0
+  code.Fallthru();
+  // B1
+  code.Jump(0);
+
+  static int expected[] = {0, 0};
+  VerifyForwarding(code, 2, expected);
+}
+
+
+TEST(FwLoop3) {
+  TestCode code;
+
+  // B0
+  code.Fallthru();
+  // B1
+  code.Fallthru();
+  // B2
+  code.Jump(0);
+
+  static int expected[] = {0, 0, 0};
+  VerifyForwarding(code, 3, expected);
+}
+
+
+TEST(FwLoop1b) {
+  TestCode code;
+
+  // B0
+  code.Fallthru();
+  // B1
+  code.Jump(1);
+
+  static int expected[] = {1, 1};
+  VerifyForwarding(code, 2, expected);
+}
+
+
+TEST(FwLoop2b) {
+  TestCode code;
+
+  // B0
+  code.Fallthru();
+  // B1
+  code.Fallthru();
+  // B2
+  code.Jump(1);
+
+  static int expected[] = {1, 1, 1};
+  VerifyForwarding(code, 3, expected);
+}
+
+
+TEST(FwLoop3b) {
+  TestCode code;
+
+  // B0
+  code.Fallthru();
+  // B1
+  code.Fallthru();
+  // B2
+  code.Fallthru();
+  // B3
+  code.Jump(1);
+
+  static int expected[] = {1, 1, 1, 1};
+  VerifyForwarding(code, 4, expected);
+}
+
+
+TEST(FwLoop2_1a) {
+  TestCode code;
+
+  // B0
+  code.Fallthru();
+  // B1
+  code.Fallthru();
+  // B2
+  code.Fallthru();
+  // B3
+  code.Jump(1);
+  // B4
+  code.Jump(2);
+
+  static int expected[] = {1, 1, 1, 1, 1};
+  VerifyForwarding(code, 5, expected);
+}
+
+
+TEST(FwLoop2_1b) {
+  TestCode code;
+
+  // B0
+  code.Fallthru();
+  // B1
+  code.Fallthru();
+  // B2
+  code.Jump(4);
+  // B3
+  code.Jump(1);
+  // B4
+  code.Jump(2);
+
+  static int expected[] = {2, 2, 2, 2, 2};
+  VerifyForwarding(code, 5, expected);
+}
+
+
+TEST(FwLoop2_1c) {
+  TestCode code;
+
+  // B0
+  code.Fallthru();
+  // B1
+  code.Fallthru();
+  // B2
+  code.Jump(4);
+  // B3
+  code.Jump(2);
+  // B4
+  code.Jump(1);
+
+  static int expected[] = {1, 1, 1, 1, 1};
+  VerifyForwarding(code, 5, expected);
+}
+
+
+TEST(FwLoop2_1d) {
+  TestCode code;
+
+  // B0
+  code.Fallthru();
+  // B1
+  code.Fallthru();
+  // B2
+  code.Jump(1);
+  // B3
+  code.Jump(1);
+  // B4
+  code.Jump(1);
+
+  static int expected[] = {1, 1, 1, 1, 1};
+  VerifyForwarding(code, 5, expected);
+}
+
+
+TEST(FwLoop3_1a) {
+  TestCode code;
+
+  // B0
+  code.Fallthru();
+  // B1
+  code.Fallthru();
+  // B2
+  code.Fallthru();
+  // B3
+  code.Jump(2);
+  // B4
+  code.Jump(1);
+  // B5
+  code.Jump(0);
+
+  static int expected[] = {2, 2, 2, 2, 2, 2};
+  VerifyForwarding(code, 6, expected);
+}
+
+
+TEST(FwDiamonds) {
+  for (int i = 0; i < 2; i++) {
+    for (int j = 0; j < 2; j++) {
+      TestCode code;
+      // B0
+      code.Branch(1, 2);
+      // B1
+      if (i) code.Other();
+      code.Jump(3);
+      // B2
+      if (j) code.Other();
+      code.Jump(3);
+      // B3
+      code.End();
+
+      int expected[] = {0, i ? 1 : 3, j ? 2 : 3, 3};
+      VerifyForwarding(code, 4, expected);
+    }
+  }
+}
+
+
+TEST(FwDiamonds2) {
+  for (int i = 0; i < 2; i++) {
+    for (int j = 0; j < 2; j++) {
+      for (int k = 0; k < 2; k++) {
+        TestCode code;
+        // B0
+        code.Branch(1, 2);
+        // B1
+        if (i) code.Other();
+        code.Jump(3);
+        // B2
+        if (j) code.Other();
+        code.Jump(3);
+        // B3
+        if (k) code.NonRedundantMoves();
+        code.Jump(4);
+        // B4
+        code.End();
+
+        int merge = k ? 3 : 4;
+        int expected[] = {0, i ? 1 : merge, j ? 2 : merge, merge, 4};
+        VerifyForwarding(code, 5, expected);
+      }
+    }
+  }
+}
+
+
+TEST(FwDoubleDiamonds) {
+  for (int i = 0; i < 2; i++) {
+    for (int j = 0; j < 2; j++) {
+      for (int x = 0; x < 2; x++) {
+        for (int y = 0; y < 2; y++) {
+          TestCode code;
+          // B0
+          code.Branch(1, 2);
+          // B1
+          if (i) code.Other();
+          code.Jump(3);
+          // B2
+          if (j) code.Other();
+          code.Jump(3);
+          // B3
+          code.Branch(4, 5);
+          // B4
+          if (x) code.Other();
+          code.Jump(6);
+          // B5
+          if (y) code.Other();
+          code.Jump(6);
+          // B6
+          code.End();
+
+          int expected[] = {0,         i ? 1 : 3, j ? 2 : 3, 3,
+                            x ? 4 : 6, y ? 5 : 6, 6};
+          VerifyForwarding(code, 7, expected);
+        }
+      }
+    }
+  }
+}
+
+template <int kSize>
+void RunPermutationsRecursive(int outer[kSize], int start,
+                              void (*run)(int*, int)) {
+  int permutation[kSize];
+
+  for (int i = 0; i < kSize; i++) permutation[i] = outer[i];
+
+  int count = kSize - start;
+  if (count == 0) return run(permutation, kSize);
+  for (int i = start; i < kSize; i++) {
+    permutation[start] = outer[i];
+    permutation[i] = outer[start];
+    RunPermutationsRecursive<kSize>(permutation, start + 1, run);
+    permutation[i] = outer[i];
+    permutation[start] = outer[start];
+  }
+}
+
+
+template <int kSize>
+void RunAllPermutations(void (*run)(int*, int)) {
+  int permutation[kSize];
+  for (int i = 0; i < kSize; i++) permutation[i] = i;
+  RunPermutationsRecursive<kSize>(permutation, 0, run);
+}
+
+
+void PrintPermutation(int* permutation, int size) {
+  printf("{ ");
+  for (int i = 0; i < size; i++) {
+    if (i > 0) printf(", ");
+    printf("%d", permutation[i]);
+  }
+  printf(" }\n");
+}
+
+
+int find(int x, int* permutation, int size) {
+  for (int i = 0; i < size; i++) {
+    if (permutation[i] == x) return i;
+  }
+  return size;
+}
+
+
+void RunPermutedChain(int* permutation, int size) {
+  TestCode code;
+  int cur = -1;
+  for (int i = 0; i < size; i++) {
+    code.Jump(find(cur + 1, permutation, size) + 1);
+    cur = permutation[i];
+  }
+  code.Jump(find(cur + 1, permutation, size) + 1);
+  code.End();
+
+  int expected[] = {size + 1, size + 1, size + 1, size + 1,
+                    size + 1, size + 1, size + 1};
+  VerifyForwarding(code, size + 2, expected);
+}
+
+
+TEST(FwPermuted_chain) {
+  RunAllPermutations<3>(RunPermutedChain);
+  RunAllPermutations<4>(RunPermutedChain);
+  RunAllPermutations<5>(RunPermutedChain);
+}
+
+
+void RunPermutedDiamond(int* permutation, int size) {
+  TestCode code;
+  int br = 1 + find(0, permutation, size);
+  code.Jump(br);
+  for (int i = 0; i < size; i++) {
+    switch (permutation[i]) {
+      case 0:
+        code.Branch(1 + find(1, permutation, size),
+                    1 + find(2, permutation, size));
+        break;
+      case 1:
+        code.Jump(1 + find(3, permutation, size));
+        break;
+      case 2:
+        code.Jump(1 + find(3, permutation, size));
+        break;
+      case 3:
+        code.Jump(5);
+        break;
+    }
+  }
+  code.End();
+
+  int expected[] = {br, 5, 5, 5, 5, 5};
+  expected[br] = br;
+  VerifyForwarding(code, 6, expected);
+}
+
+
+TEST(FwPermuted_diamond) { RunAllPermutations<4>(RunPermutedDiamond); }
+
+
+void ApplyForwarding(TestCode& code, int size, int* forward) {
+  ZoneVector<RpoNumber> vector(code.main_zone());
+  for (int i = 0; i < size; i++) {
+    vector.push_back(RpoNumber::FromInt(forward[i]));
+  }
+  JumpThreading::ApplyForwarding(vector, &code.sequence_);
+}
+
+
+void CheckJump(TestCode& code, int pos, int target) {
+  Instruction* instr = code.sequence_.InstructionAt(pos);
+  CHECK_EQ(kArchJmp, instr->arch_opcode());
+  CHECK_EQ(1, static_cast<int>(instr->InputCount()));
+  CHECK_EQ(0, static_cast<int>(instr->OutputCount()));
+  CHECK_EQ(0, static_cast<int>(instr->TempCount()));
+  CHECK_EQ(target, code.sequence_.InputRpo(instr, 0).ToInt());
+}
+
+
+void CheckNop(TestCode& code, int pos) {
+  Instruction* instr = code.sequence_.InstructionAt(pos);
+  CHECK_EQ(kArchNop, instr->arch_opcode());
+  CHECK_EQ(0, static_cast<int>(instr->InputCount()));
+  CHECK_EQ(0, static_cast<int>(instr->OutputCount()));
+  CHECK_EQ(0, static_cast<int>(instr->TempCount()));
+}
+
+
+void CheckBranch(TestCode& code, int pos, int t1, int t2) {
+  Instruction* instr = code.sequence_.InstructionAt(pos);
+  CHECK_EQ(2, static_cast<int>(instr->InputCount()));
+  CHECK_EQ(0, static_cast<int>(instr->OutputCount()));
+  CHECK_EQ(0, static_cast<int>(instr->TempCount()));
+  CHECK_EQ(t1, code.sequence_.InputRpo(instr, 0).ToInt());
+  CHECK_EQ(t2, code.sequence_.InputRpo(instr, 1).ToInt());
+}
+
+
+void CheckAssemblyOrder(TestCode& code, int size, int* expected) {
+  int i = 0;
+  for (auto const block : code.sequence_.instruction_blocks()) {
+    CHECK_EQ(expected[i++], block->ao_number().ToInt());
+  }
+}
+
+
+TEST(Rewire1) {
+  TestCode code;
+
+  // B0
+  int j1 = code.Jump(1);
+  // B1
+  int j2 = code.Jump(2);
+  // B2
+  code.End();
+
+  static int forward[] = {2, 2, 2};
+  ApplyForwarding(code, 3, forward);
+  CheckJump(code, j1, 2);
+  CheckNop(code, j2);
+
+  static int assembly[] = {0, 1, 1};
+  CheckAssemblyOrder(code, 3, assembly);
+}
+
+
+TEST(Rewire1_deferred) {
+  TestCode code;
+
+  // B0
+  int j1 = code.Jump(1);
+  // B1
+  int j2 = code.Jump(2);
+  // B2
+  code.Defer();
+  int j3 = code.Jump(3);
+  // B3
+  code.End();
+
+  static int forward[] = {3, 3, 3, 3};
+  ApplyForwarding(code, 4, forward);
+  CheckJump(code, j1, 3);
+  CheckNop(code, j2);
+  CheckNop(code, j3);
+
+  static int assembly[] = {0, 1, 2, 1};
+  CheckAssemblyOrder(code, 4, assembly);
+}
+
+
+TEST(Rewire2_deferred) {
+  TestCode code;
+
+  // B0
+  code.Other();
+  int j1 = code.Jump(1);
+  // B1
+  code.Defer();
+  code.Fallthru();
+  // B2
+  code.Defer();
+  int j2 = code.Jump(3);
+  // B3
+  code.End();
+
+  static int forward[] = {0, 1, 2, 3};
+  ApplyForwarding(code, 4, forward);
+  CheckJump(code, j1, 1);
+  CheckJump(code, j2, 3);
+
+  static int assembly[] = {0, 2, 3, 1};
+  CheckAssemblyOrder(code, 4, assembly);
+}
+
+
+TEST(Rewire_diamond) {
+  for (int i = 0; i < 2; i++) {
+    for (int j = 0; j < 2; j++) {
+      TestCode code;
+      // B0
+      int j1 = code.Jump(1);
+      // B1
+      int b1 = code.Branch(2, 3);
+      // B2
+      int j2 = code.Jump(4);
+      // B3
+      int j3 = code.Jump(4);
+      // B5
+      code.End();
+
+      int forward[] = {0, 1, i ? 4 : 2, j ? 4 : 3, 4};
+      ApplyForwarding(code, 5, forward);
+      CheckJump(code, j1, 1);
+      CheckBranch(code, b1, i ? 4 : 2, j ? 4 : 3);
+      if (i) {
+        CheckNop(code, j2);
+      } else {
+        CheckJump(code, j2, 4);
+      }
+      if (j) {
+        CheckNop(code, j3);
+      } else {
+        CheckJump(code, j3, 4);
+      }
+
+      int assembly[] = {0, 1, 2, 3, 4};
+      if (i) {
+        for (int k = 3; k < 5; k++) assembly[k]--;
+      }
+      if (j) {
+        for (int k = 4; k < 5; k++) assembly[k]--;
+      }
+      CheckAssemblyOrder(code, 5, assembly);
+    }
+  }
+}
+
+}  // namespace compiler
+}  // namespace internal
+}  // namespace v8
diff --git a/test/cctest/compiler/test-linkage.cc b/test/cctest/compiler/test-linkage.cc
index ff65d6e..117caf2 100644
--- a/test/cctest/compiler/test-linkage.cc
+++ b/test/cctest/compiler/test-linkage.cc
@@ -8,7 +8,6 @@
 #include "src/zone.h"
 
 #include "src/compiler/common-operator.h"
-#include "src/compiler/generic-node-inl.h"
 #include "src/compiler/graph.h"
 #include "src/compiler/linkage.h"
 #include "src/compiler/machine-operator.h"
@@ -23,8 +22,8 @@
 using namespace v8::internal;
 using namespace v8::internal::compiler;
 
-static SimpleOperator dummy_operator(IrOpcode::kParameter, Operator::kNoWrite,
-                                     0, 0, "dummy");
+static Operator dummy_operator(IrOpcode::kParameter, Operator::kNoWrite,
+                               "dummy", 0, 0, 0, 0, 0, 0);
 
 // So we can get a real JS function.
 static Handle<JSFunction> Compile(const char* source) {
@@ -45,7 +44,7 @@
   InitializedHandleScope handles;
   Handle<JSFunction> function = Compile("a + b");
   CompilationInfoWithZone info(function);
-  Linkage linkage(&info);
+  Linkage linkage(info.zone(), &info);
 }
 
 
@@ -60,13 +59,13 @@
     Handle<JSFunction> function = v8::Utils::OpenHandle(
         *v8::Handle<v8::Function>::Cast(CompileRun(sources[i])));
     CompilationInfoWithZone info(function);
-    Linkage linkage(&info);
+    Linkage linkage(info.zone(), &info);
 
     CallDescriptor* descriptor = linkage.GetIncomingDescriptor();
     CHECK_NE(NULL, descriptor);
 
-    CHECK_EQ(1 + i, descriptor->JSParameterCount());
-    CHECK_EQ(1, descriptor->ReturnCount());
+    CHECK_EQ(1 + i, static_cast<int>(descriptor->JSParameterCount()));
+    CHECK_EQ(1, static_cast<int>(descriptor->ReturnCount()));
     CHECK_EQ(Operator::kNoProperties, descriptor->properties());
     CHECK_EQ(true, descriptor->IsJSFunctionCall());
   }
@@ -76,7 +75,7 @@
 TEST(TestLinkageCodeStubIncoming) {
   Isolate* isolate = CcTest::InitIsolateOnce();
   CompilationInfoWithZone info(static_cast<HydrogenCodeStub*>(NULL), isolate);
-  Linkage linkage(&info);
+  Linkage linkage(info.zone(), &info);
   // TODO(titzer): test linkage creation with a bonafide code stub.
   // this just checks current behavior.
   CHECK_EQ(NULL, linkage.GetIncomingDescriptor());
@@ -87,13 +86,14 @@
   HandleAndZoneScope handles;
   Handle<JSFunction> function = Compile("a + c");
   CompilationInfoWithZone info(function);
-  Linkage linkage(&info);
+  Linkage linkage(info.zone(), &info);
 
   for (int i = 0; i < 32; i++) {
-    CallDescriptor* descriptor = linkage.GetJSCallDescriptor(i);
+    CallDescriptor* descriptor =
+        linkage.GetJSCallDescriptor(i, CallDescriptor::kNoFlags);
     CHECK_NE(NULL, descriptor);
-    CHECK_EQ(i, descriptor->JSParameterCount());
-    CHECK_EQ(1, descriptor->ReturnCount());
+    CHECK_EQ(i, static_cast<int>(descriptor->JSParameterCount()));
+    CHECK_EQ(1, static_cast<int>(descriptor->ReturnCount()));
     CHECK_EQ(Operator::kNoProperties, descriptor->properties());
     CHECK_EQ(true, descriptor->IsJSFunctionCall());
   }
diff --git a/test/cctest/compiler/test-loop-analysis.cc b/test/cctest/compiler/test-loop-analysis.cc
new file mode 100644
index 0000000..9c11268
--- /dev/null
+++ b/test/cctest/compiler/test-loop-analysis.cc
@@ -0,0 +1,862 @@
+// 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.
+
+#include "src/v8.h"
+
+#include "src/compiler/access-builder.h"
+#include "src/compiler/common-operator.h"
+#include "src/compiler/graph.h"
+#include "src/compiler/graph-visualizer.h"
+#include "src/compiler/js-graph.h"
+#include "src/compiler/js-operator.h"
+#include "src/compiler/loop-analysis.h"
+#include "src/compiler/node.h"
+#include "src/compiler/opcodes.h"
+#include "src/compiler/operator.h"
+#include "src/compiler/schedule.h"
+#include "src/compiler/scheduler.h"
+#include "src/compiler/simplified-operator.h"
+#include "src/compiler/verifier.h"
+#include "test/cctest/cctest.h"
+
+using namespace v8::internal;
+using namespace v8::internal::compiler;
+
+static Operator kIntAdd(IrOpcode::kInt32Add, Operator::kPure, "Int32Add", 2, 0,
+                        0, 1, 0, 0);
+static Operator kIntLt(IrOpcode::kInt32LessThan, Operator::kPure,
+                       "Int32LessThan", 2, 0, 0, 1, 0, 0);
+static Operator kStore(IrOpcode::kStore, Operator::kNoProperties, "Store", 0, 2,
+                       1, 0, 1, 0);
+
+static const int kNumLeafs = 4;
+
+// A helper for all tests dealing with LoopFinder.
+class LoopFinderTester : HandleAndZoneScope {
+ public:
+  LoopFinderTester()
+      : isolate(main_isolate()),
+        common(main_zone()),
+        graph(main_zone()),
+        jsgraph(&graph, &common, NULL, NULL),
+        start(graph.NewNode(common.Start(1))),
+        end(graph.NewNode(common.End(), start)),
+        p0(graph.NewNode(common.Parameter(0), start)),
+        zero(jsgraph.Int32Constant(0)),
+        one(jsgraph.OneConstant()),
+        half(jsgraph.Constant(0.5)),
+        self(graph.NewNode(common.Int32Constant(0xaabbccdd))),
+        dead(graph.NewNode(common.Dead())),
+        loop_tree(NULL) {
+    graph.SetEnd(end);
+    graph.SetStart(start);
+    leaf[0] = zero;
+    leaf[1] = one;
+    leaf[2] = half;
+    leaf[3] = p0;
+  }
+
+  Isolate* isolate;
+  CommonOperatorBuilder common;
+  Graph graph;
+  JSGraph jsgraph;
+  Node* start;
+  Node* end;
+  Node* p0;
+  Node* zero;
+  Node* one;
+  Node* half;
+  Node* self;
+  Node* dead;
+  Node* leaf[kNumLeafs];
+  LoopTree* loop_tree;
+
+  Node* Phi(Node* a) {
+    return SetSelfReferences(graph.NewNode(op(1, false), a, start));
+  }
+
+  Node* Phi(Node* a, Node* b) {
+    return SetSelfReferences(graph.NewNode(op(2, false), a, b, start));
+  }
+
+  Node* Phi(Node* a, Node* b, Node* c) {
+    return SetSelfReferences(graph.NewNode(op(3, false), a, b, c, start));
+  }
+
+  Node* Phi(Node* a, Node* b, Node* c, Node* d) {
+    return SetSelfReferences(graph.NewNode(op(4, false), a, b, c, d, start));
+  }
+
+  Node* EffectPhi(Node* a) {
+    return SetSelfReferences(graph.NewNode(op(1, true), a, start));
+  }
+
+  Node* EffectPhi(Node* a, Node* b) {
+    return SetSelfReferences(graph.NewNode(op(2, true), a, b, start));
+  }
+
+  Node* EffectPhi(Node* a, Node* b, Node* c) {
+    return SetSelfReferences(graph.NewNode(op(3, true), a, b, c, start));
+  }
+
+  Node* EffectPhi(Node* a, Node* b, Node* c, Node* d) {
+    return SetSelfReferences(graph.NewNode(op(4, true), a, b, c, d, start));
+  }
+
+  Node* SetSelfReferences(Node* node) {
+    for (Edge edge : node->input_edges()) {
+      if (edge.to() == self) node->ReplaceInput(edge.index(), node);
+    }
+    return node;
+  }
+
+  const Operator* op(int count, bool effect) {
+    return effect ? common.EffectPhi(count) : common.Phi(kMachAnyTagged, count);
+  }
+
+  Node* Return(Node* val, Node* effect, Node* control) {
+    Node* ret = graph.NewNode(common.Return(), val, effect, control);
+    end->ReplaceInput(0, ret);
+    return ret;
+  }
+
+  LoopTree* GetLoopTree() {
+    if (loop_tree == NULL) {
+      if (FLAG_trace_turbo_graph) {
+        OFStream os(stdout);
+        os << AsRPO(graph);
+      }
+      Zone zone(isolate);
+      loop_tree = LoopFinder::BuildLoopTree(&graph, &zone);
+    }
+    return loop_tree;
+  }
+
+  void CheckLoop(Node** header, int header_count, Node** body, int body_count) {
+    LoopTree* tree = GetLoopTree();
+    LoopTree::Loop* loop = tree->ContainingLoop(header[0]);
+    CHECK_NE(NULL, loop);
+
+    CHECK(header_count == static_cast<int>(loop->HeaderSize()));
+    for (int i = 0; i < header_count; i++) {
+      // Each header node should be in the loop.
+      CHECK_EQ(loop, tree->ContainingLoop(header[i]));
+      CheckRangeContains(tree->HeaderNodes(loop), header[i]);
+    }
+
+    CHECK_EQ(body_count, static_cast<int>(loop->BodySize()));
+    for (int i = 0; i < body_count; i++) {
+      // Each body node should be contained in the loop.
+      CHECK(tree->Contains(loop, body[i]));
+      CheckRangeContains(tree->BodyNodes(loop), body[i]);
+    }
+  }
+
+  void CheckRangeContains(NodeRange range, Node* node) {
+    // O(n) ftw.
+    CHECK_NE(range.end(), std::find(range.begin(), range.end(), node));
+  }
+
+  void CheckNestedLoops(Node** chain, int chain_count) {
+    LoopTree* tree = GetLoopTree();
+    for (int i = 0; i < chain_count; i++) {
+      Node* header = chain[i];
+      // Each header should be in a loop.
+      LoopTree::Loop* loop = tree->ContainingLoop(header);
+      CHECK_NE(NULL, loop);
+      // Check parentage.
+      LoopTree::Loop* parent =
+          i == 0 ? NULL : tree->ContainingLoop(chain[i - 1]);
+      CHECK_EQ(parent, loop->parent());
+      for (int j = i - 1; j >= 0; j--) {
+        // This loop should be nested inside all the outer loops.
+        Node* outer_header = chain[j];
+        LoopTree::Loop* outer = tree->ContainingLoop(outer_header);
+        CHECK(tree->Contains(outer, header));
+        CHECK(!tree->Contains(loop, outer_header));
+      }
+    }
+  }
+};
+
+
+struct While {
+  LoopFinderTester& t;
+  Node* branch;
+  Node* if_true;
+  Node* exit;
+  Node* loop;
+
+  While(LoopFinderTester& R, Node* cond) : t(R) {
+    loop = t.graph.NewNode(t.common.Loop(2), t.start, t.start);
+    branch = t.graph.NewNode(t.common.Branch(), cond, loop);
+    if_true = t.graph.NewNode(t.common.IfTrue(), branch);
+    exit = t.graph.NewNode(t.common.IfFalse(), branch);
+    loop->ReplaceInput(1, if_true);
+  }
+
+  void chain(Node* control) { loop->ReplaceInput(0, control); }
+  void nest(While& that) {
+    that.loop->ReplaceInput(1, exit);
+    this->loop->ReplaceInput(0, that.if_true);
+  }
+};
+
+
+struct Counter {
+  Node* base;
+  Node* inc;
+  Node* phi;
+  Node* add;
+
+  Counter(While& w, int32_t b, int32_t k)
+      : base(w.t.jsgraph.Int32Constant(b)), inc(w.t.jsgraph.Int32Constant(k)) {
+    Build(w);
+  }
+
+  Counter(While& w, Node* b, Node* k) : base(b), inc(k) { Build(w); }
+
+  void Build(While& w) {
+    phi = w.t.graph.NewNode(w.t.op(2, false), base, base, w.loop);
+    add = w.t.graph.NewNode(&kIntAdd, phi, inc);
+    phi->ReplaceInput(1, add);
+  }
+};
+
+
+struct StoreLoop {
+  Node* base;
+  Node* val;
+  Node* phi;
+  Node* store;
+
+  explicit StoreLoop(While& w)
+      : base(w.t.jsgraph.Int32Constant(12)),
+        val(w.t.jsgraph.Int32Constant(13)) {
+    Build(w);
+  }
+
+  StoreLoop(While& w, Node* b, Node* v) : base(b), val(v) { Build(w); }
+
+  void Build(While& w) {
+    phi = w.t.graph.NewNode(w.t.op(2, true), base, base, w.loop);
+    store = w.t.graph.NewNode(&kStore, phi, val, w.loop);
+    phi->ReplaceInput(1, store);
+  }
+};
+
+
+TEST(LaLoop1) {
+  // One loop.
+  LoopFinderTester t;
+  While w(t, t.p0);
+  t.Return(t.p0, t.start, w.exit);
+
+  Node* chain[] = {w.loop};
+  t.CheckNestedLoops(chain, 1);
+
+  Node* header[] = {w.loop};
+  Node* body[] = {w.branch, w.if_true};
+  t.CheckLoop(header, 1, body, 2);
+}
+
+
+TEST(LaLoop1c) {
+  // One loop with a counter.
+  LoopFinderTester t;
+  While w(t, t.p0);
+  Counter c(w, 0, 1);
+  t.Return(c.phi, t.start, w.exit);
+
+  Node* chain[] = {w.loop};
+  t.CheckNestedLoops(chain, 1);
+
+  Node* header[] = {w.loop, c.phi};
+  Node* body[] = {w.branch, w.if_true, c.add};
+  t.CheckLoop(header, 2, body, 3);
+}
+
+
+TEST(LaLoop1e) {
+  // One loop with an effect phi.
+  LoopFinderTester t;
+  While w(t, t.p0);
+  StoreLoop c(w);
+  t.Return(t.p0, c.phi, w.exit);
+
+  Node* chain[] = {w.loop};
+  t.CheckNestedLoops(chain, 1);
+
+  Node* header[] = {w.loop, c.phi};
+  Node* body[] = {w.branch, w.if_true, c.store};
+  t.CheckLoop(header, 2, body, 3);
+}
+
+
+TEST(LaLoop1d) {
+  // One loop with two counters.
+  LoopFinderTester t;
+  While w(t, t.p0);
+  Counter c1(w, 0, 1);
+  Counter c2(w, 1, 1);
+  t.Return(t.graph.NewNode(&kIntAdd, c1.phi, c2.phi), t.start, w.exit);
+
+  Node* chain[] = {w.loop};
+  t.CheckNestedLoops(chain, 1);
+
+  Node* header[] = {w.loop, c1.phi, c2.phi};
+  Node* body[] = {w.branch, w.if_true, c1.add, c2.add};
+  t.CheckLoop(header, 3, body, 4);
+}
+
+
+TEST(LaLoop2) {
+  // One loop following another.
+  LoopFinderTester t;
+  While w1(t, t.p0);
+  While w2(t, t.p0);
+  w2.chain(w1.exit);
+  t.Return(t.p0, t.start, w2.exit);
+
+  {
+    Node* chain[] = {w1.loop};
+    t.CheckNestedLoops(chain, 1);
+
+    Node* header[] = {w1.loop};
+    Node* body[] = {w1.branch, w1.if_true};
+    t.CheckLoop(header, 1, body, 2);
+  }
+
+  {
+    Node* chain[] = {w2.loop};
+    t.CheckNestedLoops(chain, 1);
+
+    Node* header[] = {w2.loop};
+    Node* body[] = {w2.branch, w2.if_true};
+    t.CheckLoop(header, 1, body, 2);
+  }
+}
+
+
+TEST(LaLoop2c) {
+  // One loop following another, each with counters.
+  LoopFinderTester t;
+  While w1(t, t.p0);
+  While w2(t, t.p0);
+  Counter c1(w1, 0, 1);
+  Counter c2(w2, 0, 1);
+  w2.chain(w1.exit);
+  t.Return(t.graph.NewNode(&kIntAdd, c1.phi, c2.phi), t.start, w2.exit);
+
+  {
+    Node* chain[] = {w1.loop};
+    t.CheckNestedLoops(chain, 1);
+
+    Node* header[] = {w1.loop, c1.phi};
+    Node* body[] = {w1.branch, w1.if_true, c1.add};
+    t.CheckLoop(header, 2, body, 3);
+  }
+
+  {
+    Node* chain[] = {w2.loop};
+    t.CheckNestedLoops(chain, 1);
+
+    Node* header[] = {w2.loop, c2.phi};
+    Node* body[] = {w2.branch, w2.if_true, c2.add};
+    t.CheckLoop(header, 2, body, 3);
+  }
+}
+
+
+TEST(LaLoop2cc) {
+  // One loop following another; second loop uses phi from first.
+  for (int i = 0; i < 8; i++) {
+    LoopFinderTester t;
+    While w1(t, t.p0);
+    While w2(t, t.p0);
+    Counter c1(w1, 0, 1);
+
+    // various usage scenarios for the second loop.
+    Counter c2(w2, i & 1 ? t.p0 : c1.phi, i & 2 ? t.p0 : c1.phi);
+    if (i & 3) w2.branch->ReplaceInput(0, c1.phi);
+
+    w2.chain(w1.exit);
+    t.Return(t.graph.NewNode(&kIntAdd, c1.phi, c2.phi), t.start, w2.exit);
+
+    {
+      Node* chain[] = {w1.loop};
+      t.CheckNestedLoops(chain, 1);
+
+      Node* header[] = {w1.loop, c1.phi};
+      Node* body[] = {w1.branch, w1.if_true, c1.add};
+      t.CheckLoop(header, 2, body, 3);
+    }
+
+    {
+      Node* chain[] = {w2.loop};
+      t.CheckNestedLoops(chain, 1);
+
+      Node* header[] = {w2.loop, c2.phi};
+      Node* body[] = {w2.branch, w2.if_true, c2.add};
+      t.CheckLoop(header, 2, body, 3);
+    }
+  }
+}
+
+
+TEST(LaNestedLoop1) {
+  // One loop nested in another.
+  LoopFinderTester t;
+  While w1(t, t.p0);
+  While w2(t, t.p0);
+  w2.nest(w1);
+  t.Return(t.p0, t.start, w1.exit);
+
+  Node* chain[] = {w1.loop, w2.loop};
+  t.CheckNestedLoops(chain, 2);
+
+  Node* h1[] = {w1.loop};
+  Node* b1[] = {w1.branch, w1.if_true, w2.loop, w2.branch, w2.if_true, w2.exit};
+  t.CheckLoop(h1, 1, b1, 6);
+
+  Node* h2[] = {w2.loop};
+  Node* b2[] = {w2.branch, w2.if_true};
+  t.CheckLoop(h2, 1, b2, 2);
+}
+
+
+TEST(LaNestedLoop1c) {
+  // One loop nested in another, each with a counter.
+  LoopFinderTester t;
+  While w1(t, t.p0);
+  While w2(t, t.p0);
+  Counter c1(w1, 0, 1);
+  Counter c2(w2, 0, 1);
+  w2.branch->ReplaceInput(0, c2.phi);
+  w2.nest(w1);
+  t.Return(c1.phi, t.start, w1.exit);
+
+  Node* chain[] = {w1.loop, w2.loop};
+  t.CheckNestedLoops(chain, 2);
+
+  Node* h1[] = {w1.loop, c1.phi};
+  Node* b1[] = {w1.branch, w1.if_true, w2.loop, w2.branch, w2.if_true,
+                w2.exit,   c2.phi,     c1.add,  c2.add};
+  t.CheckLoop(h1, 2, b1, 9);
+
+  Node* h2[] = {w2.loop, c2.phi};
+  Node* b2[] = {w2.branch, w2.if_true, c2.add};
+  t.CheckLoop(h2, 2, b2, 3);
+}
+
+
+TEST(LaNestedLoop2) {
+  // Two loops nested in an outer loop.
+  LoopFinderTester t;
+  While w1(t, t.p0);
+  While w2(t, t.p0);
+  While w3(t, t.p0);
+  w2.nest(w1);
+  w3.nest(w1);
+  w3.chain(w2.exit);
+  t.Return(t.p0, t.start, w1.exit);
+
+  Node* chain1[] = {w1.loop, w2.loop};
+  t.CheckNestedLoops(chain1, 2);
+
+  Node* chain2[] = {w1.loop, w3.loop};
+  t.CheckNestedLoops(chain2, 2);
+
+  Node* h1[] = {w1.loop};
+  Node* b1[] = {w1.branch, w1.if_true, w2.loop,   w2.branch,  w2.if_true,
+                w2.exit,   w3.loop,    w3.branch, w3.if_true, w3.exit};
+  t.CheckLoop(h1, 1, b1, 10);
+
+  Node* h2[] = {w2.loop};
+  Node* b2[] = {w2.branch, w2.if_true};
+  t.CheckLoop(h2, 1, b2, 2);
+
+  Node* h3[] = {w3.loop};
+  Node* b3[] = {w3.branch, w3.if_true};
+  t.CheckLoop(h3, 1, b3, 2);
+}
+
+
+TEST(LaNestedLoop3) {
+  // Three nested loops.
+  LoopFinderTester t;
+  While w1(t, t.p0);
+  While w2(t, t.p0);
+  While w3(t, t.p0);
+  w2.loop->ReplaceInput(0, w1.if_true);
+  w3.loop->ReplaceInput(0, w2.if_true);
+  w2.loop->ReplaceInput(1, w3.exit);
+  w1.loop->ReplaceInput(1, w2.exit);
+  t.Return(t.p0, t.start, w1.exit);
+
+  Node* chain[] = {w1.loop, w2.loop, w3.loop};
+  t.CheckNestedLoops(chain, 3);
+
+  Node* h1[] = {w1.loop};
+  Node* b1[] = {w1.branch, w1.if_true, w2.loop,   w2.branch,  w2.if_true,
+                w2.exit,   w3.loop,    w3.branch, w3.if_true, w3.exit};
+  t.CheckLoop(h1, 1, b1, 10);
+
+  Node* h2[] = {w2.loop};
+  Node* b2[] = {w2.branch, w2.if_true, w3.loop, w3.branch, w3.if_true, w3.exit};
+  t.CheckLoop(h2, 1, b2, 6);
+
+  Node* h3[] = {w3.loop};
+  Node* b3[] = {w3.branch, w3.if_true};
+  t.CheckLoop(h3, 1, b3, 2);
+}
+
+
+TEST(LaNestedLoop3c) {
+  // Three nested loops with counters.
+  LoopFinderTester t;
+  While w1(t, t.p0);
+  Counter c1(w1, 0, 1);
+  While w2(t, t.p0);
+  Counter c2(w2, 0, 1);
+  While w3(t, t.p0);
+  Counter c3(w3, 0, 1);
+  w2.loop->ReplaceInput(0, w1.if_true);
+  w3.loop->ReplaceInput(0, w2.if_true);
+  w2.loop->ReplaceInput(1, w3.exit);
+  w1.loop->ReplaceInput(1, w2.exit);
+  w1.branch->ReplaceInput(0, c1.phi);
+  w2.branch->ReplaceInput(0, c2.phi);
+  w3.branch->ReplaceInput(0, c3.phi);
+  t.Return(c1.phi, t.start, w1.exit);
+
+  Node* chain[] = {w1.loop, w2.loop, w3.loop};
+  t.CheckNestedLoops(chain, 3);
+
+  Node* h1[] = {w1.loop, c1.phi};
+  Node* b1[] = {w1.branch, w1.if_true, c1.add,    c2.add,     c2.add,
+                c2.phi,    c3.phi,     w2.loop,   w2.branch,  w2.if_true,
+                w2.exit,   w3.loop,    w3.branch, w3.if_true, w3.exit};
+  t.CheckLoop(h1, 2, b1, 15);
+
+  Node* h2[] = {w2.loop, c2.phi};
+  Node* b2[] = {w2.branch, w2.if_true, c2.add,     c3.add, c3.phi,
+                w3.loop,   w3.branch,  w3.if_true, w3.exit};
+  t.CheckLoop(h2, 2, b2, 9);
+
+  Node* h3[] = {w3.loop, c3.phi};
+  Node* b3[] = {w3.branch, w3.if_true, c3.add};
+  t.CheckLoop(h3, 2, b3, 3);
+}
+
+
+TEST(LaMultipleExit1) {
+  const int kMaxExits = 10;
+  Node* merge[1 + kMaxExits];
+  Node* body[2 * kMaxExits];
+
+  // A single loop with {i} exits.
+  for (int i = 1; i < kMaxExits; i++) {
+    LoopFinderTester t;
+    Node* cond = t.p0;
+
+    int merge_count = 0;
+    int body_count = 0;
+    Node* loop = t.graph.NewNode(t.common.Loop(2), t.start, t.start);
+    Node* last = loop;
+
+    for (int e = 0; e < i; e++) {
+      Node* branch = t.graph.NewNode(t.common.Branch(), cond, last);
+      Node* if_true = t.graph.NewNode(t.common.IfTrue(), branch);
+      Node* exit = t.graph.NewNode(t.common.IfFalse(), branch);
+      last = if_true;
+
+      body[body_count++] = branch;
+      body[body_count++] = if_true;
+      merge[merge_count++] = exit;
+    }
+
+    loop->ReplaceInput(1, last);  // form loop backedge.
+    Node* end = t.graph.NewNode(t.common.Merge(i), i, merge);  // form exit.
+    t.graph.SetEnd(end);
+
+    Node* h[] = {loop};
+    t.CheckLoop(h, 1, body, body_count);
+  }
+}
+
+
+TEST(LaMultipleBackedge1) {
+  const int kMaxBackedges = 10;
+  Node* loop_inputs[1 + kMaxBackedges];
+  Node* body[3 * kMaxBackedges];
+
+  // A single loop with {i} backedges.
+  for (int i = 1; i < kMaxBackedges; i++) {
+    LoopFinderTester t;
+
+    for (int j = 0; j <= i; j++) loop_inputs[j] = t.start;
+    Node* loop = t.graph.NewNode(t.common.Loop(1 + i), 1 + i, loop_inputs);
+
+    Node* cond = t.p0;
+    int body_count = 0;
+    Node* exit = loop;
+
+    for (int b = 0; b < i; b++) {
+      Node* branch = t.graph.NewNode(t.common.Branch(), cond, exit);
+      Node* if_true = t.graph.NewNode(t.common.IfTrue(), branch);
+      Node* if_false = t.graph.NewNode(t.common.IfFalse(), branch);
+      exit = if_false;
+
+      body[body_count++] = branch;
+      body[body_count++] = if_true;
+      if (b != (i - 1)) body[body_count++] = if_false;
+
+      loop->ReplaceInput(1 + b, if_true);
+    }
+
+    t.graph.SetEnd(exit);
+
+    Node* h[] = {loop};
+    t.CheckLoop(h, 1, body, body_count);
+  }
+}
+
+
+TEST(LaEdgeMatrix1) {
+  // Test various kinds of extra edges added to a simple loop.
+  for (int i = 0; i < 3; i++) {
+    for (int j = 0; j < 3; j++) {
+      for (int k = 0; k < 3; k++) {
+        LoopFinderTester t;
+
+        Node* p1 = t.jsgraph.Int32Constant(11);
+        Node* p2 = t.jsgraph.Int32Constant(22);
+        Node* p3 = t.jsgraph.Int32Constant(33);
+
+        Node* loop = t.graph.NewNode(t.common.Loop(2), t.start, t.start);
+        Node* phi =
+            t.graph.NewNode(t.common.Phi(kMachInt32, 2), t.one, p1, loop);
+        Node* cond = t.graph.NewNode(&kIntAdd, phi, p2);
+        Node* branch = t.graph.NewNode(t.common.Branch(), cond, loop);
+        Node* if_true = t.graph.NewNode(t.common.IfTrue(), branch);
+        Node* exit = t.graph.NewNode(t.common.IfFalse(), branch);
+        loop->ReplaceInput(1, if_true);
+        Node* ret = t.graph.NewNode(t.common.Return(), p3, t.start, exit);
+        t.graph.SetEnd(ret);
+
+        Node* choices[] = {p1, phi, cond};
+        p1->ReplaceUses(choices[i]);
+        p2->ReplaceUses(choices[j]);
+        p3->ReplaceUses(choices[k]);
+
+        Node* header[] = {loop, phi};
+        Node* body[] = {cond, branch, if_true};
+        t.CheckLoop(header, 2, body, 3);
+      }
+    }
+  }
+}
+
+
+void RunEdgeMatrix2(int i) {
+  DCHECK(i >= 0 && i < 5);
+  for (int j = 0; j < 5; j++) {
+    for (int k = 0; k < 5; k++) {
+      LoopFinderTester t;
+
+      Node* p1 = t.jsgraph.Int32Constant(11);
+      Node* p2 = t.jsgraph.Int32Constant(22);
+      Node* p3 = t.jsgraph.Int32Constant(33);
+
+      // outer loop.
+      Node* loop1 = t.graph.NewNode(t.common.Loop(2), t.start, t.start);
+      Node* phi1 =
+          t.graph.NewNode(t.common.Phi(kMachInt32, 2), t.one, p1, loop1);
+      Node* cond1 = t.graph.NewNode(&kIntAdd, phi1, t.one);
+      Node* branch1 = t.graph.NewNode(t.common.Branch(), cond1, loop1);
+      Node* if_true1 = t.graph.NewNode(t.common.IfTrue(), branch1);
+      Node* exit1 = t.graph.NewNode(t.common.IfFalse(), branch1);
+
+      // inner loop.
+      Node* loop2 = t.graph.NewNode(t.common.Loop(2), if_true1, t.start);
+      Node* phi2 =
+          t.graph.NewNode(t.common.Phi(kMachInt32, 2), t.one, p2, loop2);
+      Node* cond2 = t.graph.NewNode(&kIntAdd, phi2, p3);
+      Node* branch2 = t.graph.NewNode(t.common.Branch(), cond2, loop2);
+      Node* if_true2 = t.graph.NewNode(t.common.IfTrue(), branch2);
+      Node* exit2 = t.graph.NewNode(t.common.IfFalse(), branch2);
+      loop2->ReplaceInput(1, if_true2);
+      loop1->ReplaceInput(1, exit2);
+
+      Node* ret = t.graph.NewNode(t.common.Return(), phi1, t.start, exit1);
+      t.graph.SetEnd(ret);
+
+      Node* choices[] = {p1, phi1, cond1, phi2, cond2};
+      p1->ReplaceUses(choices[i]);
+      p2->ReplaceUses(choices[j]);
+      p3->ReplaceUses(choices[k]);
+
+      Node* header1[] = {loop1, phi1};
+      Node* body1[] = {cond1, branch1, if_true1, exit2,   loop2,
+                       phi2,  cond2,   branch2,  if_true2};
+      t.CheckLoop(header1, 2, body1, 9);
+
+      Node* header2[] = {loop2, phi2};
+      Node* body2[] = {cond2, branch2, if_true2};
+      t.CheckLoop(header2, 2, body2, 3);
+
+      Node* chain[] = {loop1, loop2};
+      t.CheckNestedLoops(chain, 2);
+    }
+  }
+}
+
+
+TEST(LaEdgeMatrix2_0) { RunEdgeMatrix2(0); }
+
+
+TEST(LaEdgeMatrix2_1) { RunEdgeMatrix2(1); }
+
+
+TEST(LaEdgeMatrix2_2) { RunEdgeMatrix2(2); }
+
+
+TEST(LaEdgeMatrix2_3) { RunEdgeMatrix2(3); }
+
+
+TEST(LaEdgeMatrix2_4) { RunEdgeMatrix2(4); }
+
+
+// Generates a triply-nested loop with extra edges between the phis and
+// conditions according to the edge choice parameters.
+void RunEdgeMatrix3(int c1a, int c1b, int c1c,    // line break
+                    int c2a, int c2b, int c2c,    // line break
+                    int c3a, int c3b, int c3c) {  // line break
+  LoopFinderTester t;
+
+  Node* p1a = t.jsgraph.Int32Constant(11);
+  Node* p1b = t.jsgraph.Int32Constant(22);
+  Node* p1c = t.jsgraph.Int32Constant(33);
+  Node* p2a = t.jsgraph.Int32Constant(44);
+  Node* p2b = t.jsgraph.Int32Constant(55);
+  Node* p2c = t.jsgraph.Int32Constant(66);
+  Node* p3a = t.jsgraph.Int32Constant(77);
+  Node* p3b = t.jsgraph.Int32Constant(88);
+  Node* p3c = t.jsgraph.Int32Constant(99);
+
+  // L1 depth = 0
+  Node* loop1 = t.graph.NewNode(t.common.Loop(2), t.start, t.start);
+  Node* phi1 = t.graph.NewNode(t.common.Phi(kMachInt32, 2), p1a, p1c, loop1);
+  Node* cond1 = t.graph.NewNode(&kIntAdd, phi1, p1b);
+  Node* branch1 = t.graph.NewNode(t.common.Branch(), cond1, loop1);
+  Node* if_true1 = t.graph.NewNode(t.common.IfTrue(), branch1);
+  Node* exit1 = t.graph.NewNode(t.common.IfFalse(), branch1);
+
+  // L2 depth = 1
+  Node* loop2 = t.graph.NewNode(t.common.Loop(2), if_true1, t.start);
+  Node* phi2 = t.graph.NewNode(t.common.Phi(kMachInt32, 2), p2a, p2c, loop2);
+  Node* cond2 = t.graph.NewNode(&kIntAdd, phi2, p2b);
+  Node* branch2 = t.graph.NewNode(t.common.Branch(), cond2, loop2);
+  Node* if_true2 = t.graph.NewNode(t.common.IfTrue(), branch2);
+  Node* exit2 = t.graph.NewNode(t.common.IfFalse(), branch2);
+
+  // L3 depth = 2
+  Node* loop3 = t.graph.NewNode(t.common.Loop(2), if_true2, t.start);
+  Node* phi3 = t.graph.NewNode(t.common.Phi(kMachInt32, 2), p3a, p3c, loop3);
+  Node* cond3 = t.graph.NewNode(&kIntAdd, phi3, p3b);
+  Node* branch3 = t.graph.NewNode(t.common.Branch(), cond3, loop3);
+  Node* if_true3 = t.graph.NewNode(t.common.IfTrue(), branch3);
+  Node* exit3 = t.graph.NewNode(t.common.IfFalse(), branch3);
+
+  loop3->ReplaceInput(1, if_true3);
+  loop2->ReplaceInput(1, exit3);
+  loop1->ReplaceInput(1, exit2);
+
+  Node* ret = t.graph.NewNode(t.common.Return(), phi1, t.start, exit1);
+  t.graph.SetEnd(ret);
+
+  // Mutate the graph according to the edge choices.
+
+  Node* o1[] = {t.one};
+  Node* o2[] = {t.one, phi1, cond1};
+  Node* o3[] = {t.one, phi1, cond1, phi2, cond2};
+
+  p1a->ReplaceUses(o1[c1a]);
+  p1b->ReplaceUses(o1[c1b]);
+
+  p2a->ReplaceUses(o2[c2a]);
+  p2b->ReplaceUses(o2[c2b]);
+
+  p3a->ReplaceUses(o3[c3a]);
+  p3b->ReplaceUses(o3[c3b]);
+
+  Node* l2[] = {phi1, cond1, phi2, cond2};
+  Node* l3[] = {phi1, cond1, phi2, cond2, phi3, cond3};
+
+  p1c->ReplaceUses(l2[c1c]);
+  p2c->ReplaceUses(l3[c2c]);
+  p3c->ReplaceUses(l3[c3c]);
+
+  // Run the tests and verify loop structure.
+
+  Node* chain[] = {loop1, loop2, loop3};
+  t.CheckNestedLoops(chain, 3);
+
+  Node* header1[] = {loop1, phi1};
+  Node* body1[] = {cond1, branch1, if_true1, exit2,    loop2,
+                   phi2,  cond2,   branch2,  if_true2, exit3,
+                   loop3, phi3,    cond3,    branch3,  if_true3};
+  t.CheckLoop(header1, 2, body1, 15);
+
+  Node* header2[] = {loop2, phi2};
+  Node* body2[] = {cond2, branch2, if_true2, exit3,   loop3,
+                   phi3,  cond3,   branch3,  if_true3};
+  t.CheckLoop(header2, 2, body2, 9);
+
+  Node* header3[] = {loop3, phi3};
+  Node* body3[] = {cond3, branch3, if_true3};
+  t.CheckLoop(header3, 2, body3, 3);
+}
+
+
+// Runs all combinations with a fixed {i}.
+void RunEdgeMatrix3_i(int i) {
+  for (int a = 0; a < 1; a++) {
+    for (int b = 0; b < 1; b++) {
+      for (int c = 0; c < 4; c++) {
+        for (int d = 0; d < 3; d++) {
+          for (int e = 0; e < 3; e++) {
+            for (int f = 0; f < 6; f++) {
+              for (int g = 0; g < 5; g++) {
+                for (int h = 0; h < 5; h++) {
+                  RunEdgeMatrix3(a, b, c, d, e, f, g, h, i);
+                }
+              }
+            }
+          }
+        }
+      }
+    }
+  }
+}
+
+
+// Test all possible legal triply-nested loops with conditions and phis.
+TEST(LaEdgeMatrix3_0) { RunEdgeMatrix3_i(0); }
+
+
+TEST(LaEdgeMatrix3_1) { RunEdgeMatrix3_i(1); }
+
+
+TEST(LaEdgeMatrix3_2) { RunEdgeMatrix3_i(2); }
+
+
+TEST(LaEdgeMatrix3_3) { RunEdgeMatrix3_i(3); }
+
+
+TEST(LaEdgeMatrix3_4) { RunEdgeMatrix3_i(4); }
+
+
+TEST(LaEdgeMatrix3_5) { RunEdgeMatrix3_i(5); }
diff --git a/test/cctest/compiler/test-loop-assignment-analysis.cc b/test/cctest/compiler/test-loop-assignment-analysis.cc
new file mode 100644
index 0000000..aabd95b
--- /dev/null
+++ b/test/cctest/compiler/test-loop-assignment-analysis.cc
@@ -0,0 +1,294 @@
+// 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.
+
+#include "src/compiler/ast-loop-assignment-analyzer.h"
+#include "src/parser.h"
+#include "src/rewriter.h"
+#include "src/scopes.h"
+#include "test/cctest/cctest.h"
+
+using namespace v8::internal;
+using namespace v8::internal::compiler;
+
+namespace {
+const int kBufferSize = 1024;
+
+struct TestHelper : public HandleAndZoneScope {
+  Handle<JSFunction> function;
+  LoopAssignmentAnalysis* result;
+
+  explicit TestHelper(const char* body)
+      : function(Handle<JSFunction>::null()), result(NULL) {
+    ScopedVector<char> program(kBufferSize);
+    SNPrintF(program, "function f(a,b,c) { %s; } f;", body);
+    v8::Local<v8::Value> v = CompileRun(program.start());
+    Handle<Object> obj = v8::Utils::OpenHandle(*v);
+    function = Handle<JSFunction>::cast(obj);
+  }
+
+  void CheckLoopAssignedCount(int expected, const char* var_name) {
+    // TODO(titzer): don't scope analyze every single time.
+    CompilationInfo info(function, main_zone());
+
+    CHECK(Parser::Parse(&info));
+    CHECK(Rewriter::Rewrite(&info));
+    CHECK(Scope::Analyze(&info));
+
+    Scope* scope = info.function()->scope();
+    AstValueFactory* factory = info.ast_value_factory();
+    CHECK_NE(NULL, scope);
+
+    if (result == NULL) {
+      AstLoopAssignmentAnalyzer analyzer(main_zone(), &info);
+      result = analyzer.Analyze();
+      CHECK_NE(NULL, result);
+    }
+
+    const i::AstRawString* name = factory->GetOneByteString(var_name);
+
+    i::Variable* var = scope->Lookup(name);
+    CHECK_NE(NULL, var);
+
+    if (var->location() == Variable::UNALLOCATED) {
+      CHECK_EQ(0, expected);
+    } else {
+      CHECK(var->IsStackAllocated());
+      CHECK_EQ(expected, result->GetAssignmentCountForTesting(scope, var));
+    }
+  }
+};
+}
+
+
+TEST(SimpleLoop1) {
+  TestHelper f("var x = 0; while (x) ;");
+
+  f.CheckLoopAssignedCount(0, "x");
+}
+
+
+TEST(SimpleLoop2) {
+  const char* loops[] = {
+      "while (x) { var x = 0; }",            "for(;;) { var x = 0; }",
+      "for(;x;) { var x = 0; }",             "for(;x;x) { var x = 0; }",
+      "for(var i = x; x; x) { var x = 0; }", "for(y in 0) { var x = 0; }",
+      "for(y of 0) { var x = 0; }",          "for(var x = 0; x; x++) { }",
+      "for(var x = 0; x++;) { }",            "var x; for(;x;x++) { }",
+      "var x; do { x = 1; } while (0);",     "do { var x = 1; } while (0);"};
+
+  for (size_t i = 0; i < arraysize(loops); i++) {
+    TestHelper f(loops[i]);
+    f.CheckLoopAssignedCount(1, "x");
+  }
+}
+
+
+TEST(ForInOf1) {
+  const char* loops[] = {
+      "for(x in 0) { }", "for(x of 0) { }",
+  };
+
+  for (size_t i = 0; i < arraysize(loops); i++) {
+    TestHelper f(loops[i]);
+    f.CheckLoopAssignedCount(0, "x");
+  }
+}
+
+
+TEST(Param1) {
+  TestHelper f("while (1) a = 0;");
+
+  f.CheckLoopAssignedCount(1, "a");
+  f.CheckLoopAssignedCount(0, "b");
+  f.CheckLoopAssignedCount(0, "c");
+}
+
+
+TEST(Param2) {
+  TestHelper f("for (;;) b = 0;");
+
+  f.CheckLoopAssignedCount(0, "a");
+  f.CheckLoopAssignedCount(1, "b");
+  f.CheckLoopAssignedCount(0, "c");
+}
+
+
+TEST(Param2b) {
+  TestHelper f("a; b; c; for (;;) b = 0;");
+
+  f.CheckLoopAssignedCount(0, "a");
+  f.CheckLoopAssignedCount(1, "b");
+  f.CheckLoopAssignedCount(0, "c");
+}
+
+
+TEST(Param3) {
+  TestHelper f("for(x in 0) c = 0;");
+
+  f.CheckLoopAssignedCount(0, "a");
+  f.CheckLoopAssignedCount(0, "b");
+  f.CheckLoopAssignedCount(1, "c");
+}
+
+
+TEST(Param3b) {
+  TestHelper f("a; b; c; for(x in 0) c = 0;");
+
+  f.CheckLoopAssignedCount(0, "a");
+  f.CheckLoopAssignedCount(0, "b");
+  f.CheckLoopAssignedCount(1, "c");
+}
+
+
+TEST(NestedLoop1) {
+  TestHelper f("while (x) { while (x) { var x = 0; } }");
+
+  f.CheckLoopAssignedCount(2, "x");
+}
+
+
+TEST(NestedLoop2) {
+  TestHelper f("while (0) { while (0) { var x = 0; } }");
+
+  f.CheckLoopAssignedCount(2, "x");
+}
+
+
+TEST(NestedLoop3) {
+  TestHelper f("while (0) { var y = 1; while (0) { var x = 0; } }");
+
+  f.CheckLoopAssignedCount(2, "x");
+  f.CheckLoopAssignedCount(1, "y");
+}
+
+
+TEST(NestedInc1) {
+  const char* loops[] = {
+      "while (1) a(b++);",
+      "while (1) a(0, b++);",
+      "while (1) a(0, 0, b++);",
+      "while (1) a(b++, 1, 1);",
+      "while (1) a(++b);",
+      "while (1) a + (b++);",
+      "while (1) (b++) + a;",
+      "while (1) a + c(b++);",
+      "while (1) throw b++;",
+      "while (1) switch (b++) {} ;",
+      "while (1) switch (a) {case (b++): 0; } ;",
+      "while (1) switch (a) {case b: b++; } ;",
+      "while (1) a == (b++);",
+      "while (1) a === (b++);",
+      "while (1) +(b++);",
+      "while (1) ~(b++);",
+      "while (1) new a(b++);",
+      "while (1) (b++).f;",
+      "while (1) a[b++];",
+      "while (1) (b++)();",
+      "while (1) [b++];",
+      "while (1) [0,b++];",
+      "while (1) var y = [11,b++,12];",
+      "while (1) var y = {f:11,g:(b++),h:12};",
+      "while (1) try {b++;} finally {};",
+      "while (1) try {} finally {b++};",
+      "while (1) try {b++;} catch (e) {};",
+      "while (1) try {} catch (e) {b++};",
+      "while (1) return b++;",
+      "while (1) (b++) ? b : b;",
+      "while (1) b ? (b++) : b;",
+      "while (1) b ? b : (b++);",
+  };
+
+  for (size_t i = 0; i < arraysize(loops); i++) {
+    TestHelper f(loops[i]);
+    f.CheckLoopAssignedCount(1, "b");
+  }
+}
+
+
+TEST(NestedAssign1) {
+  const char* loops[] = {
+      "while (1) a(b=1);",
+      "while (1) a(0, b=1);",
+      "while (1) a(0, 0, b=1);",
+      "while (1) a(b=1, 1, 1);",
+      "while (1) a + (b=1);",
+      "while (1) (b=1) + a;",
+      "while (1) a + c(b=1);",
+      "while (1) throw b=1;",
+      "while (1) switch (b=1) {} ;",
+      "while (1) switch (a) {case b=1: 0; } ;",
+      "while (1) switch (a) {case b: b=1; } ;",
+      "while (1) a == (b=1);",
+      "while (1) a === (b=1);",
+      "while (1) +(b=1);",
+      "while (1) ~(b=1);",
+      "while (1) new a(b=1);",
+      "while (1) (b=1).f;",
+      "while (1) a[b=1];",
+      "while (1) (b=1)();",
+      "while (1) [b=1];",
+      "while (1) [0,b=1];",
+      "while (1) var z = [11,b=1,12];",
+      "while (1) var y = {f:11,g:(b=1),h:12};",
+      "while (1) try {b=1;} finally {};",
+      "while (1) try {} finally {b=1};",
+      "while (1) try {b=1;} catch (e) {};",
+      "while (1) try {} catch (e) {b=1};",
+      "while (1) return b=1;",
+      "while (1) (b=1) ? b : b;",
+      "while (1) b ? (b=1) : b;",
+      "while (1) b ? b : (b=1);",
+  };
+
+  for (size_t i = 0; i < arraysize(loops); i++) {
+    TestHelper f(loops[i]);
+    f.CheckLoopAssignedCount(1, "b");
+  }
+}
+
+
+TEST(NestedLoops3) {
+  TestHelper f("var x, y, z, w; while (x++) while (y++) while (z++) ; w;");
+
+  f.CheckLoopAssignedCount(1, "x");
+  f.CheckLoopAssignedCount(2, "y");
+  f.CheckLoopAssignedCount(3, "z");
+  f.CheckLoopAssignedCount(0, "w");
+}
+
+
+TEST(NestedLoops3b) {
+  TestHelper f(
+      "var x, y, z, w;"
+      "while (1) { x=1; while (1) { y=1; while (1) z=1; } }"
+      "w;");
+
+  f.CheckLoopAssignedCount(1, "x");
+  f.CheckLoopAssignedCount(2, "y");
+  f.CheckLoopAssignedCount(3, "z");
+  f.CheckLoopAssignedCount(0, "w");
+}
+
+
+TEST(NestedLoops3c) {
+  TestHelper f(
+      "var x, y, z, w;"
+      "while (1) {"
+      "  x++;"
+      "  while (1) {"
+      "    y++;"
+      "    while (1) z++;"
+      "  }"
+      "  while (1) {"
+      "    y++;"
+      "    while (1) z++;"
+      "  }"
+      "}"
+      "w;");
+
+  f.CheckLoopAssignedCount(1, "x");
+  f.CheckLoopAssignedCount(3, "y");
+  f.CheckLoopAssignedCount(5, "z");
+  f.CheckLoopAssignedCount(0, "w");
+}
diff --git a/test/cctest/compiler/test-machine-operator-reducer.cc b/test/cctest/compiler/test-machine-operator-reducer.cc
index eca1f3c..648e1b9 100644
--- a/test/cctest/compiler/test-machine-operator-reducer.cc
+++ b/test/cctest/compiler/test-machine-operator-reducer.cc
@@ -5,9 +5,11 @@
 #include "test/cctest/cctest.h"
 
 #include "src/base/utils/random-number-generator.h"
+#include "src/codegen.h"
 #include "src/compiler/graph-inl.h"
 #include "src/compiler/js-graph.h"
 #include "src/compiler/machine-operator-reducer.h"
+#include "src/compiler/operator-properties.h"
 #include "src/compiler/typer.h"
 #include "test/cctest/compiler/value-helper.h"
 
@@ -49,15 +51,18 @@
 
 class ReducerTester : public HandleAndZoneScope {
  public:
-  explicit ReducerTester(int num_parameters = 0)
+  explicit ReducerTester(
+      int num_parameters = 0,
+      MachineOperatorBuilder::Flags flags = MachineOperatorBuilder::kNoFlags)
       : isolate(main_isolate()),
         binop(NULL),
         unop(NULL),
+        machine(main_zone(), kMachPtr, flags),
         common(main_zone()),
         graph(main_zone()),
         javascript(main_zone()),
-        typer(main_zone()),
-        jsgraph(&graph, &common, &javascript, &typer, &machine),
+        typer(&graph, MaybeHandle<Context>()),
+        jsgraph(&graph, &common, &javascript, &machine),
         maxuint32(Constant<int32_t>(kMaxUInt32)) {
     Node* s = graph.NewNode(common.Start(num_parameters));
     graph.SetStart(s);
@@ -96,7 +101,7 @@
   template <typename T>
   void CheckFoldBinop(volatile T expect, Node* a, Node* b) {
     CHECK_NE(NULL, binop);
-    Node* n = graph.NewNode(binop, a, b);
+    Node* n = CreateBinopNode(a, b);
     MachineOperatorReducer reducer(&jsgraph);
     Reduction reduction = reducer.Reduce(n);
     CHECK(reduction.Changed());
@@ -108,7 +113,7 @@
   // the {expect} node.
   void CheckBinop(Node* expect, Node* a, Node* b) {
     CHECK_NE(NULL, binop);
-    Node* n = graph.NewNode(binop, a, b);
+    Node* n = CreateBinopNode(a, b);
     MachineOperatorReducer reducer(&jsgraph);
     Reduction reduction = reducer.Reduce(n);
     CHECK(reduction.Changed());
@@ -120,7 +125,7 @@
   void CheckFoldBinop(Node* left_expect, Node* right_expect, Node* left,
                       Node* right) {
     CHECK_NE(NULL, binop);
-    Node* n = graph.NewNode(binop, left, right);
+    Node* n = CreateBinopNode(left, right);
     MachineOperatorReducer reducer(&jsgraph);
     Reduction reduction = reducer.Reduce(n);
     CHECK(reduction.Changed());
@@ -135,7 +140,7 @@
   void CheckFoldBinop(volatile T left_expect, const Operator* op_expect,
                       Node* right_expect, Node* left, Node* right) {
     CHECK_NE(NULL, binop);
-    Node* n = graph.NewNode(binop, left, right);
+    Node* n = CreateBinopNode(left, right);
     MachineOperatorReducer reducer(&jsgraph);
     Reduction r = reducer.Reduce(n);
     CHECK(r.Changed());
@@ -150,11 +155,13 @@
   void CheckFoldBinop(Node* left_expect, const Operator* op_expect,
                       volatile T right_expect, Node* left, Node* right) {
     CHECK_NE(NULL, binop);
-    Node* n = graph.NewNode(binop, left, right);
+    Node* n = CreateBinopNode(left, right);
     MachineOperatorReducer reducer(&jsgraph);
     Reduction r = reducer.Reduce(n);
     CHECK(r.Changed());
     CHECK_EQ(op_expect->opcode(), r.replacement()->op()->opcode());
+    CHECK_EQ(OperatorProperties::GetTotalInputCount(op_expect),
+             r.replacement()->InputCount());
     CHECK_EQ(left_expect, r.replacement()->InputAt(0));
     CHECK_EQ(right_expect, ValueOf<T>(r.replacement()->InputAt(1)->op()));
   }
@@ -167,7 +174,7 @@
     Node* p = Parameter();
     Node* k = Constant<T>(constant);
     {
-      Node* n = graph.NewNode(binop, k, p);
+      Node* n = CreateBinopNode(k, p);
       MachineOperatorReducer reducer(&jsgraph);
       Reduction reduction = reducer.Reduce(n);
       CHECK(!reduction.Changed() || reduction.replacement() == n);
@@ -175,7 +182,7 @@
       CHECK_EQ(k, n->InputAt(1));
     }
     {
-      Node* n = graph.NewNode(binop, p, k);
+      Node* n = CreateBinopNode(p, k);
       MachineOperatorReducer reducer(&jsgraph);
       Reduction reduction = reducer.Reduce(n);
       CHECK(!reduction.Changed());
@@ -191,7 +198,7 @@
     CHECK(!binop->HasProperty(Operator::kCommutative));
     Node* p = Parameter();
     Node* k = Constant<T>(constant);
-    Node* n = graph.NewNode(binop, k, p);
+    Node* n = CreateBinopNode(k, p);
     MachineOperatorReducer reducer(&jsgraph);
     Reduction reduction = reducer.Reduce(n);
     CHECK(!reduction.Changed());
@@ -202,6 +209,15 @@
   Node* Parameter(int32_t index = 0) {
     return graph.NewNode(common.Parameter(index), graph.start());
   }
+
+ private:
+  Node* CreateBinopNode(Node* left, Node* right) {
+    if (binop->ControlInputCount() > 0) {
+      return graph.NewNode(binop, left, right, graph.start());
+    } else {
+      return graph.NewNode(binop, left, right);
+    }
+  }
 };
 
 
@@ -343,7 +359,36 @@
 }
 
 
-TEST(ReduceWord32Equal) {
+static void CheckJsShift(ReducerTester* R) {
+  DCHECK(R->machine.Word32ShiftIsSafe());
+
+  Node* x = R->Parameter(0);
+  Node* y = R->Parameter(1);
+  Node* thirty_one = R->Constant<int32_t>(0x1f);
+  Node* y_and_thirty_one =
+      R->graph.NewNode(R->machine.Word32And(), y, thirty_one);
+
+  // If the underlying machine shift instructions 'and' their right operand
+  // with 0x1f then:  x << (y & 0x1f) => x << y
+  R->CheckFoldBinop(x, y, x, y_and_thirty_one);
+}
+
+
+TEST(ReduceJsShifts) {
+  ReducerTester R(0, MachineOperatorBuilder::kWord32ShiftIsSafe);
+
+  R.binop = R.machine.Word32Shl();
+  CheckJsShift(&R);
+
+  R.binop = R.machine.Word32Shr();
+  CheckJsShift(&R);
+
+  R.binop = R.machine.Word32Sar();
+  CheckJsShift(&R);
+}
+
+
+TEST(Word32Equal) {
   ReducerTester R;
   R.binop = R.machine.Word32Equal();
 
@@ -476,9 +521,9 @@
 }
 
 
-TEST(ReduceInt32UDiv) {
+TEST(ReduceUint32Div) {
   ReducerTester R;
-  R.binop = R.machine.Int32UDiv();
+  R.binop = R.machine.Uint32Div();
 
   FOR_UINT32_INPUTS(pl) {
     FOR_UINT32_INPUTS(pr) {
@@ -529,9 +574,9 @@
 }
 
 
-TEST(ReduceInt32UMod) {
+TEST(ReduceUint32Mod) {
   ReducerTester R;
-  R.binop = R.machine.Int32UMod();
+  R.binop = R.machine.Uint32Mod();
 
   FOR_INT32_INPUTS(pl) {
     FOR_INT32_INPUTS(pr) {
@@ -687,9 +732,9 @@
          pr != nans.end(); ++pr) {
       Node* nan1 = R->Constant<double>(*pl);
       Node* nan2 = R->Constant<double>(*pr);
-      R->CheckBinop(nan1, x, nan1);     // x % NaN => NaN
-      R->CheckBinop(nan1, nan1, x);     // NaN % x => NaN
-      R->CheckBinop(nan1, nan2, nan1);  // NaN % NaN => NaN
+      R->CheckBinop(nan1, x, nan1);     // x op NaN => NaN
+      R->CheckBinop(nan1, nan1, x);     // NaN op x => NaN
+      R->CheckBinop(nan1, nan2, nan1);  // NaN op NaN => NaN
     }
   }
 }
@@ -706,8 +751,15 @@
     }
   }
 
-  FOR_FLOAT64_INPUTS(i) { R.CheckPutConstantOnRight(*i); }
-  // TODO(titzer): CheckNans(&R);
+  FOR_FLOAT64_INPUTS(i) {
+    Double tmp(*i);
+    if (!tmp.IsSpecial() || tmp.IsInfinite()) {
+      // Don't check NaNs as they are reduced more.
+      R.CheckPutConstantOnRight(*i);
+    }
+  }
+
+  CheckNans(&R);
 }
 
 
@@ -721,7 +773,13 @@
       R.CheckFoldBinop<double>(x - y, x, y);
     }
   }
-  // TODO(titzer): CheckNans(&R);
+
+  Node* zero = R.Constant<double>(0.0);
+  Node* x = R.Parameter();
+
+  R.CheckBinop(x, x, zero);  // x - 0.0 => x
+
+  CheckNans(&R);
 }
 
 
@@ -783,6 +841,11 @@
     }
   }
 
+  Node* x = R.Parameter();
+  Node* zero = R.Constant<double>(0.0);
+
+  R.CheckFoldBinop<double>(v8::base::OS::nan_value(), x, zero);
+
   CheckNans(&R);
 }
 
@@ -800,9 +863,9 @@
 // TODO(titzer): test MachineOperatorReducer for Int64Mul
 // TODO(titzer): test MachineOperatorReducer for Int64UMul
 // TODO(titzer): test MachineOperatorReducer for Int64Div
-// TODO(titzer): test MachineOperatorReducer for Int64UDiv
+// TODO(titzer): test MachineOperatorReducer for Uint64Div
 // TODO(titzer): test MachineOperatorReducer for Int64Mod
-// TODO(titzer): test MachineOperatorReducer for Int64UMod
+// TODO(titzer): test MachineOperatorReducer for Uint64Mod
 // TODO(titzer): test MachineOperatorReducer for Int64Neg
 // TODO(titzer): test MachineOperatorReducer for ChangeInt32ToFloat64
 // TODO(titzer): test MachineOperatorReducer for ChangeFloat64ToInt32
diff --git a/test/cctest/compiler/test-node-algorithm.cc b/test/cctest/compiler/test-node-algorithm.cc
index 10f98a6..842d182 100644
--- a/test/cctest/compiler/test-node-algorithm.cc
+++ b/test/cctest/compiler/test-node-algorithm.cc
@@ -8,25 +8,23 @@
 
 #include "graph-tester.h"
 #include "src/compiler/common-operator.h"
-#include "src/compiler/generic-node.h"
-#include "src/compiler/generic-node-inl.h"
 #include "src/compiler/graph.h"
 #include "src/compiler/graph-inl.h"
 #include "src/compiler/graph-visualizer.h"
+#include "src/compiler/node.h"
 #include "src/compiler/operator.h"
 
 using namespace v8::internal;
 using namespace v8::internal::compiler;
 
-static SimpleOperator dummy_operator(IrOpcode::kParameter, Operator::kNoWrite,
-                                     0, 0, "dummy");
+static Operator dummy_operator(IrOpcode::kParameter, Operator::kNoWrite,
+                               "dummy", 0, 0, 0, 1, 0, 0);
 
 class PreNodeVisitor : public NullNodeVisitor {
  public:
-  GenericGraphVisit::Control Pre(Node* node) {
+  void Pre(Node* node) {
     printf("NODE ID: %d\n", node->id());
     nodes_.push_back(node);
-    return GenericGraphVisit::CONTINUE;
   }
   std::vector<Node*> nodes_;
 };
@@ -34,45 +32,14 @@
 
 class PostNodeVisitor : public NullNodeVisitor {
  public:
-  GenericGraphVisit::Control Post(Node* node) {
+  void Post(Node* node) {
     printf("NODE ID: %d\n", node->id());
     nodes_.push_back(node);
-    return GenericGraphVisit::CONTINUE;
   }
   std::vector<Node*> nodes_;
 };
 
 
-TEST(TestUseNodeVisitEmpty) {
-  GraphWithStartNodeTester graph;
-
-  PreNodeVisitor node_visitor;
-  graph.VisitNodeUsesFromStart(&node_visitor);
-
-  CHECK_EQ(1, static_cast<int>(node_visitor.nodes_.size()));
-}
-
-
-TEST(TestUseNodePreOrderVisitSimple) {
-  GraphWithStartNodeTester graph;
-  Node* n2 = graph.NewNode(&dummy_operator, graph.start());
-  Node* n3 = graph.NewNode(&dummy_operator, n2);
-  Node* n4 = graph.NewNode(&dummy_operator, n2, n3);
-  Node* n5 = graph.NewNode(&dummy_operator, n4, n2);
-  graph.SetEnd(n5);
-
-  PreNodeVisitor node_visitor;
-  graph.VisitNodeUsesFromStart(&node_visitor);
-
-  CHECK_EQ(5, static_cast<int>(node_visitor.nodes_.size()));
-  CHECK(graph.start()->id() == node_visitor.nodes_[0]->id());
-  CHECK(n2->id() == node_visitor.nodes_[1]->id());
-  CHECK(n3->id() == node_visitor.nodes_[2]->id());
-  CHECK(n4->id() == node_visitor.nodes_[3]->id());
-  CHECK(n5->id() == node_visitor.nodes_[4]->id());
-}
-
-
 TEST(TestInputNodePreOrderVisitSimple) {
   GraphWithStartNodeTester graph;
   Node* n2 = graph.NewNode(&dummy_operator, graph.start());
@@ -92,223 +59,6 @@
 }
 
 
-TEST(TestUseNodePostOrderVisitSimple) {
-  GraphWithStartNodeTester graph;
-  Node* n2 = graph.NewNode(&dummy_operator, graph.start());
-  Node* n3 = graph.NewNode(&dummy_operator, graph.start());
-  Node* n4 = graph.NewNode(&dummy_operator, n2);
-  Node* n5 = graph.NewNode(&dummy_operator, n2);
-  Node* n6 = graph.NewNode(&dummy_operator, n2);
-  Node* n7 = graph.NewNode(&dummy_operator, n3);
-  Node* end_dependencies[4] = {n4, n5, n6, n7};
-  Node* n8 = graph.NewNode(&dummy_operator, 4, end_dependencies);
-  graph.SetEnd(n8);
-
-  PostNodeVisitor node_visitor;
-  graph.VisitNodeUsesFromStart(&node_visitor);
-
-  CHECK_EQ(8, static_cast<int>(node_visitor.nodes_.size()));
-  CHECK(graph.end()->id() == node_visitor.nodes_[0]->id());
-  CHECK(n4->id() == node_visitor.nodes_[1]->id());
-  CHECK(n5->id() == node_visitor.nodes_[2]->id());
-  CHECK(n6->id() == node_visitor.nodes_[3]->id());
-  CHECK(n2->id() == node_visitor.nodes_[4]->id());
-  CHECK(n7->id() == node_visitor.nodes_[5]->id());
-  CHECK(n3->id() == node_visitor.nodes_[6]->id());
-  CHECK(graph.start()->id() == node_visitor.nodes_[7]->id());
-}
-
-
-TEST(TestUseNodePostOrderVisitLong) {
-  GraphWithStartNodeTester graph;
-  Node* n2 = graph.NewNode(&dummy_operator, graph.start());
-  Node* n3 = graph.NewNode(&dummy_operator, graph.start());
-  Node* n4 = graph.NewNode(&dummy_operator, n2);
-  Node* n5 = graph.NewNode(&dummy_operator, n2);
-  Node* n6 = graph.NewNode(&dummy_operator, n3);
-  Node* n7 = graph.NewNode(&dummy_operator, n3);
-  Node* n8 = graph.NewNode(&dummy_operator, n5);
-  Node* n9 = graph.NewNode(&dummy_operator, n5);
-  Node* n10 = graph.NewNode(&dummy_operator, n9);
-  Node* n11 = graph.NewNode(&dummy_operator, n9);
-  Node* end_dependencies[6] = {n4, n8, n10, n11, n6, n7};
-  Node* n12 = graph.NewNode(&dummy_operator, 6, end_dependencies);
-  graph.SetEnd(n12);
-
-  PostNodeVisitor node_visitor;
-  graph.VisitNodeUsesFromStart(&node_visitor);
-
-  CHECK_EQ(12, static_cast<int>(node_visitor.nodes_.size()));
-  CHECK(graph.end()->id() == node_visitor.nodes_[0]->id());
-  CHECK(n4->id() == node_visitor.nodes_[1]->id());
-  CHECK(n8->id() == node_visitor.nodes_[2]->id());
-  CHECK(n10->id() == node_visitor.nodes_[3]->id());
-  CHECK(n11->id() == node_visitor.nodes_[4]->id());
-  CHECK(n9->id() == node_visitor.nodes_[5]->id());
-  CHECK(n5->id() == node_visitor.nodes_[6]->id());
-  CHECK(n2->id() == node_visitor.nodes_[7]->id());
-  CHECK(n6->id() == node_visitor.nodes_[8]->id());
-  CHECK(n7->id() == node_visitor.nodes_[9]->id());
-  CHECK(n3->id() == node_visitor.nodes_[10]->id());
-  CHECK(graph.start()->id() == node_visitor.nodes_[11]->id());
-}
-
-
-TEST(TestUseNodePreOrderVisitCycle) {
-  GraphWithStartNodeTester graph;
-  Node* n0 = graph.start_node();
-  Node* n1 = graph.NewNode(&dummy_operator, n0);
-  Node* n2 = graph.NewNode(&dummy_operator, n1);
-  n0->AppendInput(graph.main_zone(), n2);
-  graph.SetStart(n0);
-  graph.SetEnd(n2);
-
-  PreNodeVisitor node_visitor;
-  graph.VisitNodeUsesFromStart(&node_visitor);
-
-  CHECK_EQ(3, static_cast<int>(node_visitor.nodes_.size()));
-  CHECK(n0->id() == node_visitor.nodes_[0]->id());
-  CHECK(n1->id() == node_visitor.nodes_[1]->id());
-  CHECK(n2->id() == node_visitor.nodes_[2]->id());
-}
-
-
-struct ReenterNodeVisitor : NullNodeVisitor {
-  GenericGraphVisit::Control Pre(Node* node) {
-    printf("[%d] PRE NODE: %d\n", static_cast<int>(nodes_.size()), node->id());
-    nodes_.push_back(node->id());
-    int size = static_cast<int>(nodes_.size());
-    switch (node->id()) {
-      case 0:
-        return size < 6 ? GenericGraphVisit::REENTER : GenericGraphVisit::SKIP;
-      case 1:
-        return size < 4 ? GenericGraphVisit::DEFER
-                        : GenericGraphVisit::CONTINUE;
-      default:
-        return GenericGraphVisit::REENTER;
-    }
-  }
-
-  GenericGraphVisit::Control Post(Node* node) {
-    printf("[%d] POST NODE: %d\n", static_cast<int>(nodes_.size()), node->id());
-    nodes_.push_back(-node->id());
-    return node->id() == 4 ? GenericGraphVisit::REENTER
-                           : GenericGraphVisit::CONTINUE;
-  }
-
-  void PreEdge(Node* from, int index, Node* to) {
-    printf("[%d] PRE EDGE: %d-%d\n", static_cast<int>(edges_.size()),
-           from->id(), to->id());
-    edges_.push_back(std::make_pair(from->id(), to->id()));
-  }
-
-  void PostEdge(Node* from, int index, Node* to) {
-    printf("[%d] POST EDGE: %d-%d\n", static_cast<int>(edges_.size()),
-           from->id(), to->id());
-    edges_.push_back(std::make_pair(-from->id(), -to->id()));
-  }
-
-  std::vector<int> nodes_;
-  std::vector<std::pair<int, int> > edges_;
-};
-
-
-TEST(TestUseNodeReenterVisit) {
-  GraphWithStartNodeTester graph;
-  Node* n0 = graph.start_node();
-  Node* n1 = graph.NewNode(&dummy_operator, n0);
-  Node* n2 = graph.NewNode(&dummy_operator, n0);
-  Node* n3 = graph.NewNode(&dummy_operator, n2);
-  Node* n4 = graph.NewNode(&dummy_operator, n0);
-  Node* n5 = graph.NewNode(&dummy_operator, n4);
-  n0->AppendInput(graph.main_zone(), n3);
-  graph.SetStart(n0);
-  graph.SetEnd(n5);
-
-  ReenterNodeVisitor visitor;
-  graph.VisitNodeUsesFromStart(&visitor);
-
-  CHECK_EQ(22, static_cast<int>(visitor.nodes_.size()));
-  CHECK_EQ(24, static_cast<int>(visitor.edges_.size()));
-
-  CHECK(n0->id() == visitor.nodes_[0]);
-  CHECK(n0->id() == visitor.edges_[0].first);
-  CHECK(n1->id() == visitor.edges_[0].second);
-  CHECK(n1->id() == visitor.nodes_[1]);
-  // N1 is deferred.
-  CHECK(-n1->id() == visitor.edges_[1].second);
-  CHECK(-n0->id() == visitor.edges_[1].first);
-  CHECK(n0->id() == visitor.edges_[2].first);
-  CHECK(n2->id() == visitor.edges_[2].second);
-  CHECK(n2->id() == visitor.nodes_[2]);
-  CHECK(n2->id() == visitor.edges_[3].first);
-  CHECK(n3->id() == visitor.edges_[3].second);
-  CHECK(n3->id() == visitor.nodes_[3]);
-  // Circle back to N0, which we may reenter for now.
-  CHECK(n3->id() == visitor.edges_[4].first);
-  CHECK(n0->id() == visitor.edges_[4].second);
-  CHECK(n0->id() == visitor.nodes_[4]);
-  CHECK(n0->id() == visitor.edges_[5].first);
-  CHECK(n1->id() == visitor.edges_[5].second);
-  CHECK(n1->id() == visitor.nodes_[5]);
-  // This time N1 is no longer deferred.
-  CHECK(-n1->id() == visitor.nodes_[6]);
-  CHECK(-n1->id() == visitor.edges_[6].second);
-  CHECK(-n0->id() == visitor.edges_[6].first);
-  CHECK(n0->id() == visitor.edges_[7].first);
-  CHECK(n2->id() == visitor.edges_[7].second);
-  CHECK(n2->id() == visitor.nodes_[7]);
-  CHECK(n2->id() == visitor.edges_[8].first);
-  CHECK(n3->id() == visitor.edges_[8].second);
-  CHECK(n3->id() == visitor.nodes_[8]);
-  CHECK(n3->id() == visitor.edges_[9].first);
-  CHECK(n0->id() == visitor.edges_[9].second);
-  CHECK(n0->id() == visitor.nodes_[9]);
-  // This time we break at N0 and skip it.
-  CHECK(-n0->id() == visitor.edges_[10].second);
-  CHECK(-n3->id() == visitor.edges_[10].first);
-  CHECK(-n3->id() == visitor.nodes_[10]);
-  CHECK(-n3->id() == visitor.edges_[11].second);
-  CHECK(-n2->id() == visitor.edges_[11].first);
-  CHECK(-n2->id() == visitor.nodes_[11]);
-  CHECK(-n2->id() == visitor.edges_[12].second);
-  CHECK(-n0->id() == visitor.edges_[12].first);
-  CHECK(n0->id() == visitor.edges_[13].first);
-  CHECK(n4->id() == visitor.edges_[13].second);
-  CHECK(n4->id() == visitor.nodes_[12]);
-  CHECK(n4->id() == visitor.edges_[14].first);
-  CHECK(n5->id() == visitor.edges_[14].second);
-  CHECK(n5->id() == visitor.nodes_[13]);
-  CHECK(-n5->id() == visitor.nodes_[14]);
-  CHECK(-n5->id() == visitor.edges_[15].second);
-  CHECK(-n4->id() == visitor.edges_[15].first);
-  CHECK(-n4->id() == visitor.nodes_[15]);
-  CHECK(-n4->id() == visitor.edges_[16].second);
-  CHECK(-n0->id() == visitor.edges_[16].first);
-  CHECK(-n0->id() == visitor.nodes_[16]);
-  CHECK(-n0->id() == visitor.edges_[17].second);
-  CHECK(-n3->id() == visitor.edges_[17].first);
-  CHECK(-n3->id() == visitor.nodes_[17]);
-  CHECK(-n3->id() == visitor.edges_[18].second);
-  CHECK(-n2->id() == visitor.edges_[18].first);
-  CHECK(-n2->id() == visitor.nodes_[18]);
-  CHECK(-n2->id() == visitor.edges_[19].second);
-  CHECK(-n0->id() == visitor.edges_[19].first);
-  // N4 may be reentered.
-  CHECK(n0->id() == visitor.edges_[20].first);
-  CHECK(n4->id() == visitor.edges_[20].second);
-  CHECK(n4->id() == visitor.nodes_[19]);
-  CHECK(n4->id() == visitor.edges_[21].first);
-  CHECK(n5->id() == visitor.edges_[21].second);
-  CHECK(-n5->id() == visitor.edges_[22].second);
-  CHECK(-n4->id() == visitor.edges_[22].first);
-  CHECK(-n4->id() == visitor.nodes_[20]);
-  CHECK(-n4->id() == visitor.edges_[23].second);
-  CHECK(-n0->id() == visitor.edges_[23].first);
-  CHECK(-n0->id() == visitor.nodes_[21]);
-}
-
-
 TEST(TestPrintNodeGraphToNodeGraphviz) {
   GraphWithStartNodeTester graph;
   Node* n2 = graph.NewNode(&dummy_operator, graph.start());
diff --git a/test/cctest/compiler/test-node-cache.cc b/test/cctest/compiler/test-node-cache.cc
index 3569386..a48adb9 100644
--- a/test/cctest/compiler/test-node-cache.cc
+++ b/test/cctest/compiler/test-node-cache.cc
@@ -115,46 +115,61 @@
 }
 
 
-TEST(PtrConstant_back_to_back) {
-  GraphTester graph;
-  PtrNodeCache cache;
-  int32_t buffer[50];
+static bool Contains(NodeVector* nodes, Node* n) {
+  for (size_t i = 0; i < nodes->size(); i++) {
+    if (nodes->at(i) == n) return true;
+  }
+  return false;
+}
 
-  for (int32_t* p = buffer;
-       (p - buffer) < static_cast<ptrdiff_t>(arraysize(buffer)); p++) {
-    Node** pos = cache.Find(graph.zone(), p);
-    CHECK_NE(NULL, pos);
-    for (int j = 0; j < 3; j++) {
-      Node** npos = cache.Find(graph.zone(), p);
-      CHECK_EQ(pos, npos);
+
+TEST(NodeCache_GetCachedNodes_int32) {
+  GraphTester graph;
+  Int32NodeCache cache;
+  CommonOperatorBuilder common(graph.zone());
+
+  int32_t constants[] = {0, 311, 12,  13,  14,  555, -555, -44, -33, -22, -11,
+                         0, 311, 311, 412, 412, 11,  11,   -33, -33, -22, -11};
+
+  for (size_t i = 0; i < arraysize(constants); i++) {
+    int32_t k = constants[i];
+    Node** pos = cache.Find(graph.zone(), k);
+    if (*pos != NULL) {
+      NodeVector nodes(graph.zone());
+      cache.GetCachedNodes(&nodes);
+      CHECK(Contains(&nodes, *pos));
+    } else {
+      NodeVector nodes(graph.zone());
+      Node* n = graph.NewNode(common.Int32Constant(k));
+      *pos = n;
+      cache.GetCachedNodes(&nodes);
+      CHECK(Contains(&nodes, n));
     }
   }
 }
 
 
-TEST(PtrConstant_hits) {
+TEST(NodeCache_GetCachedNodes_int64) {
   GraphTester graph;
-  PtrNodeCache cache;
-  const int32_t kSize = 50;
-  int32_t buffer[kSize];
-  Node* nodes[kSize];
+  Int64NodeCache cache;
   CommonOperatorBuilder common(graph.zone());
 
-  for (size_t i = 0; i < arraysize(buffer); i++) {
-    int k = static_cast<int>(i);
-    int32_t* p = &buffer[i];
-    nodes[i] = graph.NewNode(common.Int32Constant(k));
-    *cache.Find(graph.zone(), p) = nodes[i];
-  }
+  int64_t constants[] = {0, 311, 12,  13,  14,  555, -555, -44, -33, -22, -11,
+                         0, 311, 311, 412, 412, 11,  11,   -33, -33, -22, -11};
 
-  int hits = 0;
-  for (size_t i = 0; i < arraysize(buffer); i++) {
-    int32_t* p = &buffer[i];
-    Node** pos = cache.Find(graph.zone(), p);
+  for (size_t i = 0; i < arraysize(constants); i++) {
+    int64_t k = constants[i];
+    Node** pos = cache.Find(graph.zone(), k);
     if (*pos != NULL) {
-      CHECK_EQ(nodes[i], *pos);
-      hits++;
+      NodeVector nodes(graph.zone());
+      cache.GetCachedNodes(&nodes);
+      CHECK(Contains(&nodes, *pos));
+    } else {
+      NodeVector nodes(graph.zone());
+      Node* n = graph.NewNode(common.Int64Constant(k));
+      *pos = n;
+      cache.GetCachedNodes(&nodes);
+      CHECK(Contains(&nodes, n));
     }
   }
-  CHECK_LT(4, hits);
 }
diff --git a/test/cctest/compiler/test-node.cc b/test/cctest/compiler/test-node.cc
index 28d807e..eafabd3 100644
--- a/test/cctest/compiler/test-node.cc
+++ b/test/cctest/compiler/test-node.cc
@@ -7,15 +7,14 @@
 #include "src/v8.h"
 
 #include "graph-tester.h"
-#include "src/compiler/generic-node-inl.h"
 #include "src/compiler/node.h"
 #include "src/compiler/operator.h"
 
 using namespace v8::internal;
 using namespace v8::internal::compiler;
 
-static SimpleOperator dummy_operator(IrOpcode::kParameter, Operator::kNoWrite,
-                                     0, 0, "dummy");
+static Operator dummy_operator(IrOpcode::kParameter, Operator::kNoWrite,
+                               "dummy", 0, 0, 0, 1, 0, 0);
 
 TEST(NodeAllocation) {
   GraphTester graph;
@@ -93,10 +92,8 @@
 TEST(NodeUseIteratorEmpty) {
   GraphTester graph;
   Node* n1 = graph.NewNode(&dummy_operator);
-  Node::Uses::iterator i(n1->uses().begin());
   int use_count = 0;
-  for (; i != n1->uses().end(); ++i) {
-    Node::Edge edge(i.edge());
+  for (Edge const edge : n1->use_edges()) {
     USE(edge);
     use_count++;
   }
@@ -366,31 +363,31 @@
   Node* n1 = graph.NewNode(&dummy_operator, n0);
   Node* n2 = graph.NewNode(&dummy_operator, n0, n1);
 
-  Node::Inputs inputs(n2->inputs());
-  Node::Inputs::iterator current = inputs.begin();
+  Node::InputEdges inputs(n2->input_edges());
+  Node::InputEdges::iterator current = inputs.begin();
   CHECK(current != inputs.end());
-  CHECK(*current == n0);
+  CHECK((*current).to() == n0);
   ++current;
   CHECK(current != inputs.end());
-  CHECK(*current == n1);
+  CHECK((*current).to() == n1);
   ++current;
   CHECK(current == inputs.end());
 
   Node* n3 = graph.NewNode(&dummy_operator);
   n2->AppendInput(graph.zone(), n3);
-  inputs = n2->inputs();
+  inputs = n2->input_edges();
   current = inputs.begin();
   CHECK(current != inputs.end());
-  CHECK(*current == n0);
-  CHECK_EQ(0, current.index());
+  CHECK((*current).to() == n0);
+  CHECK_EQ(0, (*current).index());
   ++current;
   CHECK(current != inputs.end());
-  CHECK(*current == n1);
-  CHECK_EQ(1, current.index());
+  CHECK((*current).to() == n1);
+  CHECK_EQ(1, (*current).index());
   ++current;
   CHECK(current != inputs.end());
-  CHECK(*current == n3);
-  CHECK_EQ(2, current.index());
+  CHECK((*current).to() == n3);
+  CHECK_EQ(2, (*current).index());
   ++current;
   CHECK(current == inputs.end());
 }
diff --git a/test/cctest/compiler/test-operator.cc b/test/cctest/compiler/test-operator.cc
index af75d67..39f660f 100644
--- a/test/cctest/compiler/test-operator.cc
+++ b/test/cctest/compiler/test-operator.cc
@@ -2,6 +2,8 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include <sstream>
+
 #include "src/v8.h"
 
 #include "src/compiler/operator.h"
@@ -10,44 +12,45 @@
 using namespace v8::internal;
 using namespace v8::internal::compiler;
 
-#define NaN (v8::base::OS::nan_value())
-#define Infinity (std::numeric_limits<double>::infinity())
+#define NONE Operator::kNoProperties
+#define FOLD Operator::kFoldable
 
-TEST(TestOperatorMnemonic) {
-  SimpleOperator op1(10, Operator::kNoProperties, 0, 0, "ThisOne");
+
+TEST(TestOperator_Mnemonic) {
+  Operator op1(10, NONE, "ThisOne", 0, 0, 0, 0, 0, 0);
   CHECK_EQ(0, strcmp(op1.mnemonic(), "ThisOne"));
 
-  SimpleOperator op2(11, Operator::kNoProperties, 0, 0, "ThatOne");
+  Operator op2(11, NONE, "ThatOne", 0, 0, 0, 0, 0, 0);
   CHECK_EQ(0, strcmp(op2.mnemonic(), "ThatOne"));
 
-  Operator1<int> op3(12, Operator::kNoProperties, 0, 1, "Mnemonic1", 12333);
+  Operator1<int> op3(12, NONE, "Mnemonic1", 0, 0, 0, 1, 0, 0, 12333);
   CHECK_EQ(0, strcmp(op3.mnemonic(), "Mnemonic1"));
 
-  Operator1<double> op4(13, Operator::kNoProperties, 0, 1, "TheOther", 99.9);
+  Operator1<double> op4(13, NONE, "TheOther", 0, 0, 0, 1, 0, 0, 99.9);
   CHECK_EQ(0, strcmp(op4.mnemonic(), "TheOther"));
 }
 
 
-TEST(TestSimpleOperatorHash) {
-  SimpleOperator op1(17, Operator::kNoProperties, 0, 0, "Another");
-  CHECK_EQ(17, op1.HashCode());
+TEST(TestOperator_Hash) {
+  Operator op1(17, NONE, "Another", 0, 0, 0, 0, 0, 0);
+  CHECK_EQ(17, static_cast<int>(op1.HashCode()));
 
-  SimpleOperator op2(18, Operator::kNoProperties, 0, 0, "Falsch");
-  CHECK_EQ(18, op2.HashCode());
+  Operator op2(18, NONE, "Falsch", 0, 0, 0, 0, 0, 0);
+  CHECK_EQ(18, static_cast<int>(op2.HashCode()));
 }
 
 
-TEST(TestSimpleOperatorEquals) {
-  SimpleOperator op1a(19, Operator::kNoProperties, 0, 0, "Another1");
-  SimpleOperator op1b(19, Operator::kFoldable, 2, 2, "Another2");
+TEST(TestOperator_Equals) {
+  Operator op1a(19, NONE, "Another1", 0, 0, 0, 0, 0, 0);
+  Operator op1b(19, FOLD, "Another2", 2, 0, 0, 2, 0, 0);
 
   CHECK(op1a.Equals(&op1a));
   CHECK(op1a.Equals(&op1b));
   CHECK(op1b.Equals(&op1a));
   CHECK(op1b.Equals(&op1b));
 
-  SimpleOperator op2a(20, Operator::kNoProperties, 0, 0, "Falsch1");
-  SimpleOperator op2b(20, Operator::kFoldable, 1, 1, "Falsch2");
+  Operator op2a(20, NONE, "Falsch1", 0, 0, 0, 0, 0, 0);
+  Operator op2b(20, FOLD, "Falsch2", 1, 0, 0, 1, 0, 0);
 
   CHECK(op2a.Equals(&op2a));
   CHECK(op2a.Equals(&op2b));
@@ -67,52 +70,52 @@
 
 
 static SmartArrayPointer<const char> OperatorToString(Operator* op) {
-  OStringStream os;
+  std::ostringstream os;
   os << *op;
-  return SmartArrayPointer<const char>(StrDup(os.c_str()));
+  return SmartArrayPointer<const char>(StrDup(os.str().c_str()));
 }
 
 
-TEST(TestSimpleOperatorPrint) {
-  SimpleOperator op1a(19, Operator::kNoProperties, 0, 0, "Another1");
-  SimpleOperator op1b(19, Operator::kFoldable, 2, 2, "Another2");
+TEST(TestOperator_Print) {
+  Operator op1a(19, NONE, "Another1", 0, 0, 0, 0, 0, 0);
+  Operator op1b(19, FOLD, "Another2", 2, 0, 0, 2, 0, 0);
 
   CHECK_EQ("Another1", OperatorToString(&op1a).get());
   CHECK_EQ("Another2", OperatorToString(&op1b).get());
 
-  SimpleOperator op2a(20, Operator::kNoProperties, 0, 0, "Flog1");
-  SimpleOperator op2b(20, Operator::kFoldable, 1, 1, "Flog2");
+  Operator op2a(20, NONE, "Flog1", 0, 0, 0, 0, 0, 0);
+  Operator op2b(20, FOLD, "Flog2", 1, 0, 0, 1, 0, 0);
 
   CHECK_EQ("Flog1", OperatorToString(&op2a).get());
   CHECK_EQ("Flog2", OperatorToString(&op2b).get());
 }
 
 
-TEST(TestOperator1intHash) {
-  Operator1<int> op1a(23, Operator::kNoProperties, 0, 0, "Wolfie", 11);
-  Operator1<int> op1b(23, Operator::kFoldable, 2, 2, "Doggie", 11);
+TEST(TestOperator1int_Hash) {
+  Operator1<int> op1a(23, NONE, "Wolfie", 0, 0, 0, 0, 0, 0, 11);
+  Operator1<int> op1b(23, FOLD, "Doggie", 2, 0, 0, 2, 0, 0, 11);
 
-  CHECK_EQ(op1a.HashCode(), op1b.HashCode());
+  CHECK(op1a.HashCode() == op1b.HashCode());
 
-  Operator1<int> op2a(24, Operator::kNoProperties, 0, 0, "Arfie", 3);
-  Operator1<int> op2b(24, Operator::kNoProperties, 0, 0, "Arfie", 4);
+  Operator1<int> op2a(24, NONE, "Arfie", 0, 0, 0, 0, 0, 0, 3);
+  Operator1<int> op2b(24, NONE, "Arfie", 0, 0, 0, 0, 0, 0, 4);
 
-  CHECK_NE(op1a.HashCode(), op2a.HashCode());
-  CHECK_NE(op2a.HashCode(), op2b.HashCode());
+  CHECK(op1a.HashCode() != op2a.HashCode());
+  CHECK(op2a.HashCode() != op2b.HashCode());
 }
 
 
-TEST(TestOperator1intEquals) {
-  Operator1<int> op1a(23, Operator::kNoProperties, 0, 0, "Scratchy", 11);
-  Operator1<int> op1b(23, Operator::kFoldable, 2, 2, "Scratchy", 11);
+TEST(TestOperator1int_Equals) {
+  Operator1<int> op1a(23, NONE, "Scratchy", 0, 0, 0, 0, 0, 0, 11);
+  Operator1<int> op1b(23, FOLD, "Scratchy", 2, 0, 0, 2, 0, 0, 11);
 
   CHECK(op1a.Equals(&op1a));
   CHECK(op1a.Equals(&op1b));
   CHECK(op1b.Equals(&op1a));
   CHECK(op1b.Equals(&op1b));
 
-  Operator1<int> op2a(24, Operator::kNoProperties, 0, 0, "Im", 3);
-  Operator1<int> op2b(24, Operator::kNoProperties, 0, 0, "Im", 4);
+  Operator1<int> op2a(24, NONE, "Im", 0, 0, 0, 0, 0, 0, 3);
+  Operator1<int> op2b(24, NONE, "Im", 0, 0, 0, 0, 0, 0, 4);
 
   CHECK(op2a.Equals(&op2a));
   CHECK(!op2a.Equals(&op2b));
@@ -129,7 +132,7 @@
   CHECK(!op2b.Equals(&op1a));
   CHECK(!op2b.Equals(&op1b));
 
-  SimpleOperator op3(25, Operator::kNoProperties, 0, 0, "Weepy");
+  Operator op3(25, NONE, "Weepy", 0, 0, 0, 0, 0, 0);
 
   CHECK(!op1a.Equals(&op3));
   CHECK(!op1b.Equals(&op3));
@@ -143,46 +146,55 @@
 }
 
 
-TEST(TestOperator1intPrint) {
-  Operator1<int> op1(12, Operator::kNoProperties, 0, 1, "Op1Test", 0);
+TEST(TestOperator1int_Print) {
+  Operator1<int> op1(12, NONE, "Op1Test", 0, 0, 0, 1, 0, 0, 0);
   CHECK_EQ("Op1Test[0]", OperatorToString(&op1).get());
 
-  Operator1<int> op2(12, Operator::kNoProperties, 0, 1, "Op1Test", 66666666);
+  Operator1<int> op2(12, NONE, "Op1Test", 0, 0, 0, 1, 0, 0, 66666666);
   CHECK_EQ("Op1Test[66666666]", OperatorToString(&op2).get());
 
-  Operator1<int> op3(12, Operator::kNoProperties, 0, 1, "FooBar", 2347);
+  Operator1<int> op3(12, NONE, "FooBar", 0, 0, 0, 1, 0, 0, 2347);
   CHECK_EQ("FooBar[2347]", OperatorToString(&op3).get());
 
-  Operator1<int> op4(12, Operator::kNoProperties, 0, 1, "BarFoo", -879);
+  Operator1<int> op4(12, NONE, "BarFoo", 0, 0, 0, 1, 0, 0, -879);
   CHECK_EQ("BarFoo[-879]", OperatorToString(&op4).get());
 }
 
 
-TEST(TestOperator1doubleHash) {
-  Operator1<double> op1a(23, Operator::kNoProperties, 0, 0, "Wolfie", 11.77);
-  Operator1<double> op1b(23, Operator::kFoldable, 2, 2, "Doggie", 11.77);
+TEST(TestOperator1double_Hash) {
+  Operator1<double> op1a(23, NONE, "Wolfie", 0, 0, 0, 0, 0, 0, 11.77);
+  Operator1<double> op1b(23, FOLD, "Doggie", 2, 0, 0, 2, 0, 0, 11.77);
 
-  CHECK_EQ(op1a.HashCode(), op1b.HashCode());
+  CHECK(op1a.HashCode() == op1b.HashCode());
 
-  Operator1<double> op2a(24, Operator::kNoProperties, 0, 0, "Arfie", -6.7);
-  Operator1<double> op2b(24, Operator::kNoProperties, 0, 0, "Arfie", -6.8);
+  Operator1<double> op2a(24, NONE, "Arfie", 0, 0, 0, 0, 0, 0, -6.7);
+  Operator1<double> op2b(24, NONE, "Arfie", 0, 0, 0, 0, 0, 0, -6.8);
 
-  CHECK_NE(op1a.HashCode(), op2a.HashCode());
-  CHECK_NE(op2a.HashCode(), op2b.HashCode());
+  CHECK(op1a.HashCode() != op2a.HashCode());
+  CHECK(op2a.HashCode() != op2b.HashCode());
 }
 
 
-TEST(TestOperator1doubleEquals) {
-  Operator1<double> op1a(23, Operator::kNoProperties, 0, 0, "Scratchy", 11.77);
-  Operator1<double> op1b(23, Operator::kFoldable, 2, 2, "Scratchy", 11.77);
+TEST(TestOperator1doublePrint) {
+  Operator1<double> op1a(23, NONE, "Canary", 0, 0, 0, 0, 0, 0, 0.5);
+  Operator1<double> op1b(23, FOLD, "Finch", 2, 0, 0, 2, 0, 0, -1.5);
+
+  CHECK_EQ("Canary[0.5]", OperatorToString(&op1a).get());
+  CHECK_EQ("Finch[-1.5]", OperatorToString(&op1b).get());
+}
+
+
+TEST(TestOperator1double_Equals) {
+  Operator1<double> op1a(23, NONE, "Scratchy", 0, 0, 0, 0, 0, 0, 11.77);
+  Operator1<double> op1b(23, FOLD, "Scratchy", 2, 0, 0, 2, 0, 0, 11.77);
 
   CHECK(op1a.Equals(&op1a));
   CHECK(op1a.Equals(&op1b));
   CHECK(op1b.Equals(&op1a));
   CHECK(op1b.Equals(&op1b));
 
-  Operator1<double> op2a(24, Operator::kNoProperties, 0, 0, "Im", 3.1);
-  Operator1<double> op2b(24, Operator::kNoProperties, 0, 0, "Im", 3.2);
+  Operator1<double> op2a(24, NONE, "Im", 0, 0, 0, 0, 0, 0, 3.1);
+  Operator1<double> op2b(24, NONE, "Im", 0, 0, 0, 0, 0, 0, 3.2);
 
   CHECK(op2a.Equals(&op2a));
   CHECK(!op2a.Equals(&op2b));
@@ -199,7 +211,7 @@
   CHECK(!op2b.Equals(&op1a));
   CHECK(!op2b.Equals(&op1b));
 
-  SimpleOperator op3(25, Operator::kNoProperties, 0, 0, "Weepy");
+  Operator op3(25, NONE, "Weepy", 0, 0, 0, 0, 0, 0);
 
   CHECK(!op1a.Equals(&op3));
   CHECK(!op1b.Equals(&op3));
@@ -211,8 +223,8 @@
   CHECK(!op3.Equals(&op2a));
   CHECK(!op3.Equals(&op2b));
 
-  Operator1<double> op4a(24, Operator::kNoProperties, 0, 0, "Bashful", NaN);
-  Operator1<double> op4b(24, Operator::kNoProperties, 0, 0, "Bashful", NaN);
+  Operator1<double> op4a(24, NONE, "Bashful", 0, 0, 0, 0, 0, 0, 1.0);
+  Operator1<double> op4b(24, NONE, "Bashful", 0, 0, 0, 0, 0, 0, 1.0);
 
   CHECK(op4a.Equals(&op4a));
   CHECK(op4a.Equals(&op4b));
@@ -226,19 +238,46 @@
 }
 
 
-TEST(TestOperator1doublePrint) {
-  Operator1<double> op1(12, Operator::kNoProperties, 0, 1, "Op1Test", 0);
-  CHECK_EQ("Op1Test[0]", OperatorToString(&op1).get());
+TEST(TestOpParameter_Operator1double) {
+  double values[] = {7777.5, -66, 0, 11, 0.1};
 
-  Operator1<double> op2(12, Operator::kNoProperties, 0, 1, "Op1Test", 7.3);
-  CHECK_EQ("Op1Test[7.3]", OperatorToString(&op2).get());
+  for (size_t i = 0; i < arraysize(values); i++) {
+    Operator1<double> op(33, NONE, "Scurvy", 0, 0, 0, 0, 0, 0, values[i]);
+    CHECK_EQ(values[i], OpParameter<double>(&op));
+  }
+}
 
-  Operator1<double> op3(12, Operator::kNoProperties, 0, 1, "FooBar", 2e+123);
-  CHECK_EQ("FooBar[2e+123]", OperatorToString(&op3).get());
 
-  Operator1<double> op4(12, Operator::kNoProperties, 0, 1, "BarFoo", Infinity);
-  CHECK_EQ("BarFoo[inf]", OperatorToString(&op4).get());
+TEST(TestOpParameter_Operator1float) {
+  float values[] = {// thanks C++.
+                    static_cast<float>(7777.5), static_cast<float>(-66),
+                    static_cast<float>(0), static_cast<float>(11),
+                    static_cast<float>(0.1)};
 
-  Operator1<double> op5(12, Operator::kNoProperties, 0, 1, "BarFoo", NaN);
-  CHECK_EQ("BarFoo[nan]", OperatorToString(&op5).get());
+  for (size_t i = 0; i < arraysize(values); i++) {
+    Operator1<float> op(33, NONE, "Scurvy", 0, 0, 0, 0, 0, 0, values[i]);
+    CHECK_EQ(values[i], OpParameter<float>(&op));
+  }
+}
+
+
+TEST(TestOpParameter_Operator1int) {
+  int values[] = {7777, -66, 0, 11, 1, 0x666aff};
+
+  for (size_t i = 0; i < arraysize(values); i++) {
+    Operator1<int> op(33, NONE, "Scurvy", 0, 0, 0, 0, 0, 0, values[i]);
+    CHECK_EQ(values[i], OpParameter<int>(&op));
+  }
+}
+
+
+TEST(Operator_CountsOrder) {
+  Operator op(29, NONE, "Flashy", 11, 22, 33, 44, 55, 66);
+  CHECK_EQ(11, op.ValueInputCount());
+  CHECK_EQ(22, op.EffectInputCount());
+  CHECK_EQ(33, op.ControlInputCount());
+
+  CHECK_EQ(44, op.ValueOutputCount());
+  CHECK_EQ(55, op.EffectOutputCount());
+  CHECK_EQ(66, op.ControlOutputCount());
 }
diff --git a/test/cctest/compiler/test-phi-reducer.cc b/test/cctest/compiler/test-phi-reducer.cc
deleted file mode 100644
index 7d2fab6..0000000
--- a/test/cctest/compiler/test-phi-reducer.cc
+++ /dev/null
@@ -1,230 +0,0 @@
-// 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.
-
-#include "src/v8.h"
-#include "test/cctest/cctest.h"
-
-#include "src/compiler/common-operator.h"
-#include "src/compiler/graph-inl.h"
-#include "src/compiler/phi-reducer.h"
-
-using namespace v8::internal;
-using namespace v8::internal::compiler;
-
-class PhiReducerTester : HandleAndZoneScope {
- public:
-  explicit PhiReducerTester(int num_parameters = 0)
-      : isolate(main_isolate()),
-        common(main_zone()),
-        graph(main_zone()),
-        self(graph.NewNode(common.Start(num_parameters))),
-        dead(graph.NewNode(common.Dead())) {
-    graph.SetStart(self);
-  }
-
-  Isolate* isolate;
-  CommonOperatorBuilder common;
-  Graph graph;
-  Node* self;
-  Node* dead;
-
-  void CheckReduce(Node* expect, Node* phi) {
-    PhiReducer reducer;
-    Reduction reduction = reducer.Reduce(phi);
-    if (expect == phi) {
-      CHECK(!reduction.Changed());
-    } else {
-      CHECK(reduction.Changed());
-      CHECK_EQ(expect, reduction.replacement());
-    }
-  }
-
-  Node* Int32Constant(int32_t val) {
-    return graph.NewNode(common.Int32Constant(val));
-  }
-
-  Node* Float64Constant(double val) {
-    return graph.NewNode(common.Float64Constant(val));
-  }
-
-  Node* Parameter(int32_t index = 0) {
-    return graph.NewNode(common.Parameter(index), graph.start());
-  }
-
-  Node* Phi(Node* a) {
-    return SetSelfReferences(graph.NewNode(common.Phi(kMachAnyTagged, 1), a));
-  }
-
-  Node* Phi(Node* a, Node* b) {
-    return SetSelfReferences(
-        graph.NewNode(common.Phi(kMachAnyTagged, 2), a, b));
-  }
-
-  Node* Phi(Node* a, Node* b, Node* c) {
-    return SetSelfReferences(
-        graph.NewNode(common.Phi(kMachAnyTagged, 3), a, b, c));
-  }
-
-  Node* Phi(Node* a, Node* b, Node* c, Node* d) {
-    return SetSelfReferences(
-        graph.NewNode(common.Phi(kMachAnyTagged, 4), a, b, c, d));
-  }
-
-  Node* PhiWithControl(Node* a, Node* control) {
-    return SetSelfReferences(
-        graph.NewNode(common.Phi(kMachAnyTagged, 1), a, control));
-  }
-
-  Node* PhiWithControl(Node* a, Node* b, Node* control) {
-    return SetSelfReferences(
-        graph.NewNode(common.Phi(kMachAnyTagged, 2), a, b, control));
-  }
-
-  Node* SetSelfReferences(Node* node) {
-    Node::Inputs inputs = node->inputs();
-    for (Node::Inputs::iterator iter(inputs.begin()); iter != inputs.end();
-         ++iter) {
-      Node* input = *iter;
-      if (input == self) node->ReplaceInput(iter.index(), node);
-    }
-    return node;
-  }
-};
-
-
-TEST(PhiReduce1) {
-  PhiReducerTester R;
-  Node* zero = R.Int32Constant(0);
-  Node* one = R.Int32Constant(1);
-  Node* oneish = R.Float64Constant(1.1);
-  Node* param = R.Parameter();
-
-  Node* singles[] = {zero, one, oneish, param};
-  for (size_t i = 0; i < arraysize(singles); i++) {
-    R.CheckReduce(singles[i], R.Phi(singles[i]));
-  }
-}
-
-
-TEST(PhiReduce2) {
-  PhiReducerTester R;
-  Node* zero = R.Int32Constant(0);
-  Node* one = R.Int32Constant(1);
-  Node* oneish = R.Float64Constant(1.1);
-  Node* param = R.Parameter();
-
-  Node* singles[] = {zero, one, oneish, param};
-  for (size_t i = 0; i < arraysize(singles); i++) {
-    Node* a = singles[i];
-    R.CheckReduce(a, R.Phi(a, a));
-  }
-
-  for (size_t i = 0; i < arraysize(singles); i++) {
-    Node* a = singles[i];
-    R.CheckReduce(a, R.Phi(R.self, a));
-    R.CheckReduce(a, R.Phi(a, R.self));
-  }
-
-  for (size_t i = 1; i < arraysize(singles); i++) {
-    Node* a = singles[i], *b = singles[0];
-    Node* phi1 = R.Phi(b, a);
-    R.CheckReduce(phi1, phi1);
-
-    Node* phi2 = R.Phi(a, b);
-    R.CheckReduce(phi2, phi2);
-  }
-}
-
-
-TEST(PhiReduce3) {
-  PhiReducerTester R;
-  Node* zero = R.Int32Constant(0);
-  Node* one = R.Int32Constant(1);
-  Node* oneish = R.Float64Constant(1.1);
-  Node* param = R.Parameter();
-
-  Node* singles[] = {zero, one, oneish, param};
-  for (size_t i = 0; i < arraysize(singles); i++) {
-    Node* a = singles[i];
-    R.CheckReduce(a, R.Phi(a, a, a));
-  }
-
-  for (size_t i = 0; i < arraysize(singles); i++) {
-    Node* a = singles[i];
-    R.CheckReduce(a, R.Phi(R.self, a, a));
-    R.CheckReduce(a, R.Phi(a, R.self, a));
-    R.CheckReduce(a, R.Phi(a, a, R.self));
-  }
-
-  for (size_t i = 1; i < arraysize(singles); i++) {
-    Node* a = singles[i], *b = singles[0];
-    Node* phi1 = R.Phi(b, a, a);
-    R.CheckReduce(phi1, phi1);
-
-    Node* phi2 = R.Phi(a, b, a);
-    R.CheckReduce(phi2, phi2);
-
-    Node* phi3 = R.Phi(a, a, b);
-    R.CheckReduce(phi3, phi3);
-  }
-}
-
-
-TEST(PhiReduce4) {
-  PhiReducerTester R;
-  Node* zero = R.Int32Constant(0);
-  Node* one = R.Int32Constant(1);
-  Node* oneish = R.Float64Constant(1.1);
-  Node* param = R.Parameter();
-
-  Node* singles[] = {zero, one, oneish, param};
-  for (size_t i = 0; i < arraysize(singles); i++) {
-    Node* a = singles[i];
-    R.CheckReduce(a, R.Phi(a, a, a, a));
-  }
-
-  for (size_t i = 0; i < arraysize(singles); i++) {
-    Node* a = singles[i];
-    R.CheckReduce(a, R.Phi(R.self, a, a, a));
-    R.CheckReduce(a, R.Phi(a, R.self, a, a));
-    R.CheckReduce(a, R.Phi(a, a, R.self, a));
-    R.CheckReduce(a, R.Phi(a, a, a, R.self));
-
-    R.CheckReduce(a, R.Phi(R.self, R.self, a, a));
-    R.CheckReduce(a, R.Phi(a, R.self, R.self, a));
-    R.CheckReduce(a, R.Phi(a, a, R.self, R.self));
-    R.CheckReduce(a, R.Phi(R.self, a, a, R.self));
-  }
-
-  for (size_t i = 1; i < arraysize(singles); i++) {
-    Node* a = singles[i], *b = singles[0];
-    Node* phi1 = R.Phi(b, a, a, a);
-    R.CheckReduce(phi1, phi1);
-
-    Node* phi2 = R.Phi(a, b, a, a);
-    R.CheckReduce(phi2, phi2);
-
-    Node* phi3 = R.Phi(a, a, b, a);
-    R.CheckReduce(phi3, phi3);
-
-    Node* phi4 = R.Phi(a, a, a, b);
-    R.CheckReduce(phi4, phi4);
-  }
-}
-
-
-TEST(PhiReduceShouldIgnoreControlNodes) {
-  PhiReducerTester R;
-  Node* zero = R.Int32Constant(0);
-  Node* one = R.Int32Constant(1);
-  Node* oneish = R.Float64Constant(1.1);
-  Node* param = R.Parameter();
-
-  Node* singles[] = {zero, one, oneish, param};
-  for (size_t i = 0; i < arraysize(singles); ++i) {
-    R.CheckReduce(singles[i], R.PhiWithControl(singles[i], R.dead));
-    R.CheckReduce(singles[i], R.PhiWithControl(R.self, singles[i], R.dead));
-    R.CheckReduce(singles[i], R.PhiWithControl(singles[i], R.self, R.dead));
-  }
-}
diff --git a/test/cctest/compiler/test-pipeline.cc b/test/cctest/compiler/test-pipeline.cc
index f0b750a..98b0bae 100644
--- a/test/cctest/compiler/test-pipeline.cc
+++ b/test/cctest/compiler/test-pipeline.cc
@@ -5,6 +5,7 @@
 #include "src/v8.h"
 #include "test/cctest/cctest.h"
 
+#include "src/ast-numbering.h"
 #include "src/compiler.h"
 #include "src/compiler/pipeline.h"
 #include "src/handles.h"
@@ -22,10 +23,7 @@
       *v8::Handle<v8::Function>::Cast(CompileRun(source)));
   CompilationInfoWithZone info(function);
 
-  CHECK(Parser::Parse(&info));
-  CHECK(Rewriter::Rewrite(&info));
-  CHECK(Scope::Analyze(&info));
-  CHECK_NE(NULL, info.scope());
+  CHECK(Compiler::ParseAndAnalyze(&info));
 
   Pipeline pipeline(&info);
 #if V8_TURBOFAN_TARGET
diff --git a/test/cctest/compiler/test-representation-change.cc b/test/cctest/compiler/test-representation-change.cc
index 6c9026b..2dc3029 100644
--- a/test/cctest/compiler/test-representation-change.cc
+++ b/test/cctest/compiler/test-representation-change.cc
@@ -7,10 +7,10 @@
 #include "src/v8.h"
 #include "test/cctest/cctest.h"
 #include "test/cctest/compiler/graph-builder-tester.h"
+#include "test/cctest/compiler/value-helper.h"
 
 #include "src/compiler/node-matchers.h"
 #include "src/compiler/representation-change.h"
-#include "src/compiler/typer.h"
 
 using namespace v8::internal;
 using namespace v8::internal::compiler;
@@ -24,16 +24,13 @@
  public:
   explicit RepresentationChangerTester(int num_parameters = 0)
       : GraphAndBuilders(main_zone()),
-        typer_(main_zone()),
         javascript_(main_zone()),
-        jsgraph_(main_graph_, &main_common_, &javascript_, &typer_,
-                 &main_machine_),
+        jsgraph_(main_graph_, &main_common_, &javascript_, &main_machine_),
         changer_(&jsgraph_, &main_simplified_, main_isolate()) {
     Node* s = graph()->NewNode(common()->Start(num_parameters));
     graph()->SetStart(s);
   }
 
-  Typer typer_;
   JSOperatorBuilder javascript_;
   JSGraph jsgraph_;
   RepresentationChanger changer_;
@@ -51,6 +48,24 @@
     CHECK_EQ(expected, m.Value());
   }
 
+  void CheckUint32Constant(Node* n, uint32_t expected) {
+    Uint32Matcher m(n);
+    CHECK(m.HasValue());
+    CHECK_EQ(static_cast<int>(expected), static_cast<int>(m.Value()));
+  }
+
+  void CheckFloat64Constant(Node* n, double expected) {
+    Float64Matcher m(n);
+    CHECK(m.HasValue());
+    CHECK_EQ(expected, m.Value());
+  }
+
+  void CheckFloat32Constant(Node* n, float expected) {
+    CHECK_EQ(IrOpcode::kFloat32Constant, n->opcode());
+    float fval = OpParameter<float>(n->op());
+    CHECK_EQ(expected, fval);
+  }
+
   void CheckHeapConstant(Node* n, HeapObject* expected) {
     HeapObjectMatcher<HeapObject> m(n);
     CHECK(m.HasValue());
@@ -88,28 +103,8 @@
 }  // namespace v8::internal::compiler
 
 
-// TODO(titzer): add kRepFloat32 when fully supported.
-static const MachineType all_reps[] = {kRepBit, kRepWord32, kRepWord64,
-                                       kRepFloat64, kRepTagged};
-
-
-// TODO(titzer): lift this to ValueHelper
-static const double double_inputs[] = {
-    0.0,   -0.0,    1.0,    -1.0,        0.1,         1.4,    -1.7,
-    2,     5,       6,      982983,      888,         -999.8, 3.1e7,
-    -2e66, 2.3e124, -12e73, V8_INFINITY, -V8_INFINITY};
-
-
-static const int32_t int32_inputs[] = {
-    0,      1,                                -1,
-    2,      5,                                6,
-    982983, 888,                              -999,
-    65535,  static_cast<int32_t>(0xFFFFFFFF), static_cast<int32_t>(0x80000000)};
-
-
-static const uint32_t uint32_inputs[] = {
-    0,      1,   static_cast<uint32_t>(-1),   2,     5,          6,
-    982983, 888, static_cast<uint32_t>(-999), 65535, 0xFFFFFFFF, 0x80000000};
+static const MachineType all_reps[] = {kRepBit,     kRepWord32,  kRepWord64,
+                                       kRepFloat32, kRepFloat64, kRepTagged};
 
 
 TEST(BoolToBit_constant) {
@@ -142,24 +137,234 @@
 TEST(ToTagged_constant) {
   RepresentationChangerTester r;
 
-  for (size_t i = 0; i < arraysize(double_inputs); i++) {
-    Node* n = r.jsgraph()->Float64Constant(double_inputs[i]);
-    Node* c = r.changer()->GetRepresentationFor(n, kRepFloat64, kRepTagged);
-    r.CheckNumberConstant(c, double_inputs[i]);
+  {
+    FOR_FLOAT64_INPUTS(i) {
+      Node* n = r.jsgraph()->Float64Constant(*i);
+      Node* c = r.changer()->GetRepresentationFor(n, kRepFloat64, kRepTagged);
+      r.CheckNumberConstant(c, *i);
+    }
   }
 
-  for (size_t i = 0; i < arraysize(int32_inputs); i++) {
-    Node* n = r.jsgraph()->Int32Constant(int32_inputs[i]);
-    Node* c = r.changer()->GetRepresentationFor(n, kRepWord32 | kTypeInt32,
-                                                kRepTagged);
-    r.CheckNumberConstant(c, static_cast<double>(int32_inputs[i]));
+  {
+    FOR_FLOAT64_INPUTS(i) {
+      Node* n = r.jsgraph()->Constant(*i);
+      Node* c = r.changer()->GetRepresentationFor(n, kRepFloat64, kRepTagged);
+      r.CheckNumberConstant(c, *i);
+    }
   }
 
-  for (size_t i = 0; i < arraysize(uint32_inputs); i++) {
-    Node* n = r.jsgraph()->Int32Constant(uint32_inputs[i]);
-    Node* c = r.changer()->GetRepresentationFor(n, kRepWord32 | kTypeUint32,
-                                                kRepTagged);
-    r.CheckNumberConstant(c, static_cast<double>(uint32_inputs[i]));
+  {
+    FOR_FLOAT32_INPUTS(i) {
+      Node* n = r.jsgraph()->Float32Constant(*i);
+      Node* c = r.changer()->GetRepresentationFor(n, kRepFloat32, kRepTagged);
+      r.CheckNumberConstant(c, *i);
+    }
+  }
+
+  {
+    FOR_INT32_INPUTS(i) {
+      Node* n = r.jsgraph()->Int32Constant(*i);
+      Node* c = r.changer()->GetRepresentationFor(n, kRepWord32 | kTypeInt32,
+                                                  kRepTagged);
+      r.CheckNumberConstant(c, *i);
+    }
+  }
+
+  {
+    FOR_UINT32_INPUTS(i) {
+      Node* n = r.jsgraph()->Int32Constant(*i);
+      Node* c = r.changer()->GetRepresentationFor(n, kRepWord32 | kTypeUint32,
+                                                  kRepTagged);
+      r.CheckNumberConstant(c, *i);
+    }
+  }
+}
+
+
+TEST(ToFloat64_constant) {
+  RepresentationChangerTester r;
+
+  {
+    FOR_FLOAT64_INPUTS(i) {
+      Node* n = r.jsgraph()->Float64Constant(*i);
+      Node* c = r.changer()->GetRepresentationFor(n, kRepFloat64, kRepFloat64);
+      CHECK_EQ(n, c);
+    }
+  }
+
+  {
+    FOR_FLOAT64_INPUTS(i) {
+      Node* n = r.jsgraph()->Constant(*i);
+      Node* c = r.changer()->GetRepresentationFor(n, kRepTagged, kRepFloat64);
+      r.CheckFloat64Constant(c, *i);
+    }
+  }
+
+  {
+    FOR_FLOAT32_INPUTS(i) {
+      Node* n = r.jsgraph()->Float32Constant(*i);
+      Node* c = r.changer()->GetRepresentationFor(n, kRepFloat32, kRepFloat64);
+      r.CheckFloat64Constant(c, *i);
+    }
+  }
+
+  {
+    FOR_INT32_INPUTS(i) {
+      Node* n = r.jsgraph()->Int32Constant(*i);
+      Node* c = r.changer()->GetRepresentationFor(n, kRepWord32 | kTypeInt32,
+                                                  kRepFloat64);
+      r.CheckFloat64Constant(c, *i);
+    }
+  }
+
+  {
+    FOR_UINT32_INPUTS(i) {
+      Node* n = r.jsgraph()->Int32Constant(*i);
+      Node* c = r.changer()->GetRepresentationFor(n, kRepWord32 | kTypeUint32,
+                                                  kRepFloat64);
+      r.CheckFloat64Constant(c, *i);
+    }
+  }
+}
+
+
+static bool IsFloat32Int32(int32_t val) {
+  return val >= -(1 << 23) && val <= (1 << 23);
+}
+
+
+static bool IsFloat32Uint32(uint32_t val) { return val <= (1 << 23); }
+
+
+TEST(ToFloat32_constant) {
+  RepresentationChangerTester r;
+
+  {
+    FOR_FLOAT32_INPUTS(i) {
+      Node* n = r.jsgraph()->Float32Constant(*i);
+      Node* c = r.changer()->GetRepresentationFor(n, kRepFloat32, kRepFloat32);
+      CHECK_EQ(n, c);
+    }
+  }
+
+  {
+    FOR_FLOAT32_INPUTS(i) {
+      Node* n = r.jsgraph()->Constant(*i);
+      Node* c = r.changer()->GetRepresentationFor(n, kRepTagged, kRepFloat32);
+      r.CheckFloat32Constant(c, *i);
+    }
+  }
+
+  {
+    FOR_FLOAT32_INPUTS(i) {
+      Node* n = r.jsgraph()->Float64Constant(*i);
+      Node* c = r.changer()->GetRepresentationFor(n, kRepFloat64, kRepFloat32);
+      r.CheckFloat32Constant(c, *i);
+    }
+  }
+
+  {
+    FOR_INT32_INPUTS(i) {
+      if (!IsFloat32Int32(*i)) continue;
+      Node* n = r.jsgraph()->Int32Constant(*i);
+      Node* c = r.changer()->GetRepresentationFor(n, kRepWord32 | kTypeInt32,
+                                                  kRepFloat32);
+      r.CheckFloat32Constant(c, static_cast<float>(*i));
+    }
+  }
+
+  {
+    FOR_UINT32_INPUTS(i) {
+      if (!IsFloat32Uint32(*i)) continue;
+      Node* n = r.jsgraph()->Int32Constant(*i);
+      Node* c = r.changer()->GetRepresentationFor(n, kRepWord32 | kTypeUint32,
+                                                  kRepFloat32);
+      r.CheckFloat32Constant(c, static_cast<float>(*i));
+    }
+  }
+}
+
+
+TEST(ToInt32_constant) {
+  RepresentationChangerTester r;
+
+  {
+    FOR_INT32_INPUTS(i) {
+      Node* n = r.jsgraph()->Int32Constant(*i);
+      Node* c = r.changer()->GetRepresentationFor(n, kRepWord32 | kTypeInt32,
+                                                  kRepWord32);
+      r.CheckInt32Constant(c, *i);
+    }
+  }
+
+  {
+    FOR_INT32_INPUTS(i) {
+      if (!IsFloat32Int32(*i)) continue;
+      Node* n = r.jsgraph()->Float32Constant(static_cast<float>(*i));
+      Node* c = r.changer()->GetRepresentationFor(n, kRepFloat32 | kTypeInt32,
+                                                  kRepWord32);
+      r.CheckInt32Constant(c, *i);
+    }
+  }
+
+  {
+    FOR_INT32_INPUTS(i) {
+      Node* n = r.jsgraph()->Float64Constant(*i);
+      Node* c = r.changer()->GetRepresentationFor(n, kRepFloat64 | kTypeInt32,
+                                                  kRepWord32);
+      r.CheckInt32Constant(c, *i);
+    }
+  }
+
+  {
+    FOR_INT32_INPUTS(i) {
+      Node* n = r.jsgraph()->Constant(*i);
+      Node* c = r.changer()->GetRepresentationFor(n, kRepTagged | kTypeInt32,
+                                                  kRepWord32);
+      r.CheckInt32Constant(c, *i);
+    }
+  }
+}
+
+
+TEST(ToUint32_constant) {
+  RepresentationChangerTester r;
+
+  {
+    FOR_UINT32_INPUTS(i) {
+      Node* n = r.jsgraph()->Int32Constant(*i);
+      Node* c = r.changer()->GetRepresentationFor(n, kRepWord32 | kTypeUint32,
+                                                  kRepWord32);
+      r.CheckUint32Constant(c, *i);
+    }
+  }
+
+  {
+    FOR_UINT32_INPUTS(i) {
+      if (!IsFloat32Uint32(*i)) continue;
+      Node* n = r.jsgraph()->Float32Constant(static_cast<float>(*i));
+      Node* c = r.changer()->GetRepresentationFor(n, kRepFloat32 | kTypeUint32,
+                                                  kRepWord32);
+      r.CheckUint32Constant(c, *i);
+    }
+  }
+
+  {
+    FOR_UINT32_INPUTS(i) {
+      Node* n = r.jsgraph()->Float64Constant(*i);
+      Node* c = r.changer()->GetRepresentationFor(n, kRepFloat64 | kTypeUint32,
+                                                  kRepWord32);
+      r.CheckUint32Constant(c, *i);
+    }
+  }
+
+  {
+    FOR_UINT32_INPUTS(i) {
+      Node* n = r.jsgraph()->Constant(static_cast<double>(*i));
+      Node* c = r.changer()->GetRepresentationFor(n, kRepTagged | kTypeUint32,
+                                                  kRepWord32);
+      r.CheckUint32Constant(c, *i);
+    }
   }
 }
 
@@ -177,6 +382,23 @@
 }
 
 
+static void CheckTwoChanges(IrOpcode::Value expected2,
+                            IrOpcode::Value expected1, MachineTypeUnion from,
+                            MachineTypeUnion to) {
+  RepresentationChangerTester r;
+
+  Node* n = r.Parameter();
+  Node* c1 = r.changer()->GetRepresentationFor(n, from, to);
+
+  CHECK_NE(c1, n);
+  CHECK_EQ(expected1, c1->opcode());
+  Node* c2 = c1->InputAt(0);
+  CHECK_NE(c2, n);
+  CHECK_EQ(expected2, c2->opcode());
+  CHECK_EQ(n, c2->InputAt(0));
+}
+
+
 TEST(SingleChanges) {
   CheckChange(IrOpcode::kChangeBoolToBit, kRepTagged, kRepBit);
   CheckChange(IrOpcode::kChangeBitToBool, kRepBit, kRepTagged);
@@ -202,6 +424,28 @@
               kRepWord32);
   CheckChange(IrOpcode::kChangeFloat64ToUint32, kRepFloat64 | kTypeUint32,
               kRepWord32);
+
+  CheckChange(IrOpcode::kTruncateFloat64ToFloat32, kRepFloat64, kRepFloat32);
+
+  // Int32,Uint32 <-> Float32 require two changes.
+  CheckTwoChanges(IrOpcode::kChangeInt32ToFloat64,
+                  IrOpcode::kTruncateFloat64ToFloat32, kRepWord32 | kTypeInt32,
+                  kRepFloat32);
+  CheckTwoChanges(IrOpcode::kChangeUint32ToFloat64,
+                  IrOpcode::kTruncateFloat64ToFloat32, kRepWord32 | kTypeUint32,
+                  kRepFloat32);
+  CheckTwoChanges(IrOpcode::kChangeFloat32ToFloat64,
+                  IrOpcode::kChangeFloat64ToInt32, kRepFloat32 | kTypeInt32,
+                  kRepWord32);
+  CheckTwoChanges(IrOpcode::kChangeFloat32ToFloat64,
+                  IrOpcode::kChangeFloat64ToUint32, kRepFloat32 | kTypeUint32,
+                  kRepWord32);
+
+  // Float32 <-> Tagged require two changes.
+  CheckTwoChanges(IrOpcode::kChangeFloat32ToFloat64,
+                  IrOpcode::kChangeFloat64ToTagged, kRepFloat32, kRepTagged);
+  CheckTwoChanges(IrOpcode::kChangeTaggedToFloat64,
+                  IrOpcode::kTruncateFloat64ToFloat32, kRepTagged, kRepFloat32);
 }
 
 
@@ -215,6 +459,11 @@
               kRepWord32 | kTypeUint32);
   CheckChange(IrOpcode::kChangeInt32ToFloat64, kRepWord32, kRepFloat64);
   CheckChange(IrOpcode::kChangeFloat64ToInt32, kRepFloat64, kRepWord32);
+
+  CheckTwoChanges(IrOpcode::kChangeInt32ToFloat64,
+                  IrOpcode::kTruncateFloat64ToFloat32, kRepWord32, kRepFloat32);
+  CheckTwoChanges(IrOpcode::kChangeFloat32ToFloat64,
+                  IrOpcode::kChangeFloat64ToInt32, kRepFloat32, kRepWord32);
 }
 
 
@@ -295,11 +544,4 @@
       r.CheckTypeError(all_reps[i] | all_reps[j], kRepTagged);
     }
   }
-
-  // TODO(titzer): Float32 representation changes trigger type errors now.
-  // Enforce current behavior to test all paths through representation changer.
-  for (size_t i = 0; i < arraysize(all_reps); i++) {
-    r.CheckTypeError(all_reps[i], kRepFloat32);
-    r.CheckTypeError(kRepFloat32, all_reps[i]);
-  }
 }
diff --git a/test/cctest/compiler/test-run-inlining.cc b/test/cctest/compiler/test-run-inlining.cc
index ad82fec..19b96ba 100644
--- a/test/cctest/compiler/test-run-inlining.cc
+++ b/test/cctest/compiler/test-run-inlining.cc
@@ -25,7 +25,8 @@
     frames_seen++;
     it.Advance();
   }
-  CHECK_EQ(args[0]->ToInt32()->Value(), topmost->GetInlineCount());
+  CHECK_EQ(args[0]->ToInt32(args.GetIsolate())->Value(),
+           topmost->GetInlineCount());
 }
 
 
@@ -37,16 +38,20 @@
 }
 
 
+static uint32_t kInlineFlags = CompilationInfo::kInliningEnabled |
+                               CompilationInfo::kContextSpecializing |
+                               CompilationInfo::kTypingEnabled;
+
+
 TEST(SimpleInlining) {
   FLAG_turbo_deoptimization = true;
   FunctionTester T(
       "(function(){"
-      "function foo(s) { AssertInlineCount(2); return s; };"
-      "function bar(s, t) { return foo(s); };"
-      "return bar;})();",
-      CompilationInfo::kInliningEnabled |
-          CompilationInfo::kContextSpecializing |
-          CompilationInfo::kTypingEnabled);
+      "  function foo(s) { AssertInlineCount(2); return s; };"
+      "  function bar(s, t) { return foo(s); };"
+      "  return bar;"
+      "})();",
+      kInlineFlags);
 
   InstallAssertInlineCountHelper(CcTest::isolate());
   T.CheckCall(T.Val(1), T.Val(1), T.Val(2));
@@ -57,13 +62,11 @@
   FLAG_turbo_deoptimization = true;
   FunctionTester T(
       "(function(){"
-      "function foo(s) { %DeoptimizeFunction(bar); return "
-      "s; };"
-      "function bar(s, t) { return foo(s); };"
-      "return bar;})();",
-      CompilationInfo::kInliningEnabled |
-          CompilationInfo::kContextSpecializing |
-          CompilationInfo::kTypingEnabled);
+      "  function foo(s) { %DeoptimizeFunction(bar); return s; };"
+      "  function bar(s, t) { return foo(s); };"
+      "  return bar;"
+      "})();",
+      kInlineFlags);
 
   InstallAssertInlineCountHelper(CcTest::isolate());
   T.CheckCall(T.Val(1), T.Val(1), T.Val(2));
@@ -74,13 +77,11 @@
   FLAG_turbo_deoptimization = true;
   FunctionTester T(
       "(function () {"
-      "function foo(s) { AssertInlineCount(2); var x = 12; return s + x; };"
-      "function bar(s, t) { return foo(s); };"
-      "return bar;"
+      "  function foo(s) { AssertInlineCount(2); var x = 12; return s + x; };"
+      "  function bar(s, t) { return foo(s); };"
+      "  return bar;"
       "})();",
-      CompilationInfo::kInliningEnabled |
-          CompilationInfo::kContextSpecializing |
-          CompilationInfo::kTypingEnabled);
+      kInlineFlags);
 
   InstallAssertInlineCountHelper(CcTest::isolate());
   T.CheckCall(T.Val(13), T.Val(1), T.Val(2));
@@ -91,16 +92,14 @@
   FLAG_turbo_deoptimization = true;
   FunctionTester T(
       "(function () {"
-      "function foo(s) { "
-      "  AssertInlineCount(2); %DeoptimizeFunction(bar); var x = 12;"
-      "  return s + x;"
-      "};"
-      "function bar(s, t) { return foo(s); };"
-      "return bar;"
+      "  function foo(s) {"
+      "    AssertInlineCount(2); %DeoptimizeFunction(bar); var x = 12;"
+      "    return s + x;"
+      "  };"
+      "  function bar(s, t) { return foo(s); };"
+      "  return bar;"
       "})();",
-      CompilationInfo::kInliningEnabled |
-          CompilationInfo::kContextSpecializing |
-          CompilationInfo::kTypingEnabled);
+      kInlineFlags);
 
   InstallAssertInlineCountHelper(CcTest::isolate());
   T.CheckCall(T.Val(13), T.Val(1), T.Val(2));
@@ -111,14 +110,12 @@
   FLAG_turbo_deoptimization = true;
   FunctionTester T(
       "var f = (function () {"
-      "var x = 42;"
-      "function bar(s) { return x + s; };"
-      "return (function (s) { return bar(s); });"
+      "  var x = 42;"
+      "  function bar(s) { return x + s; };"
+      "  return (function (s) { return bar(s); });"
       "})();"
-      "(function (s) { return f(s)})",
-      CompilationInfo::kInliningEnabled |
-          CompilationInfo::kContextSpecializing |
-          CompilationInfo::kTypingEnabled);
+      "(function (s) { return f(s) })",
+      kInlineFlags);
 
   InstallAssertInlineCountHelper(CcTest::isolate());
   T.CheckCall(T.Val(42 + 12), T.Val(12), T.undefined());
@@ -132,12 +129,10 @@
   FunctionTester T(
       "var x = 42;"
       "(function () {"
-      "function bar(s, t) { return eval(\"AssertInlineCount(1); x\") };"
-      "return bar;"
+      "  function bar(s, t) { return eval(\"AssertInlineCount(1); x\") };"
+      "  return bar;"
       "})();",
-      CompilationInfo::kInliningEnabled |
-          CompilationInfo::kContextSpecializing |
-          CompilationInfo::kTypingEnabled);
+      kInlineFlags);
 
   InstallAssertInlineCountHelper(CcTest::isolate());
   T.CheckCall(T.Val(42), T.Val("x"), T.undefined());
@@ -148,13 +143,11 @@
   FLAG_turbo_deoptimization = true;
   FunctionTester T(
       "(function () {"
-      "var x = 42;"
-      "function bar(s, t, u, v) { AssertInlineCount(2); return x + s; };"
-      "return (function (s,t) { return bar(s); });"
+      "  var x = 42;"
+      "  function bar(s, t, u, v) { AssertInlineCount(2); return x + s; };"
+      "  return (function (s,t) { return bar(s); });"
       "})();",
-      CompilationInfo::kInliningEnabled |
-          CompilationInfo::kContextSpecializing |
-          CompilationInfo::kTypingEnabled);
+      kInlineFlags);
 
   InstallAssertInlineCountHelper(CcTest::isolate());
   T.CheckCall(T.Val(42 + 12), T.Val(12), T.undefined());
@@ -165,16 +158,14 @@
   FLAG_turbo_deoptimization = true;
   FunctionTester T(
       "(function () {"
-      "function foo(s,t,u,v) { AssertInlineCount(2); %DeoptimizeFunction(bar); "
-      "return baz(); };"
-      "function bar() { return foo(11); };"
-      "function baz() { return foo.arguments.length == 1 && "
-      "                        foo.arguments[0] == 11 ; }"
-      "return bar;"
+      "  function foo(s,t,u,v) { AssertInlineCount(2);"
+      "                          %DeoptimizeFunction(bar); return baz(); };"
+      "  function bar() { return foo(11); };"
+      "  function baz() { return foo.arguments.length == 1 &&"
+      "                          foo.arguments[0] == 11; }"
+      "  return bar;"
       "})();",
-      CompilationInfo::kInliningEnabled |
-          CompilationInfo::kContextSpecializing |
-          CompilationInfo::kTypingEnabled);
+      kInlineFlags);
 
   InstallAssertInlineCountHelper(CcTest::isolate());
   T.CheckCall(T.true_value(), T.Val(12), T.Val(14));
@@ -185,14 +176,12 @@
   FLAG_turbo_deoptimization = true;
   FunctionTester T(
       "(function () {"
-      "var x = 42;"
-      "function foo(s) { AssertInlineCount(2); return x + s; };"
-      "function bar(s,t) { return foo(s,t,13); };"
-      "return bar;"
+      "  var x = 42;"
+      "  function foo(s) { AssertInlineCount(2); return x + s; };"
+      "  function bar(s,t) { return foo(s,t,13); };"
+      "  return bar;"
       "})();",
-      CompilationInfo::kInliningEnabled |
-          CompilationInfo::kContextSpecializing |
-          CompilationInfo::kTypingEnabled);
+      kInlineFlags);
 
   InstallAssertInlineCountHelper(CcTest::isolate());
   T.CheckCall(T.Val(42 + 12), T.Val(12), T.undefined());
@@ -203,18 +192,16 @@
   FLAG_turbo_deoptimization = true;
   FunctionTester T(
       "(function () {"
-      "function foo(s) { AssertInlineCount(2); %DeoptimizeFunction(bar); "
-      "return baz(); };"
-      "function bar() { return foo(13, 14, 15); };"
-      "function baz() { return foo.arguments.length == 3 && "
-      "                        foo.arguments[0] == 13 && "
-      "                        foo.arguments[1] == 14 && "
-      "                        foo.arguments[2] == 15; }"
-      "return bar;"
+      "  function foo(s) { AssertInlineCount(2); %DeoptimizeFunction(bar);"
+      "                    return baz(); };"
+      "  function bar() { return foo(13, 14, 15); };"
+      "  function baz() { return foo.arguments.length == 3 &&"
+      "                          foo.arguments[0] == 13 &&"
+      "                          foo.arguments[1] == 14 &&"
+      "                          foo.arguments[2] == 15; }"
+      "  return bar;"
       "})();",
-      CompilationInfo::kInliningEnabled |
-          CompilationInfo::kContextSpecializing |
-          CompilationInfo::kTypingEnabled);
+      kInlineFlags);
 
   InstallAssertInlineCountHelper(CcTest::isolate());
   T.CheckCall(T.true_value(), T.Val(12), T.Val(14));
@@ -225,13 +212,11 @@
   FLAG_turbo_deoptimization = true;
   FunctionTester T(
       "(function () {"
-      "var x = 42;"
-      "function bar(s) { AssertInlineCount(2); return x + s; };"
-      "return (function (s,t) { return bar(s) + bar(t); });"
+      "  var x = 42;"
+      "  function bar(s) { AssertInlineCount(2); return x + s; };"
+      "  return (function (s,t) { return bar(s) + bar(t); });"
       "})();",
-      CompilationInfo::kInliningEnabled |
-          CompilationInfo::kContextSpecializing |
-          CompilationInfo::kTypingEnabled);
+      kInlineFlags);
 
   InstallAssertInlineCountHelper(CcTest::isolate());
   T.CheckCall(T.Val(2 * 42 + 12 + 4), T.Val(12), T.Val(4));
@@ -242,14 +227,12 @@
   FLAG_turbo_deoptimization = true;
   FunctionTester T(
       "(function () {"
-      "var x = 42;"
-      "function foo(s) { AssertInlineCount(2); return x + s; };"
-      "function bar(s,t) { return foo(foo(s)); };"
-      "return bar;"
+      "  var x = 42;"
+      "  function foo(s) { AssertInlineCount(2); return x + s; };"
+      "  function bar(s,t) { return foo(foo(s)); };"
+      "  return bar;"
       "})();",
-      CompilationInfo::kInliningEnabled |
-          CompilationInfo::kContextSpecializing |
-          CompilationInfo::kTypingEnabled);
+      kInlineFlags);
 
   InstallAssertInlineCountHelper(CcTest::isolate());
   T.CheckCall(T.Val(42 + 42 + 12), T.Val(12), T.Val(4));
@@ -260,15 +243,13 @@
   FLAG_turbo_deoptimization = true;
   FunctionTester T(
       "(function () {"
-      "var x = 41;"
-      "function foo(s) { AssertInlineCount(2); if (s % 2 == 0) {"
-      "                  return x - s } else { return x + s; } };"
-      "function bar(s,t) { return foo(foo(s)); };"
-      "return bar;"
+      "  var x = 41;"
+      "  function foo(s) { AssertInlineCount(2); if (s % 2 == 0) {"
+      "                    return x - s } else { return x + s; } };"
+      "  function bar(s,t) { return foo(foo(s)); };"
+      "  return bar;"
       "})();",
-      CompilationInfo::kInliningEnabled |
-          CompilationInfo::kContextSpecializing |
-          CompilationInfo::kTypingEnabled);
+      kInlineFlags);
 
   InstallAssertInlineCountHelper(CcTest::isolate());
   T.CheckCall(T.Val(-11), T.Val(11), T.Val(4));
@@ -279,34 +260,60 @@
   FLAG_turbo_deoptimization = true;
   FunctionTester T(
       "(function () {"
-      "var x = 41;"
-      "function foo(s,t) { AssertInlineCount(2); if (s % 2 == 0) {"
-      "                    return x - s * t } else { return x + s * t; } };"
-      "function bar(s,t) { return foo(foo(s, 3), 5); };"
-      "return bar;"
+      "  var x = 41;"
+      "  function foo(s,t) { AssertInlineCount(2); if (s % 2 == 0) {"
+      "                      return x - s * t } else { return x + s * t; } };"
+      "  function bar(s,t) { return foo(foo(s, 3), 5); };"
+      "  return bar;"
       "})();",
-      CompilationInfo::kInliningEnabled |
-          CompilationInfo::kContextSpecializing |
-          CompilationInfo::kTypingEnabled);
+      kInlineFlags);
 
   InstallAssertInlineCountHelper(CcTest::isolate());
   T.CheckCall(T.Val(-329), T.Val(11), T.Val(4));
 }
 
 
-TEST(InlineLoop) {
+TEST(InlineLoopGuardedEmpty) {
   FLAG_turbo_deoptimization = true;
   FunctionTester T(
       "(function () {"
-      "var x = 41;"
-      "function foo(s) { AssertInlineCount(2); while (s > 0) {"
-      "                  s = s - 1; }; return s; };"
-      "function bar(s,t) { return foo(foo(s)); };"
-      "return bar;"
+      "  function foo(s) { AssertInlineCount(2); if (s) while (s); return s; };"
+      "  function bar(s,t) { return foo(s); };"
+      "  return bar;"
       "})();",
-      CompilationInfo::kInliningEnabled |
-          CompilationInfo::kContextSpecializing |
-          CompilationInfo::kTypingEnabled);
+      kInlineFlags);
+
+  InstallAssertInlineCountHelper(CcTest::isolate());
+  T.CheckCall(T.Val(0.0), T.Val(0.0), T.Val(4));
+}
+
+
+TEST(InlineLoopGuardedOnce) {
+  FLAG_turbo_deoptimization = true;
+  FunctionTester T(
+      "(function () {"
+      "  function foo(s,t) { AssertInlineCount(2); if (t > 0) while (s > 0) {"
+      "                      s = s - 1; }; return s; };"
+      "  function bar(s,t) { return foo(s,t); };"
+      "  return bar;"
+      "})();",
+      kInlineFlags);
+
+  InstallAssertInlineCountHelper(CcTest::isolate());
+  T.CheckCall(T.Val(0.0), T.Val(11), T.Val(4));
+}
+
+
+TEST(InlineLoopGuardedTwice) {
+  FLAG_turbo_deoptimization = true;
+  FunctionTester T(
+      "(function () {"
+      "  function foo(s,t) { AssertInlineCount(2); if (t > 0) while (s > 0) {"
+      "                      s = s - 1; }; return s; };"
+      "  function bar(s,t) { return foo(foo(s,t),t); };"
+      "  return bar;"
+      "})();",
+      kInlineFlags);
 
   InstallAssertInlineCountHelper(CcTest::isolate());
   T.CheckCall(T.Val(0.0), T.Val(11), T.Val(4));
@@ -317,15 +324,13 @@
   FLAG_turbo_deoptimization = true;
   FunctionTester T(
       "(function () {"
-      "var x = Object.create({}, { y: { value:42, writable:false } });"
-      "function foo(s) { 'use strict';"
-      "                   x.y = 9; };"
-      "function bar(s,t) { return foo(s); };"
-      "return bar;"
+      "  var x = Object.create({}, { y: { value:42, writable:false } });"
+      "  function foo(s) { 'use strict';"
+      "                     x.y = 9; };"
+      "  function bar(s,t) { return foo(s); };"
+      "  return bar;"
       "})();",
-      CompilationInfo::kInliningEnabled |
-          CompilationInfo::kContextSpecializing |
-          CompilationInfo::kTypingEnabled);
+      kInlineFlags);
 
   InstallAssertInlineCountHelper(CcTest::isolate());
   T.CheckThrows(T.undefined(), T.undefined());
@@ -336,18 +341,100 @@
   FLAG_turbo_deoptimization = true;
   FunctionTester T(
       "(function () {"
-      "var x = Object.create({}, { y: { value:42, writable:false } });"
-      "function foo(s) { x.y = 9; return x.y; };"
-      "function bar(s,t) { \'use strict\'; return foo(s); };"
-      "return bar;"
+      "  var x = Object.create({}, { y: { value:42, writable:false } });"
+      "  function foo(s) { x.y = 9; return x.y; };"
+      "  function bar(s,t) { \'use strict\'; return foo(s); };"
+      "  return bar;"
       "})();",
-      CompilationInfo::kInliningEnabled |
-          CompilationInfo::kContextSpecializing |
-          CompilationInfo::kTypingEnabled);
+      kInlineFlags);
 
   InstallAssertInlineCountHelper(CcTest::isolate());
   T.CheckCall(T.Val(42), T.undefined(), T.undefined());
 }
 
 
+TEST(InlineIntrinsicIsSmi) {
+  FLAG_turbo_deoptimization = true;
+  FunctionTester T(
+      "(function () {"
+      "  var x = 42;"
+      "  function bar(s,t) { return %_IsSmi(x); };"
+      "  return bar;"
+      "})();",
+      kInlineFlags);
+
+  InstallAssertInlineCountHelper(CcTest::isolate());
+  T.CheckCall(T.true_value(), T.Val(12), T.Val(4));
+}
+
+
+TEST(InlineIntrinsicIsNonNegativeSmi) {
+  FLAG_turbo_deoptimization = true;
+  FunctionTester T(
+      "(function () {"
+      "  var x = 42;"
+      "  function bar(s,t) { return %_IsNonNegativeSmi(x); };"
+      "  return bar;"
+      "})();",
+      kInlineFlags);
+
+  InstallAssertInlineCountHelper(CcTest::isolate());
+  T.CheckCall(T.true_value(), T.Val(12), T.Val(4));
+}
+
+
+TEST(InlineIntrinsicIsArray) {
+  FLAG_turbo_deoptimization = true;
+  FunctionTester T(
+      "(function () {"
+      "  var x = [1,2,3];"
+      "  function bar(s,t) { return %_IsArray(x); };"
+      "  return bar;"
+      "})();",
+      kInlineFlags);
+
+  InstallAssertInlineCountHelper(CcTest::isolate());
+  T.CheckCall(T.true_value(), T.Val(12), T.Val(4));
+
+  FunctionTester T2(
+      "(function () {"
+      "  var x = 32;"
+      "  function bar(s,t) { return %_IsArray(x); };"
+      "  return bar;"
+      "})();",
+      kInlineFlags);
+
+  T2.CheckCall(T.false_value(), T.Val(12), T.Val(4));
+
+  FunctionTester T3(
+      "(function () {"
+      "  var x = bar;"
+      "  function bar(s,t) { return %_IsArray(x); };"
+      "  return bar;"
+      "})();",
+      kInlineFlags);
+
+  T3.CheckCall(T.false_value(), T.Val(12), T.Val(4));
+}
+
+
+TEST(InlineWithArguments) {
+  FLAG_turbo_deoptimization = true;
+  FunctionTester T(
+      "(function () {"
+      "  function foo(s,t,u) { AssertInlineCount(2);"
+      "    return foo.arguments.length == 3 &&"
+      "           foo.arguments[0] == 13 &&"
+      "           foo.arguments[1] == 14 &&"
+      "           foo.arguments[2] == 15;"
+      "  }"
+      "  function bar() { return foo(13, 14, 15); };"
+      "  return bar;"
+      "})();",
+      kInlineFlags);
+
+  InstallAssertInlineCountHelper(CcTest::isolate());
+  T.CheckCall(T.true_value(), T.Val(12), T.Val(14));
+}
+
 #endif  // V8_TURBOFAN_TARGET
diff --git a/test/cctest/compiler/test-run-intrinsics.cc b/test/cctest/compiler/test-run-intrinsics.cc
index a1b5676..76cbb8f 100644
--- a/test/cctest/compiler/test-run-intrinsics.cc
+++ b/test/cctest/compiler/test-run-intrinsics.cc
@@ -8,10 +8,12 @@
 
 using namespace v8::internal;
 using namespace v8::internal::compiler;
-
+uint32_t flags = CompilationInfo::kInliningEnabled;
 
 TEST(IsSmi) {
-  FunctionTester T("(function(a) { return %_IsSmi(a); })");
+  FLAG_turbo_inlining_intrinsics = true;
+  FLAG_turbo_deoptimization = true;
+  FunctionTester T("(function(a) { return %_IsSmi(a); })", flags);
 
   T.CheckTrue(T.Val(1));
   T.CheckFalse(T.Val(1.1));
@@ -23,7 +25,9 @@
 
 
 TEST(IsNonNegativeSmi) {
-  FunctionTester T("(function(a) { return %_IsNonNegativeSmi(a); })");
+  FLAG_turbo_inlining_intrinsics = true;
+  FLAG_turbo_deoptimization = true;
+  FunctionTester T("(function(a) { return %_IsNonNegativeSmi(a); })", flags);
 
   T.CheckTrue(T.Val(1));
   T.CheckFalse(T.Val(1.1));
@@ -35,7 +39,9 @@
 
 
 TEST(IsMinusZero) {
-  FunctionTester T("(function(a) { return %_IsMinusZero(a); })");
+  FLAG_turbo_inlining_intrinsics = true;
+  FLAG_turbo_deoptimization = true;
+  FunctionTester T("(function(a) { return %_IsMinusZero(a); })", flags);
 
   T.CheckFalse(T.Val(1));
   T.CheckFalse(T.Val(1.1));
@@ -47,7 +53,9 @@
 
 
 TEST(IsArray) {
-  FunctionTester T("(function(a) { return %_IsArray(a); })");
+  FLAG_turbo_inlining_intrinsics = true;
+  FLAG_turbo_deoptimization = true;
+  FunctionTester T("(function(a) { return %_IsArray(a); })", flags);
 
   T.CheckFalse(T.NewObject("(function() {})"));
   T.CheckTrue(T.NewObject("([1])"));
@@ -61,7 +69,9 @@
 
 
 TEST(IsObject) {
-  FunctionTester T("(function(a) { return %_IsObject(a); })");
+  FLAG_turbo_inlining_intrinsics = true;
+  FLAG_turbo_deoptimization = true;
+  FunctionTester T("(function(a) { return %_IsObject(a); })", flags);
 
   T.CheckFalse(T.NewObject("(function() {})"));
   T.CheckTrue(T.NewObject("([1])"));
@@ -75,7 +85,9 @@
 
 
 TEST(IsFunction) {
-  FunctionTester T("(function(a) { return %_IsFunction(a); })");
+  FLAG_turbo_inlining_intrinsics = true;
+  FLAG_turbo_deoptimization = true;
+  FunctionTester T("(function(a) { return %_IsFunction(a); })", flags);
 
   T.CheckTrue(T.NewObject("(function() {})"));
   T.CheckFalse(T.NewObject("([1])"));
@@ -89,7 +101,9 @@
 
 
 TEST(IsRegExp) {
-  FunctionTester T("(function(a) { return %_IsRegExp(a); })");
+  FLAG_turbo_inlining_intrinsics = true;
+  FLAG_turbo_deoptimization = true;
+  FunctionTester T("(function(a) { return %_IsRegExp(a); })", flags);
 
   T.CheckFalse(T.NewObject("(function() {})"));
   T.CheckFalse(T.NewObject("([1])"));
@@ -103,7 +117,9 @@
 
 
 TEST(ClassOf) {
-  FunctionTester T("(function(a) { return %_ClassOf(a); })");
+  FLAG_turbo_inlining_intrinsics = true;
+  FLAG_turbo_deoptimization = true;
+  FunctionTester T("(function(a) { return %_ClassOf(a); })", flags);
 
   T.CheckCall(T.Val("Function"), T.NewObject("(function() {})"));
   T.CheckCall(T.Val("Array"), T.NewObject("([1])"));
@@ -117,7 +133,9 @@
 
 
 TEST(ObjectEquals) {
-  FunctionTester T("(function(a,b) { return %_ObjectEquals(a,b); })");
+  FLAG_turbo_inlining_intrinsics = true;
+  FLAG_turbo_deoptimization = true;
+  FunctionTester T("(function(a,b) { return %_ObjectEquals(a,b); })", flags);
   CompileRun("var o = {}");
 
   T.CheckTrue(T.NewObject("(o)"), T.NewObject("(o)"));
@@ -130,7 +148,9 @@
 
 
 TEST(ValueOf) {
-  FunctionTester T("(function(a) { return %_ValueOf(a); })");
+  FLAG_turbo_inlining_intrinsics = true;
+  FLAG_turbo_deoptimization = true;
+  FunctionTester T("(function(a) { return %_ValueOf(a); })", flags);
 
   T.CheckCall(T.Val("a"), T.Val("a"));
   T.CheckCall(T.Val("b"), T.NewObject("(new String('b'))"));
@@ -140,7 +160,9 @@
 
 
 TEST(SetValueOf) {
-  FunctionTester T("(function(a,b) { return %_SetValueOf(a,b); })");
+  FLAG_turbo_inlining_intrinsics = true;
+  FLAG_turbo_deoptimization = true;
+  FunctionTester T("(function(a,b) { return %_SetValueOf(a,b); })", flags);
 
   T.CheckCall(T.Val("a"), T.NewObject("(new String)"), T.Val("a"));
   T.CheckCall(T.Val(123), T.NewObject("(new Number)"), T.Val(123));
@@ -149,7 +171,9 @@
 
 
 TEST(StringCharFromCode) {
-  FunctionTester T("(function(a) { return %_StringCharFromCode(a); })");
+  FLAG_turbo_inlining_intrinsics = true;
+  FLAG_turbo_deoptimization = true;
+  FunctionTester T("(function(a) { return %_StringCharFromCode(a); })", flags);
 
   T.CheckCall(T.Val("a"), T.Val(97));
   T.CheckCall(T.Val("\xE2\x9D\x8A"), T.Val(0x274A));
@@ -158,7 +182,9 @@
 
 
 TEST(StringCharAt) {
-  FunctionTester T("(function(a,b) { return %_StringCharAt(a,b); })");
+  FLAG_turbo_inlining_intrinsics = true;
+  FLAG_turbo_deoptimization = true;
+  FunctionTester T("(function(a,b) { return %_StringCharAt(a,b); })", flags);
 
   T.CheckCall(T.Val("e"), T.Val("huge fan!"), T.Val(3));
   T.CheckCall(T.Val("f"), T.Val("\xE2\x9D\x8A fan!"), T.Val(2));
@@ -167,7 +193,10 @@
 
 
 TEST(StringCharCodeAt) {
-  FunctionTester T("(function(a,b) { return %_StringCharCodeAt(a,b); })");
+  FLAG_turbo_inlining_intrinsics = true;
+  FLAG_turbo_deoptimization = true;
+  FunctionTester T("(function(a,b) { return %_StringCharCodeAt(a,b); })",
+                   flags);
 
   T.CheckCall(T.Val('e'), T.Val("huge fan!"), T.Val(3));
   T.CheckCall(T.Val('f'), T.Val("\xE2\x9D\x8A fan!"), T.Val(2));
@@ -176,7 +205,9 @@
 
 
 TEST(StringAdd) {
-  FunctionTester T("(function(a,b) { return %_StringAdd(a,b); })");
+  FLAG_turbo_inlining_intrinsics = true;
+  FLAG_turbo_deoptimization = true;
+  FunctionTester T("(function(a,b) { return %_StringAdd(a,b); })", flags);
 
   T.CheckCall(T.Val("aaabbb"), T.Val("aaa"), T.Val("bbb"));
   T.CheckCall(T.Val("aaa"), T.Val("aaa"), T.Val(""));
@@ -185,7 +216,9 @@
 
 
 TEST(StringSubString) {
-  FunctionTester T("(function(a,b) { return %_SubString(a,b,b+3); })");
+  FLAG_turbo_inlining_intrinsics = true;
+  FLAG_turbo_deoptimization = true;
+  FunctionTester T("(function(a,b) { return %_SubString(a,b,b+3); })", flags);
 
   T.CheckCall(T.Val("aaa"), T.Val("aaabbb"), T.Val(0.0));
   T.CheckCall(T.Val("abb"), T.Val("aaabbb"), T.Val(2));
@@ -194,7 +227,9 @@
 
 
 TEST(StringCompare) {
-  FunctionTester T("(function(a,b) { return %_StringCompare(a,b); })");
+  FLAG_turbo_inlining_intrinsics = true;
+  FLAG_turbo_deoptimization = true;
+  FunctionTester T("(function(a,b) { return %_StringCompare(a,b); })", flags);
 
   T.CheckCall(T.Val(-1), T.Val("aaa"), T.Val("bbb"));
   T.CheckCall(T.Val(0.0), T.Val("bbb"), T.Val("bbb"));
@@ -203,7 +238,10 @@
 
 
 TEST(CallFunction) {
-  FunctionTester T("(function(a,b) { return %_CallFunction(a, 1, 2, 3, b); })");
+  FLAG_turbo_inlining_intrinsics = true;
+  FLAG_turbo_deoptimization = true;
+  FunctionTester T("(function(a,b) { return %_CallFunction(a, 1, 2, 3, b); })",
+                   flags);
   CompileRun("function f(a,b,c) { return a + b + c + this.d; }");
 
   T.CheckCall(T.Val(129), T.NewObject("({d:123})"), T.NewObject("f"));
diff --git a/test/cctest/compiler/test-run-jsbranches.cc b/test/cctest/compiler/test-run-jsbranches.cc
index df2fcdc..7a4a0b3 100644
--- a/test/cctest/compiler/test-run-jsbranches.cc
+++ b/test/cctest/compiler/test-run-jsbranches.cc
@@ -280,3 +280,78 @@
   T.CheckCall(T.Val(2), T.Val(2), T.false_value());
   T.CheckCall(T.undefined(), T.Val(1), T.null());
 }
+
+
+TEST(IfTrue) {
+  FunctionTester T("(function(a,b) { if (true) return a; return b; })");
+
+  T.CheckCall(T.Val(55), T.Val(55), T.Val(11));
+  T.CheckCall(T.Val(666), T.Val(666), T.Val(-444));
+}
+
+
+TEST(TernaryTrue) {
+  FunctionTester T("(function(a,b) { return true ? a : b; })");
+
+  T.CheckCall(T.Val(77), T.Val(77), T.Val(11));
+  T.CheckCall(T.Val(111), T.Val(111), T.Val(-444));
+}
+
+
+TEST(IfFalse) {
+  FunctionTester T("(function(a,b) { if (false) return a; return b; })");
+
+  T.CheckCall(T.Val(11), T.Val(22), T.Val(11));
+  T.CheckCall(T.Val(-555), T.Val(333), T.Val(-555));
+}
+
+
+TEST(TernaryFalse) {
+  FunctionTester T("(function(a,b) { return false ? a : b; })");
+
+  T.CheckCall(T.Val(99), T.Val(33), T.Val(99));
+  T.CheckCall(T.Val(-99), T.Val(-33), T.Val(-99));
+}
+
+
+TEST(WhileTrue) {
+  FunctionTester T("(function(a,b) { while (true) return a; return b; })");
+
+  T.CheckCall(T.Val(551), T.Val(551), T.Val(111));
+  T.CheckCall(T.Val(661), T.Val(661), T.Val(-444));
+}
+
+
+TEST(WhileFalse) {
+  FunctionTester T("(function(a,b) { while (false) return a; return b; })");
+
+  T.CheckCall(T.Val(115), T.Val(551), T.Val(115));
+  T.CheckCall(T.Val(-445), T.Val(661), T.Val(-445));
+}
+
+
+TEST(DoWhileTrue) {
+  FunctionTester T(
+      "(function(a,b) { do { return a; } while (true); return b; })");
+
+  T.CheckCall(T.Val(7551), T.Val(7551), T.Val(7111));
+  T.CheckCall(T.Val(7661), T.Val(7661), T.Val(-7444));
+}
+
+
+TEST(DoWhileFalse) {
+  FunctionTester T(
+      "(function(a,b) { do { "
+      "; } while (false); return b; })");
+
+  T.CheckCall(T.Val(8115), T.Val(8551), T.Val(8115));
+  T.CheckCall(T.Val(-8445), T.Val(8661), T.Val(-8445));
+}
+
+
+TEST(EmptyFor) {
+  FunctionTester T("(function(a,b) { if (a) for(;;) ; return b; })");
+
+  T.CheckCall(T.Val(8126.1), T.Val(0.0), T.Val(8126.1));
+  T.CheckCall(T.Val(1123.1), T.Val(0.0), T.Val(1123.1));
+}
diff --git a/test/cctest/compiler/test-run-machops.cc b/test/cctest/compiler/test-run-machops.cc
index 985e0f8..974d4ce 100644
--- a/test/cctest/compiler/test-run-machops.cc
+++ b/test/cctest/compiler/test-run-machops.cc
@@ -2,11 +2,12 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
+#include <cmath>
 #include <functional>
 #include <limits>
 
 #include "src/base/bits.h"
-#include "src/compiler/generic-node-inl.h"
+#include "src/codegen.h"
 #include "test/cctest/cctest.h"
 #include "test/cctest/compiler/codegen-tester.h"
 #include "test/cctest/compiler/value-helper.h"
@@ -58,25 +59,25 @@
 TEST(CodeGenInt32Binop) {
   RawMachineAssemblerTester<void> m;
 
-  const Operator* ops[] = {
+  const Operator* kOps[] = {
       m.machine()->Word32And(),      m.machine()->Word32Or(),
       m.machine()->Word32Xor(),      m.machine()->Word32Shl(),
       m.machine()->Word32Shr(),      m.machine()->Word32Sar(),
       m.machine()->Word32Equal(),    m.machine()->Int32Add(),
       m.machine()->Int32Sub(),       m.machine()->Int32Mul(),
-      m.machine()->Int32Div(),       m.machine()->Int32UDiv(),
-      m.machine()->Int32Mod(),       m.machine()->Int32UMod(),
+      m.machine()->Int32MulHigh(),   m.machine()->Int32Div(),
+      m.machine()->Uint32Div(),      m.machine()->Int32Mod(),
+      m.machine()->Uint32Mod(),      m.machine()->Uint32MulHigh(),
       m.machine()->Int32LessThan(),  m.machine()->Int32LessThanOrEqual(),
-      m.machine()->Uint32LessThan(), m.machine()->Uint32LessThanOrEqual(),
-      NULL};
+      m.machine()->Uint32LessThan(), m.machine()->Uint32LessThanOrEqual()};
 
-  for (int i = 0; ops[i] != NULL; i++) {
+  for (size_t i = 0; i < arraysize(kOps); ++i) {
     for (int j = 0; j < 8; j++) {
       for (int k = 0; k < 8; k++) {
         RawMachineAssemblerTester<int32_t> m(kMachInt32, kMachInt32);
         Node* a = Int32Input(&m, j);
         Node* b = Int32Input(&m, k);
-        m.Return(m.NewNode(ops[i], a, b));
+        m.Return(m.NewNode(kOps[i], a, b));
         m.GenerateCode();
       }
     }
@@ -127,51 +128,6 @@
 }
 
 
-TEST(RunRedundantBranch1) {
-  RawMachineAssemblerTester<int32_t> m;
-  int constant = 944777;
-
-  MLabel blocka;
-  m.Branch(m.Int32Constant(0), &blocka, &blocka);
-  m.Bind(&blocka);
-  m.Return(m.Int32Constant(constant));
-
-  CHECK_EQ(constant, m.Call());
-}
-
-
-TEST(RunRedundantBranch2) {
-  RawMachineAssemblerTester<int32_t> m;
-  int constant = 955777;
-
-  MLabel blocka, blockb;
-  m.Branch(m.Int32Constant(0), &blocka, &blocka);
-  m.Bind(&blockb);
-  m.Goto(&blocka);
-  m.Bind(&blocka);
-  m.Return(m.Int32Constant(constant));
-
-  CHECK_EQ(constant, m.Call());
-}
-
-
-TEST(RunRedundantBranch3) {
-  RawMachineAssemblerTester<int32_t> m;
-  int constant = 966777;
-
-  MLabel blocka, blockb, blockc;
-  m.Branch(m.Int32Constant(0), &blocka, &blockc);
-  m.Bind(&blocka);
-  m.Branch(m.Int32Constant(0), &blockb, &blockb);
-  m.Bind(&blockc);
-  m.Goto(&blockb);
-  m.Bind(&blockb);
-  m.Return(m.Int32Constant(constant));
-
-  CHECK_EQ(constant, m.Call());
-}
-
-
 TEST(RunDiamond2) {
   RawMachineAssemblerTester<int32_t> m;
 
@@ -571,6 +527,142 @@
 }
 
 
+TEST(RunInt32AddAndWord32EqualP) {
+  {
+    RawMachineAssemblerTester<int32_t> m(kMachInt32, kMachInt32, kMachInt32);
+    m.Return(m.Int32Add(m.Parameter(0),
+                        m.Word32Equal(m.Parameter(1), m.Parameter(2))));
+    FOR_INT32_INPUTS(i) {
+      FOR_INT32_INPUTS(j) {
+        FOR_INT32_INPUTS(k) {
+          // Use uint32_t because signed overflow is UB in C.
+          int32_t const expected =
+              bit_cast<int32_t>(bit_cast<uint32_t>(*i) + (*j == *k));
+          CHECK_EQ(expected, m.Call(*i, *j, *k));
+        }
+      }
+    }
+  }
+  {
+    RawMachineAssemblerTester<int32_t> m(kMachInt32, kMachInt32, kMachInt32);
+    m.Return(m.Int32Add(m.Word32Equal(m.Parameter(0), m.Parameter(1)),
+                        m.Parameter(2)));
+    FOR_INT32_INPUTS(i) {
+      FOR_INT32_INPUTS(j) {
+        FOR_INT32_INPUTS(k) {
+          // Use uint32_t because signed overflow is UB in C.
+          int32_t const expected =
+              bit_cast<int32_t>((*i == *j) + bit_cast<uint32_t>(*k));
+          CHECK_EQ(expected, m.Call(*i, *j, *k));
+        }
+      }
+    }
+  }
+}
+
+
+TEST(RunInt32AddAndWord32EqualImm) {
+  {
+    FOR_INT32_INPUTS(i) {
+      RawMachineAssemblerTester<int32_t> m(kMachInt32, kMachInt32);
+      m.Return(m.Int32Add(m.Int32Constant(*i),
+                          m.Word32Equal(m.Parameter(0), m.Parameter(1))));
+      FOR_INT32_INPUTS(j) {
+        FOR_INT32_INPUTS(k) {
+          // Use uint32_t because signed overflow is UB in C.
+          int32_t const expected =
+              bit_cast<int32_t>(bit_cast<uint32_t>(*i) + (*j == *k));
+          CHECK_EQ(expected, m.Call(*j, *k));
+        }
+      }
+    }
+  }
+  {
+    FOR_INT32_INPUTS(i) {
+      RawMachineAssemblerTester<int32_t> m(kMachInt32, kMachInt32);
+      m.Return(m.Int32Add(m.Word32Equal(m.Int32Constant(*i), m.Parameter(0)),
+                          m.Parameter(1)));
+      FOR_INT32_INPUTS(j) {
+        FOR_INT32_INPUTS(k) {
+          // Use uint32_t because signed overflow is UB in C.
+          int32_t const expected =
+              bit_cast<int32_t>((*i == *j) + bit_cast<uint32_t>(*k));
+          CHECK_EQ(expected, m.Call(*j, *k));
+        }
+      }
+    }
+  }
+}
+
+
+TEST(RunInt32AddAndWord32NotEqualP) {
+  {
+    RawMachineAssemblerTester<int32_t> m(kMachInt32, kMachInt32, kMachInt32);
+    m.Return(m.Int32Add(m.Parameter(0),
+                        m.Word32NotEqual(m.Parameter(1), m.Parameter(2))));
+    FOR_INT32_INPUTS(i) {
+      FOR_INT32_INPUTS(j) {
+        FOR_INT32_INPUTS(k) {
+          // Use uint32_t because signed overflow is UB in C.
+          int32_t const expected =
+              bit_cast<int32_t>(bit_cast<uint32_t>(*i) + (*j != *k));
+          CHECK_EQ(expected, m.Call(*i, *j, *k));
+        }
+      }
+    }
+  }
+  {
+    RawMachineAssemblerTester<int32_t> m(kMachInt32, kMachInt32, kMachInt32);
+    m.Return(m.Int32Add(m.Word32NotEqual(m.Parameter(0), m.Parameter(1)),
+                        m.Parameter(2)));
+    FOR_INT32_INPUTS(i) {
+      FOR_INT32_INPUTS(j) {
+        FOR_INT32_INPUTS(k) {
+          // Use uint32_t because signed overflow is UB in C.
+          int32_t const expected =
+              bit_cast<int32_t>((*i != *j) + bit_cast<uint32_t>(*k));
+          CHECK_EQ(expected, m.Call(*i, *j, *k));
+        }
+      }
+    }
+  }
+}
+
+
+TEST(RunInt32AddAndWord32NotEqualImm) {
+  {
+    FOR_INT32_INPUTS(i) {
+      RawMachineAssemblerTester<int32_t> m(kMachInt32, kMachInt32);
+      m.Return(m.Int32Add(m.Int32Constant(*i),
+                          m.Word32NotEqual(m.Parameter(0), m.Parameter(1))));
+      FOR_INT32_INPUTS(j) {
+        FOR_INT32_INPUTS(k) {
+          // Use uint32_t because signed overflow is UB in C.
+          int32_t const expected =
+              bit_cast<int32_t>(bit_cast<uint32_t>(*i) + (*j != *k));
+          CHECK_EQ(expected, m.Call(*j, *k));
+        }
+      }
+    }
+  }
+  {
+    FOR_INT32_INPUTS(i) {
+      RawMachineAssemblerTester<int32_t> m(kMachInt32, kMachInt32);
+      m.Return(m.Int32Add(m.Word32NotEqual(m.Int32Constant(*i), m.Parameter(0)),
+                          m.Parameter(1)));
+      FOR_INT32_INPUTS(j) {
+        FOR_INT32_INPUTS(k) {
+          // Use uint32_t because signed overflow is UB in C.
+          int32_t const expected =
+              bit_cast<int32_t>((*i != *j) + bit_cast<uint32_t>(*k));
+          CHECK_EQ(expected, m.Call(*j, *k));
+        }
+      }
+    }
+  }
+}
+
+
 TEST(RunInt32AddAndWord32SarP) {
   {
     RawMachineAssemblerTester<int32_t> m(kMachUint32, kMachInt32, kMachUint32);
@@ -1233,6 +1325,20 @@
 }
 
 
+TEST(RunInt32MulHighP) {
+  RawMachineAssemblerTester<int32_t> m;
+  Int32BinopTester bt(&m);
+  bt.AddReturn(m.Int32MulHigh(bt.param0, bt.param1));
+  FOR_INT32_INPUTS(i) {
+    FOR_INT32_INPUTS(j) {
+      int32_t expected = static_cast<int32_t>(
+          (static_cast<int64_t>(*i) * static_cast<int64_t>(*j)) >> 32);
+      CHECK_EQ(expected, bt.call(*i, *j));
+    }
+  }
+}
+
+
 TEST(RunInt32MulImm) {
   {
     FOR_UINT32_INPUTS(i) {
@@ -1259,6 +1365,22 @@
 
 TEST(RunInt32MulAndInt32AddP) {
   {
+    FOR_INT32_INPUTS(i) {
+      FOR_INT32_INPUTS(j) {
+        RawMachineAssemblerTester<int32_t> m(kMachInt32);
+        int32_t p0 = *i;
+        int32_t p1 = *j;
+        m.Return(m.Int32Add(m.Int32Constant(p0),
+                            m.Int32Mul(m.Parameter(0), m.Int32Constant(p1))));
+        FOR_INT32_INPUTS(k) {
+          int32_t p2 = *k;
+          int expected = p0 + static_cast<int32_t>(p1 * p2);
+          CHECK_EQ(expected, m.Call(p2));
+        }
+      }
+    }
+  }
+  {
     RawMachineAssemblerTester<int32_t> m(kMachInt32, kMachInt32, kMachInt32);
     m.Return(
         m.Int32Add(m.Parameter(0), m.Int32Mul(m.Parameter(1), m.Parameter(2))));
@@ -1347,6 +1469,20 @@
 }
 
 
+TEST(RunUint32MulHighP) {
+  RawMachineAssemblerTester<int32_t> m;
+  Int32BinopTester bt(&m);
+  bt.AddReturn(m.Uint32MulHigh(bt.param0, bt.param1));
+  FOR_UINT32_INPUTS(i) {
+    FOR_UINT32_INPUTS(j) {
+      int32_t expected = bit_cast<int32_t>(static_cast<uint32_t>(
+          (static_cast<uint64_t>(*i) * static_cast<uint64_t>(*j)) >> 32));
+      CHECK_EQ(expected, bt.call(bit_cast<int32_t>(*i), bit_cast<int32_t>(*j)));
+    }
+  }
+}
+
+
 TEST(RunInt32DivP) {
   {
     RawMachineAssemblerTester<int32_t> m;
@@ -1381,11 +1517,11 @@
 }
 
 
-TEST(RunInt32UDivP) {
+TEST(RunUint32DivP) {
   {
     RawMachineAssemblerTester<int32_t> m;
     Int32BinopTester bt(&m);
-    bt.AddReturn(m.Int32UDiv(bt.param0, bt.param1));
+    bt.AddReturn(m.Uint32Div(bt.param0, bt.param1));
     FOR_UINT32_INPUTS(i) {
       FOR_UINT32_INPUTS(j) {
         uint32_t p0 = *i;
@@ -1400,7 +1536,7 @@
   {
     RawMachineAssemblerTester<int32_t> m;
     Int32BinopTester bt(&m);
-    bt.AddReturn(m.Int32Add(bt.param0, m.Int32UDiv(bt.param0, bt.param1)));
+    bt.AddReturn(m.Int32Add(bt.param0, m.Uint32Div(bt.param0, bt.param1)));
     FOR_UINT32_INPUTS(i) {
       FOR_UINT32_INPUTS(j) {
         uint32_t p0 = *i;
@@ -1449,11 +1585,11 @@
 }
 
 
-TEST(RunInt32UModP) {
+TEST(RunUint32ModP) {
   {
     RawMachineAssemblerTester<int32_t> m;
     Int32BinopTester bt(&m);
-    bt.AddReturn(m.Int32UMod(bt.param0, bt.param1));
+    bt.AddReturn(m.Uint32Mod(bt.param0, bt.param1));
     FOR_UINT32_INPUTS(i) {
       FOR_UINT32_INPUTS(j) {
         uint32_t p0 = *i;
@@ -1468,7 +1604,7 @@
   {
     RawMachineAssemblerTester<int32_t> m;
     Int32BinopTester bt(&m);
-    bt.AddReturn(m.Int32Add(bt.param0, m.Int32UMod(bt.param0, bt.param1)));
+    bt.AddReturn(m.Int32Add(bt.param0, m.Uint32Mod(bt.param0, bt.param1)));
     FOR_UINT32_INPUTS(i) {
       FOR_UINT32_INPUTS(j) {
         uint32_t p0 = *i;
@@ -2658,22 +2794,23 @@
 TEST(RunDeadInt32Binops) {
   RawMachineAssemblerTester<int32_t> m;
 
-  const Operator* ops[] = {
-      m.machine()->Word32And(),             m.machine()->Word32Or(),
-      m.machine()->Word32Xor(),             m.machine()->Word32Shl(),
-      m.machine()->Word32Shr(),             m.machine()->Word32Sar(),
-      m.machine()->Word32Ror(),             m.machine()->Word32Equal(),
-      m.machine()->Int32Add(),              m.machine()->Int32Sub(),
-      m.machine()->Int32Mul(),              m.machine()->Int32Div(),
-      m.machine()->Int32UDiv(),             m.machine()->Int32Mod(),
-      m.machine()->Int32UMod(),             m.machine()->Int32LessThan(),
-      m.machine()->Int32LessThanOrEqual(),  m.machine()->Uint32LessThan(),
-      m.machine()->Uint32LessThanOrEqual(), NULL};
+  const Operator* kOps[] = {
+      m.machine()->Word32And(),            m.machine()->Word32Or(),
+      m.machine()->Word32Xor(),            m.machine()->Word32Shl(),
+      m.machine()->Word32Shr(),            m.machine()->Word32Sar(),
+      m.machine()->Word32Ror(),            m.machine()->Word32Equal(),
+      m.machine()->Int32Add(),             m.machine()->Int32Sub(),
+      m.machine()->Int32Mul(),             m.machine()->Int32MulHigh(),
+      m.machine()->Int32Div(),             m.machine()->Uint32Div(),
+      m.machine()->Int32Mod(),             m.machine()->Uint32Mod(),
+      m.machine()->Uint32MulHigh(),        m.machine()->Int32LessThan(),
+      m.machine()->Int32LessThanOrEqual(), m.machine()->Uint32LessThan(),
+      m.machine()->Uint32LessThanOrEqual()};
 
-  for (int i = 0; ops[i] != NULL; i++) {
+  for (size_t i = 0; i < arraysize(kOps); ++i) {
     RawMachineAssemblerTester<int32_t> m(kMachInt32, kMachInt32);
-    int constant = 0x55555 + i;
-    m.NewNode(ops[i], m.Parameter(0), m.Parameter(1));
+    int32_t constant = static_cast<int32_t>(0x55555 + i);
+    m.NewNode(kOps[i], m.Parameter(0), m.Parameter(1));
     m.Return(m.Int32Constant(constant));
 
     CHECK_EQ(constant, m.Call(1, 1));
@@ -3102,6 +3239,38 @@
 }
 
 
+TEST(RunChangeUint32ToFloat64_spilled) {
+  RawMachineAssemblerTester<int32_t> m;
+  const int kNumInputs = 32;
+  int32_t magic = 0x786234;
+  uint32_t input[kNumInputs];
+  double result[kNumInputs];
+  Node* input_node[kNumInputs];
+
+  for (int i = 0; i < kNumInputs; i++) {
+    input_node[i] =
+        m.Load(kMachUint32, m.PointerConstant(&input), m.Int32Constant(i * 4));
+  }
+
+  for (int i = 0; i < kNumInputs; i++) {
+    m.Store(kMachFloat64, m.PointerConstant(&result), m.Int32Constant(i * 8),
+            m.ChangeUint32ToFloat64(input_node[i]));
+  }
+
+  m.Return(m.Int32Constant(magic));
+
+  for (int i = 0; i < kNumInputs; i++) {
+    input[i] = 100 + i;
+  }
+
+  CHECK_EQ(magic, m.Call());
+
+  for (int i = 0; i < kNumInputs; i++) {
+    CHECK_EQ(result[i], static_cast<double>(100 + i));
+  }
+}
+
+
 TEST(RunChangeFloat64ToInt32_A) {
   RawMachineAssemblerTester<int32_t> m;
   int32_t magic = 0x786234;
@@ -3272,6 +3441,38 @@
 }
 
 
+TEST(RunTruncateFloat64ToFloat32_spilled) {
+  RawMachineAssemblerTester<uint32_t> m;
+  const int kNumInputs = 32;
+  int32_t magic = 0x786234;
+  double input[kNumInputs];
+  float result[kNumInputs];
+  Node* input_node[kNumInputs];
+
+  for (int i = 0; i < kNumInputs; i++) {
+    input_node[i] =
+        m.Load(kMachFloat64, m.PointerConstant(&input), m.Int32Constant(i * 8));
+  }
+
+  for (int i = 0; i < kNumInputs; i++) {
+    m.Store(kMachFloat32, m.PointerConstant(&result), m.Int32Constant(i * 4),
+            m.TruncateFloat64ToFloat32(input_node[i]));
+  }
+
+  m.Return(m.Int32Constant(magic));
+
+  for (int i = 0; i < kNumInputs; i++) {
+    input[i] = 0.1 + i;
+  }
+
+  CHECK_EQ(magic, m.Call());
+
+  for (int i = 0; i < kNumInputs; i++) {
+    CHECK_EQ(result[i], DoubleToFloat32(input[i]));
+  }
+}
+
+
 TEST(RunDeadChangeFloat64ToInt32) {
   RawMachineAssemblerTester<int32_t> m;
   const int magic = 0x88abcda4;
@@ -4242,4 +4443,249 @@
   }
 }
 
+
+TEST(RunChangeFloat32ToFloat64) {
+  double actual = 0.0f;
+  float expected = 0.0;
+  RawMachineAssemblerTester<int32_t> m;
+  m.StoreToPointer(
+      &actual, kMachFloat64,
+      m.ChangeFloat32ToFloat64(m.LoadFromPointer(&expected, kMachFloat32)));
+  m.Return(m.Int32Constant(0));
+  FOR_FLOAT32_INPUTS(i) {
+    expected = *i;
+    CHECK_EQ(0, m.Call());
+    CHECK_EQ(expected, actual);
+  }
+}
+
+
+TEST(RunChangeFloat32ToFloat64_spilled) {
+  RawMachineAssemblerTester<int32_t> m;
+  const int kNumInputs = 32;
+  int32_t magic = 0x786234;
+  float input[kNumInputs];
+  double result[kNumInputs];
+  Node* input_node[kNumInputs];
+
+  for (int i = 0; i < kNumInputs; i++) {
+    input_node[i] =
+        m.Load(kMachFloat32, m.PointerConstant(&input), m.Int32Constant(i * 4));
+  }
+
+  for (int i = 0; i < kNumInputs; i++) {
+    m.Store(kMachFloat64, m.PointerConstant(&result), m.Int32Constant(i * 8),
+            m.ChangeFloat32ToFloat64(input_node[i]));
+  }
+
+  m.Return(m.Int32Constant(magic));
+
+  for (int i = 0; i < kNumInputs; i++) {
+    input[i] = 100.9f + i;
+  }
+
+  CHECK_EQ(magic, m.Call());
+
+  for (int i = 0; i < kNumInputs; i++) {
+    CHECK_EQ(result[i], static_cast<double>(input[i]));
+  }
+}
+
+
+TEST(RunTruncateFloat64ToFloat32) {
+  float actual = 0.0f;
+  double input = 0.0;
+  RawMachineAssemblerTester<int32_t> m;
+  m.StoreToPointer(
+      &actual, kMachFloat32,
+      m.TruncateFloat64ToFloat32(m.LoadFromPointer(&input, kMachFloat64)));
+  m.Return(m.Int32Constant(0));
+  FOR_FLOAT64_INPUTS(i) {
+    input = *i;
+    volatile double expected = DoubleToFloat32(input);
+    CHECK_EQ(0, m.Call());
+    CHECK_EQ(expected, actual);
+  }
+}
+
+
+TEST(RunFloat32Constant) {
+  FOR_FLOAT32_INPUTS(i) {
+    float expected = *i;
+    float actual = *i;
+    RawMachineAssemblerTester<int32_t> m;
+    m.StoreToPointer(&actual, kMachFloat32, m.Float32Constant(expected));
+    m.Return(m.Int32Constant(0));
+    CHECK_EQ(0, m.Call());
+    CHECK_EQ(expected, actual);
+  }
+}
+
+
+static double two_30 = 1 << 30;             // 2^30 is a smi boundary.
+static double two_52 = two_30 * (1 << 22);  // 2^52 is a precision boundary.
+static double kValues[] = {0.1,
+                           0.2,
+                           0.49999999999999994,
+                           0.5,
+                           0.7,
+                           1.0 - std::numeric_limits<double>::epsilon(),
+                           -0.1,
+                           -0.49999999999999994,
+                           -0.5,
+                           -0.7,
+                           1.1,
+                           1.0 + std::numeric_limits<double>::epsilon(),
+                           1.5,
+                           1.7,
+                           -1,
+                           -1 + std::numeric_limits<double>::epsilon(),
+                           -1 - std::numeric_limits<double>::epsilon(),
+                           -1.1,
+                           -1.5,
+                           -1.7,
+                           std::numeric_limits<double>::min(),
+                           -std::numeric_limits<double>::min(),
+                           std::numeric_limits<double>::max(),
+                           -std::numeric_limits<double>::max(),
+                           std::numeric_limits<double>::infinity(),
+                           -std::numeric_limits<double>::infinity(),
+                           two_30,
+                           two_30 + 0.1,
+                           two_30 + 0.5,
+                           two_30 + 0.7,
+                           two_30 - 1,
+                           two_30 - 1 + 0.1,
+                           two_30 - 1 + 0.5,
+                           two_30 - 1 + 0.7,
+                           -two_30,
+                           -two_30 + 0.1,
+                           -two_30 + 0.5,
+                           -two_30 + 0.7,
+                           -two_30 + 1,
+                           -two_30 + 1 + 0.1,
+                           -two_30 + 1 + 0.5,
+                           -two_30 + 1 + 0.7,
+                           two_52,
+                           two_52 + 0.1,
+                           two_52 + 0.5,
+                           two_52 + 0.5,
+                           two_52 + 0.7,
+                           two_52 + 0.7,
+                           two_52 - 1,
+                           two_52 - 1 + 0.1,
+                           two_52 - 1 + 0.5,
+                           two_52 - 1 + 0.7,
+                           -two_52,
+                           -two_52 + 0.1,
+                           -two_52 + 0.5,
+                           -two_52 + 0.7,
+                           -two_52 + 1,
+                           -two_52 + 1 + 0.1,
+                           -two_52 + 1 + 0.5,
+                           -two_52 + 1 + 0.7,
+                           two_30,
+                           two_30 - 0.1,
+                           two_30 - 0.5,
+                           two_30 - 0.7,
+                           two_30 - 1,
+                           two_30 - 1 - 0.1,
+                           two_30 - 1 - 0.5,
+                           two_30 - 1 - 0.7,
+                           -two_30,
+                           -two_30 - 0.1,
+                           -two_30 - 0.5,
+                           -two_30 - 0.7,
+                           -two_30 + 1,
+                           -two_30 + 1 - 0.1,
+                           -two_30 + 1 - 0.5,
+                           -two_30 + 1 - 0.7,
+                           two_52,
+                           two_52 - 0.1,
+                           two_52 - 0.5,
+                           two_52 - 0.5,
+                           two_52 - 0.7,
+                           two_52 - 0.7,
+                           two_52 - 1,
+                           two_52 - 1 - 0.1,
+                           two_52 - 1 - 0.5,
+                           two_52 - 1 - 0.7,
+                           -two_52,
+                           -two_52 - 0.1,
+                           -two_52 - 0.5,
+                           -two_52 - 0.7,
+                           -two_52 + 1,
+                           -two_52 + 1 - 0.1,
+                           -two_52 + 1 - 0.5,
+                           -two_52 + 1 - 0.7};
+
+
+TEST(RunFloat64Floor) {
+  double input = -1.0;
+  double result = 0.0;
+  RawMachineAssemblerTester<int32_t> m;
+  if (!m.machine()->HasFloat64Floor()) return;
+  m.StoreToPointer(&result, kMachFloat64,
+                   m.Float64Floor(m.LoadFromPointer(&input, kMachFloat64)));
+  m.Return(m.Int32Constant(0));
+  for (size_t i = 0; i < arraysize(kValues); ++i) {
+    input = kValues[i];
+    CHECK_EQ(0, m.Call());
+    double expected = std::floor(kValues[i]);
+    CHECK_EQ(expected, result);
+  }
+}
+
+
+TEST(RunFloat64Ceil) {
+  double input = -1.0;
+  double result = 0.0;
+  RawMachineAssemblerTester<int32_t> m;
+  if (!m.machine()->HasFloat64Ceil()) return;
+  m.StoreToPointer(&result, kMachFloat64,
+                   m.Float64Ceil(m.LoadFromPointer(&input, kMachFloat64)));
+  m.Return(m.Int32Constant(0));
+  for (size_t i = 0; i < arraysize(kValues); ++i) {
+    input = kValues[i];
+    CHECK_EQ(0, m.Call());
+    double expected = std::ceil(kValues[i]);
+    CHECK_EQ(expected, result);
+  }
+}
+
+
+TEST(RunFloat64RoundTruncate) {
+  double input = -1.0;
+  double result = 0.0;
+  RawMachineAssemblerTester<int32_t> m;
+  if (!m.machine()->HasFloat64Ceil()) return;
+  m.StoreToPointer(
+      &result, kMachFloat64,
+      m.Float64RoundTruncate(m.LoadFromPointer(&input, kMachFloat64)));
+  m.Return(m.Int32Constant(0));
+  for (size_t i = 0; i < arraysize(kValues); ++i) {
+    input = kValues[i];
+    CHECK_EQ(0, m.Call());
+    double expected = trunc(kValues[i]);
+    CHECK_EQ(expected, result);
+  }
+}
+
+
+TEST(RunFloat64RoundTiesAway) {
+  double input = -1.0;
+  double result = 0.0;
+  RawMachineAssemblerTester<int32_t> m;
+  if (!m.machine()->HasFloat64RoundTiesAway()) return;
+  m.StoreToPointer(
+      &result, kMachFloat64,
+      m.Float64RoundTiesAway(m.LoadFromPointer(&input, kMachFloat64)));
+  m.Return(m.Int32Constant(0));
+  for (size_t i = 0; i < arraysize(kValues); ++i) {
+    input = kValues[i];
+    CHECK_EQ(0, m.Call());
+    double expected = round(kValues[i]);
+    CHECK_EQ(expected, result);
+  }
+}
 #endif  // V8_TURBOFAN_TARGET
diff --git a/test/cctest/compiler/test-run-stackcheck.cc b/test/cctest/compiler/test-run-stackcheck.cc
new file mode 100644
index 0000000..8c1664b
--- /dev/null
+++ b/test/cctest/compiler/test-run-stackcheck.cc
@@ -0,0 +1,18 @@
+// 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.
+
+#include "src/v8.h"
+
+#include "test/cctest/compiler/function-tester.h"
+
+using namespace v8::internal;
+using namespace v8::internal::compiler;
+
+TEST(TerminateAtMethodEntry) {
+  FunctionTester T("(function(a,b) { return 23; })");
+
+  T.CheckCall(T.Val(23));
+  T.isolate->stack_guard()->RequestTerminateExecution();
+  T.CheckThrows(T.undefined(), T.undefined());
+}
diff --git a/test/cctest/compiler/test-schedule.cc b/test/cctest/compiler/test-schedule.cc
index 6c05c05..1eb3547 100644
--- a/test/cctest/compiler/test-schedule.cc
+++ b/test/cctest/compiler/test-schedule.cc
@@ -5,7 +5,6 @@
 #include "src/v8.h"
 
 #include "src/compiler/common-operator.h"
-#include "src/compiler/generic-node-inl.h"
 #include "src/compiler/graph.h"
 #include "src/compiler/machine-operator.h"
 #include "src/compiler/node.h"
@@ -16,26 +15,25 @@
 using namespace v8::internal;
 using namespace v8::internal::compiler;
 
-static SimpleOperator dummy_operator(IrOpcode::kParameter, Operator::kNoWrite,
-                                     0, 0, "dummy");
+static Operator dummy_operator(IrOpcode::kParameter, Operator::kNoWrite,
+                               "dummy", 0, 0, 0, 0, 0, 0);
 
 TEST(TestScheduleAllocation) {
   HandleAndZoneScope scope;
   Schedule schedule(scope.main_zone());
 
   CHECK_NE(NULL, schedule.start());
-  CHECK_EQ(schedule.start(), *(schedule.all_blocks().begin()));
+  CHECK_EQ(schedule.start(), schedule.GetBlockById(BasicBlock::Id::FromInt(0)));
 }
 
 
 TEST(TestScheduleAddNode) {
   HandleAndZoneScope scope;
+  Schedule schedule(scope.main_zone());
   Graph graph(scope.main_zone());
   Node* n0 = graph.NewNode(&dummy_operator);
   Node* n1 = graph.NewNode(&dummy_operator);
 
-  Schedule schedule(scope.main_zone());
-
   BasicBlock* entry = schedule.start();
   schedule.AddNode(entry, n0);
   schedule.AddNode(entry, n1);
@@ -51,50 +49,49 @@
 
 TEST(TestScheduleAddGoto) {
   HandleAndZoneScope scope;
-
   Schedule schedule(scope.main_zone());
+
   BasicBlock* entry = schedule.start();
   BasicBlock* next = schedule.NewBasicBlock();
 
   schedule.AddGoto(entry, next);
 
-  CHECK_EQ(0, entry->PredecessorCount());
-  CHECK_EQ(1, entry->SuccessorCount());
+  CHECK_EQ(0, static_cast<int>(entry->PredecessorCount()));
+  CHECK_EQ(1, static_cast<int>(entry->SuccessorCount()));
   CHECK_EQ(next, entry->SuccessorAt(0));
 
-  CHECK_EQ(1, next->PredecessorCount());
+  CHECK_EQ(1, static_cast<int>(next->PredecessorCount()));
   CHECK_EQ(entry, next->PredecessorAt(0));
-  CHECK_EQ(0, next->SuccessorCount());
+  CHECK_EQ(0, static_cast<int>(next->SuccessorCount()));
 }
 
 
 TEST(TestScheduleAddBranch) {
   HandleAndZoneScope scope;
   Schedule schedule(scope.main_zone());
-
-  BasicBlock* entry = schedule.start();
-  BasicBlock* tblock = schedule.NewBasicBlock();
-  BasicBlock* fblock = schedule.NewBasicBlock();
-
   Graph graph(scope.main_zone());
   CommonOperatorBuilder common(scope.main_zone());
   Node* n0 = graph.NewNode(&dummy_operator);
   Node* b = graph.NewNode(common.Branch(), n0);
 
+  BasicBlock* entry = schedule.start();
+  BasicBlock* tblock = schedule.NewBasicBlock();
+  BasicBlock* fblock = schedule.NewBasicBlock();
+
   schedule.AddBranch(entry, b, tblock, fblock);
 
-  CHECK_EQ(0, entry->PredecessorCount());
-  CHECK_EQ(2, entry->SuccessorCount());
+  CHECK_EQ(0, static_cast<int>(entry->PredecessorCount()));
+  CHECK_EQ(2, static_cast<int>(entry->SuccessorCount()));
   CHECK_EQ(tblock, entry->SuccessorAt(0));
   CHECK_EQ(fblock, entry->SuccessorAt(1));
 
-  CHECK_EQ(1, tblock->PredecessorCount());
+  CHECK_EQ(1, static_cast<int>(tblock->PredecessorCount()));
   CHECK_EQ(entry, tblock->PredecessorAt(0));
-  CHECK_EQ(0, tblock->SuccessorCount());
+  CHECK_EQ(0, static_cast<int>(tblock->SuccessorCount()));
 
-  CHECK_EQ(1, fblock->PredecessorCount());
+  CHECK_EQ(1, static_cast<int>(fblock->PredecessorCount()));
   CHECK_EQ(entry, fblock->PredecessorAt(0));
-  CHECK_EQ(0, fblock->SuccessorCount());
+  CHECK_EQ(0, static_cast<int>(fblock->SuccessorCount()));
 }
 
 
@@ -106,8 +103,8 @@
   BasicBlock* entry = schedule.start();
   schedule.AddReturn(entry, n0);
 
-  CHECK_EQ(0, entry->PredecessorCount());
-  CHECK_EQ(1, entry->SuccessorCount());
+  CHECK_EQ(0, static_cast<int>(entry->PredecessorCount()));
+  CHECK_EQ(1, static_cast<int>(entry->SuccessorCount()));
   CHECK_EQ(schedule.end(), entry->SuccessorAt(0));
 }
 
@@ -120,18 +117,53 @@
   BasicBlock* entry = schedule.start();
   schedule.AddThrow(entry, n0);
 
-  CHECK_EQ(0, entry->PredecessorCount());
-  CHECK_EQ(1, entry->SuccessorCount());
+  CHECK_EQ(0, static_cast<int>(entry->PredecessorCount()));
+  CHECK_EQ(1, static_cast<int>(entry->SuccessorCount()));
   CHECK_EQ(schedule.end(), entry->SuccessorAt(0));
 }
 
 
+TEST(TestScheduleInsertBranch) {
+  HandleAndZoneScope scope;
+  Schedule schedule(scope.main_zone());
+  Graph graph(scope.main_zone());
+  CommonOperatorBuilder common(scope.main_zone());
+  Node* n0 = graph.NewNode(&dummy_operator);
+  Node* n1 = graph.NewNode(&dummy_operator);
+  Node* b = graph.NewNode(common.Branch(), n1);
+
+  BasicBlock* entry = schedule.start();
+  BasicBlock* tblock = schedule.NewBasicBlock();
+  BasicBlock* fblock = schedule.NewBasicBlock();
+  BasicBlock* merge = schedule.NewBasicBlock();
+  schedule.AddReturn(entry, n0);
+  schedule.AddGoto(tblock, merge);
+  schedule.AddGoto(fblock, merge);
+
+  schedule.InsertBranch(entry, merge, b, tblock, fblock);
+
+  CHECK_EQ(0, static_cast<int>(entry->PredecessorCount()));
+  CHECK_EQ(2, static_cast<int>(entry->SuccessorCount()));
+  CHECK_EQ(tblock, entry->SuccessorAt(0));
+  CHECK_EQ(fblock, entry->SuccessorAt(1));
+
+  CHECK_EQ(2, static_cast<int>(merge->PredecessorCount()));
+  CHECK_EQ(1, static_cast<int>(merge->SuccessorCount()));
+  CHECK_EQ(schedule.end(), merge->SuccessorAt(0));
+
+  CHECK_EQ(1, static_cast<int>(schedule.end()->PredecessorCount()));
+  CHECK_EQ(0, static_cast<int>(schedule.end()->SuccessorCount()));
+  CHECK_EQ(merge, schedule.end()->PredecessorAt(0));
+}
+
+
 TEST(BuildMulNodeGraph) {
   HandleAndZoneScope scope;
   Schedule schedule(scope.main_zone());
   Graph graph(scope.main_zone());
   CommonOperatorBuilder common(scope.main_zone());
-  MachineOperatorBuilder machine;
+  // TODO(titzer): use test operators.
+  MachineOperatorBuilder machine(scope.main_zone());
 
   Node* start = graph.NewNode(common.Start(0));
   graph.SetStart(start);
diff --git a/test/cctest/compiler/test-scheduler.cc b/test/cctest/compiler/test-scheduler.cc
index cf33123..1b79ed5 100644
--- a/test/cctest/compiler/test-scheduler.cc
+++ b/test/cctest/compiler/test-scheduler.cc
@@ -3,31 +3,71 @@
 // found in the LICENSE file.
 
 #include "src/v8.h"
-#include "test/cctest/cctest.h"
 
+#include "src/compiler/access-builder.h"
 #include "src/compiler/common-operator.h"
-#include "src/compiler/generic-node-inl.h"
-#include "src/compiler/generic-node.h"
 #include "src/compiler/graph.h"
 #include "src/compiler/graph-visualizer.h"
 #include "src/compiler/js-operator.h"
-#include "src/compiler/machine-operator.h"
 #include "src/compiler/node.h"
+#include "src/compiler/opcodes.h"
 #include "src/compiler/operator.h"
 #include "src/compiler/schedule.h"
 #include "src/compiler/scheduler.h"
+#include "src/compiler/simplified-operator.h"
 #include "src/compiler/verifier.h"
+#include "test/cctest/cctest.h"
 
 using namespace v8::internal;
 using namespace v8::internal::compiler;
 
+Operator kIntAdd(IrOpcode::kInt32Add, Operator::kPure, "Int32Add", 2, 0, 0, 1,
+                 0, 0);
+
 // TODO(titzer): pull RPO tests out to their own file.
+static void CheckRPONumbers(BasicBlockVector* order, size_t expected,
+                            bool loops_allowed) {
+  CHECK(expected == order->size());
+  for (int i = 0; i < static_cast<int>(order->size()); i++) {
+    CHECK(order->at(i)->rpo_number() == i);
+    if (!loops_allowed) {
+      CHECK_EQ(NULL, order->at(i)->loop_end());
+      CHECK_EQ(NULL, order->at(i)->loop_header());
+    }
+  }
+}
+
+
+static void CheckLoop(BasicBlockVector* order, BasicBlock** blocks,
+                      int body_size) {
+  BasicBlock* header = blocks[0];
+  BasicBlock* end = header->loop_end();
+  CHECK_NE(NULL, end);
+  CHECK_GT(end->rpo_number(), 0);
+  CHECK_EQ(body_size, end->rpo_number() - header->rpo_number());
+  for (int i = 0; i < body_size; i++) {
+    CHECK_GE(blocks[i]->rpo_number(), header->rpo_number());
+    CHECK_LT(blocks[i]->rpo_number(), end->rpo_number());
+    CHECK(header->LoopContains(blocks[i]));
+    CHECK(header->IsLoopHeader() || blocks[i]->loop_header() == header);
+  }
+  if (header->rpo_number() > 0) {
+    CHECK_NE(order->at(header->rpo_number() - 1)->loop_header(), header);
+  }
+  if (end->rpo_number() < static_cast<int>(order->size())) {
+    CHECK_NE(order->at(end->rpo_number())->loop_header(), header);
+  }
+}
+
+
 struct TestLoop {
   int count;
   BasicBlock** nodes;
   BasicBlock* header() { return nodes[0]; }
   BasicBlock* last() { return nodes[count - 1]; }
   ~TestLoop() { delete[] nodes; }
+
+  void Check(BasicBlockVector* order) { CheckLoop(order, nodes, count); }
 };
 
 
@@ -37,36 +77,15 @@
   loop->nodes = new BasicBlock* [count];
   for (int i = 0; i < count; i++) {
     loop->nodes[i] = schedule->NewBasicBlock();
-    if (i > 0) schedule->AddSuccessor(loop->nodes[i - 1], loop->nodes[i]);
+    if (i > 0) {
+      schedule->AddSuccessorForTesting(loop->nodes[i - 1], loop->nodes[i]);
+    }
   }
-  schedule->AddSuccessor(loop->nodes[count - 1], loop->nodes[0]);
+  schedule->AddSuccessorForTesting(loop->nodes[count - 1], loop->nodes[0]);
   return loop;
 }
 
 
-static void CheckRPONumbers(BasicBlockVector* order, int expected,
-                            bool loops_allowed) {
-  CHECK_EQ(expected, static_cast<int>(order->size()));
-  for (int i = 0; i < static_cast<int>(order->size()); i++) {
-    CHECK(order->at(i)->rpo_number_ == i);
-    if (!loops_allowed) CHECK_LT(order->at(i)->loop_end_, 0);
-  }
-}
-
-
-static void CheckLoopContains(BasicBlock** blocks, int body_size) {
-  BasicBlock* header = blocks[0];
-  CHECK_GT(header->loop_end_, 0);
-  CHECK_EQ(body_size, (header->loop_end_ - header->rpo_number_));
-  for (int i = 0; i < body_size; i++) {
-    int num = blocks[i]->rpo_number_;
-    CHECK(num >= header->rpo_number_ && num < header->loop_end_);
-    CHECK(header->LoopContains(blocks[i]));
-    CHECK(header->IsLoopHeader() || blocks[i]->loop_header_ == header);
-  }
-}
-
-
 static int GetScheduledNodeCount(Schedule* schedule) {
   int node_count = 0;
   for (BasicBlockVectorIter i = schedule->rpo_order()->begin();
@@ -76,7 +95,7 @@
          ++j) {
       ++node_count;
     }
-    BasicBlock::Control control = block->control_;
+    BasicBlock::Control control = block->control();
     if (control != BasicBlock::kNone) {
       ++node_count;
     }
@@ -91,11 +110,11 @@
     os << AsDOT(*graph);
   }
 
-  Schedule* schedule = Scheduler::ComputeSchedule(graph);
+  Schedule* schedule = Scheduler::ComputeSchedule(graph->zone(), graph);
 
   if (FLAG_trace_turbo_scheduler) {
     OFStream os(stdout);
-    os << *schedule << endl;
+    os << *schedule << std::endl;
   }
   ScheduleVerifier::Run(schedule);
   CHECK_EQ(expected, GetScheduledNodeCount(schedule));
@@ -107,7 +126,8 @@
   HandleAndZoneScope scope;
   Schedule schedule(scope.main_zone());
 
-  BasicBlockVector* order = Scheduler::ComputeSpecialRPO(&schedule);
+  BasicBlockVector* order =
+      Scheduler::ComputeSpecialRPO(scope.main_zone(), &schedule);
   CheckRPONumbers(order, 1, false);
   CHECK_EQ(schedule.start(), order->at(0));
 }
@@ -118,7 +138,8 @@
   Schedule schedule(scope.main_zone());
 
   schedule.AddGoto(schedule.start(), schedule.end());
-  BasicBlockVector* order = Scheduler::ComputeSpecialRPO(&schedule);
+  BasicBlockVector* order =
+      Scheduler::ComputeSpecialRPO(scope.main_zone(), &schedule);
   CheckRPONumbers(order, 2, false);
   CHECK_EQ(schedule.start(), order->at(0));
   CHECK_EQ(schedule.end(), order->at(1));
@@ -134,18 +155,18 @@
     BasicBlock* last = schedule.start();
     for (int j = 0; j < i; j++) {
       BasicBlock* block = schedule.NewBasicBlock();
+      block->set_deferred(i & 1);
       schedule.AddGoto(last, block);
       last = block;
     }
-    BasicBlockVector* order = Scheduler::ComputeSpecialRPO(&schedule);
+    BasicBlockVector* order =
+        Scheduler::ComputeSpecialRPO(scope.main_zone(), &schedule);
     CheckRPONumbers(order, 1 + i, false);
 
-    Schedule::BasicBlocks blocks(schedule.all_blocks());
-    for (Schedule::BasicBlocks::iterator iter = blocks.begin();
-         iter != blocks.end(); ++iter) {
-      BasicBlock* block = *iter;
-      if (block->rpo_number_ >= 0 && block->SuccessorCount() == 1) {
-        CHECK(block->rpo_number_ + 1 == block->SuccessorAt(0)->rpo_number_);
+    for (size_t i = 0; i < schedule.BasicBlockCount(); i++) {
+      BasicBlock* block = schedule.GetBlockById(BasicBlock::Id::FromSize(i));
+      if (block->rpo_number() >= 0 && block->SuccessorCount() == 1) {
+        CHECK(block->rpo_number() + 1 == block->SuccessorAt(0)->rpo_number());
       }
     }
   }
@@ -155,23 +176,26 @@
 TEST(RPOSelfLoop) {
   HandleAndZoneScope scope;
   Schedule schedule(scope.main_zone());
-  schedule.AddSuccessor(schedule.start(), schedule.start());
-  BasicBlockVector* order = Scheduler::ComputeSpecialRPO(&schedule);
+  schedule.AddSuccessorForTesting(schedule.start(), schedule.start());
+  BasicBlockVector* order =
+      Scheduler::ComputeSpecialRPO(scope.main_zone(), &schedule);
   CheckRPONumbers(order, 1, true);
   BasicBlock* loop[] = {schedule.start()};
-  CheckLoopContains(loop, 1);
+  CheckLoop(order, loop, 1);
 }
 
 
 TEST(RPOEntryLoop) {
   HandleAndZoneScope scope;
   Schedule schedule(scope.main_zone());
-  schedule.AddSuccessor(schedule.start(), schedule.end());
-  schedule.AddSuccessor(schedule.end(), schedule.start());
-  BasicBlockVector* order = Scheduler::ComputeSpecialRPO(&schedule);
+  BasicBlock* body = schedule.NewBasicBlock();
+  schedule.AddSuccessorForTesting(schedule.start(), body);
+  schedule.AddSuccessorForTesting(body, schedule.start());
+  BasicBlockVector* order =
+      Scheduler::ComputeSpecialRPO(scope.main_zone(), &schedule);
   CheckRPONumbers(order, 2, true);
-  BasicBlock* loop[] = {schedule.start(), schedule.end()};
-  CheckLoopContains(loop, 2);
+  BasicBlock* loop[] = {schedule.start(), body};
+  CheckLoop(order, loop, 2);
 }
 
 
@@ -179,10 +203,11 @@
   HandleAndZoneScope scope;
   Schedule schedule(scope.main_zone());
   SmartPointer<TestLoop> loop1(CreateLoop(&schedule, 2));
-  schedule.AddSuccessor(schedule.start(), loop1->header());
-  BasicBlockVector* order = Scheduler::ComputeSpecialRPO(&schedule);
+  schedule.AddSuccessorForTesting(schedule.start(), loop1->header());
+  BasicBlockVector* order =
+      Scheduler::ComputeSpecialRPO(scope.main_zone(), &schedule);
   CheckRPONumbers(order, 3, true);
-  CheckLoopContains(loop1->nodes, loop1->count);
+  loop1->Check(order);
 }
 
 
@@ -190,11 +215,12 @@
   HandleAndZoneScope scope;
   Schedule schedule(scope.main_zone());
   SmartPointer<TestLoop> loop1(CreateLoop(&schedule, 2));
-  schedule.AddSuccessor(schedule.start(), loop1->header());
-  schedule.AddSuccessor(loop1->last(), schedule.start());
-  BasicBlockVector* order = Scheduler::ComputeSpecialRPO(&schedule);
+  schedule.AddSuccessorForTesting(schedule.start(), loop1->header());
+  schedule.AddSuccessorForTesting(loop1->last(), schedule.start());
+  BasicBlockVector* order =
+      Scheduler::ComputeSpecialRPO(scope.main_zone(), &schedule);
   CheckRPONumbers(order, 3, true);
-  CheckLoopContains(loop1->nodes, loop1->count);
+  loop1->Check(order);
 }
 
 
@@ -207,18 +233,19 @@
   BasicBlock* C = schedule.NewBasicBlock();
   BasicBlock* D = schedule.end();
 
-  schedule.AddSuccessor(A, B);
-  schedule.AddSuccessor(A, C);
-  schedule.AddSuccessor(B, D);
-  schedule.AddSuccessor(C, D);
+  schedule.AddSuccessorForTesting(A, B);
+  schedule.AddSuccessorForTesting(A, C);
+  schedule.AddSuccessorForTesting(B, D);
+  schedule.AddSuccessorForTesting(C, D);
 
-  BasicBlockVector* order = Scheduler::ComputeSpecialRPO(&schedule);
+  BasicBlockVector* order =
+      Scheduler::ComputeSpecialRPO(scope.main_zone(), &schedule);
   CheckRPONumbers(order, 4, false);
 
-  CHECK_EQ(0, A->rpo_number_);
-  CHECK((B->rpo_number_ == 1 && C->rpo_number_ == 2) ||
-        (B->rpo_number_ == 2 && C->rpo_number_ == 1));
-  CHECK_EQ(3, D->rpo_number_);
+  CHECK_EQ(0, A->rpo_number());
+  CHECK((B->rpo_number() == 1 && C->rpo_number() == 2) ||
+        (B->rpo_number() == 2 && C->rpo_number() == 1));
+  CHECK_EQ(3, D->rpo_number());
 }
 
 
@@ -231,15 +258,16 @@
   BasicBlock* C = schedule.NewBasicBlock();
   BasicBlock* D = schedule.end();
 
-  schedule.AddSuccessor(A, B);
-  schedule.AddSuccessor(B, C);
-  schedule.AddSuccessor(C, B);
-  schedule.AddSuccessor(C, D);
+  schedule.AddSuccessorForTesting(A, B);
+  schedule.AddSuccessorForTesting(B, C);
+  schedule.AddSuccessorForTesting(C, B);
+  schedule.AddSuccessorForTesting(C, D);
 
-  BasicBlockVector* order = Scheduler::ComputeSpecialRPO(&schedule);
+  BasicBlockVector* order =
+      Scheduler::ComputeSpecialRPO(scope.main_zone(), &schedule);
   CheckRPONumbers(order, 4, true);
   BasicBlock* loop[] = {B, C};
-  CheckLoopContains(loop, 2);
+  CheckLoop(order, loop, 2);
 }
 
 
@@ -252,15 +280,16 @@
   BasicBlock* C = schedule.NewBasicBlock();
   BasicBlock* D = schedule.end();
 
-  schedule.AddSuccessor(A, B);
-  schedule.AddSuccessor(B, C);
-  schedule.AddSuccessor(C, B);
-  schedule.AddSuccessor(B, D);
+  schedule.AddSuccessorForTesting(A, B);
+  schedule.AddSuccessorForTesting(B, C);
+  schedule.AddSuccessorForTesting(C, B);
+  schedule.AddSuccessorForTesting(B, D);
 
-  BasicBlockVector* order = Scheduler::ComputeSpecialRPO(&schedule);
+  BasicBlockVector* order =
+      Scheduler::ComputeSpecialRPO(scope.main_zone(), &schedule);
   CheckRPONumbers(order, 4, true);
   BasicBlock* loop[] = {B, C};
-  CheckLoopContains(loop, 2);
+  CheckLoop(order, loop, 2);
 }
 
 
@@ -277,32 +306,33 @@
     BasicBlock* F = schedule.NewBasicBlock();
     BasicBlock* G = schedule.end();
 
-    schedule.AddSuccessor(A, B);
-    schedule.AddSuccessor(B, C);
-    schedule.AddSuccessor(C, D);
-    schedule.AddSuccessor(D, E);
-    schedule.AddSuccessor(E, F);
-    schedule.AddSuccessor(F, B);
-    schedule.AddSuccessor(B, G);
+    schedule.AddSuccessorForTesting(A, B);
+    schedule.AddSuccessorForTesting(B, C);
+    schedule.AddSuccessorForTesting(C, D);
+    schedule.AddSuccessorForTesting(D, E);
+    schedule.AddSuccessorForTesting(E, F);
+    schedule.AddSuccessorForTesting(F, B);
+    schedule.AddSuccessorForTesting(B, G);
 
     // Throw in extra backedges from time to time.
-    if (i == 1) schedule.AddSuccessor(B, B);
-    if (i == 2) schedule.AddSuccessor(C, B);
-    if (i == 3) schedule.AddSuccessor(D, B);
-    if (i == 4) schedule.AddSuccessor(E, B);
-    if (i == 5) schedule.AddSuccessor(F, B);
+    if (i == 1) schedule.AddSuccessorForTesting(B, B);
+    if (i == 2) schedule.AddSuccessorForTesting(C, B);
+    if (i == 3) schedule.AddSuccessorForTesting(D, B);
+    if (i == 4) schedule.AddSuccessorForTesting(E, B);
+    if (i == 5) schedule.AddSuccessorForTesting(F, B);
 
     // Throw in extra loop exits from time to time.
-    if (i == 6) schedule.AddSuccessor(B, G);
-    if (i == 7) schedule.AddSuccessor(C, G);
-    if (i == 8) schedule.AddSuccessor(D, G);
-    if (i == 9) schedule.AddSuccessor(E, G);
-    if (i == 10) schedule.AddSuccessor(F, G);
+    if (i == 6) schedule.AddSuccessorForTesting(B, G);
+    if (i == 7) schedule.AddSuccessorForTesting(C, G);
+    if (i == 8) schedule.AddSuccessorForTesting(D, G);
+    if (i == 9) schedule.AddSuccessorForTesting(E, G);
+    if (i == 10) schedule.AddSuccessorForTesting(F, G);
 
-    BasicBlockVector* order = Scheduler::ComputeSpecialRPO(&schedule);
+    BasicBlockVector* order =
+        Scheduler::ComputeSpecialRPO(scope.main_zone(), &schedule);
     CheckRPONumbers(order, 7, true);
     BasicBlock* loop[] = {B, C, D, E, F};
-    CheckLoopContains(loop, 5);
+    CheckLoop(order, loop, 5);
   }
 }
 
@@ -318,21 +348,22 @@
   BasicBlock* E = schedule.NewBasicBlock();
   BasicBlock* F = schedule.end();
 
-  schedule.AddSuccessor(A, B);
-  schedule.AddSuccessor(B, C);
-  schedule.AddSuccessor(C, D);
-  schedule.AddSuccessor(D, C);
-  schedule.AddSuccessor(D, E);
-  schedule.AddSuccessor(E, B);
-  schedule.AddSuccessor(E, F);
+  schedule.AddSuccessorForTesting(A, B);
+  schedule.AddSuccessorForTesting(B, C);
+  schedule.AddSuccessorForTesting(C, D);
+  schedule.AddSuccessorForTesting(D, C);
+  schedule.AddSuccessorForTesting(D, E);
+  schedule.AddSuccessorForTesting(E, B);
+  schedule.AddSuccessorForTesting(E, F);
 
-  BasicBlockVector* order = Scheduler::ComputeSpecialRPO(&schedule);
+  BasicBlockVector* order =
+      Scheduler::ComputeSpecialRPO(scope.main_zone(), &schedule);
   CheckRPONumbers(order, 6, true);
   BasicBlock* loop1[] = {B, C, D, E};
-  CheckLoopContains(loop1, 4);
+  CheckLoop(order, loop1, 4);
 
   BasicBlock* loop2[] = {C, D};
-  CheckLoopContains(loop2, 2);
+  CheckLoop(order, loop2, 2);
 }
 
 
@@ -349,28 +380,29 @@
   BasicBlock* G = schedule.NewBasicBlock();
   BasicBlock* H = schedule.end();
 
-  schedule.AddSuccessor(A, B);
-  schedule.AddSuccessor(B, C);
-  schedule.AddSuccessor(C, D);
-  schedule.AddSuccessor(D, E);
-  schedule.AddSuccessor(E, F);
-  schedule.AddSuccessor(F, G);
-  schedule.AddSuccessor(G, H);
+  schedule.AddSuccessorForTesting(A, B);
+  schedule.AddSuccessorForTesting(B, C);
+  schedule.AddSuccessorForTesting(C, D);
+  schedule.AddSuccessorForTesting(D, E);
+  schedule.AddSuccessorForTesting(E, F);
+  schedule.AddSuccessorForTesting(F, G);
+  schedule.AddSuccessorForTesting(G, H);
 
-  schedule.AddSuccessor(E, D);
-  schedule.AddSuccessor(F, C);
-  schedule.AddSuccessor(G, B);
+  schedule.AddSuccessorForTesting(E, D);
+  schedule.AddSuccessorForTesting(F, C);
+  schedule.AddSuccessorForTesting(G, B);
 
-  BasicBlockVector* order = Scheduler::ComputeSpecialRPO(&schedule);
+  BasicBlockVector* order =
+      Scheduler::ComputeSpecialRPO(scope.main_zone(), &schedule);
   CheckRPONumbers(order, 8, true);
   BasicBlock* loop1[] = {B, C, D, E, F, G};
-  CheckLoopContains(loop1, 6);
+  CheckLoop(order, loop1, 6);
 
   BasicBlock* loop2[] = {C, D, E, F};
-  CheckLoopContains(loop2, 4);
+  CheckLoop(order, loop2, 4);
 
   BasicBlock* loop3[] = {D, E};
-  CheckLoopContains(loop3, 2);
+  CheckLoop(order, loop3, 2);
 }
 
 
@@ -384,17 +416,18 @@
   BasicBlock* A = schedule.start();
   BasicBlock* E = schedule.end();
 
-  schedule.AddSuccessor(A, loop1->header());
-  schedule.AddSuccessor(loop1->header(), loop2->header());
-  schedule.AddSuccessor(loop2->last(), E);
+  schedule.AddSuccessorForTesting(A, loop1->header());
+  schedule.AddSuccessorForTesting(loop1->header(), loop2->header());
+  schedule.AddSuccessorForTesting(loop2->last(), E);
 
-  BasicBlockVector* order = Scheduler::ComputeSpecialRPO(&schedule);
+  BasicBlockVector* order =
+      Scheduler::ComputeSpecialRPO(scope.main_zone(), &schedule);
 
-  CheckLoopContains(loop1->nodes, loop1->count);
+  CHECK_EQ(static_cast<int>(schedule.BasicBlockCount()),
+           static_cast<int>(order->size()));
 
-  CHECK_EQ(schedule.BasicBlockCount(), static_cast<int>(order->size()));
-  CheckLoopContains(loop1->nodes, loop1->count);
-  CheckLoopContains(loop2->nodes, loop2->count);
+  loop1->Check(order);
+  loop2->Check(order);
 }
 
 
@@ -409,18 +442,18 @@
   BasicBlock* S = schedule.NewBasicBlock();
   BasicBlock* E = schedule.end();
 
-  schedule.AddSuccessor(A, loop1->header());
-  schedule.AddSuccessor(loop1->header(), S);
-  schedule.AddSuccessor(S, loop2->header());
-  schedule.AddSuccessor(loop2->last(), E);
+  schedule.AddSuccessorForTesting(A, loop1->header());
+  schedule.AddSuccessorForTesting(loop1->header(), S);
+  schedule.AddSuccessorForTesting(S, loop2->header());
+  schedule.AddSuccessorForTesting(loop2->last(), E);
 
-  BasicBlockVector* order = Scheduler::ComputeSpecialRPO(&schedule);
+  BasicBlockVector* order =
+      Scheduler::ComputeSpecialRPO(scope.main_zone(), &schedule);
 
-  CheckLoopContains(loop1->nodes, loop1->count);
-
-  CHECK_EQ(schedule.BasicBlockCount(), static_cast<int>(order->size()));
-  CheckLoopContains(loop1->nodes, loop1->count);
-  CheckLoopContains(loop2->nodes, loop2->count);
+  CHECK_EQ(static_cast<int>(schedule.BasicBlockCount()),
+           static_cast<int>(order->size()));
+  loop1->Check(order);
+  loop2->Check(order);
 }
 
 
@@ -435,15 +468,16 @@
       BasicBlock* A = schedule.start();
       BasicBlock* E = schedule.end();
 
-      schedule.AddSuccessor(A, loop1->header());
-      schedule.AddSuccessor(loop1->nodes[exit], loop2->header());
-      schedule.AddSuccessor(loop2->nodes[exit], E);
-      BasicBlockVector* order = Scheduler::ComputeSpecialRPO(&schedule);
-      CheckLoopContains(loop1->nodes, loop1->count);
+      schedule.AddSuccessorForTesting(A, loop1->header());
+      schedule.AddSuccessorForTesting(loop1->nodes[exit], loop2->header());
+      schedule.AddSuccessorForTesting(loop2->nodes[exit], E);
+      BasicBlockVector* order =
+          Scheduler::ComputeSpecialRPO(scope.main_zone(), &schedule);
 
-      CHECK_EQ(schedule.BasicBlockCount(), static_cast<int>(order->size()));
-      CheckLoopContains(loop1->nodes, loop1->count);
-      CheckLoopContains(loop2->nodes, loop2->count);
+      CHECK_EQ(static_cast<int>(schedule.BasicBlockCount()),
+               static_cast<int>(order->size()));
+      loop1->Check(order);
+      loop2->Check(order);
     }
   }
 }
@@ -461,23 +495,23 @@
   BasicBlock* C = schedule.NewBasicBlock();
   BasicBlock* E = schedule.end();
 
-  schedule.AddSuccessor(A, B);
-  schedule.AddSuccessor(B, loop1->header());
-  schedule.AddSuccessor(loop1->header(), loop2->header());
-  schedule.AddSuccessor(loop2->last(), C);
-  schedule.AddSuccessor(C, E);
-  schedule.AddSuccessor(C, B);
+  schedule.AddSuccessorForTesting(A, B);
+  schedule.AddSuccessorForTesting(B, loop1->header());
+  schedule.AddSuccessorForTesting(loop1->header(), loop2->header());
+  schedule.AddSuccessorForTesting(loop2->last(), C);
+  schedule.AddSuccessorForTesting(C, E);
+  schedule.AddSuccessorForTesting(C, B);
 
-  BasicBlockVector* order = Scheduler::ComputeSpecialRPO(&schedule);
+  BasicBlockVector* order =
+      Scheduler::ComputeSpecialRPO(scope.main_zone(), &schedule);
 
-  CheckLoopContains(loop1->nodes, loop1->count);
-
-  CHECK_EQ(schedule.BasicBlockCount(), static_cast<int>(order->size()));
-  CheckLoopContains(loop1->nodes, loop1->count);
-  CheckLoopContains(loop2->nodes, loop2->count);
+  CHECK_EQ(static_cast<int>(schedule.BasicBlockCount()),
+           static_cast<int>(order->size()));
+  loop1->Check(order);
+  loop2->Check(order);
 
   BasicBlock* loop3[] = {B, loop1->nodes[0], loop2->nodes[0], C};
-  CheckLoopContains(loop3, 4);
+  CheckLoop(order, loop3, 4);
 }
 
 
@@ -492,15 +526,16 @@
       BasicBlock* E = schedule.end();
 
       SmartPointer<TestLoop> loop1(CreateLoop(&schedule, size));
-      schedule.AddSuccessor(A, loop1->header());
-      schedule.AddSuccessor(loop1->last(), E);
+      schedule.AddSuccessorForTesting(A, loop1->header());
+      schedule.AddSuccessorForTesting(loop1->last(), E);
 
-      schedule.AddSuccessor(loop1->nodes[i], loop1->header());
-      schedule.AddSuccessor(loop1->nodes[j], E);
+      schedule.AddSuccessorForTesting(loop1->nodes[i], loop1->header());
+      schedule.AddSuccessorForTesting(loop1->nodes[j], E);
 
-      BasicBlockVector* order = Scheduler::ComputeSpecialRPO(&schedule);
+      BasicBlockVector* order =
+          Scheduler::ComputeSpecialRPO(scope.main_zone(), &schedule);
       CheckRPONumbers(order, schedule.BasicBlockCount(), true);
-      CheckLoopContains(loop1->nodes, loop1->count);
+      loop1->Check(order);
     }
   }
 }
@@ -518,16 +553,17 @@
       BasicBlock* E = schedule.end();
 
       SmartPointer<TestLoop> loop1(CreateLoop(&schedule, size));
-      schedule.AddSuccessor(A, loop1->header());
-      schedule.AddSuccessor(loop1->last(), E);
+      schedule.AddSuccessorForTesting(A, loop1->header());
+      schedule.AddSuccessorForTesting(loop1->last(), E);
 
-      schedule.AddSuccessor(loop1->nodes[i], loop1->header());
-      schedule.AddSuccessor(loop1->nodes[j], D);
-      schedule.AddSuccessor(D, E);
+      schedule.AddSuccessorForTesting(loop1->nodes[i], loop1->header());
+      schedule.AddSuccessorForTesting(loop1->nodes[j], D);
+      schedule.AddSuccessorForTesting(D, E);
 
-      BasicBlockVector* order = Scheduler::ComputeSpecialRPO(&schedule);
+      BasicBlockVector* order =
+          Scheduler::ComputeSpecialRPO(scope.main_zone(), &schedule);
       CheckRPONumbers(order, schedule.BasicBlockCount(), true);
-      CheckLoopContains(loop1->nodes, loop1->count);
+      loop1->Check(order);
     }
   }
 }
@@ -543,18 +579,19 @@
     BasicBlock* E = schedule.end();
 
     SmartPointer<TestLoop> loop1(CreateLoop(&schedule, size));
-    schedule.AddSuccessor(A, loop1->header());
-    schedule.AddSuccessor(loop1->last(), E);
+    schedule.AddSuccessorForTesting(A, loop1->header());
+    schedule.AddSuccessorForTesting(loop1->last(), E);
 
     for (int j = 0; j < size; j++) {
       BasicBlock* O = schedule.NewBasicBlock();
-      schedule.AddSuccessor(loop1->nodes[j], O);
-      schedule.AddSuccessor(O, E);
+      schedule.AddSuccessorForTesting(loop1->nodes[j], O);
+      schedule.AddSuccessorForTesting(O, E);
     }
 
-    BasicBlockVector* order = Scheduler::ComputeSpecialRPO(&schedule);
+    BasicBlockVector* order =
+        Scheduler::ComputeSpecialRPO(scope.main_zone(), &schedule);
     CheckRPONumbers(order, schedule.BasicBlockCount(), true);
-    CheckLoopContains(loop1->nodes, loop1->count);
+    loop1->Check(order);
   }
 }
 
@@ -568,22 +605,23 @@
     BasicBlock* A = schedule.start();
     BasicBlock* E = schedule.end();
     SmartPointer<TestLoop> loop1(CreateLoop(&schedule, size));
-    schedule.AddSuccessor(A, loop1->header());
-    schedule.AddSuccessor(loop1->last(), E);
+    schedule.AddSuccessorForTesting(A, loop1->header());
+    schedule.AddSuccessorForTesting(loop1->last(), E);
 
     TestLoop** loopN = new TestLoop* [size];
     for (int j = 0; j < size; j++) {
       loopN[j] = CreateLoop(&schedule, 2);
-      schedule.AddSuccessor(loop1->nodes[j], loopN[j]->header());
-      schedule.AddSuccessor(loopN[j]->last(), E);
+      schedule.AddSuccessorForTesting(loop1->nodes[j], loopN[j]->header());
+      schedule.AddSuccessorForTesting(loopN[j]->last(), E);
     }
 
-    BasicBlockVector* order = Scheduler::ComputeSpecialRPO(&schedule);
+    BasicBlockVector* order =
+        Scheduler::ComputeSpecialRPO(scope.main_zone(), &schedule);
     CheckRPONumbers(order, schedule.BasicBlockCount(), true);
-    CheckLoopContains(loop1->nodes, loop1->count);
+    loop1->Check(order);
 
     for (int j = 0; j < size; j++) {
-      CheckLoopContains(loopN[j]->nodes, loopN[j]->count);
+      loopN[j]->Check(order);
       delete loopN[j];
     }
     delete[] loopN;
@@ -598,22 +636,23 @@
   BasicBlock* A = schedule.start();
   BasicBlock* B = schedule.NewBasicBlock();
   BasicBlock* C = schedule.NewBasicBlock();
-  BasicBlock* D = schedule.end();
+  BasicBlock* D = schedule.NewBasicBlock();
   BasicBlock* E = schedule.NewBasicBlock();
 
-  schedule.AddSuccessor(A, B);
-  schedule.AddSuccessor(B, C);
-  schedule.AddSuccessor(B, D);
-  schedule.AddSuccessor(B, E);
-  schedule.AddSuccessor(C, B);
-  schedule.AddSuccessor(D, B);
-  schedule.AddSuccessor(E, B);
+  schedule.AddSuccessorForTesting(A, B);
+  schedule.AddSuccessorForTesting(B, C);
+  schedule.AddSuccessorForTesting(B, D);
+  schedule.AddSuccessorForTesting(B, E);
+  schedule.AddSuccessorForTesting(C, B);
+  schedule.AddSuccessorForTesting(D, B);
+  schedule.AddSuccessorForTesting(E, B);
 
-  BasicBlockVector* order = Scheduler::ComputeSpecialRPO(&schedule);
+  BasicBlockVector* order =
+      Scheduler::ComputeSpecialRPO(scope.main_zone(), &schedule);
   CheckRPONumbers(order, 5, true);
 
   BasicBlock* loop1[] = {B, C, D, E};
-  CheckLoopContains(loop1, 4);
+  CheckLoop(order, loop1, 4);
 }
 
 
@@ -624,7 +663,7 @@
   graph.SetStart(graph.NewNode(builder.Start(0)));
   graph.SetEnd(graph.NewNode(builder.End(), graph.start()));
 
-  USE(Scheduler::ComputeSchedule(&graph));
+  USE(Scheduler::ComputeSchedule(scope.main_zone(), &graph));
 }
 
 
@@ -639,7 +678,7 @@
 
   graph.SetEnd(graph.NewNode(builder.End(), ret));
 
-  USE(Scheduler::ComputeSchedule(&graph));
+  USE(Scheduler::ComputeSchedule(scope.main_zone(), &graph));
 }
 
 
@@ -678,9 +717,10 @@
   JSOperatorBuilder js_builder(scope.main_zone());
   const Operator* op;
 
-  Handle<Object> object =
-      Handle<Object>(isolate->heap()->undefined_value(), isolate);
-  Unique<Object> unique_constant = Unique<Object>::CreateUninitialized(object);
+  Handle<HeapObject> object =
+      Handle<HeapObject>(isolate->heap()->undefined_value(), isolate);
+  Unique<HeapObject> unique_constant =
+      Unique<HeapObject>::CreateUninitialized(object);
 
   // Manually transcripted code for:
   // function turbo_fan_test(a, b, c, y) {
@@ -823,9 +863,10 @@
   JSOperatorBuilder js_builder(scope.main_zone());
   const Operator* op;
 
-  Handle<Object> object =
-      Handle<Object>(isolate->heap()->undefined_value(), isolate);
-  Unique<Object> unique_constant = Unique<Object>::CreateUninitialized(object);
+  Handle<HeapObject> object =
+      Handle<HeapObject>(isolate->heap()->undefined_value(), isolate);
+  Unique<HeapObject> unique_constant =
+      Unique<HeapObject>::CreateUninitialized(object);
 
   // Manually transcripted code for:
   // function turbo_fan_test(a, b) {
@@ -935,9 +976,10 @@
   JSOperatorBuilder js_builder(scope.main_zone());
   const Operator* op;
 
-  Handle<Object> object =
-      Handle<Object>(isolate->heap()->undefined_value(), isolate);
-  Unique<Object> unique_constant = Unique<Object>::CreateUninitialized(object);
+  Handle<HeapObject> object =
+      Handle<HeapObject>(isolate->heap()->undefined_value(), isolate);
+  Unique<HeapObject> unique_constant =
+      Unique<HeapObject>::CreateUninitialized(object);
 
   // Manually transcripted code for:
   // function turbo_fan_test(a, b, c) {
@@ -1182,9 +1224,10 @@
   JSOperatorBuilder js_builder(scope.main_zone());
   const Operator* op;
 
-  Handle<Object> object =
-      Handle<Object>(isolate->heap()->undefined_value(), isolate);
-  Unique<Object> unique_constant = Unique<Object>::CreateUninitialized(object);
+  Handle<HeapObject> object =
+      Handle<HeapObject>(isolate->heap()->undefined_value(), isolate);
+  Unique<HeapObject> unique_constant =
+      Unique<HeapObject>::CreateUninitialized(object);
 
   // Manually transcripted code for:
   // function turbo_fan_test(a, b, c) {
@@ -1509,12 +1552,12 @@
   Graph graph(scope.main_zone());
   CommonOperatorBuilder common_builder(scope.main_zone());
   JSOperatorBuilder js_builder(scope.main_zone());
-  MachineOperatorBuilder machine_builder;
   const Operator* op;
 
-  Handle<Object> object =
-      Handle<Object>(isolate->heap()->undefined_value(), isolate);
-  Unique<Object> unique_constant = Unique<Object>::CreateUninitialized(object);
+  Handle<HeapObject> object =
+      Handle<HeapObject>(isolate->heap()->undefined_value(), isolate);
+  Unique<HeapObject> unique_constant =
+      Unique<HeapObject>::CreateUninitialized(object);
 
   // Manually transcripted code for:
   // function turbo_fan_test(a, b, c) {
@@ -1544,7 +1587,7 @@
   Node* n20 = graph.NewNode(op, nil, nil, nil, nil, nil);
   USE(n20);
   n20->ReplaceInput(0, n9);
-  op = machine_builder.Int32Add();
+  op = &kIntAdd;
   Node* n19 = graph.NewNode(op, nil, nil);
   USE(n19);
   op = common_builder.Phi(kMachAnyTagged, 2);
@@ -1668,7 +1711,6 @@
   HandleAndZoneScope scope;
   Graph graph(scope.main_zone());
   CommonOperatorBuilder common(scope.main_zone());
-  MachineOperatorBuilder machine;
 
   Node* start = graph.NewNode(common.Start(2));
   graph.SetStart(start);
@@ -1677,7 +1719,7 @@
   Node* p1 = graph.NewNode(common.Parameter(1), start);
   Node* d1 = CreateDiamond(&graph, &common, p0);
   Node* d2 = CreateDiamond(&graph, &common, p1);
-  Node* add = graph.NewNode(machine.Int32Add(), d1, d2);
+  Node* add = graph.NewNode(&kIntAdd, d1, d2);
   Node* ret = graph.NewNode(common.Return(), add, start, start);
   Node* end = graph.NewNode(common.End(), ret, start);
 
@@ -1691,7 +1733,6 @@
   HandleAndZoneScope scope;
   Graph graph(scope.main_zone());
   CommonOperatorBuilder common(scope.main_zone());
-  MachineOperatorBuilder machine;
 
   Node* start = graph.NewNode(common.Start(2));
   graph.SetStart(start);
@@ -1700,7 +1741,7 @@
   Node* p1 = graph.NewNode(common.Parameter(1), start);
   Node* d1 = CreateDiamond(&graph, &common, p0);
   Node* d2 = CreateDiamond(&graph, &common, p1);
-  Node* add = graph.NewNode(machine.Int32Add(), d1, d2);
+  Node* add = graph.NewNode(&kIntAdd, d1, d2);
   Node* d3 = CreateDiamond(&graph, &common, add);
   Node* ret = graph.NewNode(common.Return(), d3, start, start);
   Node* end = graph.NewNode(common.End(), ret, start);
@@ -1710,4 +1751,374 @@
   ComputeAndVerifySchedule(33, &graph);
 }
 
+
+TEST(NestedFloatingDiamonds) {
+  HandleAndZoneScope scope;
+  Graph graph(scope.main_zone());
+  CommonOperatorBuilder common(scope.main_zone());
+  SimplifiedOperatorBuilder simplified(scope.main_zone());
+
+  Node* start = graph.NewNode(common.Start(2));
+  graph.SetStart(start);
+
+  Node* p0 = graph.NewNode(common.Parameter(0), start);
+
+  Node* fv = graph.NewNode(common.Int32Constant(7));
+  Node* br = graph.NewNode(common.Branch(), p0, graph.start());
+  Node* t = graph.NewNode(common.IfTrue(), br);
+  Node* f = graph.NewNode(common.IfFalse(), br);
+
+  Node* map = graph.NewNode(
+      simplified.LoadElement(AccessBuilder::ForFixedArrayElement()), p0, p0, p0,
+      start, f);
+  Node* br1 = graph.NewNode(common.Branch(), map, graph.start());
+  Node* t1 = graph.NewNode(common.IfTrue(), br1);
+  Node* f1 = graph.NewNode(common.IfFalse(), br1);
+  Node* m1 = graph.NewNode(common.Merge(2), t1, f1);
+  Node* ttrue = graph.NewNode(common.Int32Constant(1));
+  Node* ffalse = graph.NewNode(common.Int32Constant(0));
+  Node* phi1 = graph.NewNode(common.Phi(kMachAnyTagged, 2), ttrue, ffalse, m1);
+
+
+  Node* m = graph.NewNode(common.Merge(2), t, f);
+  Node* phi = graph.NewNode(common.Phi(kMachAnyTagged, 2), fv, phi1, m);
+  Node* ephi1 = graph.NewNode(common.EffectPhi(2), start, map, m);
+
+  Node* ret = graph.NewNode(common.Return(), phi, ephi1, start);
+  Node* end = graph.NewNode(common.End(), ret, start);
+
+  graph.SetEnd(end);
+
+  ComputeAndVerifySchedule(23, &graph);
+}
+
+
+TEST(NestedFloatingDiamondWithChain) {
+  HandleAndZoneScope scope;
+  Graph graph(scope.main_zone());
+  CommonOperatorBuilder common(scope.main_zone());
+
+  Node* start = graph.NewNode(common.Start(2));
+  graph.SetStart(start);
+
+  Node* p0 = graph.NewNode(common.Parameter(0), start);
+  Node* p1 = graph.NewNode(common.Parameter(1), start);
+  Node* c = graph.NewNode(common.Int32Constant(7));
+
+  Node* brA1 = graph.NewNode(common.Branch(), p0, graph.start());
+  Node* tA1 = graph.NewNode(common.IfTrue(), brA1);
+  Node* fA1 = graph.NewNode(common.IfFalse(), brA1);
+  Node* mA1 = graph.NewNode(common.Merge(2), tA1, fA1);
+  Node* phiA1 = graph.NewNode(common.Phi(kMachAnyTagged, 2), p0, p1, mA1);
+
+  Node* brB1 = graph.NewNode(common.Branch(), p1, graph.start());
+  Node* tB1 = graph.NewNode(common.IfTrue(), brB1);
+  Node* fB1 = graph.NewNode(common.IfFalse(), brB1);
+  Node* mB1 = graph.NewNode(common.Merge(2), tB1, fB1);
+  Node* phiB1 = graph.NewNode(common.Phi(kMachAnyTagged, 2), p0, p1, mB1);
+
+  Node* brA2 = graph.NewNode(common.Branch(), phiB1, mA1);
+  Node* tA2 = graph.NewNode(common.IfTrue(), brA2);
+  Node* fA2 = graph.NewNode(common.IfFalse(), brA2);
+  Node* mA2 = graph.NewNode(common.Merge(2), tA2, fA2);
+  Node* phiA2 = graph.NewNode(common.Phi(kMachAnyTagged, 2), phiB1, c, mA2);
+
+  Node* brB2 = graph.NewNode(common.Branch(), phiA1, mB1);
+  Node* tB2 = graph.NewNode(common.IfTrue(), brB2);
+  Node* fB2 = graph.NewNode(common.IfFalse(), brB2);
+  Node* mB2 = graph.NewNode(common.Merge(2), tB2, fB2);
+  Node* phiB2 = graph.NewNode(common.Phi(kMachAnyTagged, 2), phiA1, c, mB2);
+
+  Node* add = graph.NewNode(&kIntAdd, phiA2, phiB2);
+  Node* ret = graph.NewNode(common.Return(), add, start, start);
+  Node* end = graph.NewNode(common.End(), ret, start);
+
+  graph.SetEnd(end);
+
+  ComputeAndVerifySchedule(35, &graph);
+}
+
+
+TEST(NestedFloatingDiamondWithLoop) {
+  HandleAndZoneScope scope;
+  Graph graph(scope.main_zone());
+  CommonOperatorBuilder common(scope.main_zone());
+
+  Node* start = graph.NewNode(common.Start(2));
+  graph.SetStart(start);
+
+  Node* p0 = graph.NewNode(common.Parameter(0), start);
+
+  Node* fv = graph.NewNode(common.Int32Constant(7));
+  Node* br = graph.NewNode(common.Branch(), p0, graph.start());
+  Node* t = graph.NewNode(common.IfTrue(), br);
+  Node* f = graph.NewNode(common.IfFalse(), br);
+
+  Node* loop = graph.NewNode(common.Loop(2), f, start);
+  Node* ind = graph.NewNode(common.Phi(kMachAnyTagged, 2), p0, p0, loop);
+
+  Node* add = graph.NewNode(&kIntAdd, ind, fv);
+  Node* br1 = graph.NewNode(common.Branch(), add, loop);
+  Node* t1 = graph.NewNode(common.IfTrue(), br1);
+  Node* f1 = graph.NewNode(common.IfFalse(), br1);
+
+  loop->ReplaceInput(1, t1);  // close loop.
+  ind->ReplaceInput(1, ind);  // close induction variable.
+
+  Node* m = graph.NewNode(common.Merge(2), t, f1);
+  Node* phi = graph.NewNode(common.Phi(kMachAnyTagged, 2), fv, ind, m);
+
+  Node* ret = graph.NewNode(common.Return(), phi, start, start);
+  Node* end = graph.NewNode(common.End(), ret, start);
+
+  graph.SetEnd(end);
+
+  ComputeAndVerifySchedule(20, &graph);
+}
+
+
+TEST(LoopedFloatingDiamond1) {
+  HandleAndZoneScope scope;
+  Graph graph(scope.main_zone());
+  CommonOperatorBuilder common(scope.main_zone());
+
+  Node* start = graph.NewNode(common.Start(2));
+  graph.SetStart(start);
+
+  Node* p0 = graph.NewNode(common.Parameter(0), start);
+
+  Node* c = graph.NewNode(common.Int32Constant(7));
+  Node* loop = graph.NewNode(common.Loop(2), start, start);
+  Node* ind = graph.NewNode(common.Phi(kMachAnyTagged, 2), p0, p0, loop);
+  Node* add = graph.NewNode(&kIntAdd, ind, c);
+
+  Node* br = graph.NewNode(common.Branch(), add, loop);
+  Node* t = graph.NewNode(common.IfTrue(), br);
+  Node* f = graph.NewNode(common.IfFalse(), br);
+
+  Node* br1 = graph.NewNode(common.Branch(), p0, graph.start());
+  Node* t1 = graph.NewNode(common.IfTrue(), br1);
+  Node* f1 = graph.NewNode(common.IfFalse(), br1);
+  Node* m1 = graph.NewNode(common.Merge(2), t1, f1);
+  Node* phi1 = graph.NewNode(common.Phi(kMachAnyTagged, 2), add, p0, m1);
+
+  loop->ReplaceInput(1, t);    // close loop.
+  ind->ReplaceInput(1, phi1);  // close induction variable.
+
+  Node* ret = graph.NewNode(common.Return(), ind, start, f);
+  Node* end = graph.NewNode(common.End(), ret, f);
+
+  graph.SetEnd(end);
+
+  ComputeAndVerifySchedule(20, &graph);
+}
+
+
+TEST(LoopedFloatingDiamond2) {
+  HandleAndZoneScope scope;
+  Graph graph(scope.main_zone());
+  CommonOperatorBuilder common(scope.main_zone());
+
+  Node* start = graph.NewNode(common.Start(2));
+  graph.SetStart(start);
+
+  Node* p0 = graph.NewNode(common.Parameter(0), start);
+
+  Node* c = graph.NewNode(common.Int32Constant(7));
+  Node* loop = graph.NewNode(common.Loop(2), start, start);
+  Node* ind = graph.NewNode(common.Phi(kMachAnyTagged, 2), p0, p0, loop);
+
+  Node* br1 = graph.NewNode(common.Branch(), p0, graph.start());
+  Node* t1 = graph.NewNode(common.IfTrue(), br1);
+  Node* f1 = graph.NewNode(common.IfFalse(), br1);
+  Node* m1 = graph.NewNode(common.Merge(2), t1, f1);
+  Node* phi1 = graph.NewNode(common.Phi(kMachAnyTagged, 2), c, ind, m1);
+
+  Node* add = graph.NewNode(&kIntAdd, ind, phi1);
+
+  Node* br = graph.NewNode(common.Branch(), add, loop);
+  Node* t = graph.NewNode(common.IfTrue(), br);
+  Node* f = graph.NewNode(common.IfFalse(), br);
+
+  loop->ReplaceInput(1, t);   // close loop.
+  ind->ReplaceInput(1, add);  // close induction variable.
+
+  Node* ret = graph.NewNode(common.Return(), ind, start, f);
+  Node* end = graph.NewNode(common.End(), ret, f);
+
+  graph.SetEnd(end);
+
+  ComputeAndVerifySchedule(20, &graph);
+}
+
+
+TEST(LoopedFloatingDiamond3) {
+  HandleAndZoneScope scope;
+  Graph graph(scope.main_zone());
+  CommonOperatorBuilder common(scope.main_zone());
+
+  Node* start = graph.NewNode(common.Start(2));
+  graph.SetStart(start);
+
+  Node* p0 = graph.NewNode(common.Parameter(0), start);
+
+  Node* c = graph.NewNode(common.Int32Constant(7));
+  Node* loop = graph.NewNode(common.Loop(2), start, start);
+  Node* ind = graph.NewNode(common.Phi(kMachAnyTagged, 2), p0, p0, loop);
+
+  Node* br1 = graph.NewNode(common.Branch(), p0, graph.start());
+  Node* t1 = graph.NewNode(common.IfTrue(), br1);
+  Node* f1 = graph.NewNode(common.IfFalse(), br1);
+
+  Node* loop1 = graph.NewNode(common.Loop(2), t1, start);
+  Node* ind1 = graph.NewNode(common.Phi(kMachAnyTagged, 2), p0, p0, loop);
+
+  Node* add1 = graph.NewNode(&kIntAdd, ind1, c);
+  Node* br2 = graph.NewNode(common.Branch(), add1, loop1);
+  Node* t2 = graph.NewNode(common.IfTrue(), br2);
+  Node* f2 = graph.NewNode(common.IfFalse(), br2);
+
+  loop1->ReplaceInput(1, t2);   // close inner loop.
+  ind1->ReplaceInput(1, ind1);  // close inner induction variable.
+
+  Node* m1 = graph.NewNode(common.Merge(2), f1, f2);
+  Node* phi1 = graph.NewNode(common.Phi(kMachAnyTagged, 2), c, ind1, m1);
+
+  Node* add = graph.NewNode(&kIntAdd, ind, phi1);
+
+  Node* br = graph.NewNode(common.Branch(), add, loop);
+  Node* t = graph.NewNode(common.IfTrue(), br);
+  Node* f = graph.NewNode(common.IfFalse(), br);
+
+  loop->ReplaceInput(1, t);   // close loop.
+  ind->ReplaceInput(1, add);  // close induction variable.
+
+  Node* ret = graph.NewNode(common.Return(), ind, start, f);
+  Node* end = graph.NewNode(common.End(), ret, f);
+
+  graph.SetEnd(end);
+
+  ComputeAndVerifySchedule(28, &graph);
+}
+
+
+TEST(PhisPushedDownToDifferentBranches) {
+  HandleAndZoneScope scope;
+  Graph graph(scope.main_zone());
+  CommonOperatorBuilder common(scope.main_zone());
+
+  Node* start = graph.NewNode(common.Start(2));
+  graph.SetStart(start);
+
+  Node* p0 = graph.NewNode(common.Parameter(0), start);
+  Node* p1 = graph.NewNode(common.Parameter(1), start);
+
+  Node* v1 = graph.NewNode(common.Int32Constant(1));
+  Node* v2 = graph.NewNode(common.Int32Constant(2));
+  Node* v3 = graph.NewNode(common.Int32Constant(3));
+  Node* v4 = graph.NewNode(common.Int32Constant(4));
+  Node* br = graph.NewNode(common.Branch(), p0, graph.start());
+  Node* t = graph.NewNode(common.IfTrue(), br);
+  Node* f = graph.NewNode(common.IfFalse(), br);
+  Node* m = graph.NewNode(common.Merge(2), t, f);
+  Node* phi = graph.NewNode(common.Phi(kMachAnyTagged, 2), v1, v2, m);
+  Node* phi2 = graph.NewNode(common.Phi(kMachAnyTagged, 2), v3, v4, m);
+
+  Node* br2 = graph.NewNode(common.Branch(), p1, graph.start());
+  Node* t2 = graph.NewNode(common.IfTrue(), br2);
+  Node* f2 = graph.NewNode(common.IfFalse(), br2);
+  Node* m2 = graph.NewNode(common.Merge(2), t2, f2);
+  Node* phi3 = graph.NewNode(common.Phi(kMachAnyTagged, 2), phi, phi2, m2);
+
+  Node* ret = graph.NewNode(common.Return(), phi3, start, start);
+  Node* end = graph.NewNode(common.End(), ret, start);
+
+  graph.SetEnd(end);
+
+  ComputeAndVerifySchedule(24, &graph);
+}
+
+
+TEST(BranchHintTrue) {
+  HandleAndZoneScope scope;
+  Graph graph(scope.main_zone());
+  CommonOperatorBuilder common(scope.main_zone());
+
+  Node* start = graph.NewNode(common.Start(1));
+  graph.SetStart(start);
+
+  Node* p0 = graph.NewNode(common.Parameter(0), start);
+  Node* tv = graph.NewNode(common.Int32Constant(6));
+  Node* fv = graph.NewNode(common.Int32Constant(7));
+  Node* br = graph.NewNode(common.Branch(BranchHint::kTrue), p0, start);
+  Node* t = graph.NewNode(common.IfTrue(), br);
+  Node* f = graph.NewNode(common.IfFalse(), br);
+  Node* m = graph.NewNode(common.Merge(2), t, f);
+  Node* phi = graph.NewNode(common.Phi(kMachAnyTagged, 2), tv, fv, m);
+  Node* ret = graph.NewNode(common.Return(), phi, start, start);
+  Node* end = graph.NewNode(common.End(), ret, start);
+
+  graph.SetEnd(end);
+
+  Schedule* schedule = ComputeAndVerifySchedule(13, &graph);
+  // Make sure the false block is marked as deferred.
+  CHECK(!schedule->block(t)->deferred());
+  CHECK(schedule->block(f)->deferred());
+}
+
+
+TEST(BranchHintFalse) {
+  HandleAndZoneScope scope;
+  Graph graph(scope.main_zone());
+  CommonOperatorBuilder common(scope.main_zone());
+
+  Node* start = graph.NewNode(common.Start(1));
+  graph.SetStart(start);
+
+  Node* p0 = graph.NewNode(common.Parameter(0), start);
+  Node* tv = graph.NewNode(common.Int32Constant(6));
+  Node* fv = graph.NewNode(common.Int32Constant(7));
+  Node* br = graph.NewNode(common.Branch(BranchHint::kFalse), p0, start);
+  Node* t = graph.NewNode(common.IfTrue(), br);
+  Node* f = graph.NewNode(common.IfFalse(), br);
+  Node* m = graph.NewNode(common.Merge(2), t, f);
+  Node* phi = graph.NewNode(common.Phi(kMachAnyTagged, 2), tv, fv, m);
+  Node* ret = graph.NewNode(common.Return(), phi, start, start);
+  Node* end = graph.NewNode(common.End(), ret, start);
+
+  graph.SetEnd(end);
+
+  Schedule* schedule = ComputeAndVerifySchedule(13, &graph);
+  // Make sure the true block is marked as deferred.
+  CHECK(schedule->block(t)->deferred());
+  CHECK(!schedule->block(f)->deferred());
+}
+
+
+TEST(ScheduleTerminate) {
+  HandleAndZoneScope scope;
+  Graph graph(scope.main_zone());
+  CommonOperatorBuilder common(scope.main_zone());
+
+  Node* start = graph.NewNode(common.Start(1));
+  graph.SetStart(start);
+
+  Node* loop = graph.NewNode(common.Loop(2), start, start);
+  loop->ReplaceInput(1, loop);  // self loop, NTL.
+
+  Node* effect = graph.NewNode(common.EffectPhi(1), start, loop);
+  effect->ReplaceInput(0, effect);
+
+  Node* terminate = graph.NewNode(common.Terminate(1), effect, loop);
+  Node* end = graph.NewNode(common.End(), terminate);
+
+  graph.SetEnd(end);
+
+  Schedule* schedule = ComputeAndVerifySchedule(6, &graph);
+  BasicBlock* block = schedule->block(loop);
+  CHECK_NE(NULL, loop);
+  CHECK_EQ(block, schedule->block(effect));
+  CHECK_GE(block->rpo_number(), 0);
+}
+
 #endif
diff --git a/test/cctest/compiler/test-simplified-lowering.cc b/test/cctest/compiler/test-simplified-lowering.cc
index 96fb965..147aa32 100644
--- a/test/cctest/compiler/test-simplified-lowering.cc
+++ b/test/cctest/compiler/test-simplified-lowering.cc
@@ -5,8 +5,9 @@
 #include <limits>
 
 #include "src/compiler/access-builder.h"
+#include "src/compiler/change-lowering.h"
 #include "src/compiler/control-builders.h"
-#include "src/compiler/generic-node-inl.h"
+#include "src/compiler/graph-reducer.h"
 #include "src/compiler/graph-visualizer.h"
 #include "src/compiler/node-properties-inl.h"
 #include "src/compiler/pipeline.h"
@@ -35,11 +36,10 @@
                            MachineType p3 = kMachNone,
                            MachineType p4 = kMachNone)
       : GraphBuilderTester<ReturnType>(p0, p1, p2, p3, p4),
-        typer(this->zone()),
+        typer(this->graph(), MaybeHandle<Context>()),
         javascript(this->zone()),
-        jsgraph(this->graph(), this->common(), &javascript, &typer,
-                this->machine()),
-        lowering(&jsgraph) {}
+        jsgraph(this->graph(), this->common(), &javascript, this->machine()),
+        lowering(&jsgraph, this->zone()) {}
 
   Typer typer;
   JSOperatorBuilder javascript;
@@ -48,16 +48,40 @@
 
   void LowerAllNodes() {
     this->End();
+    typer.Run();
     lowering.LowerAllNodes();
   }
 
+  void LowerAllNodesAndLowerChanges() {
+    this->End();
+    typer.Run();
+    lowering.LowerAllNodes();
+
+    Zone* zone = this->zone();
+    CompilationInfo info(zone->isolate(), zone);
+    Linkage linkage(
+        zone, Linkage::GetSimplifiedCDescriptor(zone, this->machine_sig_));
+    ChangeLowering lowering(&jsgraph, &linkage);
+    GraphReducer reducer(this->graph(), this->zone());
+    reducer.AddReducer(&lowering);
+    reducer.ReduceGraph();
+    Verifier::Run(this->graph());
+  }
+
+  void CheckNumberCall(double expected, double input) {
+    // TODO(titzer): make calls to NewNumber work in cctests.
+    if (expected <= Smi::kMinValue) return;
+    if (expected >= Smi::kMaxValue) return;
+    Handle<Object> num = factory()->NewNumber(input);
+    Object* result = this->Call(*num);
+    CHECK(factory()->NewNumber(expected)->SameValue(result));
+  }
+
   Factory* factory() { return this->isolate()->factory(); }
   Heap* heap() { return this->isolate()->heap(); }
 };
 
 
-#ifndef V8_TARGET_ARCH_ARM64
-// TODO(titzer): these result in a stub call that doesn't work on ARM64.
 // TODO(titzer): factor these tests out to test-run-simplifiedops.cc.
 // TODO(titzer): test tagged representation for input to NumberToInt32.
 TEST(RunNumberToInt32_float64) {
@@ -68,6 +92,7 @@
   FieldAccess load = {kUntaggedBase, 0, Handle<Name>(), Type::Number(),
                       kMachFloat64};
   Node* loaded = t.LoadField(load, t.PointerConstant(&input));
+  NodeProperties::SetBounds(loaded, Bounds(Type::Number()));
   Node* convert = t.NumberToInt32(loaded);
   FieldAccess store = {kUntaggedBase, 0, Handle<Name>(), Type::Signed32(),
                        kMachInt32};
@@ -96,6 +121,7 @@
   FieldAccess load = {kUntaggedBase, 0, Handle<Name>(), Type::Number(),
                       kMachFloat64};
   Node* loaded = t.LoadField(load, t.PointerConstant(&input));
+  NodeProperties::SetBounds(loaded, Bounds(Type::Number()));
   Node* convert = t.NumberToUint32(loaded);
   FieldAccess store = {kUntaggedBase, 0, Handle<Name>(), Type::Unsigned32(),
                        kMachUint32};
@@ -113,7 +139,6 @@
     }
   }
 }
-#endif
 
 
 // Create a simple JSObject with a unique map.
@@ -207,10 +232,8 @@
 TEST(RunLoadStoreFixedArrayIndex) {
   SimplifiedLoweringTester<Object*> t(kMachAnyTagged);
   ElementAccess access = AccessBuilder::ForFixedArrayElement();
-  Node* load = t.LoadElement(access, t.Parameter(0), t.Int32Constant(0),
-                             t.Int32Constant(2));
-  t.StoreElement(access, t.Parameter(0), t.Int32Constant(1), t.Int32Constant(2),
-                 load);
+  Node* load = t.LoadElement(access, t.Parameter(0), t.Int32Constant(0));
+  t.StoreElement(access, t.Parameter(0), t.Int32Constant(1), load);
   t.Return(load);
 
   t.LowerAllNodes();
@@ -235,14 +258,13 @@
   const int index = 12;
   const int array_length = 2 * index;
   ElementAccess buffer_access =
-      AccessBuilder::ForBackingStoreElement(kMachInt8);
+      AccessBuilder::ForTypedArrayElement(v8::kExternalInt8Array, true);
   Node* backing_store = t.LoadField(
       AccessBuilder::ForJSArrayBufferBackingStore(), t.Parameter(0));
   Node* load =
-      t.LoadElement(buffer_access, backing_store, t.Int32Constant(index),
-                    t.Int32Constant(array_length));
+      t.LoadElement(buffer_access, backing_store, t.Int32Constant(index));
   t.StoreElement(buffer_access, backing_store, t.Int32Constant(index + 1),
-                 t.Int32Constant(array_length), load);
+                 load);
   t.Return(t.jsgraph.TrueConstant());
 
   t.LowerAllNodes();
@@ -329,9 +351,8 @@
                               kMachAnyTagged};
 
       SimplifiedLoweringTester<Object*> t;
-      Node* load = t.LoadElement(
-          access, t.PointerConstant(smis), t.Int32Constant(static_cast<int>(j)),
-          t.Int32Constant(static_cast<int>(arraysize(smis))));
+      Node* load = t.LoadElement(access, t.PointerConstant(smis),
+                                 t.Int32Constant(static_cast<int>(j)));
       t.Return(load);
       t.LowerAllNodes();
 
@@ -360,8 +381,7 @@
       SimplifiedLoweringTester<Object*> t(kMachAnyTagged);
       Node* p0 = t.Parameter(0);
       t.StoreElement(access, t.PointerConstant(smis),
-                     t.Int32Constant(static_cast<int>(j)),
-                     t.Int32Constant(static_cast<int>(arraysize(smis))), p0);
+                     t.Int32Constant(static_cast<int>(j)), p0);
       t.Return(p0);
       t.LowerAllNodes();
 
@@ -427,10 +447,8 @@
 
     SimplifiedLoweringTester<Object*> t;
     Node* ptr = GetBaseNode(&t);
-    Node* load = t.LoadElement(access, ptr, t.Int32Constant(from_index),
-                               t.Int32Constant(static_cast<int>(num_elements)));
-    t.StoreElement(access, ptr, t.Int32Constant(to_index),
-                   t.Int32Constant(static_cast<int>(num_elements)), load);
+    Node* load = t.LoadElement(access, ptr, t.Int32Constant(from_index));
+    t.StoreElement(access, ptr, t.Int32Constant(to_index), load);
     t.Return(t.jsgraph.TrueConstant());
     t.LowerAllNodes();
     t.GenerateCode();
@@ -648,9 +666,9 @@
   explicit TestingGraph(Type* p0_type, Type* p1_type = Type::None(),
                         Type* p2_type = Type::None())
       : GraphAndBuilders(main_zone()),
-        typer(main_zone()),
+        typer(graph(), MaybeHandle<Context>()),
         javascript(main_zone()),
-        jsgraph(graph(), common(), &javascript, &typer, machine()) {
+        jsgraph(graph(), common(), &javascript, machine()) {
     start = graph()->NewNode(common()->Start(2));
     graph()->SetStart(start);
     ret =
@@ -660,6 +678,7 @@
     p0 = graph()->NewNode(common()->Parameter(0), start);
     p1 = graph()->NewNode(common()->Parameter(1), start);
     p2 = graph()->NewNode(common()->Parameter(2), start);
+    typer.Run();
     NodeProperties::SetBounds(p0, Bounds(p0_type));
     NodeProperties::SetBounds(p1, Bounds(p1_type));
     NodeProperties::SetBounds(p2, Bounds(p2_type));
@@ -679,10 +698,7 @@
     CHECK_EQ(expected, node->opcode());
   }
 
-  void Lower() {
-    SimplifiedLowering lowering(&jsgraph);
-    lowering.LowerAllNodes();
-  }
+  void Lower() { SimplifiedLowering(&jsgraph, jsgraph.zone()).LowerAllNodes(); }
 
   // Inserts the node as the return value of the graph.
   Node* Return(Node* node) {
@@ -718,6 +734,17 @@
     }
   }
 
+  Node* ExampleWithTypeAndRep(Type* type, MachineType mach_type) {
+    FieldAccess access = {kUntaggedBase, 0, Handle<Name>::null(), type,
+                          mach_type};
+    // TODO(titzer): using loads here just to force the representation is ugly.
+    Node* node = graph()->NewNode(simplified()->LoadField(access),
+                                  jsgraph.IntPtrConstant(0), graph()->start(),
+                                  graph()->start());
+    NodeProperties::SetBounds(node, Bounds(type));
+    return node;
+  }
+
   Node* Use(Node* node, MachineType type) {
     if (type & kTypeInt32) {
       return graph()->NewNode(machine()->Int32LessThan(), node,
@@ -731,6 +758,9 @@
     } else if (type & kRepWord64) {
       return graph()->NewNode(machine()->Int64LessThan(), node,
                               Int64Constant(1));
+    } else if (type & kRepWord32) {
+      return graph()->NewNode(machine()->Word32Equal(), node,
+                              jsgraph.Int32Constant(1));
     } else {
       return graph()->NewNode(simplified()->ReferenceEqual(Type::Any()), node,
                               jsgraph.TrueConstant());
@@ -757,6 +787,50 @@
 };
 
 
+TEST(LowerAnyToBoolean_bit_bit) {
+  // AnyToBoolean(x: kRepBit) used as kRepBit
+  HandleAndZoneScope scope;
+  Factory* f = scope.main_zone()->isolate()->factory();
+  Handle<Object> zero = f->NewNumber(0);
+  Handle<Object> one = f->NewNumber(1);
+  Type* singleton_zero = Type::Constant(zero, scope.main_zone());
+  Type* singleton_one = Type::Constant(one, scope.main_zone());
+  Type* zero_one_range = Type::Range(zero, one, scope.main_zone());
+  static Type* kTypes[] = {
+      singleton_zero, singleton_one, zero_one_range, Type::Boolean(),
+      Type::Union(Type::Boolean(), singleton_zero, scope.main_zone()),
+      Type::Union(Type::Boolean(), singleton_one, scope.main_zone()),
+      Type::Union(Type::Boolean(), zero_one_range, scope.main_zone())};
+  for (Type* type : kTypes) {
+    TestingGraph t(type);
+    Node* x = t.ExampleWithTypeAndRep(type, kRepBit);
+    Node* cnv = t.graph()->NewNode(t.simplified()->AnyToBoolean(), x);
+    Node* use = t.Branch(cnv);
+    t.Lower();
+    CHECK_EQ(x, use->InputAt(0));
+  }
+}
+
+
+#if V8_TURBOFAN_TARGET
+
+TEST(LowerAnyToBoolean_tagged_tagged) {
+  // AnyToBoolean(x: kRepTagged) used as kRepTagged
+  TestingGraph t(Type::Any());
+  Node* x = t.p0;
+  Node* cnv = t.graph()->NewNode(t.simplified()->AnyToBoolean(), x);
+  Node* use = t.Use(cnv, kRepTagged);
+  t.Return(use);
+  t.Lower();
+  CHECK_EQ(IrOpcode::kCall, cnv->opcode());
+  CHECK_EQ(IrOpcode::kHeapConstant, cnv->InputAt(0)->opcode());
+  CHECK_EQ(x, cnv->InputAt(1));
+  CHECK_EQ(t.jsgraph.NoContextConstant(), cnv->InputAt(2));
+}
+
+#endif
+
+
 TEST(LowerBooleanNot_bit_bit) {
   // BooleanNot(x: kRepBit) used as kRepBit
   TestingGraph t(Type::Boolean());
@@ -765,7 +839,7 @@
   Node* use = t.Branch(inv);
   t.Lower();
   Node* cmp = use->InputAt(0);
-  CHECK_EQ(t.machine()->WordEqual()->opcode(), cmp->opcode());
+  CHECK_EQ(t.machine()->Word32Equal()->opcode(), cmp->opcode());
   CHECK(b == cmp->InputAt(0) || b == cmp->InputAt(1));
   Node* f = t.jsgraph.Int32Constant(0);
   CHECK(f == cmp->InputAt(0) || f == cmp->InputAt(1));
@@ -782,7 +856,7 @@
   t.Lower();
   CHECK_EQ(IrOpcode::kChangeBitToBool, use->InputAt(0)->opcode());
   Node* cmp = use->InputAt(0)->InputAt(0);
-  CHECK_EQ(t.machine()->WordEqual()->opcode(), cmp->opcode());
+  CHECK_EQ(t.machine()->Word32Equal()->opcode(), cmp->opcode());
   CHECK(b == cmp->InputAt(0) || b == cmp->InputAt(1));
   Node* f = t.jsgraph.Int32Constant(0);
   CHECK(f == cmp->InputAt(0) || f == cmp->InputAt(1));
@@ -921,24 +995,50 @@
 
 
 TEST(LowerNumberAddSub_to_int32) {
-  TestingGraph t(Type::Signed32(), Type::Signed32());
-  t.CheckLoweringTruncatedBinop(IrOpcode::kInt32Add,
-                                t.simplified()->NumberAdd(),
-                                t.simplified()->NumberToInt32());
-  t.CheckLoweringTruncatedBinop(IrOpcode::kInt32Sub,
-                                t.simplified()->NumberSubtract(),
-                                t.simplified()->NumberToInt32());
+  HandleAndZoneScope scope;
+  Factory* f = scope.main_zone()->isolate()->factory();
+  Type* small_range =
+      Type::Range(f->NewNumber(1), f->NewNumber(10), scope.main_zone());
+  Type* large_range =
+      Type::Range(f->NewNumber(-1e+13), f->NewNumber(1e+14), scope.main_zone());
+  static Type* types[] = {Type::Signed32(), Type::Integral32(), small_range,
+                          large_range};
+
+  for (size_t i = 0; i < arraysize(types); i++) {
+    for (size_t j = 0; j < arraysize(types); j++) {
+      TestingGraph t(types[i], types[j]);
+      t.CheckLoweringTruncatedBinop(IrOpcode::kInt32Add,
+                                    t.simplified()->NumberAdd(),
+                                    t.simplified()->NumberToInt32());
+      t.CheckLoweringTruncatedBinop(IrOpcode::kInt32Sub,
+                                    t.simplified()->NumberSubtract(),
+                                    t.simplified()->NumberToInt32());
+    }
+  }
 }
 
 
 TEST(LowerNumberAddSub_to_uint32) {
-  TestingGraph t(Type::Unsigned32(), Type::Unsigned32());
-  t.CheckLoweringTruncatedBinop(IrOpcode::kInt32Add,
-                                t.simplified()->NumberAdd(),
-                                t.simplified()->NumberToUint32());
-  t.CheckLoweringTruncatedBinop(IrOpcode::kInt32Sub,
-                                t.simplified()->NumberSubtract(),
-                                t.simplified()->NumberToUint32());
+  HandleAndZoneScope scope;
+  Factory* f = scope.main_zone()->isolate()->factory();
+  Type* small_range =
+      Type::Range(f->NewNumber(1), f->NewNumber(10), scope.main_zone());
+  Type* large_range =
+      Type::Range(f->NewNumber(-1e+13), f->NewNumber(1e+14), scope.main_zone());
+  static Type* types[] = {Type::Signed32(), Type::Integral32(), small_range,
+                          large_range};
+
+  for (size_t i = 0; i < arraysize(types); i++) {
+    for (size_t j = 0; j < arraysize(types); j++) {
+      TestingGraph t(types[i], types[j]);
+      t.CheckLoweringTruncatedBinop(IrOpcode::kInt32Add,
+                                    t.simplified()->NumberAdd(),
+                                    t.simplified()->NumberToUint32());
+      t.CheckLoweringTruncatedBinop(IrOpcode::kInt32Sub,
+                                    t.simplified()->NumberSubtract(),
+                                    t.simplified()->NumberToUint32());
+    }
+  }
 }
 
 
@@ -958,8 +1058,10 @@
     TestingGraph t(test_types[i], test_types[i]);
 
     t.CheckLoweringBinop(IrOpcode::kFloat64Div, t.simplified()->NumberDivide());
-    t.CheckLoweringBinop(IrOpcode::kFloat64Mod,
-                         t.simplified()->NumberModulus());
+    if (!test_types[i]->Is(Type::Unsigned32())) {
+      t.CheckLoweringBinop(IrOpcode::kFloat64Mod,
+                           t.simplified()->NumberModulus());
+    }
   }
 }
 
@@ -1006,7 +1108,7 @@
 TEST(LowerNumberToInt32_to_TruncateFloat64ToInt32) {
   // NumberToInt32(x: kRepFloat64) used as kMachInt32
   TestingGraph t(Type::Number());
-  Node* p0 = t.ExampleWithOutput(kMachFloat64);
+  Node* p0 = t.ExampleWithTypeAndRep(Type::Number(), kMachFloat64);
   Node* trunc = t.graph()->NewNode(t.simplified()->NumberToInt32(), p0);
   Node* use = t.Use(trunc, kMachInt32);
   t.Return(use);
@@ -1030,17 +1132,6 @@
 }
 
 
-TEST(LowerNumberToInt32_to_ChangeFloat64ToTagged) {
-  // TODO(titzer): NumberToInt32(x: kRepFloat64 | kTypeInt32) used as kRepTagged
-}
-
-
-TEST(LowerNumberToInt32_to_ChangeFloat64ToInt32) {
-  // TODO(titzer): NumberToInt32(x: kRepFloat64 | kTypeInt32) used as kRepWord32
-  // | kTypeInt32
-}
-
-
 TEST(LowerNumberToUint32_to_nop) {
   // NumberToUint32(x: kRepTagged | kTypeUint32) used as kRepTagged
   TestingGraph t(Type::Unsigned32());
@@ -1078,6 +1169,8 @@
   // NumberToUint32(x: kRepFloat64) used as kMachUint32
   TestingGraph t(Type::Number());
   Node* p0 = t.ExampleWithOutput(kMachFloat64);
+  // TODO(titzer): run the typer here, or attach machine type to param.
+  NodeProperties::SetBounds(p0, Bounds(Type::Number()));
   Node* trunc = t.graph()->NewNode(t.simplified()->NumberToUint32(), p0);
   Node* use = t.Use(trunc, kMachUint32);
   t.Return(use);
@@ -1101,20 +1194,67 @@
 }
 
 
-TEST(LowerNumberToUint32_to_ChangeFloat64ToTagged) {
-  // TODO(titzer): NumberToUint32(x: kRepFloat64 | kTypeUint32) used as
-  // kRepTagged
+TEST(LowerNumberToUint32_to_TruncateFloat64ToInt32_uint32) {
+  // NumberToUint32(x: kRepFloat64) used as kRepWord32
+  TestingGraph t(Type::Unsigned32());
+  Node* input = t.ExampleWithTypeAndRep(Type::Number(), kMachFloat64);
+  Node* trunc = t.graph()->NewNode(t.simplified()->NumberToUint32(), input);
+  Node* use = t.Use(trunc, kRepWord32);
+  t.Return(use);
+  t.Lower();
+  CheckChangeOf(IrOpcode::kTruncateFloat64ToInt32, input, use->InputAt(0));
 }
 
 
-TEST(LowerNumberToUint32_to_ChangeFloat64ToUint32) {
-  // TODO(titzer): NumberToUint32(x: kRepFloat64 | kTypeUint32) used as
-  // kRepWord32
+TEST(LowerNumberToUI32_of_Float64_used_as_word32) {
+  // NumberTo(Int,Uint)32(x: kRepFloat64 | kType(Int,Uint)32) used as
+  // kType(Int,Uint)32 | kRepWord32
+  Type* types[] = {Type::Signed32(), Type::Unsigned32()};
+  MachineType mach[] = {kTypeInt32, kTypeUint32, kMachNone};
+
+  for (int i = 0; i < 2; i++) {
+    for (int u = 0; u < 3; u++) {
+      TestingGraph t(types[i]);
+      Node* input = t.ExampleWithTypeAndRep(
+          types[i], static_cast<MachineType>(kRepFloat64 | mach[i]));
+      const Operator* op = i == 0 ? t.simplified()->NumberToInt32()
+                                  : t.simplified()->NumberToUint32();
+      Node* trunc = t.graph()->NewNode(op, input);
+      Node* use = t.Use(trunc, static_cast<MachineType>(kRepWord32 | mach[u]));
+      t.Return(use);
+      t.Lower();
+      IrOpcode::Value opcode = i == 0 ? IrOpcode::kChangeFloat64ToInt32
+                                      : IrOpcode::kChangeFloat64ToUint32;
+      CheckChangeOf(opcode, input, use->InputAt(0));
+    }
+  }
 }
 
 
-TEST(LowerNumberToUint32_to_TruncateFloat64ToUint32) {
-  // TODO(titzer): NumberToUint32(x: kRepFloat64) used as kRepWord32
+TEST(LowerNumberToUI32_of_Float64_used_as_tagged) {
+  // NumberTo(Int,Uint)32(x: kRepFloat64 | kType(Int,Uint)32) used as
+  // kType(Int,Uint)32 | kRepTagged
+  Type* types[] = {Type::Signed32(), Type::Unsigned32(), Type::Any()};
+  MachineType mach[] = {kTypeInt32, kTypeUint32, kMachNone};
+
+  for (int i = 0; i < 2; i++) {
+    for (int u = 0; u < 3; u++) {
+      TestingGraph t(types[i]);
+      Node* input = t.ExampleWithTypeAndRep(
+          types[i], static_cast<MachineType>(kRepFloat64 | mach[i]));
+      const Operator* op = i == 0 ? t.simplified()->NumberToInt32()
+                                  : t.simplified()->NumberToUint32();
+      Node* trunc = t.graph()->NewNode(op, input);
+      // TODO(titzer): we use the store here to force the representation.
+      FieldAccess access = {kTaggedBase, 0, Handle<Name>(), types[u],
+                            static_cast<MachineType>(mach[u] | kRepTagged)};
+      Node* store = t.graph()->NewNode(t.simplified()->StoreField(access), t.p0,
+                                       trunc, t.start, t.start);
+      t.Effect(store);
+      t.Lower();
+      CheckChangeOf(IrOpcode::kChangeFloat64ToTagged, input, store->InputAt(2));
+    }
+  }
 }
 
 
@@ -1268,45 +1408,54 @@
 }
 
 
+namespace {
+
 void CheckFieldAccessArithmetic(FieldAccess access, Node* load_or_store) {
-  Int32Matcher index = Int32Matcher(load_or_store->InputAt(1));
-  CHECK(index.Is(access.offset - access.tag()));
+  IntPtrMatcher mindex(load_or_store->InputAt(1));
+  CHECK(mindex.Is(access.offset - access.tag()));
 }
 
 
 Node* CheckElementAccessArithmetic(ElementAccess access, Node* load_or_store) {
-  Int32BinopMatcher index(load_or_store->InputAt(1));
-  CHECK_EQ(IrOpcode::kInt32Add, index.node()->opcode());
-  CHECK(index.right().Is(access.header_size - access.tag()));
+  Node* index = load_or_store->InputAt(1);
+  if (kPointerSize == 8) {
+    CHECK_EQ(IrOpcode::kChangeUint32ToUint64, index->opcode());
+    index = index->InputAt(0);
+  }
 
-  int element_size = ElementSizeOf(access.machine_type);
+  Int32BinopMatcher mindex(index);
+  CHECK_EQ(IrOpcode::kInt32Add, mindex.node()->opcode());
+  CHECK(mindex.right().Is(access.header_size - access.tag()));
 
-  if (element_size != 1) {
-    Int32BinopMatcher mul(index.left().node());
-    CHECK_EQ(IrOpcode::kInt32Mul, mul.node()->opcode());
-    CHECK(mul.right().Is(element_size));
-    return mul.left().node();
+  const int element_size_shift = ElementSizeLog2Of(access.machine_type);
+  if (element_size_shift) {
+    Int32BinopMatcher shl(mindex.left().node());
+    CHECK_EQ(IrOpcode::kWord32Shl, shl.node()->opcode());
+    CHECK(shl.right().Is(element_size_shift));
+    return shl.left().node();
   } else {
-    return index.left().node();
+    return mindex.left().node();
   }
 }
 
 
-static const MachineType machine_reps[] = {
-    kRepBit,    kMachInt8,    kMachInt16,    kMachInt32,
-    kMachInt64, kMachFloat64, kMachAnyTagged};
+const MachineType kMachineReps[] = {kRepBit,       kMachInt8,  kMachInt16,
+                                    kMachInt32,    kMachInt64, kMachFloat64,
+                                    kMachAnyTagged};
+
+}  // namespace
 
 
 TEST(LowerLoadField_to_load) {
   TestingGraph t(Type::Any(), Type::Signed32());
 
-  for (size_t i = 0; i < arraysize(machine_reps); i++) {
+  for (size_t i = 0; i < arraysize(kMachineReps); i++) {
     FieldAccess access = {kTaggedBase, FixedArrayBase::kHeaderSize,
-                          Handle<Name>::null(), Type::Any(), machine_reps[i]};
+                          Handle<Name>::null(), Type::Any(), kMachineReps[i]};
 
     Node* load =
         t.graph()->NewNode(t.simplified()->LoadField(access), t.p0, t.start);
-    Node* use = t.Use(load, machine_reps[i]);
+    Node* use = t.Use(load, kMachineReps[i]);
     t.Return(use);
     t.Lower();
     CHECK_EQ(IrOpcode::kLoad, load->opcode());
@@ -1314,7 +1463,7 @@
     CheckFieldAccessArithmetic(access, load);
 
     MachineType rep = OpParameter<MachineType>(load);
-    CHECK_EQ(machine_reps[i], rep);
+    CHECK_EQ(kMachineReps[i], rep);
   }
 }
 
@@ -1322,12 +1471,12 @@
 TEST(LowerStoreField_to_store) {
   TestingGraph t(Type::Any(), Type::Signed32());
 
-  for (size_t i = 0; i < arraysize(machine_reps); i++) {
+  for (size_t i = 0; i < arraysize(kMachineReps); i++) {
     FieldAccess access = {kTaggedBase, FixedArrayBase::kHeaderSize,
-                          Handle<Name>::null(), Type::Any(), machine_reps[i]};
+                          Handle<Name>::null(), Type::Any(), kMachineReps[i]};
 
 
-    Node* val = t.ExampleWithOutput(machine_reps[i]);
+    Node* val = t.ExampleWithOutput(kMachineReps[i]);
     Node* store = t.graph()->NewNode(t.simplified()->StoreField(access), t.p0,
                                      val, t.start, t.start);
     t.Effect(store);
@@ -1337,10 +1486,10 @@
     CheckFieldAccessArithmetic(access, store);
 
     StoreRepresentation rep = OpParameter<StoreRepresentation>(store);
-    if (machine_reps[i] & kRepTagged) {
+    if (kMachineReps[i] & kRepTagged) {
       CHECK_EQ(kFullWriteBarrier, rep.write_barrier_kind());
     }
-    CHECK_EQ(machine_reps[i], rep.machine_type());
+    CHECK_EQ(kMachineReps[i], rep.machine_type());
   }
 }
 
@@ -1348,14 +1497,13 @@
 TEST(LowerLoadElement_to_load) {
   TestingGraph t(Type::Any(), Type::Signed32());
 
-  for (size_t i = 0; i < arraysize(machine_reps); i++) {
+  for (size_t i = 0; i < arraysize(kMachineReps); i++) {
     ElementAccess access = {kTaggedBase, FixedArrayBase::kHeaderSize,
-                            Type::Any(), machine_reps[i]};
+                            Type::Any(), kMachineReps[i]};
 
-    Node* load =
-        t.graph()->NewNode(t.simplified()->LoadElement(access), t.p0, t.p1,
-                           t.jsgraph.Int32Constant(1024), t.start);
-    Node* use = t.Use(load, machine_reps[i]);
+    Node* load = t.graph()->NewNode(t.simplified()->LoadElement(access), t.p0,
+                                    t.p1, t.start, t.start);
+    Node* use = t.Use(load, kMachineReps[i]);
     t.Return(use);
     t.Lower();
     CHECK_EQ(IrOpcode::kLoad, load->opcode());
@@ -1363,7 +1511,7 @@
     CheckElementAccessArithmetic(access, load);
 
     MachineType rep = OpParameter<MachineType>(load);
-    CHECK_EQ(machine_reps[i], rep);
+    CHECK_EQ(kMachineReps[i], rep);
   }
 }
 
@@ -1371,14 +1519,13 @@
 TEST(LowerStoreElement_to_store) {
   TestingGraph t(Type::Any(), Type::Signed32());
 
-  for (size_t i = 0; i < arraysize(machine_reps); i++) {
+  for (size_t i = 0; i < arraysize(kMachineReps); i++) {
     ElementAccess access = {kTaggedBase, FixedArrayBase::kHeaderSize,
-                            Type::Any(), machine_reps[i]};
+                            Type::Any(), kMachineReps[i]};
 
-    Node* val = t.ExampleWithOutput(machine_reps[i]);
+    Node* val = t.ExampleWithOutput(kMachineReps[i]);
     Node* store = t.graph()->NewNode(t.simplified()->StoreElement(access), t.p0,
-                                     t.p1, t.jsgraph.Int32Constant(1024), val,
-                                     t.start, t.start);
+                                     t.p1, val, t.start, t.start);
     t.Effect(store);
     t.Lower();
     CHECK_EQ(IrOpcode::kStore, store->opcode());
@@ -1386,10 +1533,10 @@
     CheckElementAccessArithmetic(access, store);
 
     StoreRepresentation rep = OpParameter<StoreRepresentation>(store);
-    if (machine_reps[i] & kRepTagged) {
+    if (kMachineReps[i] & kRepTagged) {
       CHECK_EQ(kFullWriteBarrier, rep.write_barrier_kind());
     }
-    CHECK_EQ(machine_reps[i], rep.machine_type());
+    CHECK_EQ(kMachineReps[i], rep.machine_type());
   }
 }
 
@@ -1397,12 +1544,12 @@
 TEST(InsertChangeForLoadElementIndex) {
   // LoadElement(obj: Tagged, index: kTypeInt32 | kRepTagged, length) =>
   //   Load(obj, Int32Add(Int32Mul(ChangeTaggedToInt32(index), #k), #k))
-  TestingGraph t(Type::Any(), Type::Signed32(), Type::Any());
+  TestingGraph t(Type::Any(), Type::Signed32());
   ElementAccess access = {kTaggedBase, FixedArrayBase::kHeaderSize, Type::Any(),
                           kMachAnyTagged};
 
   Node* load = t.graph()->NewNode(t.simplified()->LoadElement(access), t.p0,
-                                  t.p1, t.p2, t.start);
+                                  t.p1, t.start, t.start);
   t.Return(load);
   t.Lower();
   CHECK_EQ(IrOpcode::kLoad, load->opcode());
@@ -1416,12 +1563,12 @@
 TEST(InsertChangeForStoreElementIndex) {
   // StoreElement(obj: Tagged, index: kTypeInt32 | kRepTagged, length, val) =>
   //   Store(obj, Int32Add(Int32Mul(ChangeTaggedToInt32(index), #k), #k), val)
-  TestingGraph t(Type::Any(), Type::Signed32(), Type::Any());
+  TestingGraph t(Type::Any(), Type::Signed32());
   ElementAccess access = {kTaggedBase, FixedArrayBase::kHeaderSize, Type::Any(),
                           kMachAnyTagged};
 
   Node* store =
-      t.graph()->NewNode(t.simplified()->StoreElement(access), t.p0, t.p1, t.p2,
+      t.graph()->NewNode(t.simplified()->StoreElement(access), t.p0, t.p1,
                          t.jsgraph.TrueConstant(), t.start, t.start);
   t.Effect(store);
   t.Lower();
@@ -1440,7 +1587,7 @@
                           kMachFloat64};
 
   Node* load = t.graph()->NewNode(t.simplified()->LoadElement(access), t.p0,
-                                  t.p1, t.p1, t.start);
+                                  t.p1, t.start, t.start);
   t.Return(load);
   t.Lower();
   CHECK_EQ(IrOpcode::kLoad, load->opcode());
@@ -1467,13 +1614,13 @@
 
 TEST(InsertChangeForStoreElement) {
   // TODO(titzer): test all load/store representation change insertions.
-  TestingGraph t(Type::Any(), Type::Signed32(), Type::Any());
+  TestingGraph t(Type::Any(), Type::Signed32());
   ElementAccess access = {kTaggedBase, FixedArrayBase::kHeaderSize, Type::Any(),
                           kMachFloat64};
 
-  Node* store = t.graph()->NewNode(t.simplified()->StoreElement(access), t.p0,
-                                   t.jsgraph.Int32Constant(0), t.p2, t.p1,
-                                   t.start, t.start);
+  Node* store =
+      t.graph()->NewNode(t.simplified()->StoreElement(access), t.p0,
+                         t.jsgraph.Int32Constant(0), t.p1, t.start, t.start);
   t.Effect(store);
   t.Lower();
 
@@ -1504,10 +1651,11 @@
   TestingGraph t(Type::Any(), Type::Signed32());
   static const MachineType kMachineTypes[] = {kMachInt32, kMachUint32,
                                               kMachFloat64};
+  Type* kTypes[] = {Type::Signed32(), Type::Unsigned32(), Type::Number()};
 
   for (size_t i = 0; i < arraysize(kMachineTypes); i++) {
     FieldAccess access = {kTaggedBase, FixedArrayBase::kHeaderSize,
-                          Handle<Name>::null(), Type::Any(), kMachineTypes[i]};
+                          Handle<Name>::null(), kTypes[i], kMachineTypes[i]};
 
     Node* load0 =
         t.graph()->NewNode(t.simplified()->LoadField(access), t.p0, t.start);
@@ -1525,36 +1673,405 @@
 }
 
 
-// TODO(titzer): this tests current behavior of assuming an implicit
-// representation change in loading float32s. Fix when float32 is fully
-// supported.
-TEST(ImplicitFloat32ToFloat64InLoads) {
-  TestingGraph t(Type::Any());
+TEST(RunNumberDivide_minus_1_TruncatingToInt32) {
+  SimplifiedLoweringTester<Object*> t(kMachAnyTagged);
+  Node* num = t.NumberToInt32(t.Parameter(0));
+  Node* div = t.NumberDivide(num, t.jsgraph.Constant(-1));
+  Node* trunc = t.NumberToInt32(div);
+  t.Return(trunc);
 
-  FieldAccess access = {kTaggedBase, FixedArrayBase::kHeaderSize,
-                        Handle<Name>::null(), Type::Any(), kMachFloat32};
+  if (Pipeline::SupportedTarget()) {
+    t.LowerAllNodesAndLowerChanges();
+    t.GenerateCode();
 
-  Node* load =
-      t.graph()->NewNode(t.simplified()->LoadField(access), t.p0, t.start);
-  t.Return(load);
-  t.Lower();
-  CHECK_EQ(IrOpcode::kLoad, load->opcode());
-  CHECK_EQ(t.p0, load->InputAt(0));
-  CheckChangeOf(IrOpcode::kChangeFloat64ToTagged, load, t.ret->InputAt(0));
+    FOR_INT32_INPUTS(i) {
+      int32_t x = 0 - *i;
+      t.CheckNumberCall(static_cast<double>(x), static_cast<double>(*i));
+    }
+  }
 }
 
 
-TEST(ImplicitFloat64ToFloat32InStores) {
-  TestingGraph t(Type::Any(), Type::Signed32());
-  FieldAccess access = {kTaggedBase, FixedArrayBase::kHeaderSize,
-                        Handle<Name>::null(), Type::Any(), kMachFloat32};
+TEST(NumberMultiply_TruncatingToInt32) {
+  int32_t constants[] = {-100, -10, -1, 0, 1, 100, 1000};
 
-  Node* store = t.graph()->NewNode(t.simplified()->StoreField(access), t.p0,
-                                   t.p1, t.start, t.start);
-  t.Effect(store);
+  for (size_t i = 0; i < arraysize(constants); i++) {
+    TestingGraph t(Type::Signed32());
+    Node* k = t.jsgraph.Constant(constants[i]);
+    Node* mul = t.graph()->NewNode(t.simplified()->NumberMultiply(), t.p0, k);
+    Node* trunc = t.graph()->NewNode(t.simplified()->NumberToInt32(), mul);
+    t.Return(trunc);
+    t.Lower();
+
+    CHECK_EQ(IrOpcode::kInt32Mul, mul->opcode());
+  }
+}
+
+
+TEST(RunNumberMultiply_TruncatingToInt32) {
+  int32_t constants[] = {-100, -10, -1, 0, 1, 100, 1000, 3000999};
+
+  for (size_t i = 0; i < arraysize(constants); i++) {
+    double k = static_cast<double>(constants[i]);
+    SimplifiedLoweringTester<Object*> t(kMachAnyTagged);
+    Node* num = t.NumberToInt32(t.Parameter(0));
+    Node* mul = t.NumberMultiply(num, t.jsgraph.Constant(k));
+    Node* trunc = t.NumberToInt32(mul);
+    t.Return(trunc);
+
+    if (Pipeline::SupportedTarget()) {
+      t.LowerAllNodesAndLowerChanges();
+      t.GenerateCode();
+
+      FOR_INT32_INPUTS(i) {
+        int32_t x = DoubleToInt32(static_cast<double>(*i) * k);
+        t.CheckNumberCall(static_cast<double>(x), static_cast<double>(*i));
+      }
+    }
+  }
+}
+
+
+TEST(RunNumberMultiply_TruncatingToUint32) {
+  uint32_t constants[] = {0, 1, 2, 3, 4, 100, 1000, 1024, 2048, 3000999};
+
+  for (size_t i = 0; i < arraysize(constants); i++) {
+    double k = static_cast<double>(constants[i]);
+    SimplifiedLoweringTester<Object*> t(kMachAnyTagged);
+    Node* num = t.NumberToUint32(t.Parameter(0));
+    Node* mul = t.NumberMultiply(num, t.jsgraph.Constant(k));
+    Node* trunc = t.NumberToUint32(mul);
+    t.Return(trunc);
+
+    if (Pipeline::SupportedTarget()) {
+      t.LowerAllNodesAndLowerChanges();
+      t.GenerateCode();
+
+      FOR_UINT32_INPUTS(i) {
+        uint32_t x = DoubleToUint32(static_cast<double>(*i) * k);
+        t.CheckNumberCall(static_cast<double>(x), static_cast<double>(*i));
+      }
+    }
+  }
+}
+
+
+TEST(RunNumberDivide_2_TruncatingToUint32) {
+  SimplifiedLoweringTester<Object*> t(kMachAnyTagged);
+  Node* num = t.NumberToUint32(t.Parameter(0));
+  Node* div = t.NumberDivide(num, t.jsgraph.Constant(2));
+  Node* trunc = t.NumberToUint32(div);
+  t.Return(trunc);
+
+  if (Pipeline::SupportedTarget()) {
+    t.LowerAllNodesAndLowerChanges();
+    t.GenerateCode();
+
+    FOR_UINT32_INPUTS(i) {
+      uint32_t x = DoubleToUint32(static_cast<double>(*i / 2.0));
+      t.CheckNumberCall(static_cast<double>(x), static_cast<double>(*i));
+    }
+  }
+}
+
+
+TEST(NumberMultiply_ConstantOutOfRange) {
+  TestingGraph t(Type::Signed32());
+  Node* k = t.jsgraph.Constant(1000000023);
+  Node* mul = t.graph()->NewNode(t.simplified()->NumberMultiply(), t.p0, k);
+  Node* trunc = t.graph()->NewNode(t.simplified()->NumberToInt32(), mul);
+  t.Return(trunc);
   t.Lower();
 
-  CHECK_EQ(IrOpcode::kStore, store->opcode());
-  CHECK_EQ(t.p0, store->InputAt(0));
-  CheckChangeOf(IrOpcode::kChangeTaggedToFloat64, t.p1, store->InputAt(2));
+  CHECK_EQ(IrOpcode::kFloat64Mul, mul->opcode());
+}
+
+
+TEST(NumberMultiply_NonTruncating) {
+  TestingGraph t(Type::Signed32());
+  Node* k = t.jsgraph.Constant(111);
+  Node* mul = t.graph()->NewNode(t.simplified()->NumberMultiply(), t.p0, k);
+  t.Return(mul);
+  t.Lower();
+
+  CHECK_EQ(IrOpcode::kFloat64Mul, mul->opcode());
+}
+
+
+TEST(NumberDivide_TruncatingToInt32) {
+  int32_t constants[] = {-100, -10, 1, 4, 100, 1000};
+
+  for (size_t i = 0; i < arraysize(constants); i++) {
+    TestingGraph t(Type::Signed32());
+    Node* k = t.jsgraph.Constant(constants[i]);
+    Node* div = t.graph()->NewNode(t.simplified()->NumberDivide(), t.p0, k);
+    Node* use = t.Use(div, kMachInt32);
+    t.Return(use);
+    t.Lower();
+
+    CHECK_EQ(IrOpcode::kInt32Div, use->InputAt(0)->opcode());
+  }
+}
+
+
+TEST(RunNumberDivide_TruncatingToInt32) {
+  int32_t constants[] = {-100, -10, -1, 1, 2, 100, 1000, 1024, 2048};
+
+  for (size_t i = 0; i < arraysize(constants); i++) {
+    int32_t k = constants[i];
+    SimplifiedLoweringTester<Object*> t(kMachAnyTagged);
+    Node* num = t.NumberToInt32(t.Parameter(0));
+    Node* div = t.NumberDivide(num, t.jsgraph.Constant(k));
+    Node* trunc = t.NumberToInt32(div);
+    t.Return(trunc);
+
+    if (Pipeline::SupportedTarget()) {
+      t.LowerAllNodesAndLowerChanges();
+      t.GenerateCode();
+
+      FOR_INT32_INPUTS(i) {
+        if (*i == INT_MAX) continue;  // exclude max int.
+        int32_t x = DoubleToInt32(static_cast<double>(*i) / k);
+        t.CheckNumberCall(static_cast<double>(x), static_cast<double>(*i));
+      }
+    }
+  }
+}
+
+
+TEST(NumberDivide_TruncatingToUint32) {
+  double constants[] = {1, 3, 100, 1000, 100998348};
+
+  for (size_t i = 0; i < arraysize(constants); i++) {
+    TestingGraph t(Type::Unsigned32());
+    Node* k = t.jsgraph.Constant(constants[i]);
+    Node* div = t.graph()->NewNode(t.simplified()->NumberDivide(), t.p0, k);
+    Node* use = t.Use(div, kMachUint32);
+    t.Return(use);
+    t.Lower();
+
+    CHECK_EQ(IrOpcode::kUint32Div, use->InputAt(0)->opcode());
+  }
+}
+
+
+TEST(RunNumberDivide_TruncatingToUint32) {
+  uint32_t constants[] = {100, 10, 1, 1, 2, 4, 1000, 1024, 2048};
+
+  for (size_t i = 0; i < arraysize(constants); i++) {
+    uint32_t k = constants[i];
+    SimplifiedLoweringTester<Object*> t(kMachAnyTagged);
+    Node* num = t.NumberToUint32(t.Parameter(0));
+    Node* div = t.NumberDivide(num, t.jsgraph.Constant(static_cast<double>(k)));
+    Node* trunc = t.NumberToUint32(div);
+    t.Return(trunc);
+
+    if (Pipeline::SupportedTarget()) {
+      t.LowerAllNodesAndLowerChanges();
+      t.GenerateCode();
+
+      FOR_UINT32_INPUTS(i) {
+        uint32_t x = *i / k;
+        t.CheckNumberCall(static_cast<double>(x), static_cast<double>(*i));
+      }
+    }
+  }
+}
+
+
+TEST(NumberDivide_BadConstants) {
+  {
+    TestingGraph t(Type::Signed32());
+    Node* k = t.jsgraph.Constant(-1);
+    Node* div = t.graph()->NewNode(t.simplified()->NumberDivide(), t.p0, k);
+    Node* use = t.Use(div, kMachInt32);
+    t.Return(use);
+    t.Lower();
+
+    CHECK_EQ(IrOpcode::kInt32Sub, use->InputAt(0)->opcode());
+  }
+
+  {
+    TestingGraph t(Type::Signed32());
+    Node* k = t.jsgraph.Constant(0);
+    Node* div = t.graph()->NewNode(t.simplified()->NumberDivide(), t.p0, k);
+    Node* use = t.Use(div, kMachInt32);
+    t.Return(use);
+    t.Lower();
+
+    CHECK_EQ(IrOpcode::kInt32Constant, use->InputAt(0)->opcode());
+    CHECK_EQ(0, OpParameter<int32_t>(use->InputAt(0)));
+  }
+
+  {
+    TestingGraph t(Type::Unsigned32());
+    Node* k = t.jsgraph.Constant(0);
+    Node* div = t.graph()->NewNode(t.simplified()->NumberDivide(), t.p0, k);
+    Node* use = t.Use(div, kMachUint32);
+    t.Return(use);
+    t.Lower();
+
+    CHECK_EQ(IrOpcode::kInt32Constant, use->InputAt(0)->opcode());
+    CHECK_EQ(0, OpParameter<int32_t>(use->InputAt(0)));
+  }
+}
+
+
+TEST(NumberModulus_TruncatingToInt32) {
+  int32_t constants[] = {-100, -10, 1, 4, 100, 1000};
+
+  for (size_t i = 0; i < arraysize(constants); i++) {
+    TestingGraph t(Type::Signed32());
+    Node* k = t.jsgraph.Constant(constants[i]);
+    Node* mod = t.graph()->NewNode(t.simplified()->NumberModulus(), t.p0, k);
+    Node* use = t.Use(mod, kMachInt32);
+    t.Return(use);
+    t.Lower();
+
+    CHECK_EQ(IrOpcode::kInt32Mod, use->InputAt(0)->opcode());
+  }
+}
+
+
+TEST(RunNumberModulus_TruncatingToInt32) {
+  int32_t constants[] = {-100, -10, -1, 1, 2, 100, 1000, 1024, 2048};
+
+  for (size_t i = 0; i < arraysize(constants); i++) {
+    int32_t k = constants[i];
+    SimplifiedLoweringTester<Object*> t(kMachAnyTagged);
+    Node* num = t.NumberToInt32(t.Parameter(0));
+    Node* mod = t.NumberModulus(num, t.jsgraph.Constant(k));
+    Node* trunc = t.NumberToInt32(mod);
+    t.Return(trunc);
+
+    if (Pipeline::SupportedTarget()) {
+      t.LowerAllNodesAndLowerChanges();
+      t.GenerateCode();
+
+      FOR_INT32_INPUTS(i) {
+        if (*i == INT_MAX) continue;  // exclude max int.
+        int32_t x = DoubleToInt32(std::fmod(static_cast<double>(*i), k));
+        t.CheckNumberCall(static_cast<double>(x), static_cast<double>(*i));
+      }
+    }
+  }
+}
+
+
+TEST(NumberModulus_TruncatingToUint32) {
+  double constants[] = {1, 3, 100, 1000, 100998348};
+
+  for (size_t i = 0; i < arraysize(constants); i++) {
+    TestingGraph t(Type::Unsigned32());
+    Node* k = t.jsgraph.Constant(constants[i]);
+    Node* mod = t.graph()->NewNode(t.simplified()->NumberModulus(), t.p0, k);
+    Node* trunc = t.graph()->NewNode(t.simplified()->NumberToUint32(), mod);
+    Node* ret = t.Return(trunc);
+    t.Lower();
+
+    CHECK_EQ(IrOpcode::kUint32Mod, ret->InputAt(0)->opcode());
+  }
+}
+
+
+TEST(RunNumberModulus_TruncatingToUint32) {
+  uint32_t constants[] = {1, 2, 100, 1000, 1024, 2048};
+
+  for (size_t i = 0; i < arraysize(constants); i++) {
+    uint32_t k = constants[i];
+    SimplifiedLoweringTester<Object*> t(kMachAnyTagged);
+    Node* num = t.NumberToUint32(t.Parameter(0));
+    Node* mod =
+        t.NumberModulus(num, t.jsgraph.Constant(static_cast<double>(k)));
+    Node* trunc = t.NumberToUint32(mod);
+    t.Return(trunc);
+
+    if (Pipeline::SupportedTarget()) {
+      t.LowerAllNodesAndLowerChanges();
+      t.GenerateCode();
+
+      FOR_UINT32_INPUTS(i) {
+        uint32_t x = *i % k;
+        t.CheckNumberCall(static_cast<double>(x), static_cast<double>(*i));
+      }
+    }
+  }
+}
+
+
+TEST(NumberModulus_Int32) {
+  int32_t constants[] = {-100, -10, 1, 4, 100, 1000};
+
+  for (size_t i = 0; i < arraysize(constants); i++) {
+    TestingGraph t(Type::Signed32());
+    Node* k = t.jsgraph.Constant(constants[i]);
+    Node* mod = t.graph()->NewNode(t.simplified()->NumberModulus(), t.p0, k);
+    t.Return(mod);
+    t.Lower();
+
+    CHECK_EQ(IrOpcode::kFloat64Mod, mod->opcode());  // Pesky -0 behavior.
+  }
+}
+
+
+TEST(NumberModulus_Uint32) {
+  const double kConstants[] = {2, 100, 1000, 1024, 2048};
+  const MachineType kTypes[] = {kMachInt32, kMachUint32};
+
+  for (auto const type : kTypes) {
+    for (auto const c : kConstants) {
+      TestingGraph t(Type::Unsigned32());
+      Node* k = t.jsgraph.Constant(c);
+      Node* mod = t.graph()->NewNode(t.simplified()->NumberModulus(), t.p0, k);
+      Node* use = t.Use(mod, type);
+      t.Return(use);
+      t.Lower();
+
+      CHECK_EQ(IrOpcode::kUint32Mod, use->InputAt(0)->opcode());
+    }
+  }
+}
+
+
+TEST(PhiRepresentation) {
+  HandleAndZoneScope scope;
+  Zone* z = scope.main_zone();
+
+  struct TestData {
+    Type* arg1;
+    Type* arg2;
+    MachineType use;
+    MachineTypeUnion expected;
+  };
+
+  TestData test_data[] = {
+      {Type::Signed32(), Type::Unsigned32(), kMachInt32,
+       kRepWord32 | kTypeNumber},
+      {Type::Signed32(), Type::Unsigned32(), kMachUint32,
+       kRepWord32 | kTypeNumber},
+      {Type::Signed32(), Type::Signed32(), kMachInt32, kMachInt32},
+      {Type::Unsigned32(), Type::Unsigned32(), kMachInt32, kMachUint32},
+      {Type::Number(), Type::Signed32(), kMachInt32, kMachFloat64},
+      {Type::Signed32(), Type::String(), kMachInt32, kMachAnyTagged}};
+
+  for (auto const d : test_data) {
+    TestingGraph t(d.arg1, d.arg2, Type::Boolean());
+
+    Node* br = t.graph()->NewNode(t.common()->Branch(), t.p2, t.start);
+    Node* tb = t.graph()->NewNode(t.common()->IfTrue(), br);
+    Node* fb = t.graph()->NewNode(t.common()->IfFalse(), br);
+    Node* m = t.graph()->NewNode(t.common()->Merge(2), tb, fb);
+
+    Node* phi =
+        t.graph()->NewNode(t.common()->Phi(kMachAnyTagged, 2), t.p0, t.p1, m);
+
+    Bounds phi_bounds = Bounds::Either(Bounds(d.arg1), Bounds(d.arg2), z);
+    NodeProperties::SetBounds(phi, phi_bounds);
+
+    Node* use = t.Use(phi, d.use);
+    t.Return(use);
+    t.Lower();
+
+    CHECK_EQ(d.expected, OpParameter<MachineType>(phi));
+  }
 }
diff --git a/test/cctest/compiler/test-typer.cc b/test/cctest/compiler/test-typer.cc
new file mode 100644
index 0000000..5f7f55a
--- /dev/null
+++ b/test/cctest/compiler/test-typer.cc
@@ -0,0 +1,380 @@
+// 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.
+
+#include <functional>
+
+#include "src/codegen.h"
+#include "src/compiler/js-operator.h"
+#include "src/compiler/node-properties-inl.h"
+#include "src/compiler/typer.h"
+#include "test/cctest/cctest.h"
+#include "test/cctest/compiler/graph-builder-tester.h"
+#include "test/cctest/types-fuzz.h"
+
+using namespace v8::internal;
+using namespace v8::internal::compiler;
+
+
+// TODO(titzer): generate a large set of deterministic inputs for these tests.
+class TyperTester : public HandleAndZoneScope, public GraphAndBuilders {
+ public:
+  TyperTester()
+      : GraphAndBuilders(main_zone()),
+        types_(main_zone(), isolate()),
+        typer_(graph(), MaybeHandle<Context>()),
+        javascript_(main_zone()) {
+    Node* s = graph()->NewNode(common()->Start(3));
+    graph()->SetStart(s);
+    context_node_ = graph()->NewNode(common()->Parameter(2), graph()->start());
+    rng_ = isolate()->random_number_generator();
+
+    integers.push_back(0);
+    integers.push_back(0);
+    integers.push_back(-1);
+    integers.push_back(+1);
+    integers.push_back(-V8_INFINITY);
+    integers.push_back(+V8_INFINITY);
+    for (int i = 0; i < 5; ++i) {
+      double x = rng_->NextInt();
+      integers.push_back(x);
+      x *= rng_->NextInt();
+      if (!IsMinusZero(x)) integers.push_back(x);
+    }
+
+    int32s.push_back(0);
+    int32s.push_back(0);
+    int32s.push_back(-1);
+    int32s.push_back(+1);
+    int32s.push_back(kMinInt);
+    int32s.push_back(kMaxInt);
+    for (int i = 0; i < 10; ++i) {
+      int32s.push_back(rng_->NextInt());
+    }
+  }
+
+  Types<Type, Type*, Zone> types_;
+  Typer typer_;
+  JSOperatorBuilder javascript_;
+  Node* context_node_;
+  v8::base::RandomNumberGenerator* rng_;
+  std::vector<double> integers;
+  std::vector<double> int32s;
+
+  Isolate* isolate() { return main_isolate(); }
+  Graph* graph() { return main_graph_; }
+  CommonOperatorBuilder* common() { return &main_common_; }
+
+  Node* Parameter(int index = 0) {
+    return graph()->NewNode(common()->Parameter(index), graph()->start());
+  }
+
+  Type* TypeBinaryOp(const Operator* op, Type* lhs, Type* rhs) {
+    Node* p0 = Parameter(0);
+    Node* p1 = Parameter(1);
+    NodeProperties::SetBounds(p0, Bounds(lhs));
+    NodeProperties::SetBounds(p1, Bounds(rhs));
+    Node* n = graph()->NewNode(
+        op, p0, p1, context_node_, graph()->start(), graph()->start());
+    return NodeProperties::GetBounds(n).upper;
+  }
+
+  Type* RandomRange(bool int32 = false) {
+    std::vector<double>& numbers = int32 ? int32s : integers;
+    double i = numbers[rng_->NextInt(static_cast<int>(numbers.size()))];
+    double j = numbers[rng_->NextInt(static_cast<int>(numbers.size()))];
+    return NewRange(i, j);
+  }
+
+  Type* NewRange(double i, double j) {
+    Factory* f = isolate()->factory();
+    i::Handle<i::Object> min = f->NewNumber(i);
+    i::Handle<i::Object> max = f->NewNumber(j);
+    if (min->Number() > max->Number()) std::swap(min, max);
+    return Type::Range(min, max, main_zone());
+  }
+
+  double RandomInt(double min, double max) {
+    switch (rng_->NextInt(4)) {
+      case 0: return min;
+      case 1: return max;
+      default: break;
+    }
+    if (min == +V8_INFINITY) return +V8_INFINITY;
+    if (max == -V8_INFINITY) return -V8_INFINITY;
+    if (min == -V8_INFINITY && max == +V8_INFINITY) {
+      return rng_->NextInt() * static_cast<double>(rng_->NextInt());
+    }
+    double result = nearbyint(min + (max - min) * rng_->NextDouble());
+    if (IsMinusZero(result)) return 0;
+    if (std::isnan(result)) return rng_->NextInt(2) ? min : max;
+    DCHECK(min <= result && result <= max);
+    return result;
+  }
+
+  double RandomInt(Type::RangeType* range) {
+    return RandomInt(range->Min()->Number(), range->Max()->Number());
+  }
+
+  // Careful, this function runs O(max_width^5) trials.
+  template <class BinaryFunction>
+  void TestBinaryArithOpCloseToZero(const Operator* op, BinaryFunction opfun,
+                                    int max_width) {
+    const int min_min = -2 - max_width / 2;
+    const int max_min = 2 + max_width / 2;
+    for (int width = 0; width < max_width; width++) {
+      for (int lmin = min_min; lmin <= max_min; lmin++) {
+        for (int rmin = min_min; rmin <= max_min; rmin++) {
+          Type* r1 = NewRange(lmin, lmin + width);
+          Type* r2 = NewRange(rmin, rmin + width);
+          Type* expected_type = TypeBinaryOp(op, r1, r2);
+
+          for (int x1 = lmin; x1 < lmin + width; x1++) {
+            for (int x2 = rmin; x2 < rmin + width; x2++) {
+              double result_value = opfun(x1, x2);
+              Type* result_type = Type::Constant(
+                  isolate()->factory()->NewNumber(result_value), main_zone());
+              CHECK(result_type->Is(expected_type));
+            }
+          }
+        }
+      }
+    }
+  }
+
+  template <class BinaryFunction>
+  void TestBinaryArithOp(const Operator* op, BinaryFunction opfun) {
+    TestBinaryArithOpCloseToZero(op, opfun, 8);
+    for (int i = 0; i < 100; ++i) {
+      Type::RangeType* r1 = RandomRange()->AsRange();
+      Type::RangeType* r2 = RandomRange()->AsRange();
+      Type* expected_type = TypeBinaryOp(op, r1, r2);
+      for (int i = 0; i < 10; i++) {
+        double x1 = RandomInt(r1);
+        double x2 = RandomInt(r2);
+        double result_value = opfun(x1, x2);
+        Type* result_type = Type::Constant(
+            isolate()->factory()->NewNumber(result_value), main_zone());
+        CHECK(result_type->Is(expected_type));
+      }
+    }
+  }
+
+  template <class BinaryFunction>
+  void TestBinaryCompareOp(const Operator* op, BinaryFunction opfun) {
+    for (int i = 0; i < 100; ++i) {
+      Type::RangeType* r1 = RandomRange()->AsRange();
+      Type::RangeType* r2 = RandomRange()->AsRange();
+      Type* expected_type = TypeBinaryOp(op, r1, r2);
+      for (int i = 0; i < 10; i++) {
+        double x1 = RandomInt(r1);
+        double x2 = RandomInt(r2);
+        bool result_value = opfun(x1, x2);
+        Type* result_type =
+            Type::Constant(result_value ? isolate()->factory()->true_value()
+                                        : isolate()->factory()->false_value(),
+                           main_zone());
+        CHECK(result_type->Is(expected_type));
+      }
+    }
+  }
+
+  template <class BinaryFunction>
+  void TestBinaryBitOp(const Operator* op, BinaryFunction opfun) {
+    for (int i = 0; i < 100; ++i) {
+      Type::RangeType* r1 = RandomRange(true)->AsRange();
+      Type::RangeType* r2 = RandomRange(true)->AsRange();
+      Type* expected_type = TypeBinaryOp(op, r1, r2);
+      for (int i = 0; i < 10; i++) {
+        int32_t x1 = static_cast<int32_t>(RandomInt(r1));
+        int32_t x2 = static_cast<int32_t>(RandomInt(r2));
+        double result_value = opfun(x1, x2);
+        Type* result_type = Type::Constant(
+            isolate()->factory()->NewNumber(result_value), main_zone());
+        CHECK(result_type->Is(expected_type));
+      }
+    }
+  }
+
+  Type* RandomSubtype(Type* type) {
+    Type* subtype;
+    do {
+      subtype = types_.Fuzz();
+    } while (!subtype->Is(type));
+    return subtype;
+  }
+
+  void TestBinaryMonotonicity(const Operator* op) {
+    for (int i = 0; i < 50; ++i) {
+      Type* type1 = types_.Fuzz();
+      Type* type2 = types_.Fuzz();
+      Type* type = TypeBinaryOp(op, type1, type2);
+      Type* subtype1 = RandomSubtype(type1);;
+      Type* subtype2 = RandomSubtype(type2);;
+      Type* subtype = TypeBinaryOp(op, subtype1, subtype2);
+      CHECK(subtype->Is(type));
+    }
+  }
+};
+
+
+static int32_t shift_left(int32_t x, int32_t y) { return x << y; }
+static int32_t shift_right(int32_t x, int32_t y) { return x >> y; }
+static int32_t bit_or(int32_t x, int32_t y) { return x | y; }
+static int32_t bit_and(int32_t x, int32_t y) { return x & y; }
+static int32_t bit_xor(int32_t x, int32_t y) { return x ^ y; }
+
+
+//------------------------------------------------------------------------------
+// Soundness
+//   For simplicity, we currently only test soundness on expression operators
+//   that have a direct equivalent in C++.  Also, testing is currently limited
+//   to ranges as input types.
+
+
+TEST(TypeJSAdd) {
+  TyperTester t;
+  t.TestBinaryArithOp(t.javascript_.Add(), std::plus<double>());
+}
+
+
+TEST(TypeJSSubtract) {
+  TyperTester t;
+  t.TestBinaryArithOp(t.javascript_.Subtract(), std::minus<double>());
+}
+
+
+TEST(TypeJSMultiply) {
+  TyperTester t;
+  t.TestBinaryArithOp(t.javascript_.Multiply(), std::multiplies<double>());
+}
+
+
+TEST(TypeJSDivide) {
+  TyperTester t;
+  t.TestBinaryArithOp(t.javascript_.Divide(), std::divides<double>());
+}
+
+
+TEST(TypeJSModulus) {
+  TyperTester t;
+  t.TestBinaryArithOp(t.javascript_.Modulus(), modulo);
+}
+
+
+TEST(TypeJSBitwiseOr) {
+  TyperTester t;
+  t.TestBinaryBitOp(t.javascript_.BitwiseOr(), bit_or);
+}
+
+
+TEST(TypeJSBitwiseAnd) {
+  TyperTester t;
+  t.TestBinaryBitOp(t.javascript_.BitwiseAnd(), bit_and);
+}
+
+
+TEST(TypeJSBitwiseXor) {
+  TyperTester t;
+  t.TestBinaryBitOp(t.javascript_.BitwiseXor(), bit_xor);
+}
+
+
+TEST(TypeJSShiftLeft) {
+  TyperTester t;
+  t.TestBinaryBitOp(t.javascript_.ShiftLeft(), shift_left);
+}
+
+
+TEST(TypeJSShiftRight) {
+  TyperTester t;
+  t.TestBinaryBitOp(t.javascript_.ShiftRight(), shift_right);
+}
+
+
+TEST(TypeJSLessThan) {
+  TyperTester t;
+  t.TestBinaryCompareOp(t.javascript_.LessThan(), std::less<double>());
+}
+
+
+TEST(TypeJSLessThanOrEqual) {
+  TyperTester t;
+  t.TestBinaryCompareOp(
+      t.javascript_.LessThanOrEqual(), std::less_equal<double>());
+}
+
+
+TEST(TypeJSGreaterThan) {
+  TyperTester t;
+  t.TestBinaryCompareOp(t.javascript_.GreaterThan(), std::greater<double>());
+}
+
+
+TEST(TypeJSGreaterThanOrEqual) {
+  TyperTester t;
+  t.TestBinaryCompareOp(
+      t.javascript_.GreaterThanOrEqual(), std::greater_equal<double>());
+}
+
+
+TEST(TypeJSEqual) {
+  TyperTester t;
+  t.TestBinaryCompareOp(t.javascript_.Equal(), std::equal_to<double>());
+}
+
+
+TEST(TypeJSNotEqual) {
+  TyperTester t;
+  t.TestBinaryCompareOp(t.javascript_.NotEqual(), std::not_equal_to<double>());
+}
+
+
+// For numbers there's no difference between strict and non-strict equality.
+TEST(TypeJSStrictEqual) {
+  TyperTester t;
+  t.TestBinaryCompareOp(t.javascript_.StrictEqual(), std::equal_to<double>());
+}
+
+
+TEST(TypeJSStrictNotEqual) {
+  TyperTester t;
+  t.TestBinaryCompareOp(
+      t.javascript_.StrictNotEqual(), std::not_equal_to<double>());
+}
+
+
+//------------------------------------------------------------------------------
+// Monotonicity
+
+
+// List should be in sync with JS_SIMPLE_BINOP_LIST.
+#define JSBINOP_LIST(V) \
+  V(Equal) \
+  V(NotEqual) \
+  V(StrictEqual) \
+  V(StrictNotEqual) \
+  V(LessThan) \
+  V(GreaterThan) \
+  V(LessThanOrEqual) \
+  V(GreaterThanOrEqual) \
+  V(BitwiseOr) \
+  V(BitwiseXor) \
+  V(BitwiseAnd) \
+  V(ShiftLeft) \
+  V(ShiftRight) \
+  V(ShiftRightLogical) \
+  V(Add) \
+  V(Subtract) \
+  V(Multiply) \
+  V(Divide) \
+  V(Modulus)
+
+
+#define TEST_FUNC(name)                             \
+  TEST(Monotonicity_##name) {                       \
+    TyperTester t;                                  \
+    t.TestBinaryMonotonicity(t.javascript_.name()); \
+  }
+JSBINOP_LIST(TEST_FUNC)
+#undef TEST_FUNC
diff --git a/test/cctest/compiler/value-helper.h b/test/cctest/compiler/value-helper.h
index b5da982..218a773 100644
--- a/test/cctest/compiler/value-helper.h
+++ b/test/cctest/compiler/value-helper.h
@@ -60,6 +60,45 @@
     CheckHeapConstant(isolate_->heap()->false_value(), node);
   }
 
+  static std::vector<float> float32_vector() {
+    static const float kValues[] = {
+        -std::numeric_limits<float>::infinity(), -2.70497e+38f, -1.4698e+37f,
+        -1.22813e+35f,                           -1.20555e+35f, -1.34584e+34f,
+        -1.0079e+32f,                            -6.49364e+26f, -3.06077e+25f,
+        -1.46821e+25f,                           -1.17658e+23f, -1.9617e+22f,
+        -2.7357e+20f,                            -1.48708e+13f, -1.89633e+12f,
+        -4.66622e+11f,                           -2.22581e+11f, -1.45381e+10f,
+        -1.3956e+09f,                            -1.32951e+09f, -1.30721e+09f,
+        -1.19756e+09f,                           -9.26822e+08f, -6.35647e+08f,
+        -4.00037e+08f,                           -1.81227e+08f, -5.09256e+07f,
+        -964300.0f,                              -192446.0f,    -28455.0f,
+        -27194.0f,                               -26401.0f,     -20575.0f,
+        -17069.0f,                               -9167.0f,      -960.178f,
+        -113.0f,                                 -62.0f,        -15.0f,
+        -7.0f,                                   -0.0256635f,   -4.60374e-07f,
+        -3.63759e-10f,                           -4.30175e-14f, -5.27385e-15f,
+        -1.48084e-15f,                           -1.05755e-19f, -3.2995e-21f,
+        -1.67354e-23f,                           -1.11885e-23f, -1.78506e-30f,
+        -5.07594e-31f,                           -3.65799e-31f, -1.43718e-34f,
+        -1.27126e-38f,                           -0.0f,         0.0f,
+        1.17549e-38f,                            1.56657e-37f,  4.08512e-29f,
+        3.31357e-28f,                            6.25073e-22f,  4.1723e-13f,
+        1.44343e-09f,                            5.27004e-08f,  9.48298e-08f,
+        5.57888e-07f,                            4.89988e-05f,  0.244326f,
+        12.4895f,                                19.0f,         47.0f,
+        106.0f,                                  538.324f,      564.536f,
+        819.124f,                                7048.0f,       12611.0f,
+        19878.0f,                                20309.0f,      797056.0f,
+        1.77219e+09f,                            1.51116e+11f,  4.18193e+13f,
+        3.59167e+16f,                            3.38211e+19f,  2.67488e+20f,
+        1.78831e+21f,                            9.20914e+21f,  8.35654e+23f,
+        1.4495e+24f,                             5.94015e+25f,  4.43608e+30f,
+        2.44502e+33f,                            2.61152e+33f,  1.38178e+37f,
+        1.71306e+37f,                            3.31899e+38f,  3.40282e+38f,
+        std::numeric_limits<float>::infinity()};
+    return std::vector<float>(&kValues[0], &kValues[arraysize(kValues)]);
+  }
+
   static std::vector<double> float64_vector() {
     static const double nan = v8::base::OS::nan_value();
     static const double values[] = {
@@ -82,6 +121,8 @@
   static const std::vector<uint32_t> uint32_vector() {
     static const uint32_t kValues[] = {
         0x00000000, 0x00000001, 0xffffffff, 0x1b09788b, 0x04c5fce8, 0xcc0de5bf,
+        // This row is useful for testing lea optimizations on intel.
+        0x00000002, 0x00000003, 0x00000004, 0x00000005, 0x00000008, 0x00000009,
         0x273a798e, 0x187937a3, 0xece3af83, 0x5495a16b, 0x0b668ecc, 0x11223344,
         0x0000009e, 0x00000043, 0x0000af73, 0x0000116b, 0x00658ecc, 0x002b3b4c,
         0x88776655, 0x70000000, 0x07200000, 0x7fffffff, 0x56123761, 0x7fffff00,
@@ -117,6 +158,7 @@
 
 #define FOR_INT32_INPUTS(var) FOR_INPUTS(int32_t, int32, var)
 #define FOR_UINT32_INPUTS(var) FOR_INPUTS(uint32_t, uint32, var)
+#define FOR_FLOAT32_INPUTS(var) FOR_INPUTS(float, float32, var)
 #define FOR_FLOAT64_INPUTS(var) FOR_INPUTS(double, float64, var)
 
 #define FOR_INT32_SHIFTS(var) for (int32_t var = 0; var < 32; var++)
diff --git a/test/cctest/test-accessors.cc b/test/cctest/test-accessors.cc
index 5bf61c8..5f452ea 100644
--- a/test/cctest/test-accessors.cc
+++ b/test/cctest/test-accessors.cc
@@ -38,6 +38,7 @@
 using ::v8::Value;
 using ::v8::Context;
 using ::v8::Local;
+using ::v8::Name;
 using ::v8::String;
 using ::v8::Script;
 using ::v8::Function;
@@ -513,7 +514,7 @@
 }
 
 
-void JSONStringifyGetter(Local<String> name,
+void JSONStringifyGetter(Local<Name> name,
                          const v8::PropertyCallbackInfo<v8::Value>& info) {
   info.GetReturnValue().Set(v8_str("crbug-161028"));
 }
@@ -525,8 +526,8 @@
   v8::HandleScope scope(isolate);
 
   v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
-  obj->SetNamedPropertyHandler(
-      JSONStringifyGetter, NULL, NULL, NULL, JSONStringifyEnumerator);
+  obj->SetHandler(v8::NamedPropertyHandlerConfiguration(
+      JSONStringifyGetter, NULL, NULL, NULL, JSONStringifyEnumerator));
   env->Global()->Set(v8_str("obj"), obj->NewInstance());
   v8::Handle<v8::String> expected = v8_str("{\"regress\":\"crbug-161028\"}");
   CHECK(CompileRun("JSON.stringify(obj)")->Equals(expected));
@@ -577,3 +578,30 @@
   CHECK(v8::Utils::OpenHandle(*CompileRun("getter()"))->IsJSGlobalProxy());
   CHECK(v8::Utils::OpenHandle(*CompileRun("set_value"))->IsJSGlobalProxy());
 }
+
+
+static void EmptyGetter(Local<Name> name,
+                        const v8::PropertyCallbackInfo<v8::Value>& info) {
+  ApiTestFuzzer::Fuzz();
+}
+
+
+static void OneProperty(Local<String> name,
+                        const v8::PropertyCallbackInfo<v8::Value>& info) {
+  ApiTestFuzzer::Fuzz();
+  info.GetReturnValue().Set(v8_num(1));
+}
+
+
+THREADED_TEST(Regress433458) {
+  LocalContext env;
+  v8::Isolate* isolate = env->GetIsolate();
+  v8::HandleScope scope(isolate);
+  v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
+  obj->SetHandler(v8::NamedPropertyHandlerConfiguration(EmptyGetter));
+  obj->SetNativeDataProperty(v8_str("prop"), OneProperty);
+  env->Global()->Set(v8_str("obj"), obj->NewInstance());
+  CompileRun(
+      "Object.defineProperty(obj, 'prop', { writable: false });"
+      "Object.defineProperty(obj, 'prop', { writable: true });");
+}
diff --git a/test/cctest/test-alloc.cc b/test/cctest/test-alloc.cc
index d647a31..2e071ac 100644
--- a/test/cctest/test-alloc.cc
+++ b/test/cctest/test-alloc.cc
@@ -86,7 +86,7 @@
       Builtins::kIllegal)).ToObjectChecked();
 
   // Return success.
-  return Smi::FromInt(42);
+  return heap->true_value();
 }
 
 
@@ -100,7 +100,7 @@
   v8::Handle<v8::Context> env = v8::Context::New(CcTest::isolate());
   env->Enter();
   Handle<Object> o = Test();
-  CHECK(o->IsSmi() && Smi::cast(*o)->value() == 42);
+  CHECK(o->IsTrue());
   env->Exit();
 }
 
@@ -162,7 +162,7 @@
   // Call the accessor through JavaScript.
   v8::Handle<v8::Value> result = v8::Script::Compile(
       v8::String::NewFromUtf8(CcTest::isolate(), "(new Foo).get"))->Run();
-  CHECK_EQ(42, result->Int32Value());
+  CHECK_EQ(true, result->BooleanValue());
   env->Exit();
 }
 
@@ -198,7 +198,8 @@
   const size_t code_range_size = 32*MB;
   CcTest::InitializeVM();
   CodeRange code_range(reinterpret_cast<Isolate*>(CcTest::isolate()));
-  code_range.SetUp(code_range_size);
+  code_range.SetUp(code_range_size +
+                   kReservedCodeRangePages * v8::base::OS::CommitPageSize());
   size_t current_allocated = 0;
   size_t total_allocated = 0;
   List< ::Block> blocks(1000);
diff --git a/test/cctest/test-api.cc b/test/cctest/test-api.cc
index 0e80384..06cf553 100644
--- a/test/cctest/test-api.cc
+++ b/test/cctest/test-api.cc
@@ -185,7 +185,8 @@
 }
 
 
-static void TestSignature(const char* loop_js, Local<Value> receiver) {
+static void TestSignature(const char* loop_js, Local<Value> receiver,
+                          v8::Isolate* isolate) {
   i::ScopedVector<char> source(200);
   i::SNPrintF(source,
               "for (var i = 0; i < 10; i++) {"
@@ -202,7 +203,7 @@
     CHECK_EQ(10, signature_callback_count);
   } else {
     CHECK_EQ(v8_str("TypeError: Illegal invocation"),
-             try_catch.Exception()->ToString());
+             try_catch.Exception()->ToString(isolate));
   }
 }
 
@@ -267,17 +268,17 @@
     i::SNPrintF(
         source, "var test_object = %s; test_object", test_objects[i]);
     Local<Value> test_object = CompileRun(source.start());
-    TestSignature("test_object.prop();", test_object);
-    TestSignature("test_object.accessor;", test_object);
-    TestSignature("test_object[accessor_key];", test_object);
-    TestSignature("test_object.accessor = 1;", test_object);
-    TestSignature("test_object[accessor_key] = 1;", test_object);
+    TestSignature("test_object.prop();", test_object, isolate);
+    TestSignature("test_object.accessor;", test_object, isolate);
+    TestSignature("test_object[accessor_key];", test_object, isolate);
+    TestSignature("test_object.accessor = 1;", test_object, isolate);
+    TestSignature("test_object[accessor_key] = 1;", test_object, isolate);
     if (i >= bad_signature_start_offset) test_object = Local<Value>();
-    TestSignature("test_object.prop_sig();", test_object);
-    TestSignature("test_object.accessor_sig;", test_object);
-    TestSignature("test_object[accessor_sig_key];", test_object);
-    TestSignature("test_object.accessor_sig = 1;", test_object);
-    TestSignature("test_object[accessor_sig_key] = 1;", test_object);
+    TestSignature("test_object.prop_sig();", test_object, isolate);
+    TestSignature("test_object.accessor_sig;", test_object, isolate);
+    TestSignature("test_object[accessor_sig_key];", test_object, isolate);
+    TestSignature("test_object.accessor_sig = 1;", test_object, isolate);
+    TestSignature("test_object[accessor_sig_key] = 1;", test_object, isolate);
   }
 }
 
@@ -356,7 +357,7 @@
   v8::Isolate* isolate = env->GetIsolate();
   v8::HandleScope scope(isolate);
   v8::Handle<v8::Primitive> undef = v8::Undefined(isolate);
-  Local<String> undef_str = undef->ToString();
+  Local<String> undef_str = undef->ToString(isolate);
   char* value = i::NewArray<char>(undef_str->Utf8Length() + 1);
   undef_str->WriteUtf8(value);
   CHECK_EQ(0, strcmp(value, "undefined"));
@@ -742,6 +743,58 @@
 }
 
 
+class RandomLengthResource : public v8::String::ExternalStringResource {
+ public:
+  explicit RandomLengthResource(int length) : length_(length) {}
+  virtual const uint16_t* data() const { return string_; }
+  virtual size_t length() const { return length_; }
+
+ private:
+  uint16_t string_[10];
+  int length_;
+};
+
+
+class RandomLengthOneByteResource
+    : public v8::String::ExternalOneByteStringResource {
+ public:
+  explicit RandomLengthOneByteResource(int length) : length_(length) {}
+  virtual const char* data() const { return string_; }
+  virtual size_t length() const { return length_; }
+
+ private:
+  char string_[10];
+  int length_;
+};
+
+
+THREADED_TEST(NewExternalForVeryLongString) {
+  {
+    LocalContext env;
+    v8::HandleScope scope(env->GetIsolate());
+    v8::TryCatch try_catch;
+    RandomLengthOneByteResource r(1 << 30);
+    v8::Local<v8::String> str = v8::String::NewExternal(CcTest::isolate(), &r);
+    CHECK(str.IsEmpty());
+    CHECK(try_catch.HasCaught());
+    String::Utf8Value exception_value(try_catch.Exception());
+    CHECK_EQ("RangeError: Invalid string length", *exception_value);
+  }
+
+  {
+    LocalContext env;
+    v8::HandleScope scope(env->GetIsolate());
+    v8::TryCatch try_catch;
+    RandomLengthResource r(1 << 30);
+    v8::Local<v8::String> str = v8::String::NewExternal(CcTest::isolate(), &r);
+    CHECK(str.IsEmpty());
+    CHECK(try_catch.HasCaught());
+    String::Utf8Value exception_value(try_catch.Exception());
+    CHECK_EQ("RangeError: Invalid string length", *exception_value);
+  }
+}
+
+
 THREADED_TEST(ScavengeExternalString) {
   i::FLAG_stress_compaction = false;
   i::FLAG_gc_global = false;
@@ -934,7 +987,7 @@
   // If CPU profiler is active check that when API callback is invoked
   // VMState is set to EXTERNAL.
   if (isolate->cpu_profiler()->is_profiling()) {
-    CHECK_EQ(i::EXTERNAL, isolate->current_vm_state());
+    CHECK_EQ(v8::EXTERNAL, isolate->current_vm_state());
     CHECK(isolate->external_callback_scope());
     CHECK_EQ(callback, isolate->external_callback_scope()->callback());
   }
@@ -1181,7 +1234,8 @@
 
 THREADED_PROFILED_TEST(FastReturnValues) {
   LocalContext env;
-  v8::HandleScope scope(CcTest::isolate());
+  v8::Isolate* isolate = env->GetIsolate();
+  v8::HandleScope scope(isolate);
   v8::Handle<v8::Value> value;
   // check int32_t and uint32_t
   int32_t int_values[] = {
@@ -1206,13 +1260,13 @@
   // check double
   value = TestFastReturnValues<double>();
   CHECK(value->IsNumber());
-  CHECK_EQ(kFastReturnValueDouble, value->ToNumber()->Value());
+  CHECK_EQ(kFastReturnValueDouble, value->ToNumber(isolate)->Value());
   // check bool values
   for (int i = 0; i < 2; i++) {
     fast_return_value_bool = i == 0;
     value = TestFastReturnValues<bool>();
     CHECK(value->IsBoolean());
-    CHECK_EQ(fast_return_value_bool, value->ToBoolean()->Value());
+    CHECK_EQ(fast_return_value_bool, value->ToBoolean(isolate)->Value());
   }
   // check oddballs
   ReturnValueOddball oddballs[] = {
@@ -1542,6 +1596,34 @@
 }
 
 
+THREADED_TEST(IsGeneratorFunctionOrObject) {
+  LocalContext env;
+  v8::HandleScope scope(env->GetIsolate());
+
+  CompileRun("function *gen() { yield 1; }\nfunction func() {}");
+  v8::Handle<Value> gen = CompileRun("gen");
+  v8::Handle<Value> genObj = CompileRun("gen()");
+  v8::Handle<Value> object = CompileRun("{a:42}");
+  v8::Handle<Value> func = CompileRun("func");
+
+  CHECK(gen->IsGeneratorFunction());
+  CHECK(gen->IsFunction());
+  CHECK(!gen->IsGeneratorObject());
+
+  CHECK(!genObj->IsGeneratorFunction());
+  CHECK(!genObj->IsFunction());
+  CHECK(genObj->IsGeneratorObject());
+
+  CHECK(!object->IsGeneratorFunction());
+  CHECK(!object->IsFunction());
+  CHECK(!object->IsGeneratorObject());
+
+  CHECK(!func->IsGeneratorFunction());
+  CHECK(func->IsFunction());
+  CHECK(!func->IsGeneratorObject());
+}
+
+
 THREADED_TEST(ArgumentsObject) {
   LocalContext env;
   v8::HandleScope scope(env->GetIsolate());
@@ -1904,7 +1986,7 @@
 int echo_named_call_count;
 
 
-static void EchoNamedProperty(Local<String> name,
+static void EchoNamedProperty(Local<Name> name,
                               const v8::PropertyCallbackInfo<v8::Value>& info) {
   ApiTestFuzzer::Fuzz();
   CHECK_EQ(v8_str("data"), info.Data());
@@ -1946,18 +2028,41 @@
   SimpleAccessorSetter(Local<String>::Cast(sym->Name()), value, info);
 }
 
-void EmptyInterceptorGetter(Local<String> name,
-                            const v8::PropertyCallbackInfo<v8::Value>& info) {
+void SymbolAccessorGetterReturnsDefault(
+    Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
+  CHECK(name->IsSymbol());
+  Local<Symbol> sym = Local<Symbol>::Cast(name);
+  if (sym->Name()->IsUndefined()) return;
+  info.GetReturnValue().Set(info.Data());
 }
 
-void EmptyInterceptorSetter(Local<String> name,
-                            Local<Value> value,
-                            const v8::PropertyCallbackInfo<v8::Value>& info) {
+static void ThrowingSymbolAccessorGetter(
+    Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
+  info.GetReturnValue().Set(info.GetIsolate()->ThrowException(name));
 }
 
-void InterceptorGetter(Local<String> name,
-                       const v8::PropertyCallbackInfo<v8::Value>& info) {
-  // Intercept names that start with 'interceptor_'.
+
+void EmptyInterceptorGetter(Local<Name> name,
+                            const v8::PropertyCallbackInfo<v8::Value>& info) {}
+
+
+void EmptyInterceptorSetter(Local<Name> name, Local<Value> value,
+                            const v8::PropertyCallbackInfo<v8::Value>& info) {}
+
+
+void EmptyGenericInterceptorGetter(
+    Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {}
+
+
+void EmptyGenericInterceptorSetter(
+    Local<Name> name, Local<Value> value,
+    const v8::PropertyCallbackInfo<v8::Value>& info) {}
+
+
+void StringInterceptorGetter(
+    Local<String> name,
+    const v8::PropertyCallbackInfo<v8::Value>&
+        info) {  // Intercept names that start with 'interceptor_'.
   String::Utf8Value utf8(name);
   char* name_str = *utf8;
   char prefix[] = "interceptor_";
@@ -1969,9 +2074,9 @@
   info.GetReturnValue().Set(self->GetHiddenValue(v8_str(name_str + i)));
 }
 
-void InterceptorSetter(Local<String> name,
-                       Local<Value> value,
-                       const v8::PropertyCallbackInfo<v8::Value>& info) {
+
+void StringInterceptorSetter(Local<String> name, Local<Value> value,
+                             const v8::PropertyCallbackInfo<v8::Value>& info) {
   // Intercept accesses that set certain integer values, for which the name does
   // not start with 'accessor_'.
   String::Utf8Value utf8(name);
@@ -1990,6 +2095,57 @@
   }
 }
 
+void InterceptorGetter(Local<Name> generic_name,
+                       const v8::PropertyCallbackInfo<v8::Value>& info) {
+  if (generic_name->IsSymbol()) return;
+  StringInterceptorGetter(Local<String>::Cast(generic_name), info);
+}
+
+void InterceptorSetter(Local<Name> generic_name, Local<Value> value,
+                       const v8::PropertyCallbackInfo<v8::Value>& info) {
+  if (generic_name->IsSymbol()) return;
+  StringInterceptorSetter(Local<String>::Cast(generic_name), value, info);
+}
+
+void GenericInterceptorGetter(Local<Name> generic_name,
+                              const v8::PropertyCallbackInfo<v8::Value>& info) {
+  Local<String> str;
+  if (generic_name->IsSymbol()) {
+    Local<Value> name = Local<Symbol>::Cast(generic_name)->Name();
+    if (name->IsUndefined()) return;
+    str = String::Concat(v8_str("_sym_"), Local<String>::Cast(name));
+  } else {
+    Local<String> name = Local<String>::Cast(generic_name);
+    String::Utf8Value utf8(name);
+    char* name_str = *utf8;
+    if (*name_str == '_') return;
+    str = String::Concat(v8_str("_str_"), name);
+  }
+
+  Handle<Object> self = Handle<Object>::Cast(info.This());
+  info.GetReturnValue().Set(self->Get(str));
+}
+
+void GenericInterceptorSetter(Local<Name> generic_name, Local<Value> value,
+                              const v8::PropertyCallbackInfo<v8::Value>& info) {
+  Local<String> str;
+  if (generic_name->IsSymbol()) {
+    Local<Value> name = Local<Symbol>::Cast(generic_name)->Name();
+    if (name->IsUndefined()) return;
+    str = String::Concat(v8_str("_sym_"), Local<String>::Cast(name));
+  } else {
+    Local<String> name = Local<String>::Cast(generic_name);
+    String::Utf8Value utf8(name);
+    char* name_str = *utf8;
+    if (*name_str == '_') return;
+    str = String::Concat(v8_str("_str_"), name);
+  }
+
+  Handle<Object> self = Handle<Object>::Cast(info.This());
+  self->Set(str, value);
+  info.GetReturnValue().Set(value);
+}
+
 void AddAccessor(Handle<FunctionTemplate> templ,
                  Handle<String> name,
                  v8::AccessorGetterCallback getter,
@@ -2011,6 +2167,13 @@
   templ->PrototypeTemplate()->SetAccessor(name, getter, setter);
 }
 
+void AddInterceptor(Handle<FunctionTemplate> templ,
+                    v8::GenericNamedPropertyGetterCallback getter,
+                    v8::GenericNamedPropertySetterCallback setter) {
+  templ->InstanceTemplate()->SetHandler(
+      v8::NamedPropertyHandlerConfiguration(getter, setter));
+}
+
 
 THREADED_TEST(EmptyInterceptorDoesNotShadowAccessors) {
   v8::HandleScope scope(CcTest::isolate());
@@ -2030,6 +2193,62 @@
 }
 
 
+THREADED_TEST(LegacyInterceptorDoesNotSeeSymbols) {
+  LocalContext env;
+  v8::Isolate* isolate = CcTest::isolate();
+  v8::HandleScope scope(isolate);
+  Handle<FunctionTemplate> parent = FunctionTemplate::New(isolate);
+  Handle<FunctionTemplate> child = FunctionTemplate::New(isolate);
+  v8::Local<v8::Symbol> age = v8::Symbol::New(isolate, v8_str("age"));
+
+  child->Inherit(parent);
+  AddAccessor(parent, age, SymbolAccessorGetter, SymbolAccessorSetter);
+  AddInterceptor(child, StringInterceptorGetter, StringInterceptorSetter);
+
+  env->Global()->Set(v8_str("Child"), child->GetFunction());
+  env->Global()->Set(v8_str("age"), age);
+  CompileRun(
+      "var child = new Child;"
+      "child[age] = 10;");
+  ExpectInt32("child[age]", 10);
+  ExpectBoolean("child.hasOwnProperty('age')", false);
+  ExpectBoolean("child.hasOwnProperty('accessor_age')", true);
+}
+
+
+THREADED_TEST(GenericInterceptorDoesSeeSymbols) {
+  LocalContext env;
+  v8::Isolate* isolate = CcTest::isolate();
+  v8::HandleScope scope(isolate);
+  Handle<FunctionTemplate> parent = FunctionTemplate::New(isolate);
+  Handle<FunctionTemplate> child = FunctionTemplate::New(isolate);
+  v8::Local<v8::Symbol> age = v8::Symbol::New(isolate, v8_str("age"));
+  v8::Local<v8::Symbol> anon = v8::Symbol::New(isolate);
+
+  child->Inherit(parent);
+  AddAccessor(parent, age, SymbolAccessorGetter, SymbolAccessorSetter);
+  AddInterceptor(child, GenericInterceptorGetter, GenericInterceptorSetter);
+
+  env->Global()->Set(v8_str("Child"), child->GetFunction());
+  env->Global()->Set(v8_str("age"), age);
+  env->Global()->Set(v8_str("anon"), anon);
+  CompileRun(
+      "var child = new Child;"
+      "child[age] = 10;");
+  ExpectInt32("child[age]", 10);
+  ExpectInt32("child._sym_age", 10);
+
+  // Check that it also sees strings.
+  CompileRun("child.foo = 47");
+  ExpectInt32("child.foo", 47);
+  ExpectInt32("child._str_foo", 47);
+
+  // Check that the interceptor can punt (in this case, on anonymous symbols).
+  CompileRun("child[anon] = 31337");
+  ExpectInt32("child[anon]", 31337);
+}
+
+
 THREADED_TEST(ExecutableAccessorIsPreservedOnAttributeChange) {
   v8::Isolate* isolate = CcTest::isolate();
   v8::HandleScope scope(isolate);
@@ -2275,9 +2494,8 @@
   v8::HandleScope scope(CcTest::isolate());
   v8::Handle<v8::FunctionTemplate> templ =
       v8::FunctionTemplate::New(CcTest::isolate());
-  templ->InstanceTemplate()->SetNamedPropertyHandler(EchoNamedProperty,
-                                                     0, 0, 0, 0,
-                                                     v8_str("data"));
+  templ->InstanceTemplate()->SetHandler(v8::NamedPropertyHandlerConfiguration(
+      EchoNamedProperty, 0, 0, 0, 0, v8_str("data")));
   LocalContext env;
   env->Global()->Set(v8_str("obj"),
                      templ->GetFunction()->NewInstance());
@@ -2312,9 +2530,8 @@
   v8::Isolate* isolate = CcTest::isolate();
   v8::HandleScope scope(isolate);
   v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
-  templ->InstanceTemplate()->SetIndexedPropertyHandler(EchoIndexedProperty,
-                                                       0, 0, 0, 0,
-                                                       v8_num(637));
+  templ->InstanceTemplate()->SetHandler(v8::IndexedPropertyHandlerConfiguration(
+      EchoIndexedProperty, 0, 0, 0, 0, v8_num(637)));
   LocalContext env;
   env->Global()->Set(v8_str("obj"),
                      templ->GetFunction()->NewInstance());
@@ -2334,8 +2551,7 @@
 }
 
 static void CheckThisNamedPropertyHandler(
-    Local<String> name,
-    const v8::PropertyCallbackInfo<v8::Value>& info) {
+    Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
   CheckReturnValue(info, FUNCTION_ADDR(CheckThisNamedPropertyHandler));
   ApiTestFuzzer::Fuzz();
   CHECK(info.This()->Equals(bottom));
@@ -2352,8 +2568,7 @@
 
 
 void CheckThisNamedPropertySetter(
-    Local<String> property,
-    Local<Value> value,
+    Local<Name> property, Local<Value> value,
     const v8::PropertyCallbackInfo<v8::Value>& info) {
   CheckReturnValue(info, FUNCTION_ADDR(CheckThisNamedPropertySetter));
   ApiTestFuzzer::Fuzz();
@@ -2370,8 +2585,7 @@
 
 
 void CheckThisNamedPropertyQuery(
-    Local<String> property,
-    const v8::PropertyCallbackInfo<v8::Integer>& info) {
+    Local<Name> property, const v8::PropertyCallbackInfo<v8::Integer>& info) {
   CheckReturnValue(info, FUNCTION_ADDR(CheckThisNamedPropertyQuery));
   ApiTestFuzzer::Fuzz();
   CHECK(info.This()->Equals(bottom));
@@ -2388,8 +2602,7 @@
 
 
 void CheckThisNamedPropertyDeleter(
-    Local<String> property,
-    const v8::PropertyCallbackInfo<v8::Boolean>& info) {
+    Local<Name> property, const v8::PropertyCallbackInfo<v8::Boolean>& info) {
   CheckReturnValue(info, FUNCTION_ADDR(CheckThisNamedPropertyDeleter));
   ApiTestFuzzer::Fuzz();
   CHECK(info.This()->Equals(bottom));
@@ -2419,19 +2632,15 @@
 
   // Set up a prototype chain with three interceptors.
   v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
-  templ->InstanceTemplate()->SetIndexedPropertyHandler(
-      CheckThisIndexedPropertyHandler,
-      CheckThisIndexedPropertySetter,
-      CheckThisIndexedPropertyQuery,
-      CheckThisIndexedPropertyDeleter,
-      CheckThisIndexedPropertyEnumerator);
+  templ->InstanceTemplate()->SetHandler(v8::IndexedPropertyHandlerConfiguration(
+      CheckThisIndexedPropertyHandler, CheckThisIndexedPropertySetter,
+      CheckThisIndexedPropertyQuery, CheckThisIndexedPropertyDeleter,
+      CheckThisIndexedPropertyEnumerator));
 
-  templ->InstanceTemplate()->SetNamedPropertyHandler(
-      CheckThisNamedPropertyHandler,
-      CheckThisNamedPropertySetter,
-      CheckThisNamedPropertyQuery,
-      CheckThisNamedPropertyDeleter,
-      CheckThisNamedPropertyEnumerator);
+  templ->InstanceTemplate()->SetHandler(v8::NamedPropertyHandlerConfiguration(
+      CheckThisNamedPropertyHandler, CheckThisNamedPropertySetter,
+      CheckThisNamedPropertyQuery, CheckThisNamedPropertyDeleter,
+      CheckThisNamedPropertyEnumerator));
 
   bottom = templ->GetFunction()->NewInstance();
   Local<v8::Object> top = templ->GetFunction()->NewInstance();
@@ -2463,8 +2672,7 @@
 
 
 static void PrePropertyHandlerGet(
-    Local<String> key,
-    const v8::PropertyCallbackInfo<v8::Value>& info) {
+    Local<Name> key, const v8::PropertyCallbackInfo<v8::Value>& info) {
   ApiTestFuzzer::Fuzz();
   if (v8_str("pre")->Equals(key)) {
     info.GetReturnValue().Set(v8_str("PrePropertyHandler: pre"));
@@ -2473,8 +2681,7 @@
 
 
 static void PrePropertyHandlerQuery(
-    Local<String> key,
-    const v8::PropertyCallbackInfo<v8::Integer>& info) {
+    Local<Name> key, const v8::PropertyCallbackInfo<v8::Integer>& info) {
   if (v8_str("pre")->Equals(key)) {
     info.GetReturnValue().Set(static_cast<int32_t>(v8::None));
   }
@@ -2485,9 +2692,8 @@
   v8::Isolate* isolate = CcTest::isolate();
   v8::HandleScope scope(isolate);
   v8::Handle<v8::FunctionTemplate> desc = v8::FunctionTemplate::New(isolate);
-  desc->InstanceTemplate()->SetNamedPropertyHandler(PrePropertyHandlerGet,
-                                                    0,
-                                                    PrePropertyHandlerQuery);
+  desc->InstanceTemplate()->SetHandler(v8::NamedPropertyHandlerConfiguration(
+      PrePropertyHandlerGet, 0, PrePropertyHandlerQuery));
   LocalContext env(NULL, desc->InstanceTemplate());
   CompileRun("var pre = 'Object: pre'; var on = 'Object: on';");
   v8::Handle<Value> result_pre = CompileRun("pre");
@@ -2560,16 +2766,17 @@
 
 
 static void ThrowingPropertyHandlerGet(
-    Local<String> key,
-    const v8::PropertyCallbackInfo<v8::Value>& info) {
+    Local<Name> key, const v8::PropertyCallbackInfo<v8::Value>& info) {
+  // Since this interceptor is used on "with" objects, the runtime will look up
+  // @@unscopables.  Punt.
+  if (key->IsSymbol()) return;
   ApiTestFuzzer::Fuzz();
   info.GetReturnValue().Set(info.GetIsolate()->ThrowException(key));
 }
 
 
 static void ThrowingPropertyHandlerSet(
-    Local<String> key,
-    Local<Value>,
+    Local<Name> key, Local<Value>,
     const v8::PropertyCallbackInfo<v8::Value>& info) {
   info.GetIsolate()->ThrowException(key);
   info.GetReturnValue().SetUndefined();  // not the same as empty handle
@@ -2580,8 +2787,8 @@
   v8::Isolate* isolate = CcTest::isolate();
   v8::HandleScope scope(isolate);
   v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
-  obj->SetNamedPropertyHandler(ThrowingPropertyHandlerGet,
-                               ThrowingPropertyHandlerSet);
+  obj->SetHandler(v8::NamedPropertyHandlerConfiguration(
+      ThrowingPropertyHandlerGet, ThrowingPropertyHandlerSet));
   LocalContext env;
   env->Global()->Set(v8_str("obj"), obj->NewInstance());
   v8::Handle<Value> otto = CompileRun(
@@ -2749,6 +2956,16 @@
 }
 
 
+THREADED_TEST(GetIsolate) {
+  LocalContext env;
+  v8::Isolate* isolate = env->GetIsolate();
+  v8::HandleScope scope(isolate);
+  Local<v8::Object> obj = v8::Object::New(isolate);
+  CHECK_EQ(isolate, obj->GetIsolate());
+  CHECK_EQ(isolate, CcTest::global()->GetIsolate());
+}
+
+
 THREADED_TEST(IdentityHash) {
   LocalContext env;
   v8::Isolate* isolate = env->GetIsolate();
@@ -2813,6 +3030,53 @@
 }
 
 
+TEST(SymbolIdentityHash) {
+  LocalContext env;
+  v8::Isolate* isolate = env->GetIsolate();
+  v8::HandleScope scope(isolate);
+
+  {
+    Local<v8::Symbol> symbol = v8::Symbol::New(isolate);
+    int hash = symbol->GetIdentityHash();
+    int hash1 = symbol->GetIdentityHash();
+    CHECK_EQ(hash, hash1);
+    CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
+    int hash3 = symbol->GetIdentityHash();
+    CHECK_EQ(hash, hash3);
+  }
+
+  {
+    v8::Handle<v8::Symbol> js_symbol =
+        CompileRun("Symbol('foo')").As<v8::Symbol>();
+    int hash = js_symbol->GetIdentityHash();
+    int hash1 = js_symbol->GetIdentityHash();
+    CHECK_EQ(hash, hash1);
+    CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
+    int hash3 = js_symbol->GetIdentityHash();
+    CHECK_EQ(hash, hash3);
+  }
+}
+
+
+TEST(StringIdentityHash) {
+  LocalContext env;
+  v8::Isolate* isolate = env->GetIsolate();
+  v8::HandleScope scope(isolate);
+
+  Local<v8::String> str = v8::String::NewFromUtf8(isolate, "str1");
+  int hash = str->GetIdentityHash();
+  int hash1 = str->GetIdentityHash();
+  CHECK_EQ(hash, hash1);
+  CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
+  int hash3 = str->GetIdentityHash();
+  CHECK_EQ(hash, hash3);
+
+  Local<v8::String> str2 = v8::String::NewFromUtf8(isolate, "str1");
+  int hash4 = str2->GetIdentityHash();
+  CHECK_EQ(hash, hash4);
+}
+
+
 THREADED_TEST(SymbolProperties) {
   LocalContext env;
   v8::Isolate* isolate = env->GetIsolate();
@@ -3195,6 +3459,24 @@
 }
 
 
+THREADED_TEST(ArrayBuffer_DisableNeuter) {
+  LocalContext env;
+  v8::Isolate* isolate = env->GetIsolate();
+  v8::HandleScope handle_scope(isolate);
+
+  i::ScopedVector<uint8_t> my_data(100);
+  memset(my_data.start(), 0, 100);
+  Local<v8::ArrayBuffer> ab =
+      v8::ArrayBuffer::New(isolate, my_data.start(), 100);
+  CHECK(ab->IsNeuterable());
+
+  i::Handle<i::JSArrayBuffer> buf = v8::Utils::OpenHandle(*ab);
+  buf->set_is_neuterable(false);
+
+  CHECK(!ab->IsNeuterable());
+}
+
+
 static void CheckDataViewIsNeutered(v8::Handle<v8::DataView> dv) {
   CHECK_EQ(0, static_cast<int>(dv->ByteLength()));
   CHECK_EQ(0, static_cast<int>(dv->ByteOffset()));
@@ -3411,7 +3693,7 @@
 
 static bool interceptor_for_hidden_properties_called;
 static void InterceptorForHiddenProperties(
-    Local<String> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
+    Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
   interceptor_for_hidden_properties_called = true;
 }
 
@@ -3428,7 +3710,8 @@
   // Associate an interceptor with an object and start setting hidden values.
   Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(isolate);
   Local<v8::ObjectTemplate> instance_templ = fun_templ->InstanceTemplate();
-  instance_templ->SetNamedPropertyHandler(InterceptorForHiddenProperties);
+  instance_templ->SetHandler(
+      v8::NamedPropertyHandlerConfiguration(InterceptorForHiddenProperties));
   Local<v8::Function> function = fun_templ->GetFunction();
   Local<v8::Object> obj = function->NewInstance();
   CHECK(obj->SetHiddenValue(key, v8::Integer::New(isolate, 2302)));
@@ -4144,6 +4427,45 @@
 }
 
 
+THREADED_TEST(WeakRootsSurviveTwoRoundsOfGC) {
+  LocalContext env;
+  v8::Isolate* iso = env->GetIsolate();
+  HandleScope scope(iso);
+
+  WeakCallCounter counter(1234);
+
+  WeakCallCounterAndPersistent<Value> weak_obj(&counter);
+
+  // Create a weak object that references a internalized string.
+  {
+    HandleScope scope(iso);
+    weak_obj.handle.Reset(iso, Object::New(iso));
+    weak_obj.handle.SetWeak(&weak_obj, &WeakPointerCallback);
+    CHECK(weak_obj.handle.IsWeak());
+    Local<Object>::New(iso, weak_obj.handle.As<Object>())->Set(
+        v8_str("x"),
+        String::NewFromUtf8(iso, "magic cookie", String::kInternalizedString));
+  }
+  // Do a single full GC
+  i::Isolate* i_iso = reinterpret_cast<v8::internal::Isolate*>(iso);
+  i::Heap* heap = i_iso->heap();
+  heap->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
+
+  // We should have received the weak callback.
+  CHECK_EQ(1, counter.NumberOfWeakCalls());
+
+  // Check that the string is still alive.
+  {
+    HandleScope scope(iso);
+    i::MaybeHandle<i::String> magic_string =
+        i::StringTable::LookupStringIfExists(
+            i_iso,
+            v8::Utils::OpenHandle(*String::NewFromUtf8(iso, "magic cookie")));
+    magic_string.Check();
+  }
+}
+
+
 // TODO(mstarzinger): This should be a THREADED_TEST but causes failures
 // on the buildbots, so was made non-threaded for the time being.
 TEST(ApiObjectGroupsCycleForScavenger) {
@@ -4266,13 +4588,14 @@
 
 TEST(TryCatchCustomException) {
   LocalContext env;
-  v8::HandleScope scope(env->GetIsolate());
+  v8::Isolate* isolate = env->GetIsolate();
+  v8::HandleScope scope(isolate);
   v8::TryCatch try_catch;
   CompileRun("function CustomError() { this.a = 'b'; }"
              "(function f() { throw new CustomError(); })();");
   CHECK(try_catch.HasCaught());
-  CHECK(try_catch.Exception()->ToObject()->
-            Get(v8_str("a"))->Equals(v8_str("b")));
+  CHECK(try_catch.Exception()->ToObject(isolate)->Get(v8_str("a"))->Equals(
+      v8_str("b")));
 }
 
 
@@ -4766,49 +5089,51 @@
 
 THREADED_TEST(ConversionNumber) {
   LocalContext env;
-  v8::HandleScope scope(env->GetIsolate());
+  v8::Isolate* isolate = env->GetIsolate();
+  v8::HandleScope scope(isolate);
   // Very large number.
   CompileRun("var obj = Math.pow(2,32) * 1237;");
   Local<Value> obj = env->Global()->Get(v8_str("obj"));
-  CHECK_EQ(5312874545152.0, obj->ToNumber()->Value());
-  CHECK_EQ(0, obj->ToInt32()->Value());
-  CHECK(0u == obj->ToUint32()->Value());  // NOLINT - no CHECK_EQ for unsigned.
+  CHECK_EQ(5312874545152.0, obj->ToNumber(isolate)->Value());
+  CHECK_EQ(0, obj->ToInt32(isolate)->Value());
+  CHECK(0u ==
+        obj->ToUint32(isolate)->Value());  // NOLINT - no CHECK_EQ for unsigned.
   // Large number.
   CompileRun("var obj = -1234567890123;");
   obj = env->Global()->Get(v8_str("obj"));
-  CHECK_EQ(-1234567890123.0, obj->ToNumber()->Value());
-  CHECK_EQ(-1912276171, obj->ToInt32()->Value());
-  CHECK(2382691125u == obj->ToUint32()->Value());  // NOLINT
+  CHECK_EQ(-1234567890123.0, obj->ToNumber(isolate)->Value());
+  CHECK_EQ(-1912276171, obj->ToInt32(isolate)->Value());
+  CHECK(2382691125u == obj->ToUint32(isolate)->Value());  // NOLINT
   // Small positive integer.
   CompileRun("var obj = 42;");
   obj = env->Global()->Get(v8_str("obj"));
-  CHECK_EQ(42.0, obj->ToNumber()->Value());
-  CHECK_EQ(42, obj->ToInt32()->Value());
-  CHECK(42u == obj->ToUint32()->Value());  // NOLINT
+  CHECK_EQ(42.0, obj->ToNumber(isolate)->Value());
+  CHECK_EQ(42, obj->ToInt32(isolate)->Value());
+  CHECK(42u == obj->ToUint32(isolate)->Value());  // NOLINT
   // Negative integer.
   CompileRun("var obj = -37;");
   obj = env->Global()->Get(v8_str("obj"));
-  CHECK_EQ(-37.0, obj->ToNumber()->Value());
-  CHECK_EQ(-37, obj->ToInt32()->Value());
-  CHECK(4294967259u == obj->ToUint32()->Value());  // NOLINT
+  CHECK_EQ(-37.0, obj->ToNumber(isolate)->Value());
+  CHECK_EQ(-37, obj->ToInt32(isolate)->Value());
+  CHECK(4294967259u == obj->ToUint32(isolate)->Value());  // NOLINT
   // Positive non-int32 integer.
   CompileRun("var obj = 0x81234567;");
   obj = env->Global()->Get(v8_str("obj"));
-  CHECK_EQ(2166572391.0, obj->ToNumber()->Value());
-  CHECK_EQ(-2128394905, obj->ToInt32()->Value());
-  CHECK(2166572391u == obj->ToUint32()->Value());  // NOLINT
+  CHECK_EQ(2166572391.0, obj->ToNumber(isolate)->Value());
+  CHECK_EQ(-2128394905, obj->ToInt32(isolate)->Value());
+  CHECK(2166572391u == obj->ToUint32(isolate)->Value());  // NOLINT
   // Fraction.
   CompileRun("var obj = 42.3;");
   obj = env->Global()->Get(v8_str("obj"));
-  CHECK_EQ(42.3, obj->ToNumber()->Value());
-  CHECK_EQ(42, obj->ToInt32()->Value());
-  CHECK(42u == obj->ToUint32()->Value());  // NOLINT
+  CHECK_EQ(42.3, obj->ToNumber(isolate)->Value());
+  CHECK_EQ(42, obj->ToInt32(isolate)->Value());
+  CHECK(42u == obj->ToUint32(isolate)->Value());  // NOLINT
   // Large negative fraction.
   CompileRun("var obj = -5726623061.75;");
   obj = env->Global()->Get(v8_str("obj"));
-  CHECK_EQ(-5726623061.75, obj->ToNumber()->Value());
-  CHECK_EQ(-1431655765, obj->ToInt32()->Value());
-  CHECK(2863311531u == obj->ToUint32()->Value());  // NOLINT
+  CHECK_EQ(-5726623061.75, obj->ToNumber(isolate)->Value());
+  CHECK_EQ(-1431655765, obj->ToInt32(isolate)->Value());
+  CHECK(2863311531u == obj->ToUint32(isolate)->Value());  // NOLINT
 }
 
 
@@ -4873,29 +5198,29 @@
     "var obj = new TestClass();");
   Local<Value> obj = env->Global()->Get(v8_str("obj"));
 
-  v8::TryCatch try_catch;
+  v8::TryCatch try_catch(isolate);
 
-  Local<Value> to_string_result = obj->ToString();
+  Local<Value> to_string_result = obj->ToString(isolate);
   CHECK(to_string_result.IsEmpty());
   CheckUncle(&try_catch);
 
-  Local<Value> to_number_result = obj->ToNumber();
+  Local<Value> to_number_result = obj->ToNumber(isolate);
   CHECK(to_number_result.IsEmpty());
   CheckUncle(&try_catch);
 
-  Local<Value> to_integer_result = obj->ToInteger();
+  Local<Value> to_integer_result = obj->ToInteger(isolate);
   CHECK(to_integer_result.IsEmpty());
   CheckUncle(&try_catch);
 
-  Local<Value> to_uint32_result = obj->ToUint32();
+  Local<Value> to_uint32_result = obj->ToUint32(isolate);
   CHECK(to_uint32_result.IsEmpty());
   CheckUncle(&try_catch);
 
-  Local<Value> to_int32_result = obj->ToInt32();
+  Local<Value> to_int32_result = obj->ToInt32(isolate);
   CHECK(to_int32_result.IsEmpty());
   CheckUncle(&try_catch);
 
-  Local<Value> to_object_result = v8::Undefined(isolate)->ToObject();
+  Local<Value> to_object_result = v8::Undefined(isolate)->ToObject(isolate);
   CHECK(to_object_result.IsEmpty());
   CHECK(try_catch.HasCaught());
   try_catch.Reset();
@@ -4931,7 +5256,7 @@
   }
   v8::HandleScope scope(args.GetIsolate());
   v8::TryCatch try_catch;
-  Local<Value> result = CompileRun(args[0]->ToString());
+  Local<Value> result = CompileRun(args[0]->ToString(args.GetIsolate()));
   CHECK(!try_catch.HasCaught() || result.IsEmpty());
   args.GetReturnValue().Set(try_catch.HasCaught());
 }
@@ -5980,7 +6305,7 @@
 }
 
 
-static void XPropertyGetter(Local<String> property,
+static void XPropertyGetter(Local<Name> property,
                             const v8::PropertyCallbackInfo<v8::Value>& info) {
   ApiTestFuzzer::Fuzz();
   CHECK(info.Data()->IsUndefined());
@@ -5992,7 +6317,7 @@
   v8::Isolate* isolate = CcTest::isolate();
   v8::HandleScope scope(isolate);
   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
-  templ->SetNamedPropertyHandler(XPropertyGetter);
+  templ->SetHandler(v8::NamedPropertyHandlerConfiguration(XPropertyGetter));
   LocalContext context;
   context->Global()->Set(v8_str("obj"), templ->NewInstance());
   Local<Script> script = v8_compile("obj.x");
@@ -6007,7 +6332,7 @@
   v8::Isolate* isolate = CcTest::isolate();
   v8::HandleScope scope(isolate);
   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
-  templ->SetNamedPropertyHandler(XPropertyGetter);
+  templ->SetHandler(v8::NamedPropertyHandlerConfiguration(XPropertyGetter));
   LocalContext context;
   // Create an object with a named interceptor.
   context->Global()->Set(v8_str("interceptor_obj"), templ->NewInstance());
@@ -6041,7 +6366,7 @@
 
   context1->Enter();
   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
-  templ->SetNamedPropertyHandler(XPropertyGetter);
+  templ->SetHandler(v8::NamedPropertyHandlerConfiguration(XPropertyGetter));
   // Create an object with a named interceptor.
   v8::Local<v8::Object> object = templ->NewInstance();
   context1->Global()->Set(v8_str("interceptor_obj"), object);
@@ -6076,8 +6401,7 @@
 
 
 static void SetXOnPrototypeGetter(
-    Local<String> property,
-    const v8::PropertyCallbackInfo<v8::Value>& info) {
+    Local<Name> property, const v8::PropertyCallbackInfo<v8::Value>& info) {
   // Set x on the prototype object and do not handle the get request.
   v8::Handle<v8::Value> proto = info.Holder()->GetPrototype();
   proto.As<v8::Object>()->Set(v8_str("x"),
@@ -6094,7 +6418,8 @@
       v8::FunctionTemplate::New(isolate);
   Local<v8::ObjectTemplate> instance_template
       = function_template->InstanceTemplate();
-  instance_template->SetNamedPropertyHandler(SetXOnPrototypeGetter);
+  instance_template->SetHandler(
+      v8::NamedPropertyHandlerConfiguration(SetXOnPrototypeGetter));
   LocalContext context;
   context->Global()->Set(v8_str("F"), function_template->GetFunction());
   // Create an instance of F and introduce a map transition for x.
@@ -6130,8 +6455,8 @@
   v8::Isolate* isolate = CcTest::isolate();
   v8::HandleScope scope(isolate);
   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
-  templ->SetIndexedPropertyHandler(IndexedPropertyGetter,
-                                   IndexedPropertySetter);
+  templ->SetHandler(v8::IndexedPropertyHandlerConfiguration(
+      IndexedPropertyGetter, IndexedPropertySetter));
   LocalContext context;
   context->Global()->Set(v8_str("obj"), templ->NewInstance());
   Local<Script> getter_script = v8_compile(
@@ -6196,11 +6521,9 @@
   v8::Isolate* isolate = CcTest::isolate();
   v8::HandleScope scope(isolate);
   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
-  templ->SetIndexedPropertyHandler(UnboxedDoubleIndexedPropertyGetter,
-                                   UnboxedDoubleIndexedPropertySetter,
-                                   0,
-                                   0,
-                                   UnboxedDoubleIndexedPropertyEnumerator);
+  templ->SetHandler(v8::IndexedPropertyHandlerConfiguration(
+      UnboxedDoubleIndexedPropertyGetter, UnboxedDoubleIndexedPropertySetter, 0,
+      0, UnboxedDoubleIndexedPropertyEnumerator));
   LocalContext context;
   context->Global()->Set(v8_str("obj"), templ->NewInstance());
   // When obj is created, force it to be Stored in a FastDoubleArray.
@@ -6210,7 +6533,7 @@
       "for (x in obj) {key_count++;};"
       "obj;");
   Local<Value> result = create_unboxed_double_script->Run();
-  CHECK(result->ToObject()->HasRealIndexedProperty(2000));
+  CHECK(result->ToObject(isolate)->HasRealIndexedProperty(2000));
   Local<Script> key_count_check = v8_compile("key_count;");
   result = key_count_check->Run();
   CHECK_EQ(v8_num(40013), result);
@@ -6252,11 +6575,9 @@
   v8::Isolate* isolate = CcTest::isolate();
   v8::HandleScope scope(isolate);
   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
-  templ->SetIndexedPropertyHandler(SloppyIndexedPropertyGetter,
-                                   0,
-                                   0,
-                                   0,
-                                   SloppyArgsIndexedPropertyEnumerator);
+  templ->SetHandler(v8::IndexedPropertyHandlerConfiguration(
+      SloppyIndexedPropertyGetter, 0, 0, 0,
+      SloppyArgsIndexedPropertyEnumerator));
   LocalContext context;
   context->Global()->Set(v8_str("obj"), templ->NewInstance());
   Local<Script> create_args_script = v8_compile(
@@ -6278,7 +6599,8 @@
   v8::Isolate* isolate = CcTest::isolate();
   v8::HandleScope scope(isolate);
   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
-  templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
+  templ->SetHandler(
+      v8::IndexedPropertyHandlerConfiguration(IdentityIndexedPropertyGetter));
 
   LocalContext context;
   context->Global()->Set(v8_str("obj"), templ->NewInstance());
@@ -6300,7 +6622,8 @@
   v8::Isolate* isolate = CcTest::isolate();
   v8::HandleScope scope(isolate);
   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
-  templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
+  templ->SetHandler(
+      v8::IndexedPropertyHandlerConfiguration(IdentityIndexedPropertyGetter));
 
   LocalContext context;
   context->Global()->Set(v8_str("obj"), templ->NewInstance());
@@ -6324,7 +6647,8 @@
   v8::Isolate* isolate = CcTest::isolate();
   v8::HandleScope scope(isolate);
   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
-  templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
+  templ->SetHandler(
+      v8::IndexedPropertyHandlerConfiguration(IdentityIndexedPropertyGetter));
 
   LocalContext context;
   Local<v8::Object> obj = templ->NewInstance();
@@ -6352,7 +6676,8 @@
   v8::Isolate* isolate = CcTest::isolate();
   v8::HandleScope scope(isolate);
   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
-  templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
+  templ->SetHandler(
+      v8::IndexedPropertyHandlerConfiguration(IdentityIndexedPropertyGetter));
 
   LocalContext context;
   Local<v8::Object> obj = templ->NewInstance();
@@ -6390,7 +6715,8 @@
   v8::Isolate* isolate = CcTest::isolate();
   v8::HandleScope scope(isolate);
   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
-  templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
+  templ->SetHandler(
+      v8::IndexedPropertyHandlerConfiguration(IdentityIndexedPropertyGetter));
 
   LocalContext context;
   Local<v8::Object> obj = templ->NewInstance();
@@ -6414,7 +6740,8 @@
   v8::Isolate* isolate = CcTest::isolate();
   v8::HandleScope scope(isolate);
   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
-  templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
+  templ->SetHandler(
+      v8::IndexedPropertyHandlerConfiguration(IdentityIndexedPropertyGetter));
 
   LocalContext context;
   Local<v8::Object> obj = templ->NewInstance();
@@ -6454,7 +6781,8 @@
   v8::Isolate* isolate = CcTest::isolate();
   v8::HandleScope scope(isolate);
   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
-  templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
+  templ->SetHandler(
+      v8::IndexedPropertyHandlerConfiguration(IdentityIndexedPropertyGetter));
 
   LocalContext context;
   Local<v8::Object> obj = templ->NewInstance();
@@ -6484,7 +6812,8 @@
   v8::Isolate* isolate = CcTest::isolate();
   v8::HandleScope scope(isolate);
   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
-  templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
+  templ->SetHandler(
+      v8::IndexedPropertyHandlerConfiguration(IdentityIndexedPropertyGetter));
 
   LocalContext context;
   Local<v8::Object> obj = templ->NewInstance();
@@ -6515,7 +6844,8 @@
   v8::Isolate* isolate = CcTest::isolate();
   v8::HandleScope scope(isolate);
   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
-  templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
+  templ->SetHandler(
+      v8::IndexedPropertyHandlerConfiguration(IdentityIndexedPropertyGetter));
 
   LocalContext context;
   Local<v8::Object> obj = templ->NewInstance();
@@ -6546,7 +6876,8 @@
   v8::Isolate* isolate = CcTest::isolate();
   v8::HandleScope scope(isolate);
   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
-  templ->SetIndexedPropertyHandler(IdentityIndexedPropertyGetter);
+  templ->SetHandler(
+      v8::IndexedPropertyHandlerConfiguration(IdentityIndexedPropertyGetter));
 
   LocalContext context;
   Local<v8::Object> obj = templ->NewInstance();
@@ -7371,14 +7702,175 @@
 };
 
 
-static void DisposeAndSetFlag(
-    const v8::WeakCallbackData<v8::Object, FlagAndPersistent>& data) {
-  data.GetParameter()->handle.Reset();
+static void SetFlag(const v8::PhantomCallbackData<FlagAndPersistent>& data) {
   data.GetParameter()->flag = true;
 }
 
 
+static void IndependentWeakHandle(bool global_gc, bool interlinked) {
+  v8::Isolate* iso = CcTest::isolate();
+  v8::HandleScope scope(iso);
+  v8::Handle<Context> context = Context::New(iso);
+  Context::Scope context_scope(context);
+
+  FlagAndPersistent object_a, object_b;
+
+  intptr_t big_heap_size;
+
+  {
+    v8::HandleScope handle_scope(iso);
+    Local<Object> a(v8::Object::New(iso));
+    Local<Object> b(v8::Object::New(iso));
+    object_a.handle.Reset(iso, a);
+    object_b.handle.Reset(iso, b);
+    if (interlinked) {
+      a->Set(v8_str("x"), b);
+      b->Set(v8_str("x"), a);
+    }
+    if (global_gc) {
+      CcTest::heap()->CollectAllGarbage(TestHeap::Heap::kNoGCFlags);
+    } else {
+      CcTest::heap()->CollectGarbage(i::NEW_SPACE);
+    }
+    // We are relying on this creating a big flag array and reserving the space
+    // up front.
+    v8::Handle<Value> big_array = CompileRun("new Array(50000)");
+    a->Set(v8_str("y"), big_array);
+    big_heap_size = CcTest::heap()->SizeOfObjects();
+  }
+
+  object_a.flag = false;
+  object_b.flag = false;
+  object_a.handle.SetPhantom(&object_a, &SetFlag);
+  object_b.handle.SetPhantom(&object_b, &SetFlag);
+  CHECK(!object_b.handle.IsIndependent());
+  object_a.handle.MarkIndependent();
+  object_b.handle.MarkIndependent();
+  CHECK(object_b.handle.IsIndependent());
+  if (global_gc) {
+    CcTest::heap()->CollectAllGarbage(TestHeap::Heap::kNoGCFlags);
+  } else {
+    CcTest::heap()->CollectGarbage(i::NEW_SPACE);
+  }
+  // A single GC should be enough to reclaim the memory, since we are using
+  // phantom handles.
+  CHECK_LT(CcTest::heap()->SizeOfObjects(), big_heap_size - 200000);
+  CHECK(object_a.flag);
+  CHECK(object_b.flag);
+}
+
+
 THREADED_TEST(IndependentWeakHandle) {
+  IndependentWeakHandle(false, false);
+  IndependentWeakHandle(false, true);
+  IndependentWeakHandle(true, false);
+  IndependentWeakHandle(true, true);
+}
+
+
+class Trivial {
+ public:
+  explicit Trivial(int x) : x_(x) {}
+
+  int x() { return x_; }
+  void set_x(int x) { x_ = x; }
+
+ private:
+  int x_;
+};
+
+
+class Trivial2 {
+ public:
+  Trivial2(int x, int y) : y_(y), x_(x) {}
+
+  int x() { return x_; }
+  void set_x(int x) { x_ = x; }
+
+  int y() { return y_; }
+  void set_y(int y) { y_ = y; }
+
+ private:
+  int y_;
+  int x_;
+};
+
+
+void CheckInternalFields(
+    const v8::InternalFieldsCallbackData<Trivial, Trivial2>& data) {
+  Trivial* t1 = data.GetInternalField1();
+  Trivial2* t2 = data.GetInternalField2();
+  CHECK_EQ(42, t1->x());
+  CHECK_EQ(103, t2->x());
+  t1->set_x(1729);
+  t2->set_x(33550336);
+}
+
+
+void InternalFieldCallback(bool global_gc) {
+  LocalContext env;
+  v8::Isolate* isolate = env->GetIsolate();
+  v8::HandleScope scope(isolate);
+
+  Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
+  Local<v8::ObjectTemplate> instance_templ = templ->InstanceTemplate();
+  Trivial* t1;
+  Trivial2* t2;
+  instance_templ->SetInternalFieldCount(2);
+  {
+    v8::HandleScope scope(isolate);
+    Local<v8::Object> obj = templ->GetFunction()->NewInstance();
+    v8::Persistent<v8::Object> handle(isolate, obj);
+    CHECK_EQ(2, obj->InternalFieldCount());
+    CHECK(obj->GetInternalField(0)->IsUndefined());
+    t1 = new Trivial(42);
+    t2 = new Trivial2(103, 9);
+
+    obj->SetAlignedPointerInInternalField(0, t1);
+    t1 = reinterpret_cast<Trivial*>(obj->GetAlignedPointerFromInternalField(0));
+    CHECK_EQ(42, t1->x());
+
+    obj->SetAlignedPointerInInternalField(1, t2);
+    t2 =
+        reinterpret_cast<Trivial2*>(obj->GetAlignedPointerFromInternalField(1));
+    CHECK_EQ(103, t2->x());
+
+    handle.SetPhantom(CheckInternalFields, 0, 1);
+    if (!global_gc) {
+      handle.MarkIndependent();
+    }
+  }
+  if (global_gc) {
+    CcTest::heap()->CollectAllGarbage(TestHeap::Heap::kNoGCFlags);
+  } else {
+    CcTest::heap()->CollectGarbage(i::NEW_SPACE);
+  }
+
+  CHECK_EQ(1729, t1->x());
+  CHECK_EQ(33550336, t2->x());
+
+  delete t1;
+  delete t2;
+}
+
+
+THREADED_TEST(InternalFieldCallback) {
+  InternalFieldCallback(false);
+  InternalFieldCallback(true);
+}
+
+
+static void ResetUseValueAndSetFlag(
+    const v8::WeakCallbackData<v8::Object, FlagAndPersistent>& data) {
+  // Blink will reset the handle, and then use the other handle, so they
+  // can't use the same backing slot.
+  data.GetParameter()->handle.Reset();
+  data.GetValue()->IsBoolean();  // Make sure the handle still works.
+  data.GetParameter()->flag = true;
+}
+
+
+static void ResetWeakHandle(bool global_gc) {
   v8::Isolate* iso = CcTest::isolate();
   v8::HandleScope scope(iso);
   v8::Handle<Context> context = Context::New(iso);
@@ -7388,24 +7880,44 @@
 
   {
     v8::HandleScope handle_scope(iso);
-    object_a.handle.Reset(iso, v8::Object::New(iso));
-    object_b.handle.Reset(iso, v8::Object::New(iso));
+    Local<Object> a(v8::Object::New(iso));
+    Local<Object> b(v8::Object::New(iso));
+    object_a.handle.Reset(iso, a);
+    object_b.handle.Reset(iso, b);
+    if (global_gc) {
+      CcTest::heap()->CollectAllGarbage(
+          TestHeap::Heap::kAbortIncrementalMarkingMask);
+    } else {
+      CcTest::heap()->CollectGarbage(i::NEW_SPACE);
+    }
   }
 
   object_a.flag = false;
   object_b.flag = false;
-  object_a.handle.SetWeak(&object_a, &DisposeAndSetFlag);
-  object_b.handle.SetWeak(&object_b, &DisposeAndSetFlag);
-  CHECK(!object_b.handle.IsIndependent());
-  object_a.handle.MarkIndependent();
-  object_b.handle.MarkIndependent();
-  CHECK(object_b.handle.IsIndependent());
-  CcTest::heap()->CollectGarbage(i::NEW_SPACE);
+  object_a.handle.SetWeak(&object_a, &ResetUseValueAndSetFlag);
+  object_b.handle.SetWeak(&object_b, &ResetUseValueAndSetFlag);
+  if (!global_gc) {
+    object_a.handle.MarkIndependent();
+    object_b.handle.MarkIndependent();
+    CHECK(object_b.handle.IsIndependent());
+  }
+  if (global_gc) {
+    CcTest::heap()->CollectAllGarbage(
+        TestHeap::Heap::kAbortIncrementalMarkingMask);
+  } else {
+    CcTest::heap()->CollectGarbage(i::NEW_SPACE);
+  }
   CHECK(object_a.flag);
   CHECK(object_b.flag);
 }
 
 
+THREADED_TEST(ResetWeakHandle) {
+  ResetWeakHandle(false);
+  ResetWeakHandle(true);
+}
+
+
 static void InvokeScavenge() {
   CcTest::heap()->CollectGarbage(i::NEW_SPACE);
 }
@@ -7533,9 +8045,8 @@
 }
 
 
-static void NoBlockGetterX(Local<String> name,
-                           const v8::PropertyCallbackInfo<v8::Value>&) {
-}
+static void NoBlockGetterX(Local<Name> name,
+                           const v8::PropertyCallbackInfo<v8::Value>&) {}
 
 
 static void NoBlockGetterI(uint32_t index,
@@ -7543,7 +8054,7 @@
 }
 
 
-static void PDeleter(Local<String> name,
+static void PDeleter(Local<Name> name,
                      const v8::PropertyCallbackInfo<v8::Boolean>& info) {
   if (!name->Equals(v8_str("foo"))) {
     return;  // not intercepted
@@ -7567,8 +8078,10 @@
   v8::Isolate* isolate = CcTest::isolate();
   v8::HandleScope scope(isolate);
   v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
-  obj->SetNamedPropertyHandler(NoBlockGetterX, NULL, NULL, PDeleter, NULL);
-  obj->SetIndexedPropertyHandler(NoBlockGetterI, NULL, NULL, IDeleter, NULL);
+  obj->SetHandler(v8::NamedPropertyHandlerConfiguration(NoBlockGetterX, NULL,
+                                                        NULL, PDeleter, NULL));
+  obj->SetHandler(v8::IndexedPropertyHandlerConfiguration(
+      NoBlockGetterI, NULL, NULL, IDeleter, NULL));
   LocalContext context;
   context->Global()->Set(v8_str("k"), obj->NewInstance());
   CompileRun(
@@ -7590,7 +8103,7 @@
 }
 
 
-static void GetK(Local<String> name,
+static void GetK(Local<Name> name,
                  const v8::PropertyCallbackInfo<v8::Value>& info) {
   ApiTestFuzzer::Fuzz();
   if (name->Equals(v8_str("foo")) ||
@@ -7631,8 +8144,10 @@
   v8::Isolate* isolate = CcTest::isolate();
   v8::HandleScope scope(isolate);
   v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
-  obj->SetNamedPropertyHandler(GetK, NULL, NULL, NULL, NamedEnum);
-  obj->SetIndexedPropertyHandler(IndexedGetK, NULL, NULL, NULL, IndexedEnum);
+  obj->SetHandler(
+      v8::NamedPropertyHandlerConfiguration(GetK, NULL, NULL, NULL, NamedEnum));
+  obj->SetHandler(v8::IndexedPropertyHandlerConfiguration(
+      IndexedGetK, NULL, NULL, NULL, IndexedEnum));
   LocalContext context;
   context->Global()->Set(v8_str("k"), obj->NewInstance());
   v8::Handle<v8::Array> result = v8::Handle<v8::Array>::Cast(CompileRun(
@@ -7724,7 +8239,7 @@
 }
 
 
-static void PGetter2(Local<String> name,
+static void PGetter2(Local<Name> name,
                      const v8::PropertyCallbackInfo<v8::Value>& info) {
   ApiTestFuzzer::Fuzz();
   p_getter_count2++;
@@ -7761,7 +8276,7 @@
   v8::Isolate* isolate = CcTest::isolate();
   v8::HandleScope scope(isolate);
   v8::Handle<v8::ObjectTemplate> obj = ObjectTemplate::New(isolate);
-  obj->SetNamedPropertyHandler(PGetter2);
+  obj->SetHandler(v8::NamedPropertyHandlerConfiguration(PGetter2));
   p_getter_count2 = 0;
   RunHolderTest(obj);
   CHECK_EQ(40, p_getter_count2);
@@ -8419,6 +8934,85 @@
 }
 
 
+static void ThrowV8Exception(const v8::FunctionCallbackInfo<v8::Value>& info) {
+  ApiTestFuzzer::Fuzz();
+  v8::Handle<String> foo = v8_str("foo");
+  v8::Handle<String> message = v8_str("message");
+  v8::Handle<Value> error = v8::Exception::Error(foo);
+  CHECK(error->IsObject());
+  CHECK(error.As<v8::Object>()->Get(message)->Equals(foo));
+  info.GetIsolate()->ThrowException(error);
+  info.GetReturnValue().SetUndefined();
+}
+
+
+THREADED_TEST(ExceptionCreateMessage) {
+  LocalContext context;
+  v8::HandleScope scope(context->GetIsolate());
+  v8::Handle<String> foo_str = v8_str("foo");
+  v8::Handle<String> message_str = v8_str("message");
+
+  v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
+
+  Local<v8::FunctionTemplate> fun =
+      v8::FunctionTemplate::New(context->GetIsolate(), ThrowV8Exception);
+  v8::Local<v8::Object> global = context->Global();
+  global->Set(v8_str("throwV8Exception"), fun->GetFunction());
+
+  TryCatch try_catch;
+  CompileRun(
+      "function f1() {\n"
+      "  throwV8Exception();\n"
+      "};\n"
+      "f1();");
+  CHECK(try_catch.HasCaught());
+
+  v8::Handle<v8::Value> error = try_catch.Exception();
+  CHECK(error->IsObject());
+  CHECK(error.As<v8::Object>()->Get(message_str)->Equals(foo_str));
+
+  v8::Handle<v8::Message> message = v8::Exception::CreateMessage(error);
+  CHECK(!message.IsEmpty());
+  CHECK_EQ(2, message->GetLineNumber());
+  CHECK_EQ(2, message->GetStartColumn());
+
+  v8::Handle<v8::StackTrace> stackTrace = message->GetStackTrace();
+  CHECK(!stackTrace.IsEmpty());
+  CHECK_EQ(2, stackTrace->GetFrameCount());
+
+  stackTrace = v8::Exception::GetStackTrace(error);
+  CHECK(!stackTrace.IsEmpty());
+  CHECK_EQ(2, stackTrace->GetFrameCount());
+
+  v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
+
+  // Now check message location when SetCaptureStackTraceForUncaughtExceptions
+  // is false.
+  try_catch.Reset();
+
+  CompileRun(
+      "function f2() {\n"
+      "  return throwV8Exception();\n"
+      "};\n"
+      "f2();");
+  CHECK(try_catch.HasCaught());
+
+  error = try_catch.Exception();
+  CHECK(error->IsObject());
+  CHECK(error.As<v8::Object>()->Get(message_str)->Equals(foo_str));
+
+  message = v8::Exception::CreateMessage(error);
+  CHECK(!message.IsEmpty());
+  CHECK_EQ(2, message->GetLineNumber());
+  CHECK_EQ(9, message->GetStartColumn());
+
+  // Should be empty stack trace.
+  stackTrace = message->GetStackTrace();
+  CHECK(stackTrace.IsEmpty());
+  CHECK(v8::Exception::GetStackTrace(error).IsEmpty());
+}
+
+
 static void YGetter(Local<String> name,
                     const v8::PropertyCallbackInfo<v8::Value>& info) {
   ApiTestFuzzer::Fuzz();
@@ -8532,6 +9126,33 @@
   v8::V8::RemoveMessageListeners(ApiUncaughtExceptionTestListener);
 }
 
+
+TEST(ApiUncaughtExceptionInObjectObserve) {
+  v8::internal::FLAG_stack_size = 150;
+  report_count = 0;
+  LocalContext env;
+  v8::Isolate* isolate = env->GetIsolate();
+  v8::HandleScope scope(isolate);
+  v8::V8::AddMessageListener(ApiUncaughtExceptionTestListener);
+  CompileRun(
+      "var obj = {};"
+      "var observe_count = 0;"
+      "function observer1() { ++observe_count; };"
+      "function observer2() { ++observe_count; };"
+      "function observer_throws() { throw new Error(); };"
+      "function stack_overflow() { return (function f(x) { f(x+1); })(0); };"
+      "Object.observe(obj, observer_throws.bind());"
+      "Object.observe(obj, observer1);"
+      "Object.observe(obj, stack_overflow);"
+      "Object.observe(obj, observer2);"
+      "Object.observe(obj, observer_throws.bind());"
+      "obj.foo = 'bar';");
+  CHECK_EQ(3, report_count);
+  ExpectInt32("observe_count", 2);
+  v8::V8::RemoveMessageListeners(ApiUncaughtExceptionTestListener);
+}
+
+
 static const char* script_resource_name = "ExceptionInNativeScript.js";
 static void ExceptionInNativeScriptTestListener(v8::Handle<v8::Message> message,
                                                 v8::Handle<Value>) {
@@ -8603,7 +9224,7 @@
 
 void CEvaluate(const v8::FunctionCallbackInfo<v8::Value>& args) {
   v8::HandleScope scope(args.GetIsolate());
-  CompileRun(args[0]->ToString());
+  CompileRun(args[0]->ToString(args.GetIsolate()));
 }
 
 
@@ -8877,11 +9498,11 @@
   CHECK(indexed_security_check_with_gc_called);
 
   named_security_check_with_gc_called = false;
-  CHECK(CompileRun("obj.foo")->ToString()->Equals(v8_str("1001")));
+  CHECK(CompileRun("obj.foo")->ToString(isolate)->Equals(v8_str("1001")));
   CHECK(named_security_check_with_gc_called);
 
   indexed_security_check_with_gc_called = false;
-  CHECK(CompileRun("obj[0]")->ToString()->Equals(v8_str("1002")));
+  CHECK(CompileRun("obj[0]")->ToString(isolate)->Equals(v8_str("1002")));
   CHECK(indexed_security_check_with_gc_called);
 }
 
@@ -9609,20 +10230,52 @@
   LocalContext env;
   env->Global()->Set(v8_str("prohibited"), obj_template->NewInstance());
 
-  v8::TryCatch try_catch;
-  CompileRun(
-      "function f() { return super.hasOwnProperty; };"
-      "var m = f.toMethod(prohibited);"
-      "m();");
-  CHECK(try_catch.HasCaught());
+  {
+    v8::TryCatch try_catch;
+    CompileRun(
+        "function f() { return super.hasOwnProperty; };"
+        "var m = f.toMethod(prohibited);"
+        "m();");
+    CHECK(try_catch.HasCaught());
+  }
+
+  {
+    v8::TryCatch try_catch;
+    CompileRun(
+        "function f() { return super[42]; };"
+        "var m = f.toMethod(prohibited);"
+        "m();");
+    CHECK(try_catch.HasCaught());
+  }
+
+  {
+    v8::TryCatch try_catch;
+    CompileRun(
+        "function f() { super.hasOwnProperty = function () {}; };"
+        "var m = f.toMethod(prohibited);"
+        "m();");
+    CHECK(try_catch.HasCaught());
+  }
+
+  {
+    v8::TryCatch try_catch;
+    CompileRun(
+        "Object.defineProperty(Object.prototype, 'x', { set : function(){}});"
+        "function f() { "
+        "     'use strict';"
+        "     super.x = function () {}; "
+        "};"
+        "var m = f.toMethod(prohibited);"
+        "m();");
+    CHECK(try_catch.HasCaught());
+  }
 }
 
 
 static void IndexedPropertyEnumerator(
     const v8::PropertyCallbackInfo<v8::Array>& info) {
-  v8::Handle<v8::Array> result = v8::Array::New(info.GetIsolate(), 2);
+  v8::Handle<v8::Array> result = v8::Array::New(info.GetIsolate(), 1);
   result->Set(0, v8::Integer::New(info.GetIsolate(), 7));
-  result->Set(1, v8::Object::New(info.GetIsolate()));
   info.GetReturnValue().Set(result);
 }
 
@@ -9631,7 +10284,7 @@
     const v8::PropertyCallbackInfo<v8::Array>& info) {
   v8::Handle<v8::Array> result = v8::Array::New(info.GetIsolate(), 2);
   result->Set(0, v8_str("x"));
-  result->Set(1, v8::Object::New(info.GetIsolate()));
+  result->Set(1, v8::Symbol::GetIterator(info.GetIsolate()));
   info.GetReturnValue().Set(result);
 }
 
@@ -9644,10 +10297,10 @@
 
   obj_template->Set(v8_str("7"), v8::Integer::New(CcTest::isolate(), 7));
   obj_template->Set(v8_str("x"), v8::Integer::New(CcTest::isolate(), 42));
-  obj_template->SetIndexedPropertyHandler(NULL, NULL, NULL, NULL,
-                                          IndexedPropertyEnumerator);
-  obj_template->SetNamedPropertyHandler(NULL, NULL, NULL, NULL,
-                                        NamedPropertyEnumerator);
+  obj_template->SetHandler(v8::IndexedPropertyHandlerConfiguration(
+      NULL, NULL, NULL, NULL, IndexedPropertyEnumerator));
+  obj_template->SetHandler(v8::NamedPropertyHandlerConfiguration(
+      NULL, NULL, NULL, NULL, NamedPropertyEnumerator));
 
   LocalContext context;
   v8::Handle<v8::Object> global = context->Global();
@@ -9657,13 +10310,26 @@
       CompileRun("Object.getOwnPropertyNames(object)");
   CHECK(result->IsArray());
   v8::Handle<v8::Array> result_array = v8::Handle<v8::Array>::Cast(result);
-  CHECK_EQ(3, result_array->Length());
+  CHECK_EQ(2, result_array->Length());
   CHECK(result_array->Get(0)->IsString());
   CHECK(result_array->Get(1)->IsString());
-  CHECK(result_array->Get(2)->IsString());
   CHECK_EQ(v8_str("7"), result_array->Get(0));
-  CHECK_EQ(v8_str("[object Object]"), result_array->Get(1));
-  CHECK_EQ(v8_str("x"), result_array->Get(2));
+  CHECK_EQ(v8_str("x"), result_array->Get(1));
+
+  result = CompileRun("var ret = []; for (var k in object) ret.push(k); ret");
+  CHECK(result->IsArray());
+  result_array = v8::Handle<v8::Array>::Cast(result);
+  CHECK_EQ(2, result_array->Length());
+  CHECK(result_array->Get(0)->IsString());
+  CHECK(result_array->Get(1)->IsString());
+  CHECK_EQ(v8_str("7"), result_array->Get(0));
+  CHECK_EQ(v8_str("x"), result_array->Get(1));
+
+  result = CompileRun("Object.getOwnPropertySymbols(object)");
+  CHECK(result->IsArray());
+  result_array = v8::Handle<v8::Array>::Cast(result);
+  CHECK_EQ(1, result_array->Length());
+  CHECK_EQ(result_array->Get(0), v8::Symbol::GetIterator(isolate));
 }
 
 
@@ -9937,15 +10603,13 @@
 
 
 static void AccessControlNamedGetter(
-    Local<String>,
-    const v8::PropertyCallbackInfo<v8::Value>& info) {
+    Local<Name>, const v8::PropertyCallbackInfo<v8::Value>& info) {
   info.GetReturnValue().Set(42);
 }
 
 
 static void AccessControlNamedSetter(
-    Local<String>,
-    Local<Value> value,
+    Local<Name>, Local<Value> value,
     const v8::PropertyCallbackInfo<v8::Value>& info) {
   info.GetReturnValue().Set(value);
 }
@@ -9984,10 +10648,10 @@
       v8::ObjectTemplate::New(isolate);
   object_template->SetAccessCheckCallbacks(NamedAccessCounter,
                                            IndexedAccessCounter);
-  object_template->SetNamedPropertyHandler(AccessControlNamedGetter,
-                                           AccessControlNamedSetter);
-  object_template->SetIndexedPropertyHandler(AccessControlIndexedGetter,
-                                             AccessControlIndexedSetter);
+  object_template->SetHandler(v8::NamedPropertyHandlerConfiguration(
+      AccessControlNamedGetter, AccessControlNamedSetter));
+  object_template->SetHandler(v8::IndexedPropertyHandlerConfiguration(
+      AccessControlIndexedGetter, AccessControlIndexedSetter));
   Local<v8::Object> object = object_template->NewInstance();
 
   v8::HandleScope scope1(isolate);
@@ -10069,8 +10733,7 @@
 
 
 static void GlobalObjectInstancePropertiesGet(
-    Local<String> key,
-    const v8::PropertyCallbackInfo<v8::Value>&) {
+    Local<Name> key, const v8::PropertyCallbackInfo<v8::Value>&) {
   ApiTestFuzzer::Fuzz();
 }
 
@@ -10082,8 +10745,8 @@
   Local<Value> global_object;
 
   Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
-  t->InstanceTemplate()->SetNamedPropertyHandler(
-      GlobalObjectInstancePropertiesGet);
+  t->InstanceTemplate()->SetHandler(
+      v8::NamedPropertyHandlerConfiguration(GlobalObjectInstancePropertiesGet));
   Local<ObjectTemplate> instance_template = t->InstanceTemplate();
   instance_template->Set(v8_str("x"), v8_num(42));
   instance_template->Set(v8_str("f"),
@@ -10207,9 +10870,8 @@
 }
 
 
-static void ShadowNamedGet(Local<String> key,
-                           const v8::PropertyCallbackInfo<v8::Value>&) {
-}
+static void ShadowNamedGet(Local<Name> key,
+                           const v8::PropertyCallbackInfo<v8::Value>&) {}
 
 
 THREADED_TEST(ShadowObject) {
@@ -10221,8 +10883,10 @@
   LocalContext context(NULL, global_template);
 
   Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate);
-  t->InstanceTemplate()->SetNamedPropertyHandler(ShadowNamedGet);
-  t->InstanceTemplate()->SetIndexedPropertyHandler(ShadowIndexedGet);
+  t->InstanceTemplate()->SetHandler(
+      v8::NamedPropertyHandlerConfiguration(ShadowNamedGet));
+  t->InstanceTemplate()->SetHandler(
+      v8::IndexedPropertyHandlerConfiguration(ShadowIndexedGet));
   Local<ObjectTemplate> proto = t->PrototypeTemplate();
   Local<ObjectTemplate> instance = t->InstanceTemplate();
 
@@ -10709,7 +11373,7 @@
         "(function() { var o = new obj('tipli'); return o.a; })()");
     CHECK(!try_catch.HasCaught());
     CHECK(value->IsString());
-    String::Utf8Value string_value1(value->ToString());
+    String::Utf8Value string_value1(value->ToString(isolate));
     CHECK_EQ("tipli", *string_value1);
 
     Local<Value> args2[] = { v8_str("tipli") };
@@ -10719,7 +11383,7 @@
     value = object2->Get(v8_str("a"));
     CHECK(!try_catch.HasCaught());
     CHECK(value->IsString());
-    String::Utf8Value string_value2(value->ToString());
+    String::Utf8Value string_value2(value->ToString(isolate));
     CHECK_EQ("tipli", *string_value2);
 
     // Call the Object's constructor with a Boolean.
@@ -10982,8 +11646,7 @@
 
 
 // Test that calling eval in a context which has been detached from
-// its global throws an exception.  This behavior is consistent with
-// other JavaScript implementations.
+// its global proxy works.
 THREADED_TEST(EvalInDetachedGlobal) {
   v8::Isolate* isolate = CcTest::isolate();
   v8::HandleScope scope(isolate);
@@ -11011,8 +11674,7 @@
   context0->DetachGlobal();
   v8::TryCatch catcher;
   x_value = CompileRun("fun('x')");
-  CHECK(x_value.IsEmpty());
-  CHECK(catcher.HasCaught());
+  CHECK_EQ(42, x_value->Int32Value());
   context1->Exit();
 }
 
@@ -11330,8 +11992,7 @@
 
 
 static void InterceptorHasOwnPropertyGetter(
-    Local<String> name,
-    const v8::PropertyCallbackInfo<v8::Value>& info) {
+    Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
   ApiTestFuzzer::Fuzz();
 }
 
@@ -11342,7 +12003,8 @@
   v8::HandleScope scope(isolate);
   Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(isolate);
   Local<v8::ObjectTemplate> instance_templ = fun_templ->InstanceTemplate();
-  instance_templ->SetNamedPropertyHandler(InterceptorHasOwnPropertyGetter);
+  instance_templ->SetHandler(
+      v8::NamedPropertyHandlerConfiguration(InterceptorHasOwnPropertyGetter));
   Local<Function> function = fun_templ->GetFunction();
   context->Global()->Set(v8_str("constructor"), function);
   v8::Handle<Value> value = CompileRun(
@@ -11361,8 +12023,7 @@
 
 
 static void InterceptorHasOwnPropertyGetterGC(
-    Local<String> name,
-    const v8::PropertyCallbackInfo<v8::Value>& info) {
+    Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
   ApiTestFuzzer::Fuzz();
   CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
 }
@@ -11374,7 +12035,8 @@
   v8::HandleScope scope(isolate);
   Local<v8::FunctionTemplate> fun_templ = v8::FunctionTemplate::New(isolate);
   Local<v8::ObjectTemplate> instance_templ = fun_templ->InstanceTemplate();
-  instance_templ->SetNamedPropertyHandler(InterceptorHasOwnPropertyGetterGC);
+  instance_templ->SetHandler(
+      v8::NamedPropertyHandlerConfiguration(InterceptorHasOwnPropertyGetterGC));
   Local<Function> function = fun_templ->GetFunction();
   context->Global()->Set(v8_str("constructor"), function);
   // Let's first make some stuff so we can be sure to get a good GC.
@@ -11398,18 +12060,14 @@
 }
 
 
-typedef void (*NamedPropertyGetter)(
-    Local<String> property,
-    const v8::PropertyCallbackInfo<v8::Value>& info);
-
-
-static void CheckInterceptorLoadIC(NamedPropertyGetter getter,
-                                   const char* source,
-                                   int expected) {
+static void CheckInterceptorLoadIC(
+    v8::GenericNamedPropertyGetterCallback getter, const char* source,
+    int expected) {
   v8::Isolate* isolate = CcTest::isolate();
   v8::HandleScope scope(isolate);
   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
-  templ->SetNamedPropertyHandler(getter, 0, 0, 0, 0, v8_str("data"));
+  templ->SetHandler(v8::NamedPropertyHandlerConfiguration(getter, 0, 0, 0, 0,
+                                                          v8_str("data")));
   LocalContext context;
   context->Global()->Set(v8_str("o"), templ->NewInstance());
   v8::Handle<Value> value = CompileRun(source);
@@ -11418,8 +12076,7 @@
 
 
 static void InterceptorLoadICGetter(
-    Local<String> name,
-    const v8::PropertyCallbackInfo<v8::Value>& info) {
+    Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
   ApiTestFuzzer::Fuzz();
   v8::Isolate* isolate = CcTest::isolate();
   CHECK_EQ(isolate, info.GetIsolate());
@@ -11445,8 +12102,7 @@
 // (those cases are special cased to get better performance).
 
 static void InterceptorLoadXICGetter(
-    Local<String> name,
-    const v8::PropertyCallbackInfo<v8::Value>& info) {
+    Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
   ApiTestFuzzer::Fuzz();
   info.GetReturnValue().Set(
       v8_str("x")->Equals(name) ?
@@ -11561,8 +12217,7 @@
 
 static int interceptor_load_not_handled_calls = 0;
 static void InterceptorLoadNotHandled(
-    Local<String> name,
-    const v8::PropertyCallbackInfo<v8::Value>& info) {
+    Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
   ++interceptor_load_not_handled_calls;
 }
 
@@ -11623,7 +12278,8 @@
   v8::Isolate* isolate = CcTest::isolate();
   v8::HandleScope scope(isolate);
   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
-  templ->SetNamedPropertyHandler(InterceptorLoadXICGetter);
+  templ->SetHandler(
+      v8::NamedPropertyHandlerConfiguration(InterceptorLoadXICGetter));
   templ->SetAccessor(v8_str("y"), Return239Callback);
   LocalContext context;
   context->Global()->Set(v8_str("o"), templ->NewInstance());
@@ -11653,7 +12309,8 @@
   v8::Isolate* isolate = CcTest::isolate();
   v8::HandleScope scope(isolate);
   v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate);
-  templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
+  templ_o->SetHandler(
+      v8::NamedPropertyHandlerConfiguration(InterceptorLoadXICGetter));
   v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New(isolate);
   templ_p->SetAccessor(v8_str("y"), Return239Callback);
 
@@ -11687,7 +12344,8 @@
   v8::Isolate* isolate = CcTest::isolate();
   v8::HandleScope scope(isolate);
   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
-  templ->SetNamedPropertyHandler(InterceptorLoadXICGetter);
+  templ->SetHandler(
+      v8::NamedPropertyHandlerConfiguration(InterceptorLoadXICGetter));
   templ->SetAccessor(v8_str("y"), Return239Callback);
 
   LocalContext context;
@@ -11716,7 +12374,8 @@
   v8::Isolate* isolate = CcTest::isolate();
   v8::HandleScope scope(isolate);
   v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate);
-  templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
+  templ_o->SetHandler(
+      v8::NamedPropertyHandlerConfiguration(InterceptorLoadXICGetter));
   v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New(isolate);
   templ_p->SetAccessor(v8_str("y"), Return239Callback);
 
@@ -11745,7 +12404,8 @@
   v8::Isolate* isolate = CcTest::isolate();
   v8::HandleScope scope(isolate);
   v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate);
-  templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
+  templ_o->SetHandler(
+      v8::NamedPropertyHandlerConfiguration(InterceptorLoadXICGetter));
   v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New(isolate);
   templ_p->SetAccessor(v8_str("y"), Return239Callback, SetOnThis);
 
@@ -11778,7 +12438,8 @@
   v8::Isolate* isolate = CcTest::isolate();
   v8::HandleScope scope(isolate);
   v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate);
-  templ_o->SetNamedPropertyHandler(InterceptorLoadXICGetter);
+  templ_o->SetHandler(
+      v8::NamedPropertyHandlerConfiguration(InterceptorLoadXICGetter));
   v8::Handle<v8::ObjectTemplate> templ_p = ObjectTemplate::New(isolate);
   templ_p->SetAccessor(v8_str("y"), Return239Callback, SetOnThis);
 
@@ -11804,8 +12465,7 @@
 
 
 static void InterceptorLoadICGetter0(
-    Local<String> name,
-    const v8::PropertyCallbackInfo<v8::Value>& info) {
+    Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
   ApiTestFuzzer::Fuzz();
   CHECK(v8_str("x")->Equals(name));
   info.GetReturnValue().Set(v8::Integer::New(info.GetIsolate(), 0));
@@ -11820,8 +12480,7 @@
 
 
 static void InterceptorStoreICSetter(
-    Local<String> key,
-    Local<Value> value,
+    Local<Name> key, Local<Value> value,
     const v8::PropertyCallbackInfo<v8::Value>& info) {
   CHECK(v8_str("x")->Equals(key));
   CHECK_EQ(42, value->Int32Value());
@@ -11834,9 +12493,9 @@
   v8::Isolate* isolate = CcTest::isolate();
   v8::HandleScope scope(isolate);
   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
-  templ->SetNamedPropertyHandler(InterceptorLoadICGetter,
-                                 InterceptorStoreICSetter,
-                                 0, 0, 0, v8_str("data"));
+  templ->SetHandler(v8::NamedPropertyHandlerConfiguration(
+      InterceptorLoadICGetter, InterceptorStoreICSetter, 0, 0, 0,
+      v8_str("data")));
   LocalContext context;
   context->Global()->Set(v8_str("o"), templ->NewInstance());
   CompileRun(
@@ -11850,7 +12509,8 @@
   v8::Isolate* isolate = CcTest::isolate();
   v8::HandleScope scope(isolate);
   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
-  templ->SetNamedPropertyHandler(InterceptorLoadXICGetter);
+  templ->SetHandler(
+      v8::NamedPropertyHandlerConfiguration(InterceptorLoadXICGetter));
   LocalContext context;
   context->Global()->Set(v8_str("o"), templ->NewInstance());
   v8::Handle<Value> value = CompileRun(
@@ -11869,8 +12529,7 @@
 v8::Handle<Value> call_ic_function3;
 
 static void InterceptorCallICGetter(
-    Local<String> name,
-    const v8::PropertyCallbackInfo<v8::Value>& info) {
+    Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
   ApiTestFuzzer::Fuzz();
   CHECK(v8_str("x")->Equals(name));
   info.GetReturnValue().Set(call_ic_function);
@@ -11882,7 +12541,8 @@
   v8::Isolate* isolate = CcTest::isolate();
   v8::HandleScope scope(isolate);
   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
-  templ->SetNamedPropertyHandler(InterceptorCallICGetter);
+  templ->SetHandler(
+      v8::NamedPropertyHandlerConfiguration(InterceptorCallICGetter));
   LocalContext context;
   context->Global()->Set(v8_str("o"), templ->NewInstance());
   call_ic_function =
@@ -11902,7 +12562,7 @@
   v8::Isolate* isolate = CcTest::isolate();
   v8::HandleScope scope(isolate);
   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
-  templ->SetNamedPropertyHandler(NoBlockGetterX);
+  templ->SetHandler(v8::NamedPropertyHandlerConfiguration(NoBlockGetterX));
   LocalContext context;
   context->Global()->Set(v8_str("o"), templ->NewInstance());
   v8::Handle<Value> value = CompileRun(
@@ -11917,8 +12577,7 @@
 
 static v8::Handle<Value> call_ic_function4;
 static void InterceptorCallICGetter4(
-    Local<String> name,
-    const v8::PropertyCallbackInfo<v8::Value>& info) {
+    Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
   ApiTestFuzzer::Fuzz();
   CHECK(v8_str("x")->Equals(name));
   info.GetReturnValue().Set(call_ic_function4);
@@ -11932,7 +12591,8 @@
   v8::Isolate* isolate = CcTest::isolate();
   v8::HandleScope scope(isolate);
   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
-  templ->SetNamedPropertyHandler(InterceptorCallICGetter4);
+  templ->SetHandler(
+      v8::NamedPropertyHandlerConfiguration(InterceptorCallICGetter4));
   LocalContext context;
   context->Global()->Set(v8_str("o"), templ->NewInstance());
   call_ic_function4 =
@@ -11953,7 +12613,7 @@
   v8::Isolate* isolate = CcTest::isolate();
   v8::HandleScope scope(isolate);
   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
-  templ->SetNamedPropertyHandler(NoBlockGetterX);
+  templ->SetHandler(v8::NamedPropertyHandlerConfiguration(NoBlockGetterX));
   LocalContext context;
   context->Global()->Set(v8_str("o"), templ->NewInstance());
   v8::Handle<Value> value = CompileRun(
@@ -11981,7 +12641,7 @@
   v8::Isolate* isolate = CcTest::isolate();
   v8::HandleScope scope(isolate);
   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
-  templ->SetNamedPropertyHandler(NoBlockGetterX);
+  templ->SetHandler(v8::NamedPropertyHandlerConfiguration(NoBlockGetterX));
   LocalContext context;
   context->Global()->Set(v8_str("o"), templ->NewInstance());
   v8::Handle<Value> value = CompileRun(
@@ -11998,8 +12658,7 @@
 
 static v8::Handle<Value> call_ic_function5;
 static void InterceptorCallICGetter5(
-    Local<String> name,
-    const v8::PropertyCallbackInfo<v8::Value>& info) {
+    Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
   ApiTestFuzzer::Fuzz();
   if (v8_str("x")->Equals(name))
     info.GetReturnValue().Set(call_ic_function5);
@@ -12013,7 +12672,8 @@
   v8::Isolate* isolate = CcTest::isolate();
   v8::HandleScope scope(isolate);
   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
-  templ->SetNamedPropertyHandler(InterceptorCallICGetter5);
+  templ->SetHandler(
+      v8::NamedPropertyHandlerConfiguration(InterceptorCallICGetter5));
   LocalContext context;
   context->Global()->Set(v8_str("o"), templ->NewInstance());
   call_ic_function5 =
@@ -12032,8 +12692,7 @@
 
 static v8::Handle<Value> call_ic_function6;
 static void InterceptorCallICGetter6(
-    Local<String> name,
-    const v8::PropertyCallbackInfo<v8::Value>& info) {
+    Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
   ApiTestFuzzer::Fuzz();
   if (v8_str("x")->Equals(name))
     info.GetReturnValue().Set(call_ic_function6);
@@ -12047,7 +12706,8 @@
   v8::Isolate* isolate = CcTest::isolate();
   v8::HandleScope scope(isolate);
   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
-  templ->SetNamedPropertyHandler(InterceptorCallICGetter6);
+  templ->SetHandler(
+      v8::NamedPropertyHandlerConfiguration(InterceptorCallICGetter6));
   LocalContext context;
   context->Global()->Set(v8_str("o"), templ->NewInstance());
   call_ic_function6 =
@@ -12078,7 +12738,7 @@
   v8::Isolate* isolate = CcTest::isolate();
   v8::HandleScope scope(isolate);
   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
-  templ->SetNamedPropertyHandler(NoBlockGetterX);
+  templ->SetHandler(v8::NamedPropertyHandlerConfiguration(NoBlockGetterX));
   LocalContext context;
   context->Global()->Set(v8_str("o"), templ->NewInstance());
   v8::Handle<Value> value = CompileRun(
@@ -12109,7 +12769,7 @@
   v8::Isolate* isolate = CcTest::isolate();
   v8::HandleScope scope(isolate);
   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
-  templ->SetNamedPropertyHandler(NoBlockGetterX);
+  templ->SetHandler(v8::NamedPropertyHandlerConfiguration(NoBlockGetterX));
   LocalContext context;
   context->Global()->Set(v8_str("o"), templ->NewInstance());
   v8::Handle<Value> value = CompileRun(
@@ -12135,7 +12795,7 @@
   v8::Isolate* isolate = CcTest::isolate();
   v8::HandleScope scope(isolate);
   v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate);
-  templ_o->SetNamedPropertyHandler(NoBlockGetterX);
+  templ_o->SetHandler(v8::NamedPropertyHandlerConfiguration(NoBlockGetterX));
 
   LocalContext context;
   context->Global()->Set(v8_str("o"), templ_o->NewInstance());
@@ -12160,8 +12820,7 @@
 }
 
 static void InterceptorCallICFastApi(
-    Local<String> name,
-    const v8::PropertyCallbackInfo<v8::Value>& info) {
+    Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
   ApiTestFuzzer::Fuzz();
   CheckReturnValue(info, FUNCTION_ADDR(InterceptorCallICFastApi));
   int* call_count =
@@ -12350,9 +13009,9 @@
   v8::Handle<v8::ObjectTemplate> proto_templ = fun_templ->PrototypeTemplate();
   proto_templ->Set(v8_str("method"), method_templ);
   v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
-  templ->SetNamedPropertyHandler(
+  templ->SetHandler(v8::NamedPropertyHandlerConfiguration(
       InterceptorCallICFastApi, NULL, NULL, NULL, NULL,
-      v8::External::New(isolate, &interceptor_call_count));
+      v8::External::New(isolate, &interceptor_call_count)));
   LocalContext context;
   v8::Handle<v8::Function> fun = fun_templ->GetFunction();
   GenerateSomeGarbage();
@@ -12380,9 +13039,9 @@
   proto_templ->Set(v8_str("method"), method_templ);
   fun_templ->SetHiddenPrototype(true);
   v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
-  templ->SetNamedPropertyHandler(
+  templ->SetHandler(v8::NamedPropertyHandlerConfiguration(
       InterceptorCallICFastApi, NULL, NULL, NULL, NULL,
-      v8::External::New(isolate, &interceptor_call_count));
+      v8::External::New(isolate, &interceptor_call_count)));
   LocalContext context;
   v8::Handle<v8::Function> fun = fun_templ->GetFunction();
   GenerateSomeGarbage();
@@ -12413,9 +13072,9 @@
   proto_templ->Set(v8_str("method"), method_templ);
   fun_templ->SetHiddenPrototype(true);
   v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
-  templ->SetNamedPropertyHandler(
+  templ->SetHandler(v8::NamedPropertyHandlerConfiguration(
       InterceptorCallICFastApi, NULL, NULL, NULL, NULL,
-      v8::External::New(isolate, &interceptor_call_count));
+      v8::External::New(isolate, &interceptor_call_count)));
   LocalContext context;
   v8::Handle<v8::Function> fun = fun_templ->GetFunction();
   GenerateSomeGarbage();
@@ -12452,9 +13111,9 @@
   proto_templ->Set(v8_str("method"), method_templ);
   fun_templ->SetHiddenPrototype(true);
   v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
-  templ->SetNamedPropertyHandler(
+  templ->SetHandler(v8::NamedPropertyHandlerConfiguration(
       InterceptorCallICFastApi, NULL, NULL, NULL, NULL,
-      v8::External::New(isolate, &interceptor_call_count));
+      v8::External::New(isolate, &interceptor_call_count)));
   LocalContext context;
   v8::Handle<v8::Function> fun = fun_templ->GetFunction();
   GenerateSomeGarbage();
@@ -12491,9 +13150,9 @@
   proto_templ->Set(v8_str("method"), method_templ);
   fun_templ->SetHiddenPrototype(true);
   v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
-  templ->SetNamedPropertyHandler(
+  templ->SetHandler(v8::NamedPropertyHandlerConfiguration(
       InterceptorCallICFastApi, NULL, NULL, NULL, NULL,
-      v8::External::New(isolate, &interceptor_call_count));
+      v8::External::New(isolate, &interceptor_call_count)));
   LocalContext context;
   v8::Handle<v8::Function> fun = fun_templ->GetFunction();
   GenerateSomeGarbage();
@@ -12515,7 +13174,7 @@
   CHECK(try_catch.HasCaught());
   // TODO(verwaest): Adjust message.
   CHECK_EQ(v8_str("TypeError: undefined is not a function"),
-           try_catch.Exception()->ToString());
+           try_catch.Exception()->ToString(isolate));
   CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
   CHECK_GE(interceptor_call_count, 50);
 }
@@ -12534,9 +13193,9 @@
   proto_templ->Set(v8_str("method"), method_templ);
   fun_templ->SetHiddenPrototype(true);
   v8::Handle<v8::ObjectTemplate> templ = fun_templ->InstanceTemplate();
-  templ->SetNamedPropertyHandler(
+  templ->SetHandler(v8::NamedPropertyHandlerConfiguration(
       InterceptorCallICFastApi, NULL, NULL, NULL, NULL,
-      v8::External::New(isolate, &interceptor_call_count));
+      v8::External::New(isolate, &interceptor_call_count)));
   LocalContext context;
   v8::Handle<v8::Function> fun = fun_templ->GetFunction();
   GenerateSomeGarbage();
@@ -12557,7 +13216,7 @@
       "}");
   CHECK(try_catch.HasCaught());
   CHECK_EQ(v8_str("TypeError: Illegal invocation"),
-           try_catch.Exception()->ToString());
+           try_catch.Exception()->ToString(isolate));
   CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
   CHECK_GE(interceptor_call_count, 50);
 }
@@ -12690,7 +13349,7 @@
   CHECK(try_catch.HasCaught());
   // TODO(verwaest): Adjust message.
   CHECK_EQ(v8_str("TypeError: undefined is not a function"),
-           try_catch.Exception()->ToString());
+           try_catch.Exception()->ToString(isolate));
   CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
 }
 
@@ -12728,7 +13387,7 @@
       "}");
   CHECK(try_catch.HasCaught());
   CHECK_EQ(v8_str("TypeError: Illegal invocation"),
-           try_catch.Exception()->ToString());
+           try_catch.Exception()->ToString(isolate));
   CHECK_EQ(42, context->Global()->Get(v8_str("saved_result"))->Int32Value());
 }
 
@@ -12736,8 +13395,7 @@
 v8::Handle<Value> keyed_call_ic_function;
 
 static void InterceptorKeyedCallICGetter(
-    Local<String> name,
-    const v8::PropertyCallbackInfo<v8::Value>& info) {
+    Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
   ApiTestFuzzer::Fuzz();
   if (v8_str("x")->Equals(name)) {
     info.GetReturnValue().Set(keyed_call_ic_function);
@@ -12751,7 +13409,7 @@
   v8::Isolate* isolate = CcTest::isolate();
   v8::HandleScope scope(isolate);
   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
-  templ->SetNamedPropertyHandler(NoBlockGetterX);
+  templ->SetHandler(v8::NamedPropertyHandlerConfiguration(NoBlockGetterX));
   LocalContext context;
   context->Global()->Set(v8_str("o"), templ->NewInstance());
   CompileRun(
@@ -12776,7 +13434,8 @@
   v8::Isolate* isolate = CcTest::isolate();
   v8::HandleScope scope(isolate);
   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
-  templ->SetNamedPropertyHandler(InterceptorKeyedCallICGetter);
+  templ->SetHandler(
+      v8::NamedPropertyHandlerConfiguration(InterceptorKeyedCallICGetter));
   LocalContext context;
   context->Global()->Set(v8_str("proto1"), templ->NewInstance());
   keyed_call_ic_function =
@@ -12804,7 +13463,7 @@
   v8::Isolate* isolate = CcTest::isolate();
   v8::HandleScope scope(isolate);
   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
-  templ->SetNamedPropertyHandler(NoBlockGetterX);
+  templ->SetHandler(v8::NamedPropertyHandlerConfiguration(NoBlockGetterX));
   LocalContext context;
   context->Global()->Set(v8_str("o"), templ->NewInstance());
   CompileRun(
@@ -12830,7 +13489,7 @@
   v8::Isolate* isolate = CcTest::isolate();
   v8::HandleScope scope(isolate);
   v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate);
-  templ_o->SetNamedPropertyHandler(NoBlockGetterX);
+  templ_o->SetHandler(v8::NamedPropertyHandlerConfiguration(NoBlockGetterX));
   LocalContext context;
   context->Global()->Set(v8_str("o"), templ_o->NewInstance());
 
@@ -12856,7 +13515,7 @@
   v8::Isolate* isolate = CcTest::isolate();
   v8::HandleScope scope(isolate);
   v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate);
-  templ_o->SetNamedPropertyHandler(NoBlockGetterX);
+  templ_o->SetHandler(v8::NamedPropertyHandlerConfiguration(NoBlockGetterX));
   LocalContext context;
   context->Global()->Set(v8_str("proto"), templ_o->NewInstance());
 
@@ -12879,7 +13538,7 @@
   v8::Isolate* isolate = CcTest::isolate();
   v8::HandleScope scope(isolate);
   v8::Handle<v8::ObjectTemplate> templ_o = ObjectTemplate::New(isolate);
-  templ_o->SetNamedPropertyHandler(NoBlockGetterX);
+  templ_o->SetHandler(v8::NamedPropertyHandlerConfiguration(NoBlockGetterX));
   LocalContext context;
   context->Global()->Set(v8_str("o"), templ_o->NewInstance());
 
@@ -12900,8 +13559,7 @@
 static int interceptor_call_count = 0;
 
 static void InterceptorICRefErrorGetter(
-    Local<String> name,
-    const v8::PropertyCallbackInfo<v8::Value>& info) {
+    Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
   ApiTestFuzzer::Fuzz();
   if (v8_str("x")->Equals(name) && interceptor_call_count++ < 20) {
     info.GetReturnValue().Set(call_ic_function2);
@@ -12916,7 +13574,8 @@
   v8::Isolate* isolate = CcTest::isolate();
   v8::HandleScope scope(isolate);
   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
-  templ->SetNamedPropertyHandler(InterceptorICRefErrorGetter);
+  templ->SetHandler(
+      v8::NamedPropertyHandlerConfiguration(InterceptorICRefErrorGetter));
   LocalContext context(0, templ, v8::Handle<Value>());
   call_ic_function2 = v8_compile("function h(x) { return x; }; h")->Run();
   v8::Handle<Value> value = CompileRun(
@@ -12944,8 +13603,7 @@
 static int interceptor_ic_exception_get_count = 0;
 
 static void InterceptorICExceptionGetter(
-    Local<String> name,
-    const v8::PropertyCallbackInfo<v8::Value>& info) {
+    Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
   ApiTestFuzzer::Fuzz();
   if (v8_str("x")->Equals(name) && ++interceptor_ic_exception_get_count < 20) {
     info.GetReturnValue().Set(call_ic_function3);
@@ -12964,7 +13622,8 @@
   v8::Isolate* isolate = CcTest::isolate();
   v8::HandleScope scope(isolate);
   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
-  templ->SetNamedPropertyHandler(InterceptorICExceptionGetter);
+  templ->SetHandler(
+      v8::NamedPropertyHandlerConfiguration(InterceptorICExceptionGetter));
   LocalContext context(0, templ, v8::Handle<Value>());
   call_ic_function3 = v8_compile("function h(x) { return x; }; h")->Run();
   v8::Handle<Value> value = CompileRun(
@@ -12992,9 +13651,8 @@
 static int interceptor_ic_exception_set_count = 0;
 
 static void InterceptorICExceptionSetter(
-      Local<String> key,
-      Local<Value> value,
-      const v8::PropertyCallbackInfo<v8::Value>& info) {
+    Local<Name> key, Local<Value> value,
+    const v8::PropertyCallbackInfo<v8::Value>& info) {
   ApiTestFuzzer::Fuzz();
   if (++interceptor_ic_exception_set_count > 20) {
     info.GetIsolate()->ThrowException(v8_num(42));
@@ -13009,7 +13667,8 @@
   v8::Isolate* isolate = CcTest::isolate();
   v8::HandleScope scope(isolate);
   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
-  templ->SetNamedPropertyHandler(0, InterceptorICExceptionSetter);
+  templ->SetHandler(
+      v8::NamedPropertyHandlerConfiguration(0, InterceptorICExceptionSetter));
   LocalContext context(0, templ, v8::Handle<Value>());
   v8::Handle<Value> value = CompileRun(
     "function f() {"
@@ -13028,8 +13687,8 @@
   v8::Isolate* isolate = CcTest::isolate();
   v8::HandleScope scope(isolate);
   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
-  templ->SetNamedPropertyHandler(
-      static_cast<v8::NamedPropertyGetterCallback>(0));
+  templ->SetHandler(v8::NamedPropertyHandlerConfiguration(
+      static_cast<v8::GenericNamedPropertyGetterCallback>(0)));
   LocalContext context;
   templ->Set(CcTest::isolate(), "x", v8_num(42));
   v8::Handle<v8::Object> obj = templ->NewInstance();
@@ -13045,8 +13704,8 @@
   v8::Isolate* isolate = CcTest::isolate();
   v8::HandleScope scope(isolate);
   v8::Handle<v8::ObjectTemplate> templ = ObjectTemplate::New(isolate);
-  templ->SetIndexedPropertyHandler(
-      static_cast<v8::IndexedPropertyGetterCallback>(0));
+  templ->SetHandler(v8::IndexedPropertyHandlerConfiguration(
+      static_cast<v8::IndexedPropertyGetterCallback>(0)));
   LocalContext context;
   templ->Set(CcTest::isolate(), "42", v8_num(42));
   v8::Handle<v8::Object> obj = templ->NewInstance();
@@ -13061,7 +13720,8 @@
   v8::Isolate* isolate = CcTest::isolate();
   v8::HandleScope scope(isolate);
   v8::Handle<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
-  templ->InstanceTemplate()->SetNamedPropertyHandler(InterceptorLoadXICGetter);
+  templ->InstanceTemplate()->SetHandler(
+      v8::NamedPropertyHandlerConfiguration(InterceptorLoadXICGetter));
   LocalContext env;
   env->Global()->Set(v8_str("obj"),
                      templ->GetFunction()->NewInstance());
@@ -13315,7 +13975,7 @@
 
   // Normal ToString call should call replaced Object.prototype.toString
   Local<v8::Object> instance = templ->GetFunction()->NewInstance();
-  Local<String> value = instance->ToString();
+  Local<String> value = instance->ToString(isolate);
   CHECK(value->IsString() && value->Equals(customized_tostring));
 
   // ObjectProtoToString should not call replace toString function.
@@ -13333,9 +13993,127 @@
 }
 
 
-THREADED_TEST(ObjectGetConstructorName) {
+TEST(ObjectProtoToStringES6) {
+  // TODO(dslomov, caitp): merge into ObjectProtoToString test once shipped.
+  i::FLAG_harmony_tostring = true;
   LocalContext context;
-  v8::HandleScope scope(context->GetIsolate());
+  v8::Isolate* isolate = CcTest::isolate();
+  v8::HandleScope scope(isolate);
+  Local<v8::FunctionTemplate> templ = v8::FunctionTemplate::New(isolate);
+  templ->SetClassName(v8_str("MyClass"));
+
+  Local<String> customized_tostring = v8_str("customized toString");
+
+  // Replace Object.prototype.toString
+  CompileRun(
+      "Object.prototype.toString = function() {"
+      "  return 'customized toString';"
+      "}");
+
+  // Normal ToString call should call replaced Object.prototype.toString
+  Local<v8::Object> instance = templ->GetFunction()->NewInstance();
+  Local<String> value = instance->ToString(isolate);
+  CHECK(value->IsString() && value->Equals(customized_tostring));
+
+  // ObjectProtoToString should not call replace toString function.
+  value = instance->ObjectProtoToString();
+  CHECK(value->IsString() && value->Equals(v8_str("[object MyClass]")));
+
+  // Check global
+  value = context->Global()->ObjectProtoToString();
+  CHECK(value->IsString() && value->Equals(v8_str("[object global]")));
+
+  // Check ordinary object
+  Local<Value> object = CompileRun("new Object()");
+  value = object.As<v8::Object>()->ObjectProtoToString();
+  CHECK(value->IsString() && value->Equals(v8_str("[object Object]")));
+
+  // Check that ES6 semantics using @@toStringTag work
+  Local<v8::Symbol> toStringTag = v8::Symbol::GetToStringTag(isolate);
+
+#define TEST_TOSTRINGTAG(type, tag, expected)                \
+  do {                                                       \
+    object = CompileRun("new " #type "()");                  \
+    object.As<v8::Object>()->Set(toStringTag, v8_str(#tag)); \
+    value = object.As<v8::Object>()->ObjectProtoToString();  \
+    CHECK(value->IsString() &&                               \
+          value->Equals(v8_str("[object " #expected "]")));  \
+  } while (0)
+
+  TEST_TOSTRINGTAG(Array, Object, Object);
+  TEST_TOSTRINGTAG(Object, Arguments, ~Arguments);
+  TEST_TOSTRINGTAG(Object, Array, ~Array);
+  TEST_TOSTRINGTAG(Object, Boolean, ~Boolean);
+  TEST_TOSTRINGTAG(Object, Date, ~Date);
+  TEST_TOSTRINGTAG(Object, Error, ~Error);
+  TEST_TOSTRINGTAG(Object, Function, ~Function);
+  TEST_TOSTRINGTAG(Object, Number, ~Number);
+  TEST_TOSTRINGTAG(Object, RegExp, ~RegExp);
+  TEST_TOSTRINGTAG(Object, String, ~String);
+  TEST_TOSTRINGTAG(Object, Foo, Foo);
+
+#undef TEST_TOSTRINGTAG
+
+  // @@toStringTag getter throws
+  Local<Value> obj = v8::Object::New(isolate);
+  obj.As<v8::Object>()->SetAccessor(toStringTag, ThrowingSymbolAccessorGetter);
+  {
+    TryCatch try_catch;
+    value = obj.As<v8::Object>()->ObjectProtoToString();
+    CHECK(value.IsEmpty());
+    CHECK(try_catch.HasCaught());
+  }
+
+  // @@toStringTag getter does not throw
+  obj = v8::Object::New(isolate);
+  obj.As<v8::Object>()->SetAccessor(
+      toStringTag, SymbolAccessorGetterReturnsDefault, 0, v8_str("Test"));
+  {
+    TryCatch try_catch;
+    value = obj.As<v8::Object>()->ObjectProtoToString();
+    CHECK(value->IsString() && value->Equals(v8_str("[object Test]")));
+    CHECK(!try_catch.HasCaught());
+  }
+
+  // JS @@toStringTag value
+  obj = CompileRun("obj = {}; obj[Symbol.toStringTag] = 'Test'; obj");
+  {
+    TryCatch try_catch;
+    value = obj.As<v8::Object>()->ObjectProtoToString();
+    CHECK(value->IsString() && value->Equals(v8_str("[object Test]")));
+    CHECK(!try_catch.HasCaught());
+  }
+
+  // JS @@toStringTag getter throws
+  obj = CompileRun(
+      "obj = {}; Object.defineProperty(obj, Symbol.toStringTag, {"
+      "  get: function() { throw 'Test'; }"
+      "}); obj");
+  {
+    TryCatch try_catch;
+    value = obj.As<v8::Object>()->ObjectProtoToString();
+    CHECK(value.IsEmpty());
+    CHECK(try_catch.HasCaught());
+  }
+
+  // JS @@toStringTag getter does not throw
+  obj = CompileRun(
+      "obj = {}; Object.defineProperty(obj, Symbol.toStringTag, {"
+      "  get: function() { return 'Test'; }"
+      "}); obj");
+  {
+    TryCatch try_catch;
+    value = obj.As<v8::Object>()->ObjectProtoToString();
+    CHECK(value->IsString() && value->Equals(v8_str("[object Test]")));
+    CHECK(!try_catch.HasCaught());
+  }
+}
+
+
+THREADED_TEST(ObjectGetConstructorName) {
+  v8::Isolate* isolate = CcTest::isolate();
+  LocalContext context;
+  v8::HandleScope scope(isolate);
   v8_compile("function Parent() {};"
              "function Child() {};"
              "Child.prototype = new Parent();"
@@ -13345,16 +14123,17 @@
              "var x = new outer.inner();")->Run();
 
   Local<v8::Value> p = context->Global()->Get(v8_str("p"));
-  CHECK(p->IsObject() && p->ToObject()->GetConstructorName()->Equals(
-      v8_str("Parent")));
+  CHECK(p->IsObject() &&
+        p->ToObject(isolate)->GetConstructorName()->Equals(v8_str("Parent")));
 
   Local<v8::Value> c = context->Global()->Get(v8_str("c"));
-  CHECK(c->IsObject() && c->ToObject()->GetConstructorName()->Equals(
-      v8_str("Child")));
+  CHECK(c->IsObject() &&
+        c->ToObject(isolate)->GetConstructorName()->Equals(v8_str("Child")));
 
   Local<v8::Value> x = context->Global()->Get(v8_str("x"));
-  CHECK(x->IsObject() && x->ToObject()->GetConstructorName()->Equals(
-      v8_str("outer.inner")));
+  CHECK(x->IsObject() &&
+        x->ToObject(isolate)->GetConstructorName()->Equals(
+            v8_str("outer.inner")));
 }
 
 
@@ -13902,7 +14681,7 @@
   v8::Local<Context> env = Context::New(isolate);
   env->Enter();
   v8::Handle<Value> value = NestedScope(env);
-  v8::Handle<String> str(value->ToString());
+  v8::Handle<String> str(value->ToString(isolate));
   CHECK(!str.IsEmpty());
   env->Exit();
 }
@@ -14744,7 +15523,7 @@
   v8::Handle<v8::Array> props = val.As<v8::Object>()->GetPropertyNames();
   CHECK_EQ(0, props->Length());
   for (uint32_t i = 0; i < props->Length(); i++) {
-    printf("p[%d]\n", i);
+    printf("p[%u]\n", i);
   }
 }
 
@@ -15291,7 +16070,7 @@
 #ifndef V8_INTERPRETED_REGEXP
 
 struct RegExpInterruptionData {
-  int loop_count;
+  v8::base::Atomic32 loop_count;
   UC16VectorResource* string_resource;
   v8::Persistent<v8::String> string;
 } regexp_interruption_data;
@@ -15303,9 +16082,10 @@
       : Thread(Options("TimeoutThread")), isolate_(isolate) {}
 
   virtual void Run() {
-    for (regexp_interruption_data.loop_count = 0;
-         regexp_interruption_data.loop_count < 7;
-         regexp_interruption_data.loop_count++) {
+    for (v8::base::NoBarrier_Store(&regexp_interruption_data.loop_count, 0);
+         v8::base::NoBarrier_Load(&regexp_interruption_data.loop_count) < 7;
+         v8::base::NoBarrier_AtomicIncrement(
+             &regexp_interruption_data.loop_count, 1)) {
       v8::base::OS::Sleep(50);  // Wait a bit before requesting GC.
       reinterpret_cast<i::Isolate*>(isolate_)->stack_guard()->RequestGC();
     }
@@ -15319,7 +16099,9 @@
 
 
 void RunBeforeGC(v8::GCType type, v8::GCCallbackFlags flags) {
-  if (regexp_interruption_data.loop_count != 2) return;
+  if (v8::base::NoBarrier_Load(&regexp_interruption_data.loop_count) != 2) {
+    return;
+  }
   v8::HandleScope scope(CcTest::isolate());
   v8::Local<v8::String> string = v8::Local<v8::String>::New(
       CcTest::isolate(), regexp_interruption_data.string);
@@ -15407,9 +16189,14 @@
   force_set_set_count++;
 }
 
+static void ForceSetInterceptGetter(
+    v8::Local<v8::Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
+  CHECK(name->IsString());
+  ForceSetGetter(Local<String>::Cast(name), info);
+}
+
 static void ForceSetInterceptSetter(
-    v8::Local<v8::String> name,
-    v8::Local<v8::Value> value,
+    v8::Local<v8::Name> name, v8::Local<v8::Value> value,
     const v8::PropertyCallbackInfo<v8::Value>& info) {
   force_set_set_count++;
   info.GetReturnValue().SetUndefined();
@@ -15469,7 +16256,8 @@
   v8::Isolate* isolate = CcTest::isolate();
   v8::HandleScope scope(isolate);
   v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New(isolate);
-  templ->SetNamedPropertyHandler(ForceSetGetter, ForceSetInterceptSetter);
+  templ->SetHandler(v8::NamedPropertyHandlerConfiguration(
+      ForceSetInterceptGetter, ForceSetInterceptSetter));
   LocalContext context(NULL, templ);
   v8::Handle<v8::Object> global = context->Global();
 
@@ -15537,7 +16325,7 @@
 
 
 static void ForceDeleteDeleter(
-    v8::Local<v8::String> name,
+    v8::Local<v8::Name> name,
     const v8::PropertyCallbackInfo<v8::Boolean>& info) {
   force_delete_interceptor_count++;
   if (pass_on_delete) return;
@@ -15552,7 +16340,8 @@
   v8::Isolate* isolate = CcTest::isolate();
   v8::HandleScope scope(isolate);
   v8::Handle<v8::ObjectTemplate> templ = v8::ObjectTemplate::New(isolate);
-  templ->SetNamedPropertyHandler(0, 0, 0, ForceDeleteDeleter);
+  templ->SetHandler(
+      v8::NamedPropertyHandlerConfiguration(0, 0, 0, ForceDeleteDeleter));
   LocalContext context(NULL, templ);
   v8::Handle<v8::Object> global = context->Global();
 
@@ -16195,8 +16984,8 @@
   }
   v8::Handle<v8::ObjectTemplate> templ =
       v8::ObjectTemplate::New(context->GetIsolate());
-  templ->SetIndexedPropertyHandler(NotHandledIndexedPropertyGetter,
-                                   NotHandledIndexedPropertySetter);
+  templ->SetHandler(v8::IndexedPropertyHandlerConfiguration(
+      NotHandledIndexedPropertyGetter, NotHandledIndexedPropertySetter));
   v8::Handle<v8::Object> obj = templ->NewInstance();
   obj->SetIndexedPropertiesToPixelData(pixel_data, kElementCount);
   context->Global()->Set(v8_str("pixels"), obj);
@@ -17335,6 +18124,7 @@
 static void StackTraceForUncaughtExceptionListener(
     v8::Handle<v8::Message> message,
     v8::Handle<Value>) {
+  report_count++;
   v8::Handle<v8::StackTrace> stack_trace = message->GetStackTrace();
   CHECK_EQ(2, stack_trace->GetFrameCount());
   checkStackFrame("origin", "foo", 2, 3, false, false,
@@ -17365,6 +18155,38 @@
   Function::Cast(*trouble)->Call(global, 0, NULL);
   v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
   v8::V8::RemoveMessageListeners(StackTraceForUncaughtExceptionListener);
+  CHECK_EQ(1, report_count);
+}
+
+
+TEST(GetStackTraceForUncaughtExceptionFromSimpleStackTrace) {
+  report_count = 0;
+  LocalContext env;
+  v8::HandleScope scope(env->GetIsolate());
+
+  // Create an Error object first.
+  CompileRunWithOrigin(
+      "function foo() {\n"
+      "e=new Error('err');\n"
+      "};\n"
+      "function bar() {\n"
+      "  foo();\n"
+      "};\n"
+      "var e;",
+      "origin");
+  v8::Local<v8::Object> global = env->Global();
+  Local<Value> trouble = global->Get(v8_str("bar"));
+  CHECK(trouble->IsFunction());
+  Function::Cast(*trouble)->Call(global, 0, NULL);
+
+  // Enable capturing detailed stack trace late, and throw the exception.
+  // The detailed stack trace should be extracted from the simple stack.
+  v8::V8::AddMessageListener(StackTraceForUncaughtExceptionListener);
+  v8::V8::SetCaptureStackTraceForUncaughtExceptions(true);
+  CompileRunWithOrigin("throw e", "origin");
+  v8::V8::SetCaptureStackTraceForUncaughtExceptions(false);
+  v8::V8::RemoveMessageListeners(StackTraceForUncaughtExceptionListener);
+  CHECK_EQ(1, report_count);
 }
 
 
@@ -17519,6 +18341,343 @@
 }
 
 
+v8::PromiseRejectEvent reject_event = v8::kPromiseRejectWithNoHandler;
+int promise_reject_counter = 0;
+int promise_revoke_counter = 0;
+int promise_reject_line_number = -1;
+int promise_reject_frame_count = -1;
+
+void PromiseRejectCallback(v8::PromiseRejectMessage message) {
+  if (message.GetEvent() == v8::kPromiseRejectWithNoHandler) {
+    promise_reject_counter++;
+    CcTest::global()->Set(v8_str("rejected"), message.GetPromise());
+    CcTest::global()->Set(v8_str("value"), message.GetValue());
+    v8::Handle<v8::StackTrace> stack_trace =
+        v8::Exception::CreateMessage(message.GetValue())->GetStackTrace();
+    if (!stack_trace.IsEmpty()) {
+      promise_reject_frame_count = stack_trace->GetFrameCount();
+      if (promise_reject_frame_count > 0) {
+        CHECK(stack_trace->GetFrame(0)->GetScriptName()->Equals(v8_str("pro")));
+        promise_reject_line_number = stack_trace->GetFrame(0)->GetLineNumber();
+      } else {
+        promise_reject_line_number = -1;
+      }
+    }
+  } else {
+    promise_revoke_counter++;
+    CcTest::global()->Set(v8_str("revoked"), message.GetPromise());
+    CHECK(message.GetValue().IsEmpty());
+  }
+}
+
+
+v8::Handle<v8::Promise> GetPromise(const char* name) {
+  return v8::Handle<v8::Promise>::Cast(CcTest::global()->Get(v8_str(name)));
+}
+
+
+v8::Handle<v8::Value> RejectValue() {
+  return CcTest::global()->Get(v8_str("value"));
+}
+
+
+void ResetPromiseStates() {
+  promise_reject_counter = 0;
+  promise_revoke_counter = 0;
+  promise_reject_line_number = -1;
+  promise_reject_frame_count = -1;
+  CcTest::global()->Set(v8_str("rejected"), v8_str(""));
+  CcTest::global()->Set(v8_str("value"), v8_str(""));
+  CcTest::global()->Set(v8_str("revoked"), v8_str(""));
+}
+
+
+TEST(PromiseRejectCallback) {
+  LocalContext env;
+  v8::Isolate* isolate = env->GetIsolate();
+  v8::HandleScope scope(isolate);
+
+  isolate->SetPromiseRejectCallback(PromiseRejectCallback);
+
+  ResetPromiseStates();
+
+  // Create promise p0.
+  CompileRun(
+      "var reject;            \n"
+      "var p0 = new Promise(  \n"
+      "  function(res, rej) { \n"
+      "    reject = rej;      \n"
+      "  }                    \n"
+      ");                     \n");
+  CHECK(!GetPromise("p0")->HasHandler());
+  CHECK_EQ(0, promise_reject_counter);
+  CHECK_EQ(0, promise_revoke_counter);
+
+  // Add resolve handler (and default reject handler) to p0.
+  CompileRun("var p1 = p0.then(function(){});");
+  CHECK(GetPromise("p0")->HasHandler());
+  CHECK(!GetPromise("p1")->HasHandler());
+  CHECK_EQ(0, promise_reject_counter);
+  CHECK_EQ(0, promise_revoke_counter);
+
+  // Reject p0.
+  CompileRun("reject('ppp');");
+  CHECK(GetPromise("p0")->HasHandler());
+  CHECK(!GetPromise("p1")->HasHandler());
+  CHECK_EQ(1, promise_reject_counter);
+  CHECK_EQ(0, promise_revoke_counter);
+  CHECK_EQ(v8::kPromiseRejectWithNoHandler, reject_event);
+  CHECK(GetPromise("rejected")->Equals(GetPromise("p1")));
+  CHECK(RejectValue()->Equals(v8_str("ppp")));
+
+  // Reject p0 again. Callback is not triggered again.
+  CompileRun("reject();");
+  CHECK(GetPromise("p0")->HasHandler());
+  CHECK(!GetPromise("p1")->HasHandler());
+  CHECK_EQ(1, promise_reject_counter);
+  CHECK_EQ(0, promise_revoke_counter);
+
+  // Add resolve handler to p1.
+  CompileRun("var p2 = p1.then(function(){});");
+  CHECK(GetPromise("p0")->HasHandler());
+  CHECK(GetPromise("p1")->HasHandler());
+  CHECK(!GetPromise("p2")->HasHandler());
+  CHECK_EQ(2, promise_reject_counter);
+  CHECK_EQ(1, promise_revoke_counter);
+  CHECK(GetPromise("rejected")->Equals(GetPromise("p2")));
+  CHECK(RejectValue()->Equals(v8_str("ppp")));
+  CHECK(GetPromise("revoked")->Equals(GetPromise("p1")));
+
+  ResetPromiseStates();
+
+  // Create promise q0.
+  CompileRun(
+      "var q0 = new Promise(  \n"
+      "  function(res, rej) { \n"
+      "    reject = rej;      \n"
+      "  }                    \n"
+      ");                     \n");
+  CHECK(!GetPromise("q0")->HasHandler());
+  CHECK_EQ(0, promise_reject_counter);
+  CHECK_EQ(0, promise_revoke_counter);
+
+  // Add reject handler to q0.
+  CompileRun("var q1 = q0.catch(function() {});");
+  CHECK(GetPromise("q0")->HasHandler());
+  CHECK(!GetPromise("q1")->HasHandler());
+  CHECK_EQ(0, promise_reject_counter);
+  CHECK_EQ(0, promise_revoke_counter);
+
+  // Reject q0.
+  CompileRun("reject('qq')");
+  CHECK(GetPromise("q0")->HasHandler());
+  CHECK(!GetPromise("q1")->HasHandler());
+  CHECK_EQ(0, promise_reject_counter);
+  CHECK_EQ(0, promise_revoke_counter);
+
+  // Add a new reject handler, which rejects by returning Promise.reject().
+  // The returned promise q_ triggers a reject callback at first, only to
+  // revoke it when returning it causes q2 to be rejected.
+  CompileRun(
+      "var q_;"
+      "var q2 = q0.catch(               \n"
+      "   function() {                  \n"
+      "     q_ = Promise.reject('qqq'); \n"
+      "     return q_;                  \n"
+      "   }                             \n"
+      ");                               \n");
+  CHECK(GetPromise("q0")->HasHandler());
+  CHECK(!GetPromise("q1")->HasHandler());
+  CHECK(!GetPromise("q2")->HasHandler());
+  CHECK(GetPromise("q_")->HasHandler());
+  CHECK_EQ(2, promise_reject_counter);
+  CHECK_EQ(1, promise_revoke_counter);
+  CHECK(GetPromise("rejected")->Equals(GetPromise("q2")));
+  CHECK(GetPromise("revoked")->Equals(GetPromise("q_")));
+  CHECK(RejectValue()->Equals(v8_str("qqq")));
+
+  // Add a reject handler to the resolved q1, which rejects by throwing.
+  CompileRun(
+      "var q3 = q1.then(  \n"
+      "   function() {    \n"
+      "     throw 'qqqq'; \n"
+      "   }               \n"
+      ");                 \n");
+  CHECK(GetPromise("q0")->HasHandler());
+  CHECK(GetPromise("q1")->HasHandler());
+  CHECK(!GetPromise("q2")->HasHandler());
+  CHECK(!GetPromise("q3")->HasHandler());
+  CHECK_EQ(3, promise_reject_counter);
+  CHECK_EQ(1, promise_revoke_counter);
+  CHECK(GetPromise("rejected")->Equals(GetPromise("q3")));
+  CHECK(RejectValue()->Equals(v8_str("qqqq")));
+
+  ResetPromiseStates();
+
+  // Create promise r0, which has three handlers, two of which handle rejects.
+  CompileRun(
+      "var r0 = new Promise(             \n"
+      "  function(res, rej) {            \n"
+      "    reject = rej;                 \n"
+      "  }                               \n"
+      ");                                \n"
+      "var r1 = r0.catch(function() {}); \n"
+      "var r2 = r0.then(function() {});  \n"
+      "var r3 = r0.then(function() {},   \n"
+      "                 function() {});  \n");
+  CHECK(GetPromise("r0")->HasHandler());
+  CHECK(!GetPromise("r1")->HasHandler());
+  CHECK(!GetPromise("r2")->HasHandler());
+  CHECK(!GetPromise("r3")->HasHandler());
+  CHECK_EQ(0, promise_reject_counter);
+  CHECK_EQ(0, promise_revoke_counter);
+
+  // Reject r0.
+  CompileRun("reject('rrr')");
+  CHECK(GetPromise("r0")->HasHandler());
+  CHECK(!GetPromise("r1")->HasHandler());
+  CHECK(!GetPromise("r2")->HasHandler());
+  CHECK(!GetPromise("r3")->HasHandler());
+  CHECK_EQ(1, promise_reject_counter);
+  CHECK_EQ(0, promise_revoke_counter);
+  CHECK(GetPromise("rejected")->Equals(GetPromise("r2")));
+  CHECK(RejectValue()->Equals(v8_str("rrr")));
+
+  // Add reject handler to r2.
+  CompileRun("var r4 = r2.catch(function() {});");
+  CHECK(GetPromise("r0")->HasHandler());
+  CHECK(!GetPromise("r1")->HasHandler());
+  CHECK(GetPromise("r2")->HasHandler());
+  CHECK(!GetPromise("r3")->HasHandler());
+  CHECK(!GetPromise("r4")->HasHandler());
+  CHECK_EQ(1, promise_reject_counter);
+  CHECK_EQ(1, promise_revoke_counter);
+  CHECK(GetPromise("revoked")->Equals(GetPromise("r2")));
+  CHECK(RejectValue()->Equals(v8_str("rrr")));
+
+  // Add reject handlers to r4.
+  CompileRun("var r5 = r4.then(function() {}, function() {});");
+  CHECK(GetPromise("r0")->HasHandler());
+  CHECK(!GetPromise("r1")->HasHandler());
+  CHECK(GetPromise("r2")->HasHandler());
+  CHECK(!GetPromise("r3")->HasHandler());
+  CHECK(GetPromise("r4")->HasHandler());
+  CHECK(!GetPromise("r5")->HasHandler());
+  CHECK_EQ(1, promise_reject_counter);
+  CHECK_EQ(1, promise_revoke_counter);
+
+  ResetPromiseStates();
+
+  // Create promise s0, which has three handlers, none of which handle rejects.
+  CompileRun(
+      "var s0 = new Promise(            \n"
+      "  function(res, rej) {           \n"
+      "    reject = rej;                \n"
+      "  }                              \n"
+      ");                               \n"
+      "var s1 = s0.then(function() {}); \n"
+      "var s2 = s0.then(function() {}); \n"
+      "var s3 = s0.then(function() {}); \n");
+  CHECK(GetPromise("s0")->HasHandler());
+  CHECK(!GetPromise("s1")->HasHandler());
+  CHECK(!GetPromise("s2")->HasHandler());
+  CHECK(!GetPromise("s3")->HasHandler());
+  CHECK_EQ(0, promise_reject_counter);
+  CHECK_EQ(0, promise_revoke_counter);
+
+  // Reject s0.
+  CompileRun("reject('sss')");
+  CHECK(GetPromise("s0")->HasHandler());
+  CHECK(!GetPromise("s1")->HasHandler());
+  CHECK(!GetPromise("s2")->HasHandler());
+  CHECK(!GetPromise("s3")->HasHandler());
+  CHECK_EQ(3, promise_reject_counter);
+  CHECK_EQ(0, promise_revoke_counter);
+  CHECK(RejectValue()->Equals(v8_str("sss")));
+
+  // Test stack frames.
+  V8::SetCaptureStackTraceForUncaughtExceptions(true);
+
+  ResetPromiseStates();
+
+  // Create promise t0, which is rejected in the constructor with an error.
+  CompileRunWithOrigin(
+      "var t0 = new Promise(  \n"
+      "  function(res, rej) { \n"
+      "    reference_error;   \n"
+      "  }                    \n"
+      ");                     \n",
+      "pro", 0, 0);
+  CHECK(!GetPromise("t0")->HasHandler());
+  CHECK_EQ(1, promise_reject_counter);
+  CHECK_EQ(0, promise_revoke_counter);
+  CHECK_EQ(2, promise_reject_frame_count);
+  CHECK_EQ(3, promise_reject_line_number);
+
+  ResetPromiseStates();
+
+  // Create promise u0 and chain u1 to it, which is rejected via throw.
+  CompileRunWithOrigin(
+      "var u0 = Promise.resolve();        \n"
+      "var u1 = u0.then(                  \n"
+      "           function() {            \n"
+      "             (function() {         \n"
+      "                throw new Error(); \n"
+      "              })();                \n"
+      "           }                       \n"
+      "         );                        \n",
+      "pro", 0, 0);
+  CHECK(GetPromise("u0")->HasHandler());
+  CHECK(!GetPromise("u1")->HasHandler());
+  CHECK_EQ(1, promise_reject_counter);
+  CHECK_EQ(0, promise_revoke_counter);
+  CHECK_EQ(2, promise_reject_frame_count);
+  CHECK_EQ(5, promise_reject_line_number);
+
+  // Throw in u3, which handles u1's rejection.
+  CompileRunWithOrigin(
+      "function f() {                \n"
+      "  return (function() {        \n"
+      "    return new Error();       \n"
+      "  })();                       \n"
+      "}                             \n"
+      "var u2 = Promise.reject(f()); \n"
+      "var u3 = u1.catch(            \n"
+      "           function() {       \n"
+      "             return u2;       \n"
+      "           }                  \n"
+      "         );                   \n",
+      "pro", 0, 0);
+  CHECK(GetPromise("u0")->HasHandler());
+  CHECK(GetPromise("u1")->HasHandler());
+  CHECK(GetPromise("u2")->HasHandler());
+  CHECK(!GetPromise("u3")->HasHandler());
+  CHECK_EQ(3, promise_reject_counter);
+  CHECK_EQ(2, promise_revoke_counter);
+  CHECK_EQ(3, promise_reject_frame_count);
+  CHECK_EQ(3, promise_reject_line_number);
+
+  ResetPromiseStates();
+
+  // Create promise rejected promise v0, which is incorrectly handled by v1
+  // via chaining cycle.
+  CompileRunWithOrigin(
+      "var v0 = Promise.reject(); \n"
+      "var v1 = v0.catch(         \n"
+      "           function() {    \n"
+      "             return v1;    \n"
+      "           }               \n"
+      "         );                \n",
+      "pro", 0, 0);
+  CHECK(GetPromise("v0")->HasHandler());
+  CHECK(!GetPromise("v1")->HasHandler());
+  CHECK_EQ(2, promise_reject_counter);
+  CHECK_EQ(1, promise_revoke_counter);
+  CHECK_EQ(0, promise_reject_frame_count);
+  CHECK_EQ(-1, promise_reject_line_number);
+}
+
+
 void AnalyzeStackOfEvalWithSourceURL(
     const v8::FunctionCallbackInfo<v8::Value>& args) {
   v8::HandleScope scope(args.GetIsolate());
@@ -17835,40 +18994,6 @@
 }
 
 
-TEST(Regress2107) {
-  const intptr_t MB = 1024 * 1024;
-  const int kIdlePauseInMs = 1000;
-  LocalContext env;
-  v8::Isolate* isolate = env->GetIsolate();
-  v8::HandleScope scope(env->GetIsolate());
-  intptr_t initial_size = CcTest::heap()->SizeOfObjects();
-  // Send idle notification to start a round of incremental GCs.
-  env->GetIsolate()->IdleNotification(kIdlePauseInMs);
-  // Emulate 7 page reloads.
-  for (int i = 0; i < 7; i++) {
-    {
-      v8::HandleScope inner_scope(env->GetIsolate());
-      v8::Local<v8::Context> ctx = v8::Context::New(isolate);
-      ctx->Enter();
-      CreateGarbageInOldSpace();
-      ctx->Exit();
-    }
-    env->GetIsolate()->ContextDisposedNotification();
-    env->GetIsolate()->IdleNotification(kIdlePauseInMs);
-  }
-  // Create garbage and check that idle notification still collects it.
-  CreateGarbageInOldSpace();
-  intptr_t size_with_garbage = CcTest::heap()->SizeOfObjects();
-  CHECK_GT(size_with_garbage, initial_size + MB);
-  bool finished = false;
-  for (int i = 0; i < 200 && !finished; i++) {
-    finished = env->GetIsolate()->IdleNotification(kIdlePauseInMs);
-  }
-  intptr_t final_size = CcTest::heap()->SizeOfObjects();
-  CHECK_LT(final_size, initial_size + 1);
-}
-
-
 TEST(Regress2333) {
   LocalContext env;
   for (int i = 0; i < 3; i++) {
@@ -17998,10 +19123,11 @@
 
 
 TEST(ExternalizeOldSpaceTwoByteCons) {
+  v8::Isolate* isolate = CcTest::isolate();
   LocalContext env;
-  v8::HandleScope scope(env->GetIsolate());
+  v8::HandleScope scope(isolate);
   v8::Local<v8::String> cons =
-      CompileRun("'Romeo Montague ' + 'Juliet Capulet'")->ToString();
+      CompileRun("'Romeo Montague ' + 'Juliet Capulet'")->ToString(isolate);
   CHECK(v8::Utils::OpenHandle(*cons)->IsConsString());
   CcTest::heap()->CollectAllAvailableGarbage();
   CHECK(CcTest::heap()->old_pointer_space()->Contains(
@@ -18020,10 +19146,11 @@
 
 
 TEST(ExternalizeOldSpaceOneByteCons) {
+  v8::Isolate* isolate = CcTest::isolate();
   LocalContext env;
-  v8::HandleScope scope(env->GetIsolate());
+  v8::HandleScope scope(isolate);
   v8::Local<v8::String> cons =
-      CompileRun("'Romeo Montague ' + 'Juliet Capulet'")->ToString();
+      CompileRun("'Romeo Montague ' + 'Juliet Capulet'")->ToString(isolate);
   CHECK(v8::Utils::OpenHandle(*cons)->IsConsString());
   CcTest::heap()->CollectAllAvailableGarbage();
   CHECK(CcTest::heap()->old_pointer_space()->Contains(
@@ -18042,8 +19169,9 @@
 
 
 TEST(VisitExternalStrings) {
+  v8::Isolate* isolate = CcTest::isolate();
   LocalContext env;
-  v8::HandleScope scope(env->GetIsolate());
+  v8::HandleScope scope(isolate);
   const char* string = "Some string";
   uint16_t* two_byte_string = AsciiToTwoByteString(string);
   TestResource* resource[4];
@@ -18113,7 +19241,7 @@
     const char* s = "One string to test them all";
     TestOneByteResource* inscription =
         new TestOneByteResource(i::StrDup(s), &destroyed);
-    v8::Local<v8::String> ring = CompileRun("ring")->ToString();
+    v8::Local<v8::String> ring = CompileRun("ring")->ToString(isolate);
     CHECK(v8::Utils::OpenHandle(*ring)->IsInternalizedString());
     ring->MakeExternal(inscription);
     // Ring is still alive.  Orcs are roaming freely across our lands.
@@ -18128,6 +19256,9 @@
 
 
 TEST(ExternalInternalizedStringCollectedAtGC) {
+  // TODO(mvstanton): vector ics need weak support.
+  if (i::FLAG_vector_ics) return;
+
   int destroyed = 0;
   { LocalContext env;
     v8::HandleScope handle_scope(env->GetIsolate());
@@ -18135,7 +19266,7 @@
     const char* s = "One string to test them all";
     TestOneByteResource* inscription =
         new TestOneByteResource(i::StrDup(s), &destroyed);
-    v8::Local<v8::String> ring = CompileRun("ring")->ToString();
+    v8::Local<v8::String> ring = CompileRun("ring").As<v8::String>();
     CHECK(v8::Utils::OpenHandle(*ring)->IsInternalizedString());
     ring->MakeExternal(inscription);
     // Ring is still alive.  Orcs are roaming freely across our lands.
@@ -18274,7 +19405,7 @@
     const v8::FunctionCallbackInfo<v8::Value>& args) {
   v8::HandleScope scope(args.GetIsolate());
   v8::TryCatch tc;
-  v8::Handle<v8::String> str(args[0]->ToString());
+  v8::Handle<v8::String> str(args[0]->ToString(args.GetIsolate()));
   USE(str);
   if (tc.HasCaught())
     tc.ReThrow();
@@ -18625,7 +19756,7 @@
 }
 
 
-void FooGetInterceptor(Local<String> name,
+void FooGetInterceptor(Local<Name> name,
                        const v8::PropertyCallbackInfo<v8::Value>& info) {
   CHECK(v8::Utils::OpenHandle(*info.This())->IsJSObject());
   CHECK(v8::Utils::OpenHandle(*info.Holder())->IsJSObject());
@@ -18634,8 +19765,7 @@
 }
 
 
-void FooSetInterceptor(Local<String> name,
-                       Local<Value> value,
+void FooSetInterceptor(Local<Name> name, Local<Value> value,
                        const v8::PropertyCallbackInfo<v8::Value>& info) {
   CHECK(v8::Utils::OpenHandle(*info.This())->IsJSObject());
   CHECK(v8::Utils::OpenHandle(*info.Holder())->IsJSObject());
@@ -18681,15 +19811,13 @@
 
 
 static void NamedPropertyGetterWhichReturns42(
-    Local<String> name,
-    const v8::PropertyCallbackInfo<v8::Value>& info) {
+    Local<Name> name, const v8::PropertyCallbackInfo<v8::Value>& info) {
   info.GetReturnValue().Set(v8_num(42));
 }
 
 
 static void NamedPropertySetterWhichSetsYOnThisTo23(
-    Local<String> name,
-    Local<Value> value,
+    Local<Name> name, Local<Value> value,
     const v8::PropertyCallbackInfo<v8::Value>& info) {
   if (name->Equals(v8_str("x"))) {
     Local<Object>::Cast(info.This())->Set(v8_str("y"), v8_num(23));
@@ -18701,8 +19829,9 @@
   v8::Isolate* isolate = CcTest::isolate();
   v8::HandleScope scope(isolate);
   Local<ObjectTemplate> templ = ObjectTemplate::New(isolate);
-  templ->SetNamedPropertyHandler(NamedPropertyGetterWhichReturns42,
-                                 NamedPropertySetterWhichSetsYOnThisTo23);
+  templ->SetHandler(v8::NamedPropertyHandlerConfiguration(
+      NamedPropertyGetterWhichReturns42,
+      NamedPropertySetterWhichSetsYOnThisTo23));
   LocalContext context;
   context->Global()->Set(v8_str("P"), templ->NewInstance());
   CompileRun("function C1() {"
@@ -19860,7 +20989,7 @@
   CHECK_EQ(42, object.WrapperClassId());
 
   Visitor42 visitor(&object);
-  v8::V8::VisitHandlesWithClassIds(&visitor);
+  v8::V8::VisitHandlesWithClassIds(isolate, &visitor);
   CHECK_EQ(1, visitor.counter_);
 
   object.Reset();
@@ -19994,8 +21123,8 @@
 }
 
 
-static void Getter(v8::Local<v8::String> property,
-                   const v8::PropertyCallbackInfo<v8::Value>& info ) {
+static void Getter(v8::Local<v8::Name> property,
+                   const v8::PropertyCallbackInfo<v8::Value>& info) {
   info.GetReturnValue().Set(v8_str("42!"));
 }
 
@@ -20014,7 +21143,8 @@
   v8::Context::Scope context_scope(context.local());
 
   v8::Handle<v8::ObjectTemplate> tmpl = v8::ObjectTemplate::New(isolate);
-  tmpl->SetNamedPropertyHandler(Getter, NULL, NULL, NULL, Enumerator);
+  tmpl->SetHandler(v8::NamedPropertyHandlerConfiguration(Getter, NULL, NULL,
+                                                         NULL, Enumerator));
   context->Global()->Set(v8_str("o"), tmpl->NewInstance());
   v8::Handle<v8::Array> result = v8::Handle<v8::Array>::Cast(CompileRun(
         "var result = []; for (var k in o) result.push(k); result"));
@@ -20159,8 +21289,7 @@
 
 
 void HasOwnPropertyNamedPropertyGetter(
-    Local<String> property,
-    const v8::PropertyCallbackInfo<v8::Value>& info) {
+    Local<Name> property, const v8::PropertyCallbackInfo<v8::Value>& info) {
   if (property->Equals(v8_str("foo"))) info.GetReturnValue().Set(v8_str("yes"));
 }
 
@@ -20172,15 +21301,13 @@
 
 
 void HasOwnPropertyNamedPropertyQuery(
-    Local<String> property,
-    const v8::PropertyCallbackInfo<v8::Integer>& info) {
+    Local<Name> property, const v8::PropertyCallbackInfo<v8::Integer>& info) {
   if (property->Equals(v8_str("foo"))) info.GetReturnValue().Set(1);
 }
 
 
 void HasOwnPropertyNamedPropertyQuery2(
-    Local<String> property,
-    const v8::PropertyCallbackInfo<v8::Integer>& info) {
+    Local<Name> property, const v8::PropertyCallbackInfo<v8::Integer>& info) {
   if (property->Equals(v8_str("bar"))) info.GetReturnValue().Set(1);
 }
 
@@ -20209,7 +21336,7 @@
         "Bar.prototype = new Foo();"
         "new Bar();");
     CHECK(value->IsObject());
-    Handle<Object> object = value->ToObject();
+    Handle<Object> object = value->ToObject(isolate);
     CHECK(object->Has(v8_str("foo")));
     CHECK(!object->HasOwnProperty(v8_str("foo")));
     CHECK(object->HasOwnProperty(v8_str("bar")));
@@ -20219,7 +21346,8 @@
   }
   { // Check named getter interceptors.
     Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate);
-    templ->SetNamedPropertyHandler(HasOwnPropertyNamedPropertyGetter);
+    templ->SetHandler(v8::NamedPropertyHandlerConfiguration(
+        HasOwnPropertyNamedPropertyGetter));
     Handle<Object> instance = templ->NewInstance();
     CHECK(!instance->HasOwnProperty(v8_str("42")));
     CHECK(instance->HasOwnProperty(v8_str("foo")));
@@ -20227,7 +21355,8 @@
   }
   { // Check indexed getter interceptors.
     Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate);
-    templ->SetIndexedPropertyHandler(HasOwnPropertyIndexedPropertyGetter);
+    templ->SetHandler(v8::IndexedPropertyHandlerConfiguration(
+        HasOwnPropertyIndexedPropertyGetter));
     Handle<Object> instance = templ->NewInstance();
     CHECK(instance->HasOwnProperty(v8_str("42")));
     CHECK(!instance->HasOwnProperty(v8_str("43")));
@@ -20235,14 +21364,16 @@
   }
   { // Check named query interceptors.
     Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate);
-    templ->SetNamedPropertyHandler(0, 0, HasOwnPropertyNamedPropertyQuery);
+    templ->SetHandler(v8::NamedPropertyHandlerConfiguration(
+        0, 0, HasOwnPropertyNamedPropertyQuery));
     Handle<Object> instance = templ->NewInstance();
     CHECK(instance->HasOwnProperty(v8_str("foo")));
     CHECK(!instance->HasOwnProperty(v8_str("bar")));
   }
   { // Check indexed query interceptors.
     Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate);
-    templ->SetIndexedPropertyHandler(0, 0, HasOwnPropertyIndexedPropertyQuery);
+    templ->SetHandler(v8::IndexedPropertyHandlerConfiguration(
+        0, 0, HasOwnPropertyIndexedPropertyQuery));
     Handle<Object> instance = templ->NewInstance();
     CHECK(instance->HasOwnProperty(v8_str("42")));
     CHECK(!instance->HasOwnProperty(v8_str("41")));
@@ -20256,9 +21387,9 @@
   }
   { // Check that query wins on disagreement.
     Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate);
-    templ->SetNamedPropertyHandler(HasOwnPropertyNamedPropertyGetter,
-                                   0,
-                                   HasOwnPropertyNamedPropertyQuery2);
+    templ->SetHandler(v8::NamedPropertyHandlerConfiguration(
+        HasOwnPropertyNamedPropertyGetter, 0,
+        HasOwnPropertyNamedPropertyQuery2));
     Handle<Object> instance = templ->NewInstance();
     CHECK(!instance->HasOwnProperty(v8_str("foo")));
     CHECK(instance->HasOwnProperty(v8_str("bar")));
@@ -20270,9 +21401,8 @@
   v8::Isolate* isolate = CcTest::isolate();
   v8::HandleScope scope(isolate);
   Handle<ObjectTemplate> templ = ObjectTemplate::New(isolate);
-  templ->SetIndexedPropertyHandler(NULL,
-                                   NULL,
-                                   HasOwnPropertyIndexedPropertyQuery);
+  templ->SetHandler(v8::IndexedPropertyHandlerConfiguration(
+      NULL, NULL, HasOwnPropertyIndexedPropertyQuery));
   LocalContext context;
   context->Global()->Set(v8_str("obj"), templ->NewInstance());
   CompileRun("var s = new String('foobar'); obj.__proto__ = s;");
@@ -20417,29 +21547,40 @@
 }
 
 
+static int CountLiveMapsInMapCache(i::Context* context) {
+  i::FixedArray* map_cache = i::FixedArray::cast(context->map_cache());
+  int length = map_cache->length();
+  int count = 0;
+  for (int i = 0; i < length; i++) {
+    i::Object* value = map_cache->get(i);
+    if (value->IsWeakCell() && !i::WeakCell::cast(value)->cleared()) count++;
+  }
+  return count;
+}
+
+
 THREADED_TEST(Regress1516) {
   LocalContext context;
   v8::HandleScope scope(context->GetIsolate());
 
+  // Object with 20 properties is not a common case, so it should be removed
+  // from the cache after GC.
   { v8::HandleScope temp_scope(context->GetIsolate());
-    CompileRun("({'a': 0})");
+    CompileRun(
+        "({"
+        "'a00': 0, 'a01': 0, 'a02': 0, 'a03': 0, 'a04': 0, "
+        "'a05': 0, 'a06': 0, 'a07': 0, 'a08': 0, 'a09': 0, "
+        "'a10': 0, 'a11': 0, 'a12': 0, 'a13': 0, 'a14': 0, "
+        "'a15': 0, 'a16': 0, 'a17': 0, 'a18': 0, 'a19': 0, "
+        "})");
   }
 
-  int elements;
-  { i::MapCache* map_cache =
-        i::MapCache::cast(CcTest::i_isolate()->context()->map_cache());
-    elements = map_cache->NumberOfElements();
-    CHECK_LE(1, elements);
-  }
+  int elements = CountLiveMapsInMapCache(CcTest::i_isolate()->context());
+  CHECK_LE(1, elements);
 
-  CcTest::heap()->CollectAllGarbage(
-      i::Heap::kAbortIncrementalMarkingMask);
-  { i::Object* raw_map_cache = CcTest::i_isolate()->context()->map_cache();
-    if (raw_map_cache != CcTest::heap()->undefined_value()) {
-      i::MapCache* map_cache = i::MapCache::cast(raw_map_cache);
-      CHECK_GT(elements, map_cache->NumberOfElements());
-    }
-  }
+  CcTest::heap()->CollectAllGarbage(i::Heap::kAbortIncrementalMarkingMask);
+
+  CHECK_GT(elements, CountLiveMapsInMapCache(CcTest::i_isolate()->context()));
 }
 
 
@@ -20448,12 +21589,11 @@
                                                 v8::AccessType type,
                                                 Local<Value> data) {
   // Only block read access to __proto__.
-  if (type == v8::ACCESS_GET &&
-      name->IsString() &&
-      name->ToString()->Length() == 9 &&
-      name->ToString()->Utf8Length() == 9) {
+  if (type == v8::ACCESS_GET && name->IsString() &&
+      name.As<v8::String>()->Length() == 9 &&
+      name.As<v8::String>()->Utf8Length() == 9) {
     char buffer[10];
-    CHECK_EQ(10, name->ToString()->WriteUtf8(buffer));
+    CHECK_EQ(10, name.As<v8::String>()->WriteUtf8(buffer));
     return strncmp(buffer, "__proto__", 9) != 0;
   }
 
@@ -20500,8 +21640,7 @@
       context->Global();
 
   // Global object, the  prototype of proxy_object. No security checks.
-  Local<Object> global_object =
-      proxy_object->GetPrototype()->ToObject();
+  Local<Object> global_object = proxy_object->GetPrototype()->ToObject(isolate);
 
   // Hidden prototype without security check.
   Local<Object> hidden_prototype =
@@ -20545,7 +21684,7 @@
 
   Local<Value> result5 = CompileRun("Object.getPrototypeOf(hidden)");
   CHECK(result5->Equals(
-      object_with_hidden->GetPrototype()->ToObject()->GetPrototype()));
+      object_with_hidden->GetPrototype()->ToObject(isolate)->GetPrototype()));
 
   Local<Value> result6 = CompileRun("Object.getPrototypeOf(phidden)");
   CHECK(result6.IsEmpty());
@@ -20581,8 +21720,8 @@
                          const char* code) {
   Local<Value> result = CompileRun(code);
   CHECK(result->IsObject());
-  CHECK(expected_receiver->Equals(result->ToObject()->Get(1)));
-  CHECK(expected_result->Equals(result->ToObject()->Get(0)));
+  CHECK(expected_receiver->Equals(result.As<v8::Object>()->Get(1)));
+  CHECK(expected_result->Equals(result.As<v8::Object>()->Get(0)));
 }
 
 
@@ -20970,8 +22109,8 @@
   Handle<Object> exec_state = event_details.GetExecutionState();
   Handle<Value> break_id = exec_state->Get(v8_str("break_id"));
   CompileRun("function f(id) { new FrameDetails(id, 0); }");
-  Handle<Function> fun = Handle<Function>::Cast(
-      CcTest::global()->Get(v8_str("f"))->ToObject());
+  Handle<Function> fun =
+      Handle<Function>::Cast(CcTest::global()->Get(v8_str("f")));
   fun->Call(CcTest::global(), 1, &break_id);
 }
 
@@ -20995,7 +22134,7 @@
 }
 
 
-#ifdef DEBUG
+#ifdef ENABLE_DISASSEMBLER
 static int probes_counter = 0;
 static int misses_counter = 0;
 static int updates_counter = 0;
@@ -21029,7 +22168,7 @@
 
 
 static void StubCacheHelper(bool primary) {
-#ifdef DEBUG
+#ifdef ENABLE_DISASSEMBLER
   i::FLAG_native_code_counters = true;
   if (primary) {
     i::FLAG_test_primary_stub_cache = true;
@@ -21376,7 +22515,8 @@
   LocalContext context;
   Local<ObjectTemplate> templ = ObjectTemplate::New(context->GetIsolate());
   if (interceptor) {
-    templ->SetNamedPropertyHandler(FooGetInterceptor, FooSetInterceptor);
+    templ->SetHandler(v8::NamedPropertyHandlerConfiguration(FooGetInterceptor,
+                                                            FooSetInterceptor));
   } else {
     templ->SetAccessor(v8_str("foo"),
                        GetterWhichReturns42,
@@ -21782,7 +22922,8 @@
 
 
 void HasOwnPropertyCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
-  args[0]->ToObject()->HasOwnProperty(args[1]->ToString());
+  args[0]->ToObject(args.GetIsolate())->HasOwnProperty(
+      args[1]->ToString(args.GetIsolate()));
 }
 
 
@@ -21998,8 +23139,6 @@
 
     TestBody();
 
-    isolate_->ClearInterrupt();
-
     // Verify we arrived here because interruptor was called
     // not due to a bug causing us to exit the loop too early.
     CHECK(!should_continue());
@@ -22149,7 +23288,8 @@
     proto->Set(v8_str("shouldContinue"), Function::New(
         isolate_, ShouldContinueCallback, v8::External::New(isolate_, this)));
     v8::Local<v8::ObjectTemplate> instance_template = t->InstanceTemplate();
-    instance_template->SetNamedPropertyHandler(EmptyInterceptor);
+    instance_template->SetHandler(
+        v8::NamedPropertyHandlerConfiguration(EmptyInterceptor));
 
     env_->Global()->Set(v8_str("Klass"), t->GetFunction());
 
@@ -22158,9 +23298,7 @@
 
  private:
   static void EmptyInterceptor(
-      Local<String> property,
-      const v8::PropertyCallbackInfo<v8::Value>& info) {
-  }
+      Local<Name> property, const v8::PropertyCallbackInfo<v8::Value>& info) {}
 };
 
 
@@ -22249,10 +23387,9 @@
 }
 
 
-class ClearInterruptFromAnotherThread
-    : public RequestInterruptTestBase {
+class RequestMultipleInterrupts : public RequestInterruptTestBase {
  public:
-  ClearInterruptFromAnotherThread() : i_thread(this), sem2_(0) { }
+  RequestMultipleInterrupts() : i_thread(this), counter_(0) {}
 
   virtual void StartInterruptThread() {
     i_thread.Start();
@@ -22269,39 +23406,33 @@
  private:
   class InterruptThread : public v8::base::Thread {
    public:
-    explicit InterruptThread(ClearInterruptFromAnotherThread* test)
+    enum { NUM_INTERRUPTS = 10 };
+    explicit InterruptThread(RequestMultipleInterrupts* test)
         : Thread(Options("RequestInterruptTest")), test_(test) {}
 
     virtual void Run() {
       test_->sem_.Wait();
-      test_->isolate_->RequestInterrupt(&OnInterrupt, test_);
-      test_->sem_.Wait();
-      test_->isolate_->ClearInterrupt();
-      test_->sem2_.Signal();
+      for (int i = 0; i < NUM_INTERRUPTS; i++) {
+        test_->isolate_->RequestInterrupt(&OnInterrupt, test_);
+      }
     }
 
     static void OnInterrupt(v8::Isolate* isolate, void* data) {
-      ClearInterruptFromAnotherThread* test =
-          reinterpret_cast<ClearInterruptFromAnotherThread*>(data);
-      test->sem_.Signal();
-      bool success = test->sem2_.WaitFor(v8::base::TimeDelta::FromSeconds(2));
-      // Crash instead of timeout to make this failure more prominent.
-      CHECK(success);
-      test->should_continue_ = false;
+      RequestMultipleInterrupts* test =
+          reinterpret_cast<RequestMultipleInterrupts*>(data);
+      test->should_continue_ = ++test->counter_ < NUM_INTERRUPTS;
     }
 
    private:
-     ClearInterruptFromAnotherThread* test_;
+    RequestMultipleInterrupts* test_;
   };
 
   InterruptThread i_thread;
-  v8::base::Semaphore sem2_;
+  int counter_;
 };
 
 
-TEST(ClearInterruptFromAnotherThread) {
-  ClearInterruptFromAnotherThread().RunTest();
-}
+TEST(RequestMultipleInterrupts) { RequestMultipleInterrupts().RunTest(); }
 
 
 static Local<Value> function_new_expected_env;
@@ -22606,6 +23737,7 @@
   Handle<v8::Promise::Resolver> rr = v8::Promise::Resolver::New(isolate);
   Handle<v8::Promise> p = pr->GetPromise();
   Handle<v8::Promise> r = rr->GetPromise();
+  CHECK_EQ(isolate, p->GetIsolate());
 
   // IsPromise predicate.
   CHECK(p->IsPromise());
@@ -22867,10 +23999,8 @@
   CHECK_EQ(13, line_number);
 }
 
-
-void SourceURLHelper(const char* source, const char* expected_source_url,
-                     const char* expected_source_mapping_url) {
-  Local<Script> script = v8_compile(source);
+void CheckMagicComments(Handle<Script> script, const char* expected_source_url,
+                        const char* expected_source_mapping_url) {
   if (expected_source_url != NULL) {
     v8::String::Utf8Value url(script->GetUnboundScript()->GetSourceURL());
     CHECK_EQ(expected_source_url, *url);
@@ -22886,6 +24016,12 @@
   }
 }
 
+void SourceURLHelper(const char* source, const char* expected_source_url,
+                     const char* expected_source_mapping_url) {
+  Local<Script> script = v8_compile(source);
+  CheckMagicComments(script, expected_source_url, expected_source_mapping_url);
+}
+
 
 TEST(ScriptSourceURLAndSourceMappingURL) {
   LocalContext env;
@@ -23077,7 +24213,9 @@
 void RunStreamingTest(const char** chunks,
                       v8::ScriptCompiler::StreamedSource::Encoding encoding =
                           v8::ScriptCompiler::StreamedSource::ONE_BYTE,
-                      bool expected_success = true) {
+                      bool expected_success = true,
+                      const char* expected_source_url = NULL,
+                      const char* expected_source_mapping_url = NULL) {
   LocalContext env;
   v8::Isolate* isolate = env->GetIsolate();
   v8::HandleScope scope(isolate);
@@ -23106,6 +24244,8 @@
     v8::Handle<Value> result(script->Run());
     // All scripts are supposed to return the fixed value 13 when ran.
     CHECK_EQ(13, result->Int32Value());
+    CheckMagicComments(script, expected_source_url,
+                       expected_source_mapping_url);
   } else {
     CHECK(script.IsEmpty());
     CHECK(try_catch.HasCaught());
@@ -23170,14 +24310,14 @@
 
 
 TEST(StreamingUtf8Script) {
-  // We'd want to write \uc481 instead of \xeb\x91\x80, but Windows compilers
+  // We'd want to write \uc481 instead of \xec\x92\x81, but Windows compilers
   // don't like it.
   const char* chunk1 =
       "function foo() {\n"
       "  // This function will contain an UTF-8 character which is not in\n"
       "  // ASCII.\n"
-      "  var foob\xeb\x91\x80r = 13;\n"
-      "  return foob\xeb\x91\x80r;\n"
+      "  var foob\xec\x92\x81r = 13;\n"
+      "  return foob\xec\x92\x81r;\n"
       "}\n";
   const char* chunks[] = {chunk1, "foo(); ", NULL};
   RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8);
@@ -23188,7 +24328,7 @@
   // A sanity check to prove that the approach of splitting UTF-8
   // characters is correct. Here is an UTF-8 character which will take three
   // bytes.
-  const char* reference = "\xeb\x91\x80";
+  const char* reference = "\xec\x92\x81";
   CHECK(3u == strlen(reference));  // NOLINT - no CHECK_EQ for unsigned.
 
   char chunk1[] =
@@ -23198,7 +24338,7 @@
       "  var foob";
   char chunk2[] =
       "XXXr = 13;\n"
-      "  return foob\xeb\x91\x80r;\n"
+      "  return foob\xec\x92\x81r;\n"
       "}\n";
   for (int i = 0; i < 3; ++i) {
     chunk2[i] = reference[i];
@@ -23211,7 +24351,7 @@
 TEST(StreamingUtf8ScriptWithSplitCharacters) {
   // Stream data where a multi-byte UTF-8 character is split between two data
   // chunks.
-  const char* reference = "\xeb\x91\x80";
+  const char* reference = "\xec\x92\x81";
   char chunk1[] =
       "function foo() {\n"
       "  // This function will contain an UTF-8 character which is not in\n"
@@ -23219,7 +24359,7 @@
       "  var foobX";
   char chunk2[] =
       "XXr = 13;\n"
-      "  return foob\xeb\x91\x80r;\n"
+      "  return foob\xec\x92\x81r;\n"
       "}\n";
   chunk1[strlen(chunk1) - 1] = reference[0];
   chunk2[0] = reference[1];
@@ -23235,7 +24375,7 @@
   // Case 1: a chunk contains only bytes for a split character (and no other
   // data). This kind of a chunk would be exceptionally small, but we should
   // still decode it correctly.
-  const char* reference = "\xeb\x91\x80";
+  const char* reference = "\xec\x92\x81";
   // The small chunk is at the beginning of the split character
   {
     char chunk1[] =
@@ -23246,7 +24386,7 @@
     char chunk2[] = "XX";
     char chunk3[] =
         "Xr = 13;\n"
-        "  return foob\xeb\x91\x80r;\n"
+        "  return foob\xec\x92\x81r;\n"
         "}\n";
     chunk2[0] = reference[0];
     chunk2[1] = reference[1];
@@ -23264,7 +24404,7 @@
     char chunk2[] = "XX";
     char chunk3[] =
         "r = 13;\n"
-        "  return foob\xeb\x91\x80r;\n"
+        "  return foob\xec\x92\x81r;\n"
         "}\n";
     chunk1[strlen(chunk1) - 1] = reference[0];
     chunk2[0] = reference[1];
@@ -23276,8 +24416,8 @@
   // decoded correctly and not just ignored.
   {
     char chunk1[] =
-        "var foob\xeb\x91\x80 = 13;\n"
-        "foob\xeb\x91\x80";
+        "var foob\xec\x92\x81 = 13;\n"
+        "foob\xec\x92\x81";
     const char* chunks[] = {chunk1, NULL};
     RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8);
   }
@@ -23288,7 +24428,7 @@
   // Test cases where a UTF-8 character is split over several chunks. Those
   // cases are not supported (the embedder should give the data in big enough
   // chunks), but we shouldn't crash, just produce a parse error.
-  const char* reference = "\xeb\x91\x80";
+  const char* reference = "\xec\x92\x81";
   char chunk1[] =
       "function foo() {\n"
       "  // This function will contain an UTF-8 character which is not in\n"
@@ -23297,7 +24437,7 @@
   char chunk2[] = "X";
   char chunk3[] =
       "Xr = 13;\n"
-      "  return foob\xeb\x91\x80r;\n"
+      "  return foob\xec\x92\x81r;\n"
       "}\n";
   chunk1[strlen(chunk1) - 1] = reference[0];
   chunk2[0] = reference[1];
@@ -23332,6 +24472,7 @@
   const v8::ScriptCompiler::CachedData* cached_data = source.GetCachedData();
   CHECK(cached_data != NULL);
   CHECK(cached_data->data != NULL);
+  CHECK(!cached_data->rejected);
   CHECK_GT(cached_data->length, 0);
 }
 
@@ -23339,7 +24480,7 @@
 TEST(StreamingScriptWithInvalidUtf8) {
   // Regression test for a crash: test that invalid UTF-8 bytes in the end of a
   // chunk don't produce a crash.
-  const char* reference = "\xeb\x91\x80\x80\x80";
+  const char* reference = "\xec\x92\x81\x80\x80";
   char chunk1[] =
       "function foo() {\n"
       "  // This function will contain an UTF-8 character which is not in\n"
@@ -23347,10 +24488,274 @@
       "  var foobXXXXX";  // Too many bytes which look like incomplete chars!
   char chunk2[] =
       "r = 13;\n"
-      "  return foob\xeb\x91\x80\x80\x80r;\n"
+      "  return foob\xec\x92\x81\x80\x80r;\n"
       "}\n";
   for (int i = 0; i < 5; ++i) chunk1[strlen(chunk1) - 5 + i] = reference[i];
 
   const char* chunks[] = {chunk1, chunk2, "foo();", NULL};
   RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8, false);
 }
+
+
+TEST(StreamingUtf8ScriptWithMultipleMultibyteCharactersSomeSplit) {
+  // Regression test: Stream data where there are several multi-byte UTF-8
+  // characters in a sequence and one of them is split between two data chunks.
+  const char* reference = "\xec\x92\x81";
+  char chunk1[] =
+      "function foo() {\n"
+      "  // This function will contain an UTF-8 character which is not in\n"
+      "  // ASCII.\n"
+      "  var foob\xec\x92\x81X";
+  char chunk2[] =
+      "XXr = 13;\n"
+      "  return foob\xec\x92\x81\xec\x92\x81r;\n"
+      "}\n";
+  chunk1[strlen(chunk1) - 1] = reference[0];
+  chunk2[0] = reference[1];
+  chunk2[1] = reference[2];
+  const char* chunks[] = {chunk1, chunk2, "foo();", NULL};
+  RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8);
+}
+
+
+TEST(StreamingUtf8ScriptWithMultipleMultibyteCharactersSomeSplit2) {
+  // Another regression test, similar to the previous one. The difference is
+  // that the split character is not the last one in the sequence.
+  const char* reference = "\xec\x92\x81";
+  char chunk1[] =
+      "function foo() {\n"
+      "  // This function will contain an UTF-8 character which is not in\n"
+      "  // ASCII.\n"
+      "  var foobX";
+  char chunk2[] =
+      "XX\xec\x92\x81r = 13;\n"
+      "  return foob\xec\x92\x81\xec\x92\x81r;\n"
+      "}\n";
+  chunk1[strlen(chunk1) - 1] = reference[0];
+  chunk2[0] = reference[1];
+  chunk2[1] = reference[2];
+  const char* chunks[] = {chunk1, chunk2, "foo();", NULL};
+  RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8);
+}
+
+
+void TestInvalidCacheData(v8::ScriptCompiler::CompileOptions option) {
+  const char* garbage = "garbage garbage garbage garbage garbage garbage";
+  const uint8_t* data = reinterpret_cast<const uint8_t*>(garbage);
+  int length = 16;
+  v8::ScriptCompiler::CachedData* cached_data =
+      new v8::ScriptCompiler::CachedData(data, length);
+  DCHECK(!cached_data->rejected);
+  v8::ScriptOrigin origin(v8_str("origin"));
+  v8::ScriptCompiler::Source source(v8_str("42"), origin, cached_data);
+  v8::Handle<v8::Script> script =
+      v8::ScriptCompiler::Compile(CcTest::isolate(), &source, option);
+  CHECK(cached_data->rejected);
+  CHECK_EQ(42, script->Run()->Int32Value());
+}
+
+
+TEST(InvalidCacheData) {
+  v8::V8::Initialize();
+  v8::HandleScope scope(CcTest::isolate());
+  LocalContext context;
+  TestInvalidCacheData(v8::ScriptCompiler::kConsumeParserCache);
+  TestInvalidCacheData(v8::ScriptCompiler::kConsumeCodeCache);
+}
+
+
+TEST(ParserCacheRejectedGracefully) {
+  i::FLAG_min_preparse_length = 0;
+  v8::V8::Initialize();
+  v8::HandleScope scope(CcTest::isolate());
+  LocalContext context;
+  // Produce valid cached data.
+  v8::ScriptOrigin origin(v8_str("origin"));
+  v8::Local<v8::String> source_str = v8_str("function foo() {}");
+  v8::ScriptCompiler::Source source(source_str, origin);
+  v8::Handle<v8::Script> script = v8::ScriptCompiler::Compile(
+      CcTest::isolate(), &source, v8::ScriptCompiler::kProduceParserCache);
+  CHECK(!script.IsEmpty());
+  const v8::ScriptCompiler::CachedData* original_cached_data =
+      source.GetCachedData();
+  CHECK(original_cached_data != NULL);
+  CHECK(original_cached_data->data != NULL);
+  CHECK(!original_cached_data->rejected);
+  CHECK_GT(original_cached_data->length, 0);
+  // Recompiling the same script with it won't reject the data.
+  {
+    v8::ScriptCompiler::Source source_with_cached_data(
+        source_str, origin,
+        new v8::ScriptCompiler::CachedData(original_cached_data->data,
+                                           original_cached_data->length));
+    v8::Handle<v8::Script> script =
+        v8::ScriptCompiler::Compile(CcTest::isolate(), &source_with_cached_data,
+                                    v8::ScriptCompiler::kConsumeParserCache);
+    CHECK(!script.IsEmpty());
+    const v8::ScriptCompiler::CachedData* new_cached_data =
+        source_with_cached_data.GetCachedData();
+    CHECK(new_cached_data != NULL);
+    CHECK(!new_cached_data->rejected);
+  }
+  // Compile an incompatible script with the cached data. The new script doesn't
+  // have the same starting position for the function as the old one, so the old
+  // cached data will be incompatible with it and will be rejected.
+  {
+    v8::Local<v8::String> incompatible_source_str =
+        v8_str("   function foo() {}");
+    v8::ScriptCompiler::Source source_with_cached_data(
+        incompatible_source_str, origin,
+        new v8::ScriptCompiler::CachedData(original_cached_data->data,
+                                           original_cached_data->length));
+    v8::Handle<v8::Script> script =
+        v8::ScriptCompiler::Compile(CcTest::isolate(), &source_with_cached_data,
+                                    v8::ScriptCompiler::kConsumeParserCache);
+    CHECK(!script.IsEmpty());
+    const v8::ScriptCompiler::CachedData* new_cached_data =
+        source_with_cached_data.GetCachedData();
+    CHECK(new_cached_data != NULL);
+    CHECK(new_cached_data->rejected);
+  }
+}
+
+
+TEST(StringConcatOverflow) {
+  v8::V8::Initialize();
+  v8::HandleScope scope(CcTest::isolate());
+  RandomLengthOneByteResource* r =
+      new RandomLengthOneByteResource(i::String::kMaxLength);
+  v8::Local<v8::String> str = v8::String::NewExternal(CcTest::isolate(), r);
+  CHECK(!str.IsEmpty());
+  v8::TryCatch try_catch;
+  v8::Local<v8::String> result = v8::String::Concat(str, str);
+  CHECK(result.IsEmpty());
+  CHECK(!try_catch.HasCaught());
+}
+
+
+TEST(TurboAsmDisablesNeuter) {
+  v8::V8::Initialize();
+  v8::HandleScope scope(CcTest::isolate());
+  LocalContext context;
+#if V8_TURBOFAN_TARGET
+  bool should_be_neuterable = !i::FLAG_turbo_asm;
+#else
+  bool should_be_neuterable = true;
+#endif
+  const char* load =
+      "function Module(stdlib, foreign, heap) {"
+      "  'use asm';"
+      "  var MEM32 = new stdlib.Int32Array(heap);"
+      "  function load() { return MEM32[0]; }"
+      "  return { load: load };"
+      "}"
+      "var buffer = new ArrayBuffer(4);"
+      "Module(this, {}, buffer).load();"
+      "buffer";
+
+  v8::Local<v8::ArrayBuffer> result = CompileRun(load).As<v8::ArrayBuffer>();
+  CHECK_EQ(should_be_neuterable, result->IsNeuterable());
+
+  const char* store =
+      "function Module(stdlib, foreign, heap) {"
+      "  'use asm';"
+      "  var MEM32 = new stdlib.Int32Array(heap);"
+      "  function store() { MEM32[0] = 0; }"
+      "  return { store: store };"
+      "}"
+      "var buffer = new ArrayBuffer(4);"
+      "Module(this, {}, buffer).store();"
+      "buffer";
+
+  result = CompileRun(store).As<v8::ArrayBuffer>();
+  CHECK_EQ(should_be_neuterable, result->IsNeuterable());
+}
+
+
+TEST(GetPrototypeAccessControl) {
+  i::FLAG_allow_natives_syntax = true;
+  v8::Isolate* isolate = CcTest::isolate();
+  v8::HandleScope handle_scope(isolate);
+  LocalContext env;
+
+  v8::Handle<v8::ObjectTemplate> obj_template =
+      v8::ObjectTemplate::New(isolate);
+  obj_template->SetAccessCheckCallbacks(BlockEverythingNamed,
+                                        BlockEverythingIndexed);
+
+  env->Global()->Set(v8_str("prohibited"), obj_template->NewInstance());
+
+  {
+    v8::TryCatch try_catch;
+    CompileRun(
+        "function f() { %_GetPrototype(prohibited); }"
+        "%OptimizeFunctionOnNextCall(f);"
+        "f();");
+    CHECK(try_catch.HasCaught());
+  }
+}
+
+
+TEST(GetPrototypeHidden) {
+  i::FLAG_allow_natives_syntax = true;
+  v8::Isolate* isolate = CcTest::isolate();
+  v8::HandleScope handle_scope(isolate);
+  LocalContext env;
+
+  Handle<FunctionTemplate> t = FunctionTemplate::New(isolate);
+  t->SetHiddenPrototype(true);
+  Handle<Object> proto = t->GetFunction()->NewInstance();
+  Handle<Object> object = Object::New(isolate);
+  Handle<Object> proto2 = Object::New(isolate);
+  object->SetPrototype(proto);
+  proto->SetPrototype(proto2);
+
+  env->Global()->Set(v8_str("object"), object);
+  env->Global()->Set(v8_str("proto"), proto);
+  env->Global()->Set(v8_str("proto2"), proto2);
+
+  v8::Handle<v8::Value> result = CompileRun("%_GetPrototype(object)");
+  CHECK(result->Equals(proto2));
+
+  result = CompileRun(
+      "function f() { return %_GetPrototype(object); }"
+      "%OptimizeFunctionOnNextCall(f);"
+      "f()");
+  CHECK(result->Equals(proto2));
+}
+
+
+TEST(ClassPrototypeCreationContext) {
+  i::FLAG_harmony_classes = true;
+  v8::Isolate* isolate = CcTest::isolate();
+  v8::HandleScope handle_scope(isolate);
+  LocalContext env;
+
+  Handle<Object> result = Handle<Object>::Cast(
+      CompileRun("'use strict'; class Example { }; Example.prototype"));
+  CHECK(env.local() == result->CreationContext());
+}
+
+
+TEST(SimpleStreamingScriptWithSourceURL) {
+  const char* chunks[] = {"function foo() { ret", "urn 13; } f", "oo();\n",
+                          "//# sourceURL=bar2.js\n", NULL};
+  RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8, true,
+                   "bar2.js");
+}
+
+
+TEST(StreamingScriptWithSplitSourceURL) {
+  const char* chunks[] = {"function foo() { ret", "urn 13; } f",
+                          "oo();\n//# sourceURL=b", "ar2.js\n", NULL};
+  RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8, true,
+                   "bar2.js");
+}
+
+
+TEST(StreamingScriptWithSourceMappingURLInTheMiddle) {
+  const char* chunks[] = {"function foo() { ret", "urn 13; }\n//#",
+                          " sourceMappingURL=bar2.js\n", "foo();", NULL};
+  RunStreamingTest(chunks, v8::ScriptCompiler::StreamedSource::UTF8, true, NULL,
+                   "bar2.js");
+}
diff --git a/test/cctest/test-assembler-arm.cc b/test/cctest/test-assembler-arm.cc
index ed9563d..2bcf022 100644
--- a/test/cctest/test-assembler-arm.cc
+++ b/test/cctest/test-assembler-arm.cc
@@ -25,6 +25,8 @@
 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
+#include <iostream>  // NOLINT(readability/streams)
+
 #include "src/v8.h"
 #include "test/cctest/cctest.h"
 
@@ -34,6 +36,7 @@
 #include "src/factory.h"
 #include "src/ostreams.h"
 
+using namespace v8::base;
 using namespace v8::internal;
 
 
@@ -1372,14 +1375,14 @@
   __ pkhtb(r2, r0, Operand(r1, ASR, 8));
   __ str(r2, MemOperand(r4, OFFSET_OF(T, dst1)));
 
-  __ uxtb16(r2, Operand(r0, ROR, 8));
+  __ uxtb16(r2, r0, 8);
   __ str(r2, MemOperand(r4, OFFSET_OF(T, dst2)));
 
-  __ uxtb(r2, Operand(r0, ROR, 8));
+  __ uxtb(r2, r0, 8);
   __ str(r2, MemOperand(r4, OFFSET_OF(T, dst3)));
 
   __ ldr(r0, MemOperand(r4, OFFSET_OF(T, src2)));
-  __ uxtab(r2, r0, Operand(r1, ROR, 8));
+  __ uxtab(r2, r0, r1, 8);
   __ str(r2, MemOperand(r4, OFFSET_OF(T, dst4)));
 
   __ ldm(ia_w, sp, r4.bit() | pc.bit());
@@ -1439,21 +1442,19 @@
     CHECK_EQ(expected_, t.result);
 
 
-TEST(18) {
+TEST(sdiv) {
   // Test the sdiv.
   CcTest::InitializeVM();
   Isolate* isolate = CcTest::i_isolate();
   HandleScope scope(isolate);
-
-  typedef struct {
-    uint32_t dividend;
-    uint32_t divisor;
-    uint32_t result;
-  } T;
-  T t;
-
   Assembler assm(isolate, NULL, 0);
 
+  struct T {
+    int32_t dividend;
+    int32_t divisor;
+    int32_t result;
+  } t;
+
   if (CpuFeatures::IsSupported(SUDIV)) {
     CpuFeatureScope scope(&assm, SUDIV);
 
@@ -1477,6 +1478,8 @@
 #endif
     F3 f = FUNCTION_CAST<F3>(code->entry());
     Object* dummy;
+    TEST_SDIV(0, kMinInt, 0);
+    TEST_SDIV(0, 1024, 0);
     TEST_SDIV(1073741824, kMinInt, -2);
     TEST_SDIV(kMinInt, kMinInt, -1);
     TEST_SDIV(5, 10, 2);
@@ -1495,6 +1498,322 @@
 #undef TEST_SDIV
 
 
+#define TEST_UDIV(expected_, dividend_, divisor_) \
+  t.dividend = dividend_;                         \
+  t.divisor = divisor_;                           \
+  t.result = 0;                                   \
+  dummy = CALL_GENERATED_CODE(f, &t, 0, 0, 0, 0); \
+  CHECK_EQ(expected_, t.result);
+
+
+TEST(udiv) {
+  // Test the udiv.
+  CcTest::InitializeVM();
+  Isolate* isolate = CcTest::i_isolate();
+  HandleScope scope(isolate);
+  Assembler assm(isolate, NULL, 0);
+
+  struct T {
+    uint32_t dividend;
+    uint32_t divisor;
+    uint32_t result;
+  } t;
+
+  if (CpuFeatures::IsSupported(SUDIV)) {
+    CpuFeatureScope scope(&assm, SUDIV);
+
+    __ mov(r3, Operand(r0));
+
+    __ ldr(r0, MemOperand(r3, OFFSET_OF(T, dividend)));
+    __ ldr(r1, MemOperand(r3, OFFSET_OF(T, divisor)));
+
+    __ sdiv(r2, r0, r1);
+    __ str(r2, MemOperand(r3, OFFSET_OF(T, result)));
+
+    __ bx(lr);
+
+    CodeDesc desc;
+    assm.GetCode(&desc);
+    Handle<Code> code = isolate->factory()->NewCode(
+        desc, Code::ComputeFlags(Code::STUB), Handle<Code>());
+#ifdef DEBUG
+    OFStream os(stdout);
+    code->Print(os);
+#endif
+    F3 f = FUNCTION_CAST<F3>(code->entry());
+    Object* dummy;
+    TEST_UDIV(0, 0, 0);
+    TEST_UDIV(0, 1024, 0);
+    TEST_UDIV(5, 10, 2);
+    TEST_UDIV(3, 10, 3);
+    USE(dummy);
+  }
+}
+
+
+#undef TEST_UDIV
+
+
+TEST(smmla) {
+  CcTest::InitializeVM();
+  Isolate* const isolate = CcTest::i_isolate();
+  HandleScope scope(isolate);
+  RandomNumberGenerator* const rng = isolate->random_number_generator();
+  Assembler assm(isolate, nullptr, 0);
+  __ smmla(r1, r1, r2, r3);
+  __ str(r1, MemOperand(r0));
+  __ bx(lr);
+  CodeDesc desc;
+  assm.GetCode(&desc);
+  Handle<Code> code = isolate->factory()->NewCode(
+      desc, Code::ComputeFlags(Code::STUB), Handle<Code>());
+#ifdef OBJECT_PRINT
+  code->Print(std::cout);
+#endif
+  F3 f = FUNCTION_CAST<F3>(code->entry());
+  for (size_t i = 0; i < 128; ++i) {
+    int32_t r, x = rng->NextInt(), y = rng->NextInt(), z = rng->NextInt();
+    Object* dummy = CALL_GENERATED_CODE(f, &r, x, y, z, 0);
+    CHECK_EQ(bits::SignedMulHighAndAdd32(x, y, z), r);
+    USE(dummy);
+  }
+}
+
+
+TEST(smmul) {
+  CcTest::InitializeVM();
+  Isolate* const isolate = CcTest::i_isolate();
+  HandleScope scope(isolate);
+  RandomNumberGenerator* const rng = isolate->random_number_generator();
+  Assembler assm(isolate, nullptr, 0);
+  __ smmul(r1, r1, r2);
+  __ str(r1, MemOperand(r0));
+  __ bx(lr);
+  CodeDesc desc;
+  assm.GetCode(&desc);
+  Handle<Code> code = isolate->factory()->NewCode(
+      desc, Code::ComputeFlags(Code::STUB), Handle<Code>());
+#ifdef OBJECT_PRINT
+  code->Print(std::cout);
+#endif
+  F3 f = FUNCTION_CAST<F3>(code->entry());
+  for (size_t i = 0; i < 128; ++i) {
+    int32_t r, x = rng->NextInt(), y = rng->NextInt();
+    Object* dummy = CALL_GENERATED_CODE(f, &r, x, y, 0, 0);
+    CHECK_EQ(bits::SignedMulHigh32(x, y), r);
+    USE(dummy);
+  }
+}
+
+
+TEST(sxtb) {
+  CcTest::InitializeVM();
+  Isolate* const isolate = CcTest::i_isolate();
+  HandleScope scope(isolate);
+  RandomNumberGenerator* const rng = isolate->random_number_generator();
+  Assembler assm(isolate, nullptr, 0);
+  __ sxtb(r1, r1);
+  __ str(r1, MemOperand(r0));
+  __ bx(lr);
+  CodeDesc desc;
+  assm.GetCode(&desc);
+  Handle<Code> code = isolate->factory()->NewCode(
+      desc, Code::ComputeFlags(Code::STUB), Handle<Code>());
+#ifdef OBJECT_PRINT
+  code->Print(std::cout);
+#endif
+  F3 f = FUNCTION_CAST<F3>(code->entry());
+  for (size_t i = 0; i < 128; ++i) {
+    int32_t r, x = rng->NextInt();
+    Object* dummy = CALL_GENERATED_CODE(f, &r, x, 0, 0, 0);
+    CHECK_EQ(static_cast<int32_t>(static_cast<int8_t>(x)), r);
+    USE(dummy);
+  }
+}
+
+
+TEST(sxtab) {
+  CcTest::InitializeVM();
+  Isolate* const isolate = CcTest::i_isolate();
+  HandleScope scope(isolate);
+  RandomNumberGenerator* const rng = isolate->random_number_generator();
+  Assembler assm(isolate, nullptr, 0);
+  __ sxtab(r1, r2, r1);
+  __ str(r1, MemOperand(r0));
+  __ bx(lr);
+  CodeDesc desc;
+  assm.GetCode(&desc);
+  Handle<Code> code = isolate->factory()->NewCode(
+      desc, Code::ComputeFlags(Code::STUB), Handle<Code>());
+#ifdef OBJECT_PRINT
+  code->Print(std::cout);
+#endif
+  F3 f = FUNCTION_CAST<F3>(code->entry());
+  for (size_t i = 0; i < 128; ++i) {
+    int32_t r, x = rng->NextInt(), y = rng->NextInt();
+    Object* dummy = CALL_GENERATED_CODE(f, &r, x, y, 0, 0);
+    CHECK_EQ(static_cast<int32_t>(static_cast<int8_t>(x)) + y, r);
+    USE(dummy);
+  }
+}
+
+
+TEST(sxth) {
+  CcTest::InitializeVM();
+  Isolate* const isolate = CcTest::i_isolate();
+  HandleScope scope(isolate);
+  RandomNumberGenerator* const rng = isolate->random_number_generator();
+  Assembler assm(isolate, nullptr, 0);
+  __ sxth(r1, r1);
+  __ str(r1, MemOperand(r0));
+  __ bx(lr);
+  CodeDesc desc;
+  assm.GetCode(&desc);
+  Handle<Code> code = isolate->factory()->NewCode(
+      desc, Code::ComputeFlags(Code::STUB), Handle<Code>());
+#ifdef OBJECT_PRINT
+  code->Print(std::cout);
+#endif
+  F3 f = FUNCTION_CAST<F3>(code->entry());
+  for (size_t i = 0; i < 128; ++i) {
+    int32_t r, x = rng->NextInt();
+    Object* dummy = CALL_GENERATED_CODE(f, &r, x, 0, 0, 0);
+    CHECK_EQ(static_cast<int32_t>(static_cast<int16_t>(x)), r);
+    USE(dummy);
+  }
+}
+
+
+TEST(sxtah) {
+  CcTest::InitializeVM();
+  Isolate* const isolate = CcTest::i_isolate();
+  HandleScope scope(isolate);
+  RandomNumberGenerator* const rng = isolate->random_number_generator();
+  Assembler assm(isolate, nullptr, 0);
+  __ sxtah(r1, r2, r1);
+  __ str(r1, MemOperand(r0));
+  __ bx(lr);
+  CodeDesc desc;
+  assm.GetCode(&desc);
+  Handle<Code> code = isolate->factory()->NewCode(
+      desc, Code::ComputeFlags(Code::STUB), Handle<Code>());
+#ifdef OBJECT_PRINT
+  code->Print(std::cout);
+#endif
+  F3 f = FUNCTION_CAST<F3>(code->entry());
+  for (size_t i = 0; i < 128; ++i) {
+    int32_t r, x = rng->NextInt(), y = rng->NextInt();
+    Object* dummy = CALL_GENERATED_CODE(f, &r, x, y, 0, 0);
+    CHECK_EQ(static_cast<int32_t>(static_cast<int16_t>(x)) + y, r);
+    USE(dummy);
+  }
+}
+
+
+TEST(uxtb) {
+  CcTest::InitializeVM();
+  Isolate* const isolate = CcTest::i_isolate();
+  HandleScope scope(isolate);
+  RandomNumberGenerator* const rng = isolate->random_number_generator();
+  Assembler assm(isolate, nullptr, 0);
+  __ uxtb(r1, r1);
+  __ str(r1, MemOperand(r0));
+  __ bx(lr);
+  CodeDesc desc;
+  assm.GetCode(&desc);
+  Handle<Code> code = isolate->factory()->NewCode(
+      desc, Code::ComputeFlags(Code::STUB), Handle<Code>());
+#ifdef OBJECT_PRINT
+  code->Print(std::cout);
+#endif
+  F3 f = FUNCTION_CAST<F3>(code->entry());
+  for (size_t i = 0; i < 128; ++i) {
+    int32_t r, x = rng->NextInt();
+    Object* dummy = CALL_GENERATED_CODE(f, &r, x, 0, 0, 0);
+    CHECK_EQ(static_cast<int32_t>(static_cast<uint8_t>(x)), r);
+    USE(dummy);
+  }
+}
+
+
+TEST(uxtab) {
+  CcTest::InitializeVM();
+  Isolate* const isolate = CcTest::i_isolate();
+  HandleScope scope(isolate);
+  RandomNumberGenerator* const rng = isolate->random_number_generator();
+  Assembler assm(isolate, nullptr, 0);
+  __ uxtab(r1, r2, r1);
+  __ str(r1, MemOperand(r0));
+  __ bx(lr);
+  CodeDesc desc;
+  assm.GetCode(&desc);
+  Handle<Code> code = isolate->factory()->NewCode(
+      desc, Code::ComputeFlags(Code::STUB), Handle<Code>());
+#ifdef OBJECT_PRINT
+  code->Print(std::cout);
+#endif
+  F3 f = FUNCTION_CAST<F3>(code->entry());
+  for (size_t i = 0; i < 128; ++i) {
+    int32_t r, x = rng->NextInt(), y = rng->NextInt();
+    Object* dummy = CALL_GENERATED_CODE(f, &r, x, y, 0, 0);
+    CHECK_EQ(static_cast<int32_t>(static_cast<uint8_t>(x)) + y, r);
+    USE(dummy);
+  }
+}
+
+
+TEST(uxth) {
+  CcTest::InitializeVM();
+  Isolate* const isolate = CcTest::i_isolate();
+  HandleScope scope(isolate);
+  RandomNumberGenerator* const rng = isolate->random_number_generator();
+  Assembler assm(isolate, nullptr, 0);
+  __ uxth(r1, r1);
+  __ str(r1, MemOperand(r0));
+  __ bx(lr);
+  CodeDesc desc;
+  assm.GetCode(&desc);
+  Handle<Code> code = isolate->factory()->NewCode(
+      desc, Code::ComputeFlags(Code::STUB), Handle<Code>());
+#ifdef OBJECT_PRINT
+  code->Print(std::cout);
+#endif
+  F3 f = FUNCTION_CAST<F3>(code->entry());
+  for (size_t i = 0; i < 128; ++i) {
+    int32_t r, x = rng->NextInt();
+    Object* dummy = CALL_GENERATED_CODE(f, &r, x, 0, 0, 0);
+    CHECK_EQ(static_cast<int32_t>(static_cast<uint16_t>(x)), r);
+    USE(dummy);
+  }
+}
+
+
+TEST(uxtah) {
+  CcTest::InitializeVM();
+  Isolate* const isolate = CcTest::i_isolate();
+  HandleScope scope(isolate);
+  RandomNumberGenerator* const rng = isolate->random_number_generator();
+  Assembler assm(isolate, nullptr, 0);
+  __ uxtah(r1, r2, r1);
+  __ str(r1, MemOperand(r0));
+  __ bx(lr);
+  CodeDesc desc;
+  assm.GetCode(&desc);
+  Handle<Code> code = isolate->factory()->NewCode(
+      desc, Code::ComputeFlags(Code::STUB), Handle<Code>());
+#ifdef OBJECT_PRINT
+  code->Print(std::cout);
+#endif
+  F3 f = FUNCTION_CAST<F3>(code->entry());
+  for (size_t i = 0; i < 128; ++i) {
+    int32_t r, x = rng->NextInt(), y = rng->NextInt();
+    Object* dummy = CALL_GENERATED_CODE(f, &r, x, y, 0, 0);
+    CHECK_EQ(static_cast<int32_t>(static_cast<uint16_t>(x)) + y, r);
+    USE(dummy);
+  }
+}
+
+
 TEST(code_relative_offset) {
   // Test extracting the offset of a label from the beginning of the code
   // in a register.
@@ -1565,4 +1884,100 @@
   CHECK_EQ(42, res);
 }
 
+
+TEST(ARMv8_vrintX) {
+  // Test the vrintX floating point instructions.
+  CcTest::InitializeVM();
+  Isolate* isolate = CcTest::i_isolate();
+  HandleScope scope(isolate);
+
+  typedef struct {
+    double input;
+    double ar;
+    double nr;
+    double mr;
+    double pr;
+    double zr;
+  } T;
+  T t;
+
+  // Create a function that accepts &t, and loads, manipulates, and stores
+  // the doubles and floats.
+  Assembler assm(isolate, NULL, 0);
+  Label L, C;
+
+
+  if (CpuFeatures::IsSupported(ARMv8)) {
+    CpuFeatureScope scope(&assm, ARMv8);
+
+    __ mov(ip, Operand(sp));
+    __ stm(db_w, sp, r4.bit() | fp.bit() | lr.bit());
+
+    __ mov(r4, Operand(r0));
+
+    // Test vrinta
+    __ vldr(d6, r4, OFFSET_OF(T, input));
+    __ vrinta(d5, d6);
+    __ vstr(d5, r4, OFFSET_OF(T, ar));
+
+    // Test vrintn
+    __ vldr(d6, r4, OFFSET_OF(T, input));
+    __ vrintn(d5, d6);
+    __ vstr(d5, r4, OFFSET_OF(T, nr));
+
+    // Test vrintp
+    __ vldr(d6, r4, OFFSET_OF(T, input));
+    __ vrintp(d5, d6);
+    __ vstr(d5, r4, OFFSET_OF(T, pr));
+
+    // Test vrintm
+    __ vldr(d6, r4, OFFSET_OF(T, input));
+    __ vrintm(d5, d6);
+    __ vstr(d5, r4, OFFSET_OF(T, mr));
+
+    // Test vrintz
+    __ vldr(d6, r4, OFFSET_OF(T, input));
+    __ vrintz(d5, d6);
+    __ vstr(d5, r4, OFFSET_OF(T, zr));
+
+    __ ldm(ia_w, sp, r4.bit() | fp.bit() | pc.bit());
+
+    CodeDesc desc;
+    assm.GetCode(&desc);
+    Handle<Code> code = isolate->factory()->NewCode(
+        desc, Code::ComputeFlags(Code::STUB), Handle<Code>());
+#ifdef DEBUG
+    OFStream os(stdout);
+    code->Print(os);
+#endif
+    F3 f = FUNCTION_CAST<F3>(code->entry());
+
+    Object* dummy = nullptr;
+    USE(dummy);
+
+#define CHECK_VRINT(input_val, ares, nres, mres, pres, zres) \
+  t.input = input_val;                                       \
+  dummy = CALL_GENERATED_CODE(f, &t, 0, 0, 0, 0);            \
+  CHECK_EQ(ares, t.ar);                                      \
+  CHECK_EQ(nres, t.nr);                                      \
+  CHECK_EQ(mres, t.mr);                                      \
+  CHECK_EQ(pres, t.pr);                                      \
+  CHECK_EQ(zres, t.zr);
+
+    CHECK_VRINT(-0.5, -1.0, -0.0, -1.0, -0.0, -0.0)
+    CHECK_VRINT(-0.6, -1.0, -1.0, -1.0, -0.0, -0.0)
+    CHECK_VRINT(-1.1, -1.0, -1.0, -2.0, -1.0, -1.0)
+    CHECK_VRINT(0.5, 1.0, 0.0, 0.0, 1.0, 0.0)
+    CHECK_VRINT(0.6, 1.0, 1.0, 0.0, 1.0, 0.0)
+    CHECK_VRINT(1.1, 1.0, 1.0, 1.0, 2.0, 1.0)
+    double inf = std::numeric_limits<double>::infinity();
+    CHECK_VRINT(inf, inf, inf, inf, inf, inf)
+    CHECK_VRINT(-inf, -inf, -inf, -inf, -inf, -inf)
+    CHECK_VRINT(-0.0, -0.0, -0.0, -0.0, -0.0, -0.0)
+    double nan = std::numeric_limits<double>::quiet_NaN();
+    CHECK_VRINT(nan, nan, nan, nan, nan, nan)
+
+#undef CHECK_VRINT
+  }
+}
 #undef __
diff --git a/test/cctest/test-assembler-arm64.cc b/test/cctest/test-assembler-arm64.cc
index 587a4ce..108152e 100644
--- a/test/cctest/test-assembler-arm64.cc
+++ b/test/cctest/test-assembler-arm64.cc
@@ -6554,6 +6554,95 @@
 }
 
 
+TEST(frintp) {
+  INIT_V8();
+  SETUP();
+
+  START();
+  __ Fmov(s16, 1.0);
+  __ Fmov(s17, 1.1);
+  __ Fmov(s18, 1.5);
+  __ Fmov(s19, 1.9);
+  __ Fmov(s20, 2.5);
+  __ Fmov(s21, -1.5);
+  __ Fmov(s22, -2.5);
+  __ Fmov(s23, kFP32PositiveInfinity);
+  __ Fmov(s24, kFP32NegativeInfinity);
+  __ Fmov(s25, 0.0);
+  __ Fmov(s26, -0.0);
+  __ Fmov(s27, -0.2);
+
+  __ Frintp(s0, s16);
+  __ Frintp(s1, s17);
+  __ Frintp(s2, s18);
+  __ Frintp(s3, s19);
+  __ Frintp(s4, s20);
+  __ Frintp(s5, s21);
+  __ Frintp(s6, s22);
+  __ Frintp(s7, s23);
+  __ Frintp(s8, s24);
+  __ Frintp(s9, s25);
+  __ Frintp(s10, s26);
+  __ Frintp(s11, s27);
+
+  __ Fmov(d16, -0.5);
+  __ Fmov(d17, -0.8);
+  __ Fmov(d18, 1.5);
+  __ Fmov(d19, 1.9);
+  __ Fmov(d20, 2.5);
+  __ Fmov(d21, -1.5);
+  __ Fmov(d22, -2.5);
+  __ Fmov(d23, kFP32PositiveInfinity);
+  __ Fmov(d24, kFP32NegativeInfinity);
+  __ Fmov(d25, 0.0);
+  __ Fmov(d26, -0.0);
+  __ Fmov(d27, -0.2);
+
+  __ Frintp(d12, d16);
+  __ Frintp(d13, d17);
+  __ Frintp(d14, d18);
+  __ Frintp(d15, d19);
+  __ Frintp(d16, d20);
+  __ Frintp(d17, d21);
+  __ Frintp(d18, d22);
+  __ Frintp(d19, d23);
+  __ Frintp(d20, d24);
+  __ Frintp(d21, d25);
+  __ Frintp(d22, d26);
+  __ Frintp(d23, d27);
+  END();
+
+  RUN();
+
+  CHECK_EQUAL_FP32(1.0, s0);
+  CHECK_EQUAL_FP32(2.0, s1);
+  CHECK_EQUAL_FP32(2.0, s2);
+  CHECK_EQUAL_FP32(2.0, s3);
+  CHECK_EQUAL_FP32(3.0, s4);
+  CHECK_EQUAL_FP32(-1.0, s5);
+  CHECK_EQUAL_FP32(-2.0, s6);
+  CHECK_EQUAL_FP32(kFP32PositiveInfinity, s7);
+  CHECK_EQUAL_FP32(kFP32NegativeInfinity, s8);
+  CHECK_EQUAL_FP32(0.0, s9);
+  CHECK_EQUAL_FP32(-0.0, s10);
+  CHECK_EQUAL_FP32(-0.0, s11);
+  CHECK_EQUAL_FP64(-0.0, d12);
+  CHECK_EQUAL_FP64(-0.0, d13);
+  CHECK_EQUAL_FP64(2.0, d14);
+  CHECK_EQUAL_FP64(2.0, d15);
+  CHECK_EQUAL_FP64(3.0, d16);
+  CHECK_EQUAL_FP64(-1.0, d17);
+  CHECK_EQUAL_FP64(-2.0, d18);
+  CHECK_EQUAL_FP64(kFP64PositiveInfinity, d19);
+  CHECK_EQUAL_FP64(kFP64NegativeInfinity, d20);
+  CHECK_EQUAL_FP64(0.0, d21);
+  CHECK_EQUAL_FP64(-0.0, d22);
+  CHECK_EQUAL_FP64(-0.0, d23);
+
+  TEARDOWN();
+}
+
+
 TEST(frintz) {
   INIT_V8();
   SETUP();
diff --git a/test/cctest/test-assembler-ia32.cc b/test/cctest/test-assembler-ia32.cc
index e8c7f95..f59c3c4 100644
--- a/test/cctest/test-assembler-ia32.cc
+++ b/test/cctest/test-assembler-ia32.cc
@@ -170,11 +170,10 @@
   assm.GetCode(&desc);
   Handle<Code> code = isolate->factory()->NewCode(
       desc, Code::ComputeFlags(Code::STUB), Handle<Code>());
-  // don't print the code - our disassembler can't handle cvttss2si
-  // instead print bytes
-  Disassembler::Dump(stdout,
-                     code->instruction_start(),
-                     code->instruction_start() + code->instruction_size());
+#ifdef OBJECT_PRINT
+  OFStream os(stdout);
+  code->Print(os);
+#endif
   F3 f = FUNCTION_CAST<F3>(code->entry());
   int res = f(static_cast<float>(-3.1415));
   ::printf("f() = %d\n", res);
@@ -200,11 +199,10 @@
   assm.GetCode(&desc);
   Handle<Code> code = isolate->factory()->NewCode(
       desc, Code::ComputeFlags(Code::STUB), Handle<Code>());
-  // don't print the code - our disassembler can't handle cvttsd2si
-  // instead print bytes
-  Disassembler::Dump(stdout,
-                     code->instruction_start(),
-                     code->instruction_start() + code->instruction_size());
+#ifdef OBJECT_PRINT
+  OFStream os(stdout);
+  code->Print(os);
+#endif
   F4 f = FUNCTION_CAST<F4>(code->entry());
   int res = f(2.718281828);
   ::printf("f() = %d\n", res);
@@ -261,13 +259,9 @@
   assm.GetCode(&desc);
   Handle<Code> code = isolate->factory()->NewCode(
       desc, Code::ComputeFlags(Code::STUB), Handle<Code>());
-#ifdef DEBUG
-  ::printf("\n---\n");
-  // don't print the code - our disassembler can't handle SSE instructions
-  // instead print bytes
-  Disassembler::Dump(stdout,
-                     code->instruction_start(),
-                     code->instruction_start() + code->instruction_size());
+#ifdef OBJECT_PRINT
+  OFStream os(stdout);
+  code->Print(os);
 #endif
   F5 f = FUNCTION_CAST<F5>(code->entry());
   double res = f(2.2, 1.1);
@@ -595,4 +589,458 @@
 }
 
 
+typedef int (*F9)(double x, double y, double z);
+TEST(AssemblerX64FMA_sd) {
+  CcTest::InitializeVM();
+  if (!CpuFeatures::IsSupported(FMA3)) return;
+
+  Isolate* isolate = reinterpret_cast<Isolate*>(CcTest::isolate());
+  HandleScope scope(isolate);
+  v8::internal::byte buffer[1024];
+  MacroAssembler assm(isolate, buffer, sizeof buffer);
+  {
+    CpuFeatureScope fscope(&assm, FMA3);
+    Label exit;
+    __ movsd(xmm0, Operand(esp, 1 * kPointerSize));
+    __ movsd(xmm1, Operand(esp, 3 * kPointerSize));
+    __ movsd(xmm2, Operand(esp, 5 * kPointerSize));
+    // argument in xmm0, xmm1 and xmm2
+    // xmm0 * xmm1 + xmm2
+    __ movaps(xmm3, xmm0);
+    __ mulsd(xmm3, xmm1);
+    __ addsd(xmm3, xmm2);  // Expected result in xmm3
+
+    __ sub(esp, Immediate(kDoubleSize));  // For memory operand
+    // vfmadd132sd
+    __ mov(eax, Immediate(1));  // Test number
+    __ movaps(xmm4, xmm0);
+    __ vfmadd132sd(xmm4, xmm2, xmm1);
+    __ ucomisd(xmm4, xmm3);
+    __ j(not_equal, &exit);
+    // vfmadd213sd
+    __ inc(eax);
+    __ movaps(xmm4, xmm1);
+    __ vfmadd213sd(xmm4, xmm0, xmm2);
+    __ ucomisd(xmm4, xmm3);
+    __ j(not_equal, &exit);
+    // vfmadd231sd
+    __ inc(eax);
+    __ movaps(xmm4, xmm2);
+    __ vfmadd231sd(xmm4, xmm0, xmm1);
+    __ ucomisd(xmm4, xmm3);
+    __ j(not_equal, &exit);
+
+    // vfmadd132sd
+    __ inc(eax);
+    __ movaps(xmm4, xmm0);
+    __ movsd(Operand(esp, 0), xmm1);
+    __ vfmadd132sd(xmm4, xmm2, Operand(esp, 0));
+    __ ucomisd(xmm4, xmm3);
+    __ j(not_equal, &exit);
+    // vfmadd213sd
+    __ inc(eax);
+    __ movaps(xmm4, xmm1);
+    __ movsd(Operand(esp, 0), xmm2);
+    __ vfmadd213sd(xmm4, xmm0, Operand(esp, 0));
+    __ ucomisd(xmm4, xmm3);
+    __ j(not_equal, &exit);
+    // vfmadd231sd
+    __ inc(eax);
+    __ movaps(xmm4, xmm2);
+    __ movsd(Operand(esp, 0), xmm1);
+    __ vfmadd231sd(xmm4, xmm0, Operand(esp, 0));
+    __ ucomisd(xmm4, xmm3);
+    __ j(not_equal, &exit);
+
+    // xmm0 * xmm1 - xmm2
+    __ movaps(xmm3, xmm0);
+    __ mulsd(xmm3, xmm1);
+    __ subsd(xmm3, xmm2);  // Expected result in xmm3
+
+    // vfmsub132sd
+    __ inc(eax);
+    __ movaps(xmm4, xmm0);
+    __ vfmsub132sd(xmm4, xmm2, xmm1);
+    __ ucomisd(xmm4, xmm3);
+    __ j(not_equal, &exit);
+    // vfmadd213sd
+    __ inc(eax);
+    __ movaps(xmm4, xmm1);
+    __ vfmsub213sd(xmm4, xmm0, xmm2);
+    __ ucomisd(xmm4, xmm3);
+    __ j(not_equal, &exit);
+    // vfmsub231sd
+    __ inc(eax);
+    __ movaps(xmm4, xmm2);
+    __ vfmsub231sd(xmm4, xmm0, xmm1);
+    __ ucomisd(xmm4, xmm3);
+    __ j(not_equal, &exit);
+
+    // vfmsub132sd
+    __ inc(eax);
+    __ movaps(xmm4, xmm0);
+    __ movsd(Operand(esp, 0), xmm1);
+    __ vfmsub132sd(xmm4, xmm2, Operand(esp, 0));
+    __ ucomisd(xmm4, xmm3);
+    __ j(not_equal, &exit);
+    // vfmsub213sd
+    __ inc(eax);
+    __ movaps(xmm4, xmm1);
+    __ movsd(Operand(esp, 0), xmm2);
+    __ vfmsub213sd(xmm4, xmm0, Operand(esp, 0));
+    __ ucomisd(xmm4, xmm3);
+    __ j(not_equal, &exit);
+    // vfmsub231sd
+    __ inc(eax);
+    __ movaps(xmm4, xmm2);
+    __ movsd(Operand(esp, 0), xmm1);
+    __ vfmsub231sd(xmm4, xmm0, Operand(esp, 0));
+    __ ucomisd(xmm4, xmm3);
+    __ j(not_equal, &exit);
+
+
+    // - xmm0 * xmm1 + xmm2
+    __ movaps(xmm3, xmm0);
+    __ mulsd(xmm3, xmm1);
+    __ Move(xmm4, (uint64_t)1 << 63);
+    __ xorpd(xmm3, xmm4);
+    __ addsd(xmm3, xmm2);  // Expected result in xmm3
+
+    // vfnmadd132sd
+    __ inc(eax);
+    __ movaps(xmm4, xmm0);
+    __ vfnmadd132sd(xmm4, xmm2, xmm1);
+    __ ucomisd(xmm4, xmm3);
+    __ j(not_equal, &exit);
+    // vfmadd213sd
+    __ inc(eax);
+    __ movaps(xmm4, xmm1);
+    __ vfnmadd213sd(xmm4, xmm0, xmm2);
+    __ ucomisd(xmm4, xmm3);
+    __ j(not_equal, &exit);
+    // vfnmadd231sd
+    __ inc(eax);
+    __ movaps(xmm4, xmm2);
+    __ vfnmadd231sd(xmm4, xmm0, xmm1);
+    __ ucomisd(xmm4, xmm3);
+    __ j(not_equal, &exit);
+
+    // vfnmadd132sd
+    __ inc(eax);
+    __ movaps(xmm4, xmm0);
+    __ movsd(Operand(esp, 0), xmm1);
+    __ vfnmadd132sd(xmm4, xmm2, Operand(esp, 0));
+    __ ucomisd(xmm4, xmm3);
+    __ j(not_equal, &exit);
+    // vfnmadd213sd
+    __ inc(eax);
+    __ movaps(xmm4, xmm1);
+    __ movsd(Operand(esp, 0), xmm2);
+    __ vfnmadd213sd(xmm4, xmm0, Operand(esp, 0));
+    __ ucomisd(xmm4, xmm3);
+    __ j(not_equal, &exit);
+    // vfnmadd231sd
+    __ inc(eax);
+    __ movaps(xmm4, xmm2);
+    __ movsd(Operand(esp, 0), xmm1);
+    __ vfnmadd231sd(xmm4, xmm0, Operand(esp, 0));
+    __ ucomisd(xmm4, xmm3);
+    __ j(not_equal, &exit);
+
+
+    // - xmm0 * xmm1 - xmm2
+    __ movaps(xmm3, xmm0);
+    __ mulsd(xmm3, xmm1);
+    __ Move(xmm4, (uint64_t)1 << 63);
+    __ xorpd(xmm3, xmm4);
+    __ subsd(xmm3, xmm2);  // Expected result in xmm3
+
+    // vfnmsub132sd
+    __ inc(eax);
+    __ movaps(xmm4, xmm0);
+    __ vfnmsub132sd(xmm4, xmm2, xmm1);
+    __ ucomisd(xmm4, xmm3);
+    __ j(not_equal, &exit);
+    // vfmsub213sd
+    __ inc(eax);
+    __ movaps(xmm4, xmm1);
+    __ vfnmsub213sd(xmm4, xmm0, xmm2);
+    __ ucomisd(xmm4, xmm3);
+    __ j(not_equal, &exit);
+    // vfnmsub231sd
+    __ inc(eax);
+    __ movaps(xmm4, xmm2);
+    __ vfnmsub231sd(xmm4, xmm0, xmm1);
+    __ ucomisd(xmm4, xmm3);
+    __ j(not_equal, &exit);
+
+    // vfnmsub132sd
+    __ inc(eax);
+    __ movaps(xmm4, xmm0);
+    __ movsd(Operand(esp, 0), xmm1);
+    __ vfnmsub132sd(xmm4, xmm2, Operand(esp, 0));
+    __ ucomisd(xmm4, xmm3);
+    __ j(not_equal, &exit);
+    // vfnmsub213sd
+    __ inc(eax);
+    __ movaps(xmm4, xmm1);
+    __ movsd(Operand(esp, 0), xmm2);
+    __ vfnmsub213sd(xmm4, xmm0, Operand(esp, 0));
+    __ ucomisd(xmm4, xmm3);
+    __ j(not_equal, &exit);
+    // vfnmsub231sd
+    __ inc(eax);
+    __ movaps(xmm4, xmm2);
+    __ movsd(Operand(esp, 0), xmm1);
+    __ vfnmsub231sd(xmm4, xmm0, Operand(esp, 0));
+    __ ucomisd(xmm4, xmm3);
+    __ j(not_equal, &exit);
+
+
+    __ xor_(eax, eax);
+    __ bind(&exit);
+    __ add(esp, Immediate(kDoubleSize));
+    __ ret(0);
+  }
+
+  CodeDesc desc;
+  assm.GetCode(&desc);
+  Handle<Code> code = isolate->factory()->NewCode(
+      desc, Code::ComputeFlags(Code::STUB), Handle<Code>());
+#ifdef OBJECT_PRINT
+  OFStream os(stdout);
+  code->Print(os);
+#endif
+
+  F9 f = FUNCTION_CAST<F9>(code->entry());
+  CHECK_EQ(0, f(0.000092662107262076, -2.460774966188315, -1.0958787393627414));
+}
+
+
+typedef int (*F10)(float x, float y, float z);
+TEST(AssemblerX64FMA_ss) {
+  CcTest::InitializeVM();
+  if (!CpuFeatures::IsSupported(FMA3)) return;
+
+  Isolate* isolate = reinterpret_cast<Isolate*>(CcTest::isolate());
+  HandleScope scope(isolate);
+  v8::internal::byte buffer[1024];
+  MacroAssembler assm(isolate, buffer, sizeof buffer);
+  {
+    CpuFeatureScope fscope(&assm, FMA3);
+    Label exit;
+    __ movss(xmm0, Operand(esp, 1 * kPointerSize));
+    __ movss(xmm1, Operand(esp, 2 * kPointerSize));
+    __ movss(xmm2, Operand(esp, 3 * kPointerSize));
+    // arguments in xmm0, xmm1 and xmm2
+    // xmm0 * xmm1 + xmm2
+    __ movaps(xmm3, xmm0);
+    __ mulss(xmm3, xmm1);
+    __ addss(xmm3, xmm2);  // Expected result in xmm3
+
+    __ sub(esp, Immediate(kDoubleSize));  // For memory operand
+    // vfmadd132ss
+    __ mov(eax, Immediate(1));  // Test number
+    __ movaps(xmm4, xmm0);
+    __ vfmadd132ss(xmm4, xmm2, xmm1);
+    __ ucomiss(xmm4, xmm3);
+    __ j(not_equal, &exit);
+    // vfmadd213ss
+    __ inc(eax);
+    __ movaps(xmm4, xmm1);
+    __ vfmadd213ss(xmm4, xmm0, xmm2);
+    __ ucomiss(xmm4, xmm3);
+    __ j(not_equal, &exit);
+    // vfmadd231ss
+    __ inc(eax);
+    __ movaps(xmm4, xmm2);
+    __ vfmadd231ss(xmm4, xmm0, xmm1);
+    __ ucomiss(xmm4, xmm3);
+    __ j(not_equal, &exit);
+
+    // vfmadd132ss
+    __ inc(eax);
+    __ movaps(xmm4, xmm0);
+    __ movss(Operand(esp, 0), xmm1);
+    __ vfmadd132ss(xmm4, xmm2, Operand(esp, 0));
+    __ ucomiss(xmm4, xmm3);
+    __ j(not_equal, &exit);
+    // vfmadd213ss
+    __ inc(eax);
+    __ movaps(xmm4, xmm1);
+    __ movss(Operand(esp, 0), xmm2);
+    __ vfmadd213ss(xmm4, xmm0, Operand(esp, 0));
+    __ ucomiss(xmm4, xmm3);
+    __ j(not_equal, &exit);
+    // vfmadd231ss
+    __ inc(eax);
+    __ movaps(xmm4, xmm2);
+    __ movss(Operand(esp, 0), xmm1);
+    __ vfmadd231ss(xmm4, xmm0, Operand(esp, 0));
+    __ ucomiss(xmm4, xmm3);
+    __ j(not_equal, &exit);
+
+    // xmm0 * xmm1 - xmm2
+    __ movaps(xmm3, xmm0);
+    __ mulss(xmm3, xmm1);
+    __ subss(xmm3, xmm2);  // Expected result in xmm3
+
+    // vfmsub132ss
+    __ inc(eax);
+    __ movaps(xmm4, xmm0);
+    __ vfmsub132ss(xmm4, xmm2, xmm1);
+    __ ucomiss(xmm4, xmm3);
+    __ j(not_equal, &exit);
+    // vfmadd213ss
+    __ inc(eax);
+    __ movaps(xmm4, xmm1);
+    __ vfmsub213ss(xmm4, xmm0, xmm2);
+    __ ucomiss(xmm4, xmm3);
+    __ j(not_equal, &exit);
+    // vfmsub231ss
+    __ inc(eax);
+    __ movaps(xmm4, xmm2);
+    __ vfmsub231ss(xmm4, xmm0, xmm1);
+    __ ucomiss(xmm4, xmm3);
+    __ j(not_equal, &exit);
+
+    // vfmsub132ss
+    __ inc(eax);
+    __ movaps(xmm4, xmm0);
+    __ movss(Operand(esp, 0), xmm1);
+    __ vfmsub132ss(xmm4, xmm2, Operand(esp, 0));
+    __ ucomiss(xmm4, xmm3);
+    __ j(not_equal, &exit);
+    // vfmsub213ss
+    __ inc(eax);
+    __ movaps(xmm4, xmm1);
+    __ movss(Operand(esp, 0), xmm2);
+    __ vfmsub213ss(xmm4, xmm0, Operand(esp, 0));
+    __ ucomiss(xmm4, xmm3);
+    __ j(not_equal, &exit);
+    // vfmsub231ss
+    __ inc(eax);
+    __ movaps(xmm4, xmm2);
+    __ movss(Operand(esp, 0), xmm1);
+    __ vfmsub231ss(xmm4, xmm0, Operand(esp, 0));
+    __ ucomiss(xmm4, xmm3);
+    __ j(not_equal, &exit);
+
+
+    // - xmm0 * xmm1 + xmm2
+    __ movaps(xmm3, xmm0);
+    __ mulss(xmm3, xmm1);
+    __ Move(xmm4, (uint32_t)1 << 31);
+    __ xorps(xmm3, xmm4);
+    __ addss(xmm3, xmm2);  // Expected result in xmm3
+
+    // vfnmadd132ss
+    __ inc(eax);
+    __ movaps(xmm4, xmm0);
+    __ vfnmadd132ss(xmm4, xmm2, xmm1);
+    __ ucomiss(xmm4, xmm3);
+    __ j(not_equal, &exit);
+    // vfmadd213ss
+    __ inc(eax);
+    __ movaps(xmm4, xmm1);
+    __ vfnmadd213ss(xmm4, xmm0, xmm2);
+    __ ucomiss(xmm4, xmm3);
+    __ j(not_equal, &exit);
+    // vfnmadd231ss
+    __ inc(eax);
+    __ movaps(xmm4, xmm2);
+    __ vfnmadd231ss(xmm4, xmm0, xmm1);
+    __ ucomiss(xmm4, xmm3);
+    __ j(not_equal, &exit);
+
+    // vfnmadd132ss
+    __ inc(eax);
+    __ movaps(xmm4, xmm0);
+    __ movss(Operand(esp, 0), xmm1);
+    __ vfnmadd132ss(xmm4, xmm2, Operand(esp, 0));
+    __ ucomiss(xmm4, xmm3);
+    __ j(not_equal, &exit);
+    // vfnmadd213ss
+    __ inc(eax);
+    __ movaps(xmm4, xmm1);
+    __ movss(Operand(esp, 0), xmm2);
+    __ vfnmadd213ss(xmm4, xmm0, Operand(esp, 0));
+    __ ucomiss(xmm4, xmm3);
+    __ j(not_equal, &exit);
+    // vfnmadd231ss
+    __ inc(eax);
+    __ movaps(xmm4, xmm2);
+    __ movss(Operand(esp, 0), xmm1);
+    __ vfnmadd231ss(xmm4, xmm0, Operand(esp, 0));
+    __ ucomiss(xmm4, xmm3);
+    __ j(not_equal, &exit);
+
+
+    // - xmm0 * xmm1 - xmm2
+    __ movaps(xmm3, xmm0);
+    __ mulss(xmm3, xmm1);
+    __ Move(xmm4, (uint32_t)1 << 31);
+    __ xorps(xmm3, xmm4);
+    __ subss(xmm3, xmm2);  // Expected result in xmm3
+
+    // vfnmsub132ss
+    __ inc(eax);
+    __ movaps(xmm4, xmm0);
+    __ vfnmsub132ss(xmm4, xmm2, xmm1);
+    __ ucomiss(xmm4, xmm3);
+    __ j(not_equal, &exit);
+    // vfmsub213ss
+    __ inc(eax);
+    __ movaps(xmm4, xmm1);
+    __ vfnmsub213ss(xmm4, xmm0, xmm2);
+    __ ucomiss(xmm4, xmm3);
+    __ j(not_equal, &exit);
+    // vfnmsub231ss
+    __ inc(eax);
+    __ movaps(xmm4, xmm2);
+    __ vfnmsub231ss(xmm4, xmm0, xmm1);
+    __ ucomiss(xmm4, xmm3);
+    __ j(not_equal, &exit);
+
+    // vfnmsub132ss
+    __ inc(eax);
+    __ movaps(xmm4, xmm0);
+    __ movss(Operand(esp, 0), xmm1);
+    __ vfnmsub132ss(xmm4, xmm2, Operand(esp, 0));
+    __ ucomiss(xmm4, xmm3);
+    __ j(not_equal, &exit);
+    // vfnmsub213ss
+    __ inc(eax);
+    __ movaps(xmm4, xmm1);
+    __ movss(Operand(esp, 0), xmm2);
+    __ vfnmsub213ss(xmm4, xmm0, Operand(esp, 0));
+    __ ucomiss(xmm4, xmm3);
+    __ j(not_equal, &exit);
+    // vfnmsub231ss
+    __ inc(eax);
+    __ movaps(xmm4, xmm2);
+    __ movss(Operand(esp, 0), xmm1);
+    __ vfnmsub231ss(xmm4, xmm0, Operand(esp, 0));
+    __ ucomiss(xmm4, xmm3);
+    __ j(not_equal, &exit);
+
+
+    __ xor_(eax, eax);
+    __ bind(&exit);
+    __ add(esp, Immediate(kDoubleSize));
+    __ ret(0);
+  }
+
+  CodeDesc desc;
+  assm.GetCode(&desc);
+  Handle<Code> code = isolate->factory()->NewCode(
+      desc, Code::ComputeFlags(Code::STUB), Handle<Code>());
+#ifdef OBJECT_PRINT
+  OFStream os(stdout);
+  code->Print(os);
+#endif
+
+  F10 f = FUNCTION_CAST<F10>(code->entry());
+  CHECK_EQ(0, f(9.26621069e-05f, -2.4607749f, -1.09587872f));
+}
 #undef __
diff --git a/test/cctest/test-assembler-x64.cc b/test/cctest/test-assembler-x64.cc
index 3d305b6..23d0be6 100644
--- a/test/cctest/test-assembler-x64.cc
+++ b/test/cctest/test-assembler-x64.cc
@@ -736,4 +736,454 @@
   F6 f = FUNCTION_CAST<F6>(code->entry());
   CHECK_EQ(2, f(1.0, 2.0));
 }
+
+
+typedef int (*F7)(double x, double y, double z);
+TEST(AssemblerX64FMA_sd) {
+  CcTest::InitializeVM();
+  if (!CpuFeatures::IsSupported(FMA3)) return;
+
+  Isolate* isolate = reinterpret_cast<Isolate*>(CcTest::isolate());
+  HandleScope scope(isolate);
+  v8::internal::byte buffer[1024];
+  MacroAssembler assm(isolate, buffer, sizeof buffer);
+  {
+    CpuFeatureScope fscope(&assm, FMA3);
+    Label exit;
+    // argument in xmm0, xmm1 and xmm2
+    // xmm0 * xmm1 + xmm2
+    __ movaps(xmm3, xmm0);
+    __ mulsd(xmm3, xmm1);
+    __ addsd(xmm3, xmm2);  // Expected result in xmm3
+
+    __ subq(rsp, Immediate(kDoubleSize));  // For memory operand
+    // vfmadd132sd
+    __ movl(rax, Immediate(1));  // Test number
+    __ movaps(xmm8, xmm0);
+    __ vfmadd132sd(xmm8, xmm2, xmm1);
+    __ ucomisd(xmm8, xmm3);
+    __ j(not_equal, &exit);
+    // vfmadd213sd
+    __ incq(rax);
+    __ movaps(xmm8, xmm1);
+    __ vfmadd213sd(xmm8, xmm0, xmm2);
+    __ ucomisd(xmm8, xmm3);
+    __ j(not_equal, &exit);
+    // vfmadd231sd
+    __ incq(rax);
+    __ movaps(xmm8, xmm2);
+    __ vfmadd231sd(xmm8, xmm0, xmm1);
+    __ ucomisd(xmm8, xmm3);
+    __ j(not_equal, &exit);
+
+    // vfmadd132sd
+    __ incq(rax);
+    __ movaps(xmm8, xmm0);
+    __ movsd(Operand(rsp, 0), xmm1);
+    __ vfmadd132sd(xmm8, xmm2, Operand(rsp, 0));
+    __ ucomisd(xmm8, xmm3);
+    __ j(not_equal, &exit);
+    // vfmadd213sd
+    __ incq(rax);
+    __ movaps(xmm8, xmm1);
+    __ movsd(Operand(rsp, 0), xmm2);
+    __ vfmadd213sd(xmm8, xmm0, Operand(rsp, 0));
+    __ ucomisd(xmm8, xmm3);
+    __ j(not_equal, &exit);
+    // vfmadd231sd
+    __ incq(rax);
+    __ movaps(xmm8, xmm2);
+    __ movsd(Operand(rsp, 0), xmm1);
+    __ vfmadd231sd(xmm8, xmm0, Operand(rsp, 0));
+    __ ucomisd(xmm8, xmm3);
+    __ j(not_equal, &exit);
+
+    // xmm0 * xmm1 - xmm2
+    __ movaps(xmm3, xmm0);
+    __ mulsd(xmm3, xmm1);
+    __ subsd(xmm3, xmm2);  // Expected result in xmm3
+
+    // vfmsub132sd
+    __ incq(rax);
+    __ movaps(xmm8, xmm0);
+    __ vfmsub132sd(xmm8, xmm2, xmm1);
+    __ ucomisd(xmm8, xmm3);
+    __ j(not_equal, &exit);
+    // vfmadd213sd
+    __ incq(rax);
+    __ movaps(xmm8, xmm1);
+    __ vfmsub213sd(xmm8, xmm0, xmm2);
+    __ ucomisd(xmm8, xmm3);
+    __ j(not_equal, &exit);
+    // vfmsub231sd
+    __ incq(rax);
+    __ movaps(xmm8, xmm2);
+    __ vfmsub231sd(xmm8, xmm0, xmm1);
+    __ ucomisd(xmm8, xmm3);
+    __ j(not_equal, &exit);
+
+    // vfmsub132sd
+    __ incq(rax);
+    __ movaps(xmm8, xmm0);
+    __ movsd(Operand(rsp, 0), xmm1);
+    __ vfmsub132sd(xmm8, xmm2, Operand(rsp, 0));
+    __ ucomisd(xmm8, xmm3);
+    __ j(not_equal, &exit);
+    // vfmsub213sd
+    __ incq(rax);
+    __ movaps(xmm8, xmm1);
+    __ movsd(Operand(rsp, 0), xmm2);
+    __ vfmsub213sd(xmm8, xmm0, Operand(rsp, 0));
+    __ ucomisd(xmm8, xmm3);
+    __ j(not_equal, &exit);
+    // vfmsub231sd
+    __ incq(rax);
+    __ movaps(xmm8, xmm2);
+    __ movsd(Operand(rsp, 0), xmm1);
+    __ vfmsub231sd(xmm8, xmm0, Operand(rsp, 0));
+    __ ucomisd(xmm8, xmm3);
+    __ j(not_equal, &exit);
+
+
+    // - xmm0 * xmm1 + xmm2
+    __ movaps(xmm3, xmm0);
+    __ mulsd(xmm3, xmm1);
+    __ Move(xmm4, (uint64_t)1 << 63);
+    __ xorpd(xmm3, xmm4);
+    __ addsd(xmm3, xmm2);  // Expected result in xmm3
+
+    // vfnmadd132sd
+    __ incq(rax);
+    __ movaps(xmm8, xmm0);
+    __ vfnmadd132sd(xmm8, xmm2, xmm1);
+    __ ucomisd(xmm8, xmm3);
+    __ j(not_equal, &exit);
+    // vfmadd213sd
+    __ incq(rax);
+    __ movaps(xmm8, xmm1);
+    __ vfnmadd213sd(xmm8, xmm0, xmm2);
+    __ ucomisd(xmm8, xmm3);
+    __ j(not_equal, &exit);
+    // vfnmadd231sd
+    __ incq(rax);
+    __ movaps(xmm8, xmm2);
+    __ vfnmadd231sd(xmm8, xmm0, xmm1);
+    __ ucomisd(xmm8, xmm3);
+    __ j(not_equal, &exit);
+
+    // vfnmadd132sd
+    __ incq(rax);
+    __ movaps(xmm8, xmm0);
+    __ movsd(Operand(rsp, 0), xmm1);
+    __ vfnmadd132sd(xmm8, xmm2, Operand(rsp, 0));
+    __ ucomisd(xmm8, xmm3);
+    __ j(not_equal, &exit);
+    // vfnmadd213sd
+    __ incq(rax);
+    __ movaps(xmm8, xmm1);
+    __ movsd(Operand(rsp, 0), xmm2);
+    __ vfnmadd213sd(xmm8, xmm0, Operand(rsp, 0));
+    __ ucomisd(xmm8, xmm3);
+    __ j(not_equal, &exit);
+    // vfnmadd231sd
+    __ incq(rax);
+    __ movaps(xmm8, xmm2);
+    __ movsd(Operand(rsp, 0), xmm1);
+    __ vfnmadd231sd(xmm8, xmm0, Operand(rsp, 0));
+    __ ucomisd(xmm8, xmm3);
+    __ j(not_equal, &exit);
+
+
+    // - xmm0 * xmm1 - xmm2
+    __ movaps(xmm3, xmm0);
+    __ mulsd(xmm3, xmm1);
+    __ Move(xmm4, (uint64_t)1 << 63);
+    __ xorpd(xmm3, xmm4);
+    __ subsd(xmm3, xmm2);  // Expected result in xmm3
+
+    // vfnmsub132sd
+    __ incq(rax);
+    __ movaps(xmm8, xmm0);
+    __ vfnmsub132sd(xmm8, xmm2, xmm1);
+    __ ucomisd(xmm8, xmm3);
+    __ j(not_equal, &exit);
+    // vfmsub213sd
+    __ incq(rax);
+    __ movaps(xmm8, xmm1);
+    __ vfnmsub213sd(xmm8, xmm0, xmm2);
+    __ ucomisd(xmm8, xmm3);
+    __ j(not_equal, &exit);
+    // vfnmsub231sd
+    __ incq(rax);
+    __ movaps(xmm8, xmm2);
+    __ vfnmsub231sd(xmm8, xmm0, xmm1);
+    __ ucomisd(xmm8, xmm3);
+    __ j(not_equal, &exit);
+
+    // vfnmsub132sd
+    __ incq(rax);
+    __ movaps(xmm8, xmm0);
+    __ movsd(Operand(rsp, 0), xmm1);
+    __ vfnmsub132sd(xmm8, xmm2, Operand(rsp, 0));
+    __ ucomisd(xmm8, xmm3);
+    __ j(not_equal, &exit);
+    // vfnmsub213sd
+    __ incq(rax);
+    __ movaps(xmm8, xmm1);
+    __ movsd(Operand(rsp, 0), xmm2);
+    __ vfnmsub213sd(xmm8, xmm0, Operand(rsp, 0));
+    __ ucomisd(xmm8, xmm3);
+    __ j(not_equal, &exit);
+    // vfnmsub231sd
+    __ incq(rax);
+    __ movaps(xmm8, xmm2);
+    __ movsd(Operand(rsp, 0), xmm1);
+    __ vfnmsub231sd(xmm8, xmm0, Operand(rsp, 0));
+    __ ucomisd(xmm8, xmm3);
+    __ j(not_equal, &exit);
+
+
+    __ xorl(rax, rax);
+    __ bind(&exit);
+    __ addq(rsp, Immediate(kDoubleSize));
+    __ ret(0);
+  }
+
+  CodeDesc desc;
+  assm.GetCode(&desc);
+  Handle<Code> code = isolate->factory()->NewCode(
+      desc, Code::ComputeFlags(Code::STUB), Handle<Code>());
+#ifdef OBJECT_PRINT
+  OFStream os(stdout);
+  code->Print(os);
+#endif
+
+  F7 f = FUNCTION_CAST<F7>(code->entry());
+  CHECK_EQ(0, f(0.000092662107262076, -2.460774966188315, -1.0958787393627414));
+}
+
+
+typedef int (*F8)(float x, float y, float z);
+TEST(AssemblerX64FMA_ss) {
+  CcTest::InitializeVM();
+  if (!CpuFeatures::IsSupported(FMA3)) return;
+
+  Isolate* isolate = reinterpret_cast<Isolate*>(CcTest::isolate());
+  HandleScope scope(isolate);
+  v8::internal::byte buffer[1024];
+  MacroAssembler assm(isolate, buffer, sizeof buffer);
+  {
+    CpuFeatureScope fscope(&assm, FMA3);
+    Label exit;
+    // arguments in xmm0, xmm1 and xmm2
+    // xmm0 * xmm1 + xmm2
+    __ movaps(xmm3, xmm0);
+    __ mulss(xmm3, xmm1);
+    __ addss(xmm3, xmm2);  // Expected result in xmm3
+
+    __ subq(rsp, Immediate(kDoubleSize));  // For memory operand
+    // vfmadd132ss
+    __ movl(rax, Immediate(1));  // Test number
+    __ movaps(xmm8, xmm0);
+    __ vfmadd132ss(xmm8, xmm2, xmm1);
+    __ ucomiss(xmm8, xmm3);
+    __ j(not_equal, &exit);
+    // vfmadd213ss
+    __ incq(rax);
+    __ movaps(xmm8, xmm1);
+    __ vfmadd213ss(xmm8, xmm0, xmm2);
+    __ ucomiss(xmm8, xmm3);
+    __ j(not_equal, &exit);
+    // vfmadd231ss
+    __ incq(rax);
+    __ movaps(xmm8, xmm2);
+    __ vfmadd231ss(xmm8, xmm0, xmm1);
+    __ ucomiss(xmm8, xmm3);
+    __ j(not_equal, &exit);
+
+    // vfmadd132ss
+    __ incq(rax);
+    __ movaps(xmm8, xmm0);
+    __ movss(Operand(rsp, 0), xmm1);
+    __ vfmadd132ss(xmm8, xmm2, Operand(rsp, 0));
+    __ ucomiss(xmm8, xmm3);
+    __ j(not_equal, &exit);
+    // vfmadd213ss
+    __ incq(rax);
+    __ movaps(xmm8, xmm1);
+    __ movss(Operand(rsp, 0), xmm2);
+    __ vfmadd213ss(xmm8, xmm0, Operand(rsp, 0));
+    __ ucomiss(xmm8, xmm3);
+    __ j(not_equal, &exit);
+    // vfmadd231ss
+    __ incq(rax);
+    __ movaps(xmm8, xmm2);
+    __ movss(Operand(rsp, 0), xmm1);
+    __ vfmadd231ss(xmm8, xmm0, Operand(rsp, 0));
+    __ ucomiss(xmm8, xmm3);
+    __ j(not_equal, &exit);
+
+    // xmm0 * xmm1 - xmm2
+    __ movaps(xmm3, xmm0);
+    __ mulss(xmm3, xmm1);
+    __ subss(xmm3, xmm2);  // Expected result in xmm3
+
+    // vfmsub132ss
+    __ incq(rax);
+    __ movaps(xmm8, xmm0);
+    __ vfmsub132ss(xmm8, xmm2, xmm1);
+    __ ucomiss(xmm8, xmm3);
+    __ j(not_equal, &exit);
+    // vfmadd213ss
+    __ incq(rax);
+    __ movaps(xmm8, xmm1);
+    __ vfmsub213ss(xmm8, xmm0, xmm2);
+    __ ucomiss(xmm8, xmm3);
+    __ j(not_equal, &exit);
+    // vfmsub231ss
+    __ incq(rax);
+    __ movaps(xmm8, xmm2);
+    __ vfmsub231ss(xmm8, xmm0, xmm1);
+    __ ucomiss(xmm8, xmm3);
+    __ j(not_equal, &exit);
+
+    // vfmsub132ss
+    __ incq(rax);
+    __ movaps(xmm8, xmm0);
+    __ movss(Operand(rsp, 0), xmm1);
+    __ vfmsub132ss(xmm8, xmm2, Operand(rsp, 0));
+    __ ucomiss(xmm8, xmm3);
+    __ j(not_equal, &exit);
+    // vfmsub213ss
+    __ incq(rax);
+    __ movaps(xmm8, xmm1);
+    __ movss(Operand(rsp, 0), xmm2);
+    __ vfmsub213ss(xmm8, xmm0, Operand(rsp, 0));
+    __ ucomiss(xmm8, xmm3);
+    __ j(not_equal, &exit);
+    // vfmsub231ss
+    __ incq(rax);
+    __ movaps(xmm8, xmm2);
+    __ movss(Operand(rsp, 0), xmm1);
+    __ vfmsub231ss(xmm8, xmm0, Operand(rsp, 0));
+    __ ucomiss(xmm8, xmm3);
+    __ j(not_equal, &exit);
+
+
+    // - xmm0 * xmm1 + xmm2
+    __ movaps(xmm3, xmm0);
+    __ mulss(xmm3, xmm1);
+    __ Move(xmm4, (uint32_t)1 << 31);
+    __ xorps(xmm3, xmm4);
+    __ addss(xmm3, xmm2);  // Expected result in xmm3
+
+    // vfnmadd132ss
+    __ incq(rax);
+    __ movaps(xmm8, xmm0);
+    __ vfnmadd132ss(xmm8, xmm2, xmm1);
+    __ ucomiss(xmm8, xmm3);
+    __ j(not_equal, &exit);
+    // vfmadd213ss
+    __ incq(rax);
+    __ movaps(xmm8, xmm1);
+    __ vfnmadd213ss(xmm8, xmm0, xmm2);
+    __ ucomiss(xmm8, xmm3);
+    __ j(not_equal, &exit);
+    // vfnmadd231ss
+    __ incq(rax);
+    __ movaps(xmm8, xmm2);
+    __ vfnmadd231ss(xmm8, xmm0, xmm1);
+    __ ucomiss(xmm8, xmm3);
+    __ j(not_equal, &exit);
+
+    // vfnmadd132ss
+    __ incq(rax);
+    __ movaps(xmm8, xmm0);
+    __ movss(Operand(rsp, 0), xmm1);
+    __ vfnmadd132ss(xmm8, xmm2, Operand(rsp, 0));
+    __ ucomiss(xmm8, xmm3);
+    __ j(not_equal, &exit);
+    // vfnmadd213ss
+    __ incq(rax);
+    __ movaps(xmm8, xmm1);
+    __ movss(Operand(rsp, 0), xmm2);
+    __ vfnmadd213ss(xmm8, xmm0, Operand(rsp, 0));
+    __ ucomiss(xmm8, xmm3);
+    __ j(not_equal, &exit);
+    // vfnmadd231ss
+    __ incq(rax);
+    __ movaps(xmm8, xmm2);
+    __ movss(Operand(rsp, 0), xmm1);
+    __ vfnmadd231ss(xmm8, xmm0, Operand(rsp, 0));
+    __ ucomiss(xmm8, xmm3);
+    __ j(not_equal, &exit);
+
+
+    // - xmm0 * xmm1 - xmm2
+    __ movaps(xmm3, xmm0);
+    __ mulss(xmm3, xmm1);
+    __ Move(xmm4, (uint32_t)1 << 31);
+    __ xorps(xmm3, xmm4);
+    __ subss(xmm3, xmm2);  // Expected result in xmm3
+
+    // vfnmsub132ss
+    __ incq(rax);
+    __ movaps(xmm8, xmm0);
+    __ vfnmsub132ss(xmm8, xmm2, xmm1);
+    __ ucomiss(xmm8, xmm3);
+    __ j(not_equal, &exit);
+    // vfmsub213ss
+    __ incq(rax);
+    __ movaps(xmm8, xmm1);
+    __ vfnmsub213ss(xmm8, xmm0, xmm2);
+    __ ucomiss(xmm8, xmm3);
+    __ j(not_equal, &exit);
+    // vfnmsub231ss
+    __ incq(rax);
+    __ movaps(xmm8, xmm2);
+    __ vfnmsub231ss(xmm8, xmm0, xmm1);
+    __ ucomiss(xmm8, xmm3);
+    __ j(not_equal, &exit);
+
+    // vfnmsub132ss
+    __ incq(rax);
+    __ movaps(xmm8, xmm0);
+    __ movss(Operand(rsp, 0), xmm1);
+    __ vfnmsub132ss(xmm8, xmm2, Operand(rsp, 0));
+    __ ucomiss(xmm8, xmm3);
+    __ j(not_equal, &exit);
+    // vfnmsub213ss
+    __ incq(rax);
+    __ movaps(xmm8, xmm1);
+    __ movss(Operand(rsp, 0), xmm2);
+    __ vfnmsub213ss(xmm8, xmm0, Operand(rsp, 0));
+    __ ucomiss(xmm8, xmm3);
+    __ j(not_equal, &exit);
+    // vfnmsub231ss
+    __ incq(rax);
+    __ movaps(xmm8, xmm2);
+    __ movss(Operand(rsp, 0), xmm1);
+    __ vfnmsub231ss(xmm8, xmm0, Operand(rsp, 0));
+    __ ucomiss(xmm8, xmm3);
+    __ j(not_equal, &exit);
+
+
+    __ xorl(rax, rax);
+    __ bind(&exit);
+    __ addq(rsp, Immediate(kDoubleSize));
+    __ ret(0);
+  }
+
+  CodeDesc desc;
+  assm.GetCode(&desc);
+  Handle<Code> code = isolate->factory()->NewCode(
+      desc, Code::ComputeFlags(Code::STUB), Handle<Code>());
+#ifdef OBJECT_PRINT
+  OFStream os(stdout);
+  code->Print(os);
+#endif
+
+  F8 f = FUNCTION_CAST<F8>(code->entry());
+  CHECK_EQ(0, f(9.26621069e-05f, -2.4607749f, -1.09587872f));
+}
 #undef __
diff --git a/test/cctest/test-ast.cc b/test/cctest/test-ast.cc
index 24819df..096d5c7 100644
--- a/test/cctest/test-ast.cc
+++ b/test/cctest/test-ast.cc
@@ -40,8 +40,8 @@
 
   Isolate* isolate = CcTest::i_isolate();
   Zone zone(isolate);
-  AstNode::IdGen id_gen;
-  AstNodeFactory<AstNullVisitor> factory(&zone, NULL, &id_gen);
+  AstValueFactory value_factory(&zone, 0);
+  AstNodeFactory factory(&value_factory);
   AstNode* node = factory.NewEmptyStatement(RelocInfo::kNoPosition);
   list->Add(node);
   CHECK_EQ(1, list->length());
diff --git a/test/cctest/test-dataflow.cc b/test/cctest/test-bit-vector.cc
similarity index 98%
rename from test/cctest/test-dataflow.cc
rename to test/cctest/test-bit-vector.cc
index 43d950d..ac00fab 100644
--- a/test/cctest/test-dataflow.cc
+++ b/test/cctest/test-bit-vector.cc
@@ -29,7 +29,7 @@
 
 #include "src/v8.h"
 
-#include "src/data-flow.h"
+#include "src/bit-vector.h"
 #include "test/cctest/cctest.h"
 
 using namespace v8::internal;
@@ -83,7 +83,7 @@
     BitVector v(15, &zone);
     v.Add(0);
     BitVector w(15, &zone);
-    w = v;
+    w.CopyFrom(v);
     CHECK(w.Contains(0));
     w.Add(1);
     BitVector u(w, &zone);
diff --git a/test/cctest/test-code-stubs-mips64.cc b/test/cctest/test-code-stubs-mips64.cc
index 025a8ba..1f7df38 100644
--- a/test/cctest/test-code-stubs-mips64.cc
+++ b/test/cctest/test-code-stubs-mips64.cc
@@ -104,7 +104,7 @@
   for (--reg_num; reg_num >= 2; --reg_num) {
     Register reg = Register::from_code(reg_num);
     if (!reg.is(destination_reg)) {
-      __ lw(at, MemOperand(sp, 0));
+      __ ld(at, MemOperand(sp, 0));
       __ Assert(eq, kRegisterWasClobbered, reg, Operand(at));
       __ Daddu(sp, sp, Operand(kPointerSize));
     }
diff --git a/test/cctest/test-compiler.cc b/test/cctest/test-compiler.cc
index 4d6e005..a05231e 100644
--- a/test/cctest/test-compiler.cc
+++ b/test/cctest/test-compiler.cc
@@ -306,12 +306,15 @@
   // We shouldn't have deoptimization support. We want to recompile and
   // verify that our feedback vector preserves information.
   CHECK(!f->shared()->has_deoptimization_support());
-  Handle<FixedArray> feedback_vector(f->shared()->feedback_vector());
+  Handle<TypeFeedbackVector> feedback_vector(f->shared()->feedback_vector());
 
   // Verify that we gathered feedback.
-  int expected_count = FLAG_vector_ics ? 2 : 1;
-  CHECK_EQ(expected_count, feedback_vector->length());
-  CHECK(feedback_vector->get(expected_count - 1)->IsJSFunction());
+  int expected_slots = 0;
+  int expected_ic_slots = 1;
+  CHECK_EQ(expected_slots, feedback_vector->Slots());
+  CHECK_EQ(expected_ic_slots, feedback_vector->ICSlots());
+  FeedbackVectorICSlot slot_for_a(0);
+  CHECK(feedback_vector->Get(slot_for_a)->IsJSFunction());
 
   CompileRun("%OptimizeFunctionOnNextCall(f); f(fun1);");
 
@@ -319,8 +322,7 @@
   // of the full code.
   CHECK(f->IsOptimized());
   CHECK(f->shared()->has_deoptimization_support());
-  CHECK(f->shared()->feedback_vector()->
-        get(expected_count - 1)->IsJSFunction());
+  CHECK(f->shared()->feedback_vector()->Get(slot_for_a)->IsJSFunction());
 }
 
 
@@ -346,16 +348,19 @@
           *v8::Handle<v8::Function>::Cast(
               CcTest::global()->Get(v8_str("morphing_call"))));
 
-  int expected_count = FLAG_vector_ics ? 2 : 1;
-  CHECK_EQ(expected_count, f->shared()->feedback_vector()->length());
-  // And yet it's not compiled.
+  // Not compiled, and so no feedback vector allocated yet.
   CHECK(!f->shared()->is_compiled());
+  CHECK_EQ(0, f->shared()->feedback_vector()->Slots());
+  CHECK_EQ(0, f->shared()->feedback_vector()->ICSlots());
 
   CompileRun("morphing_call();");
 
-  // The vector should have the same size despite the new scoping.
-  CHECK_EQ(expected_count, f->shared()->feedback_vector()->length());
+  // Now a feedback vector is allocated.
   CHECK(f->shared()->is_compiled());
+  int expected_slots = 0;
+  int expected_ic_slots = FLAG_vector_ics ? 2 : 1;
+  CHECK_EQ(expected_slots, f->shared()->feedback_vector()->Slots());
+  CHECK_EQ(expected_ic_slots, f->shared()->feedback_vector()->ICSlots());
 }
 
 
diff --git a/test/cctest/test-cpu-profiler.cc b/test/cctest/test-cpu-profiler.cc
index 8d429d2..0e2dd91 100644
--- a/test/cctest/test-cpu-profiler.cc
+++ b/test/cctest/test-cpu-profiler.cc
@@ -1064,6 +1064,104 @@
 }
 
 
+// This tests checks distribution of the samples through the source lines.
+TEST(TickLines) {
+  CcTest::InitializeVM();
+  LocalContext env;
+  i::FLAG_turbo_source_positions = true;
+  i::Isolate* isolate = CcTest::i_isolate();
+  i::Factory* factory = isolate->factory();
+  i::HandleScope scope(isolate);
+
+  i::EmbeddedVector<char, 512> script;
+
+  const char* func_name = "func";
+  i::SNPrintF(script,
+              "function %s() {\n"
+              "  var n = 0;\n"
+              "  var m = 100*100;\n"
+              "  while (m > 1) {\n"
+              "    m--;\n"
+              "    n += m * m * m;\n"
+              "  }\n"
+              "}\n"
+              "%s();\n",
+              func_name, func_name);
+
+  CompileRun(script.start());
+
+  i::Handle<i::JSFunction> func = v8::Utils::OpenHandle(
+      *v8::Local<v8::Function>::Cast((*env)->Global()->Get(v8_str(func_name))));
+  CHECK_NE(NULL, func->shared());
+  CHECK_NE(NULL, func->shared()->code());
+  i::Code* code = NULL;
+  if (func->code()->is_optimized_code()) {
+    code = func->code();
+  } else {
+    CHECK(func->shared()->code() == func->code() || !i::FLAG_crankshaft);
+    code = func->shared()->code();
+  }
+  CHECK_NE(NULL, code);
+  i::Address code_address = code->instruction_start();
+  CHECK_NE(NULL, code_address);
+
+  CpuProfilesCollection* profiles = new CpuProfilesCollection(isolate->heap());
+  profiles->StartProfiling("", false);
+  ProfileGenerator generator(profiles);
+  ProfilerEventsProcessor* processor = new ProfilerEventsProcessor(
+      &generator, NULL, v8::base::TimeDelta::FromMicroseconds(100));
+  processor->Start();
+  CpuProfiler profiler(isolate, profiles, &generator, processor);
+
+  // Enqueue code creation events.
+  i::Handle<i::String> str = factory->NewStringFromAsciiChecked(func_name);
+  int line = 1;
+  int column = 1;
+  profiler.CodeCreateEvent(i::Logger::FUNCTION_TAG, code, func->shared(), NULL,
+                           *str, line, column);
+
+  // Enqueue a tick event to enable code events processing.
+  EnqueueTickSampleEvent(processor, code_address);
+
+  processor->StopSynchronously();
+
+  CpuProfile* profile = profiles->StopProfiling("");
+  CHECK_NE(NULL, profile);
+
+  // Check the state of profile generator.
+  CodeEntry* func_entry = generator.code_map()->FindEntry(code_address);
+  CHECK_NE(NULL, func_entry);
+  CHECK_EQ(func_name, func_entry->name());
+  const i::JITLineInfoTable* line_info = func_entry->line_info();
+  CHECK_NE(NULL, line_info);
+  CHECK(!line_info->empty());
+
+  // Check the hit source lines using V8 Public APIs.
+  const i::ProfileTree* tree = profile->top_down();
+  ProfileNode* root = tree->root();
+  CHECK_NE(NULL, root);
+  ProfileNode* func_node = root->FindChild(func_entry);
+  CHECK_NE(NULL, func_node);
+
+  // Add 10 faked ticks to source line #5.
+  int hit_line = 5;
+  int hit_count = 10;
+  for (int i = 0; i < hit_count; i++) func_node->IncrementLineTicks(hit_line);
+
+  unsigned int line_count = func_node->GetHitLineCount();
+  CHECK_EQ(2, line_count);  // Expect two hit source lines - #1 and #5.
+  ScopedVector<v8::CpuProfileNode::LineTick> entries(line_count);
+  CHECK(func_node->GetLineTicks(&entries[0], line_count));
+  int value = 0;
+  for (int i = 0; i < entries.length(); i++)
+    if (entries[i].line == hit_line) {
+      value = entries[i].hit_count;
+      break;
+    }
+  CHECK_EQ(hit_count, value);
+}
+
+
 static const char* call_function_test_source = "function bar(iterations) {\n"
 "}\n"
 "function start(duration) {\n"
diff --git a/test/cctest/test-debug.cc b/test/cctest/test-debug.cc
index 2f0674a..c3c65fd 100644
--- a/test/cctest/test-debug.cc
+++ b/test/cctest/test-debug.cc
@@ -621,7 +621,7 @@
         last_function_hit[0] = '\0';
       } else {
         CHECK(result->IsString());
-        v8::Handle<v8::String> function_name(result->ToString());
+        v8::Handle<v8::String> function_name(result.As<v8::String>());
         function_name->WriteUtf8(last_function_hit);
       }
     }
@@ -656,7 +656,7 @@
         last_script_name_hit[0] = '\0';
       } else {
         CHECK(result->IsString());
-        v8::Handle<v8::String> script_name(result->ToString());
+        v8::Handle<v8::String> script_name(result.As<v8::String>());
         script_name->WriteUtf8(last_script_name_hit);
       }
     }
@@ -775,7 +775,7 @@
       v8::Handle<v8::Value> result =
           evaluate_check_function->Call(exec_state, argc, argv);
       if (!result->IsTrue()) {
-        v8::String::Utf8Value utf8(checks[i].expected->ToString());
+        v8::String::Utf8Value utf8(checks[i].expected);
         V8_Fatal(__FILE__, __LINE__, "%s != %s", checks[i].expr, *utf8);
       }
     }
@@ -849,7 +849,7 @@
     v8::Handle<v8::Value> result = frame_function_name->Call(exec_state,
                                                              argc, argv);
     CHECK(result->IsString());
-    v8::String::Utf8Value function_name(result->ToString());
+    v8::String::Utf8Value function_name(result->ToString(CcTest::isolate()));
     CHECK_EQ(1, StrLength(*function_name));
     CHECK_EQ((*function_name)[0],
               expected_step_sequence[break_point_hit_count]);
@@ -2860,7 +2860,7 @@
   foo->Call(env->Global(), kArgc, args);
 
   // With stepping all break locations are hit.
-  CHECK_EQ(35, break_point_hit_count);
+  CHECK_EQ(45, break_point_hit_count);
 
   v8::Debug::SetDebugEventListener(NULL);
   CheckDebuggerUnloaded();
@@ -2908,7 +2908,7 @@
   foo->Call(env->Global(), kArgc, args);
 
   // With stepping all break locations are hit.
-  CHECK_EQ(34, break_point_hit_count);
+  CHECK_EQ(44, break_point_hit_count);
 
   v8::Debug::SetDebugEventListener(NULL);
   CheckDebuggerUnloaded();
@@ -2952,7 +2952,7 @@
   foo->Call(env->Global(), 0, NULL);
 
   // With stepping all break locations are hit.
-  CHECK_EQ(55, break_point_hit_count);
+  CHECK_EQ(65, break_point_hit_count);
 
   v8::Debug::SetDebugEventListener(NULL);
   CheckDebuggerUnloaded();
@@ -2995,9 +2995,7 @@
 
 
 // Test of the stepping mechanism for named load in a loop.
-TEST(DebugStepNamedStoreLoop) {
-  DoDebugStepNamedStoreLoop(24);
-}
+TEST(DebugStepNamedStoreLoop) { DoDebugStepNamedStoreLoop(34); }
 
 
 // Test the stepping mechanism with different ICs.
@@ -3330,14 +3328,14 @@
   break_point_hit_count = 0;
   v8::Handle<v8::Value> argv_10[argc] = { v8::Number::New(isolate, 10) };
   foo->Call(env->Global(), argc, argv_10);
-  CHECK_EQ(23, break_point_hit_count);
+  CHECK_EQ(45, break_point_hit_count);
 
   // Looping 100 times.
   step_action = StepIn;
   break_point_hit_count = 0;
   v8::Handle<v8::Value> argv_100[argc] = { v8::Number::New(isolate, 100) };
   foo->Call(env->Global(), argc, argv_100);
-  CHECK_EQ(203, break_point_hit_count);
+  CHECK_EQ(405, break_point_hit_count);
 
   // Get rid of the debug event listener.
   v8::Debug::SetDebugEventListener(NULL);
@@ -3381,7 +3379,7 @@
   v8::Handle<v8::Value> argv_10[argc] = { v8::Number::New(isolate, 10) };
   result = foo->Call(env->Global(), argc, argv_10);
   CHECK_EQ(5, result->Int32Value());
-  CHECK_EQ(52, break_point_hit_count);
+  CHECK_EQ(62, break_point_hit_count);
 
   // Looping 100 times.
   step_action = StepIn;
@@ -3389,7 +3387,7 @@
   v8::Handle<v8::Value> argv_100[argc] = { v8::Number::New(isolate, 100) };
   result = foo->Call(env->Global(), argc, argv_100);
   CHECK_EQ(50, result->Int32Value());
-  CHECK_EQ(457, break_point_hit_count);
+  CHECK_EQ(557, break_point_hit_count);
 
   // Get rid of the debug event listener.
   v8::Debug::SetDebugEventListener(NULL);
@@ -3434,7 +3432,7 @@
   v8::Handle<v8::Value> argv_10[argc] = { v8::Number::New(isolate, 10) };
   result = foo->Call(env->Global(), argc, argv_10);
   CHECK_EQ(9, result->Int32Value());
-  CHECK_EQ(55, break_point_hit_count);
+  CHECK_EQ(64, break_point_hit_count);
 
   // Looping 100 times.
   step_action = StepIn;
@@ -3442,7 +3440,7 @@
   v8::Handle<v8::Value> argv_100[argc] = { v8::Number::New(isolate, 100) };
   result = foo->Call(env->Global(), argc, argv_100);
   CHECK_EQ(99, result->Int32Value());
-  CHECK_EQ(505, break_point_hit_count);
+  CHECK_EQ(604, break_point_hit_count);
 
   // Get rid of the debug event listener.
   v8::Debug::SetDebugEventListener(NULL);
@@ -3473,7 +3471,7 @@
   step_action = StepIn;
   break_point_hit_count = 0;
   foo->Call(env->Global(), 0, NULL);
-  CHECK_EQ(6, break_point_hit_count);
+  CHECK_EQ(8, break_point_hit_count);
 
   // Create a function for testing stepping. Run it to allow it to get
   // optimized.
@@ -3490,7 +3488,7 @@
   step_action = StepIn;
   break_point_hit_count = 0;
   foo->Call(env->Global(), 0, NULL);
-  CHECK_EQ(8, break_point_hit_count);
+  CHECK_EQ(10, break_point_hit_count);
 
   // Get rid of the debug event listener.
   v8::Debug::SetDebugEventListener(NULL);
@@ -4352,9 +4350,10 @@
 }
 
 
-static void NamedGetter(v8::Local<v8::String> name,
+static void NamedGetter(v8::Local<v8::Name> name,
                         const v8::PropertyCallbackInfo<v8::Value>& info) {
-  v8::String::Utf8Value n(name);
+  if (name->IsSymbol()) return;
+  v8::String::Utf8Value n(v8::Local<v8::String>::Cast(name));
   if (strcmp(*n, "a") == 0) {
     info.GetReturnValue().Set(v8::String::NewFromUtf8(info.GetIsolate(), "AA"));
     return;
@@ -4387,26 +4386,26 @@
 
   // Create object with named interceptor.
   v8::Handle<v8::ObjectTemplate> named = v8::ObjectTemplate::New(isolate);
-  named->SetNamedPropertyHandler(NamedGetter, NULL, NULL, NULL, NamedEnum);
+  named->SetHandler(v8::NamedPropertyHandlerConfiguration(
+      NamedGetter, NULL, NULL, NULL, NamedEnum));
   env->Global()->Set(
       v8::String::NewFromUtf8(isolate, "intercepted_named"),
       named->NewInstance());
 
   // Create object with indexed interceptor.
   v8::Handle<v8::ObjectTemplate> indexed = v8::ObjectTemplate::New(isolate);
-  indexed->SetIndexedPropertyHandler(IndexedGetter,
-                                     NULL,
-                                     NULL,
-                                     NULL,
-                                     IndexedEnum);
+  indexed->SetHandler(v8::IndexedPropertyHandlerConfiguration(
+      IndexedGetter, NULL, NULL, NULL, IndexedEnum));
   env->Global()->Set(
       v8::String::NewFromUtf8(isolate, "intercepted_indexed"),
       indexed->NewInstance());
 
   // Create object with both named and indexed interceptor.
   v8::Handle<v8::ObjectTemplate> both = v8::ObjectTemplate::New(isolate);
-  both->SetNamedPropertyHandler(NamedGetter, NULL, NULL, NULL, NamedEnum);
-  both->SetIndexedPropertyHandler(IndexedGetter, NULL, NULL, NULL, IndexedEnum);
+  both->SetHandler(v8::NamedPropertyHandlerConfiguration(
+      NamedGetter, NULL, NULL, NULL, NamedEnum));
+  both->SetHandler(v8::IndexedPropertyHandlerConfiguration(
+      IndexedGetter, NULL, NULL, NULL, IndexedEnum));
   env->Global()->Set(
       v8::String::NewFromUtf8(isolate, "intercepted_both"),
       both->NewInstance());
@@ -5264,6 +5263,7 @@
 
     CompileRun(source);
   }
+  threaded_debugging_barriers.barrier_4.Wait();
   isolate_->Dispose();
 }
 
@@ -5285,6 +5285,7 @@
   threaded_debugging_barriers.barrier_2.Wait();
   v8::Debug::SendCommand(isolate_, buffer, AsciiToUtf16(command_1, buffer));
   v8::Debug::SendCommand(isolate_, buffer, AsciiToUtf16(command_2, buffer));
+  threaded_debugging_barriers.barrier_4.Wait();
 }
 
 
@@ -5388,6 +5389,7 @@
     breakpoints_barriers->barrier_2.Wait();
     CompileRun(source_2);
   }
+  breakpoints_barriers->barrier_4.Wait();
   isolate_->Dispose();
 }
 
@@ -5503,6 +5505,7 @@
   CHECK_EQ(116, evaluate_int_result);
   // 9: Continue evaluation of source2, reach end.
   v8::Debug::SendCommand(isolate_, buffer, AsciiToUtf16(command_8, buffer));
+  breakpoints_barriers->barrier_4.Wait();
 }
 
 
@@ -6157,7 +6160,8 @@
         last_function_hit[0] = '\0';
       } else {
         CHECK(result->IsString());
-        v8::Handle<v8::String> function_name(result->ToString());
+        v8::Handle<v8::String> function_name(
+            result->ToString(CcTest::isolate()));
         function_name->WriteUtf8(last_function_hit);
       }
     }
@@ -7040,7 +7044,8 @@
       if (!result->IsUndefined()) {
         char fn[80];
         CHECK(result->IsString());
-        v8::Handle<v8::String> function_name(result->ToString());
+        v8::Handle<v8::String> function_name(
+            result->ToString(CcTest::isolate()));
         function_name->WriteUtf8(fn);
         if (strcmp(fn, "bar") == 0) {
           i::Deoptimizer::DeoptimizeAll(CcTest::i_isolate());
@@ -7105,12 +7110,12 @@
         v8::Handle<v8::Value> result =
             frame_function_name->Call(exec_state, argc, argv);
         CHECK(result->IsString());
-        v8::Handle<v8::String> function_name(result->ToString());
+        v8::Handle<v8::String> function_name(result->ToString(isolate));
         CHECK(function_name->Equals(v8::String::NewFromUtf8(isolate, "loop")));
         // Get the name of the first argument in frame i.
         result = frame_argument_name->Call(exec_state, argc, argv);
         CHECK(result->IsString());
-        v8::Handle<v8::String> argument_name(result->ToString());
+        v8::Handle<v8::String> argument_name(result->ToString(isolate));
         CHECK(argument_name->Equals(v8::String::NewFromUtf8(isolate, "count")));
         // Get the value of the first argument in frame i. If the
         // funtion is optimized the value will be undefined, otherwise
@@ -7123,7 +7128,7 @@
         // Get the name of the first local variable.
         result = frame_local_name->Call(exec_state, argc, argv);
         CHECK(result->IsString());
-        v8::Handle<v8::String> local_name(result->ToString());
+        v8::Handle<v8::String> local_name(result->ToString(isolate));
         CHECK(local_name->Equals(v8::String::NewFromUtf8(isolate, "local")));
         // Get the value of the first local variable. If the function
         // is optimized the value will be undefined, otherwise it will
@@ -7518,3 +7523,159 @@
   CompileRun("while (true);");
   CHECK(try_catch.HasTerminated());
 }
+
+
+static void DebugEventExpectNoException(
+    const v8::Debug::EventDetails& event_details) {
+  v8::DebugEvent event = event_details.GetEvent();
+  CHECK_NE(v8::Exception, event);
+}
+
+
+static void TryCatchWrappedThrowCallback(
+    const v8::FunctionCallbackInfo<v8::Value>& args) {
+  v8::TryCatch try_catch;
+  CompileRun("throw 'rejection';");
+  CHECK(try_catch.HasCaught());
+}
+
+
+TEST(DebugPromiseInterceptedByTryCatch) {
+  DebugLocalContext env;
+  v8::Isolate* isolate = env->GetIsolate();
+  v8::HandleScope scope(isolate);
+  v8::Debug::SetDebugEventListener(&DebugEventExpectNoException);
+  ChangeBreakOnException(false, true);
+
+  v8::Handle<v8::FunctionTemplate> fun =
+      v8::FunctionTemplate::New(isolate, TryCatchWrappedThrowCallback);
+  env->Global()->Set(v8_str("fun"), fun->GetFunction());
+
+  CompileRun("var p = new Promise(function(res, rej) { fun(); res(); });");
+  CompileRun(
+      "var r;"
+      "p.chain(function() { r = 'resolved'; },"
+      "        function() { r = 'rejected'; });");
+  CHECK(CompileRun("r")->Equals(v8_str("resolved")));
+}
+
+
+static int exception_event_counter = 0;
+
+
+static void DebugEventCountException(
+    const v8::Debug::EventDetails& event_details) {
+  v8::DebugEvent event = event_details.GetEvent();
+  if (event == v8::Exception) exception_event_counter++;
+}
+
+
+static void ThrowCallback(const v8::FunctionCallbackInfo<v8::Value>& args) {
+  CompileRun("throw 'rejection';");
+}
+
+
+TEST(DebugPromiseRejectedByCallback) {
+  DebugLocalContext env;
+  v8::Isolate* isolate = env->GetIsolate();
+  v8::HandleScope scope(isolate);
+  v8::Debug::SetDebugEventListener(&DebugEventCountException);
+  ChangeBreakOnException(false, true);
+  exception_event_counter = 0;
+
+  v8::Handle<v8::FunctionTemplate> fun =
+      v8::FunctionTemplate::New(isolate, ThrowCallback);
+  env->Global()->Set(v8_str("fun"), fun->GetFunction());
+
+  CompileRun("var p = new Promise(function(res, rej) { fun(); res(); });");
+  CompileRun(
+      "var r;"
+      "p.chain(function() { r = 'resolved'; },"
+      "        function(e) { r = 'rejected' + e; });");
+  CHECK(CompileRun("r")->Equals(v8_str("rejectedrejection")));
+  CHECK_EQ(1, exception_event_counter);
+}
+
+
+TEST(DebugBreakOnExceptionInObserveCallback) {
+  DebugLocalContext env;
+  v8::Isolate* isolate = env->GetIsolate();
+  v8::HandleScope scope(isolate);
+  v8::Debug::SetDebugEventListener(&DebugEventCountException);
+  // Break on uncaught exception
+  ChangeBreakOnException(false, true);
+  exception_event_counter = 0;
+
+  v8::Handle<v8::FunctionTemplate> fun =
+      v8::FunctionTemplate::New(isolate, ThrowCallback);
+  env->Global()->Set(v8_str("fun"), fun->GetFunction());
+
+  CompileRun(
+      "var obj = {};"
+      "var callbackRan = false;"
+      "Object.observe(obj, function() {"
+      "   callbackRan = true;"
+      "   throw Error('foo');"
+      "});"
+      "obj.prop = 1");
+  CHECK(CompileRun("callbackRan")->BooleanValue());
+  CHECK_EQ(1, exception_event_counter);
+}
+
+
+static void DebugHarmonyScopingListener(
+    const v8::Debug::EventDetails& event_details) {
+  v8::DebugEvent event = event_details.GetEvent();
+  if (event != v8::Break) return;
+
+  int break_id = CcTest::i_isolate()->debug()->break_id();
+
+  char script[128];
+  i::Vector<char> script_vector(script, sizeof(script));
+  SNPrintF(script_vector, "%%GetFrameCount(%d)", break_id);
+  ExpectInt32(script, 1);
+
+  SNPrintF(script_vector, "var frame = new FrameMirror(%d, 0);", break_id);
+  CompileRun(script);
+  ExpectInt32("frame.evaluate('x').value_", 1);
+  ExpectInt32("frame.evaluate('y').value_", 2);
+
+  CompileRun("var allScopes = frame.allScopes()");
+  ExpectInt32("allScopes.length", 2);
+
+  ExpectBoolean("allScopes[0].scopeType() === ScopeType.Script", true);
+
+  ExpectInt32("allScopes[0].scopeObject().value_.x", 1);
+
+  ExpectInt32("allScopes[0].scopeObject().value_.y", 2);
+
+  CompileRun("allScopes[0].setVariableValue('x', 5);");
+  CompileRun("allScopes[0].setVariableValue('y', 6);");
+  ExpectInt32("frame.evaluate('x + y').value_", 11);
+}
+
+
+TEST(DebugBreakInLexicalScopes) {
+  i::FLAG_harmony_scoping = true;
+  i::FLAG_allow_natives_syntax = true;
+
+  DebugLocalContext env;
+  v8::Isolate* isolate = env->GetIsolate();
+  v8::HandleScope scope(isolate);
+  v8::Debug::SetDebugEventListener(DebugHarmonyScopingListener);
+
+  CompileRun(
+      "'use strict';            \n"
+      "let x = 1;               \n");
+  ExpectInt32(
+      "'use strict';            \n"
+      "let y = 2;               \n"
+      "debugger;                \n"
+      "x * y",
+      30);
+  ExpectInt32(
+      "x = 1; y = 2; \n"
+      "debugger;"
+      "x * y",
+      30);
+}
diff --git a/test/cctest/test-decls.cc b/test/cctest/test-decls.cc
index 34f0b69..06afdd2 100644
--- a/test/cctest/test-decls.cc
+++ b/test/cctest/test-decls.cc
@@ -70,9 +70,9 @@
   int query_count() const { return query_count_; }
 
  protected:
-  virtual v8::Handle<Value> Get(Local<String> key);
-  virtual v8::Handle<Value> Set(Local<String> key, Local<Value> value);
-  virtual v8::Handle<Integer> Query(Local<String> key);
+  virtual v8::Handle<Value> Get(Local<Name> key);
+  virtual v8::Handle<Value> Set(Local<Name> key, Local<Value> value);
+  virtual v8::Handle<Integer> Query(Local<Name> key);
 
   void InitializeIfNeeded();
 
@@ -88,12 +88,11 @@
 
   // The handlers are called as static functions that forward
   // to the instance specific virtual methods.
-  static void HandleGet(Local<String> key,
+  static void HandleGet(Local<Name> key,
                         const v8::PropertyCallbackInfo<v8::Value>& info);
-  static void HandleSet(Local<String> key,
-                        Local<Value> value,
+  static void HandleSet(Local<Name> key, Local<Value> value,
                         const v8::PropertyCallbackInfo<v8::Value>& info);
-  static void HandleQuery(Local<String> key,
+  static void HandleQuery(Local<Name> key,
                           const v8::PropertyCallbackInfo<v8::Integer>& info);
 
   v8::Isolate* isolate() const { return CcTest::isolate(); }
@@ -122,11 +121,8 @@
   HandleScope scope(isolate);
   Local<FunctionTemplate> function = FunctionTemplate::New(isolate);
   Local<Value> data = External::New(CcTest::isolate(), this);
-  GetHolder(function)->SetNamedPropertyHandler(&HandleGet,
-                                               &HandleSet,
-                                               &HandleQuery,
-                                               0, 0,
-                                               data);
+  GetHolder(function)->SetHandler(v8::NamedPropertyHandlerConfiguration(
+      &HandleGet, &HandleSet, &HandleQuery, 0, 0, data));
   Local<Context> context = Context::New(isolate,
                                         0,
                                         function->InstanceTemplate(),
@@ -178,8 +174,7 @@
 
 
 void DeclarationContext::HandleGet(
-    Local<String> key,
-    const v8::PropertyCallbackInfo<v8::Value>& info) {
+    Local<Name> key, const v8::PropertyCallbackInfo<v8::Value>& info) {
   DeclarationContext* context = GetInstance(info.Data());
   context->get_count_++;
   info.GetReturnValue().Set(context->Get(key));
@@ -187,8 +182,7 @@
 
 
 void DeclarationContext::HandleSet(
-    Local<String> key,
-    Local<Value> value,
+    Local<Name> key, Local<Value> value,
     const v8::PropertyCallbackInfo<v8::Value>& info) {
   DeclarationContext* context = GetInstance(info.Data());
   context->set_count_++;
@@ -197,8 +191,7 @@
 
 
 void DeclarationContext::HandleQuery(
-    Local<String> key,
-    const v8::PropertyCallbackInfo<v8::Integer>& info) {
+    Local<Name> key, const v8::PropertyCallbackInfo<v8::Integer>& info) {
   DeclarationContext* context = GetInstance(info.Data());
   context->query_count_++;
   info.GetReturnValue().Set(context->Query(key));
@@ -211,18 +204,17 @@
 }
 
 
-v8::Handle<Value> DeclarationContext::Get(Local<String> key) {
+v8::Handle<Value> DeclarationContext::Get(Local<Name> key) {
   return v8::Handle<Value>();
 }
 
 
-v8::Handle<Value> DeclarationContext::Set(Local<String> key,
-                                          Local<Value> value) {
+v8::Handle<Value> DeclarationContext::Set(Local<Name> key, Local<Value> value) {
   return v8::Handle<Value>();
 }
 
 
-v8::Handle<Integer> DeclarationContext::Query(Local<String> key) {
+v8::Handle<Integer> DeclarationContext::Query(Local<Name> key) {
   return v8::Handle<Integer>();
 }
 
@@ -272,7 +264,7 @@
 
 class AbsentPropertyContext: public DeclarationContext {
  protected:
-  virtual v8::Handle<Integer> Query(Local<String> key) {
+  virtual v8::Handle<Integer> Query(Local<Name> key) {
     return v8::Handle<Integer>();
   }
 };
@@ -336,7 +328,7 @@
   AppearingPropertyContext() : state_(DECLARE) { }
 
  protected:
-  virtual v8::Handle<Integer> Query(Local<String> key) {
+  virtual v8::Handle<Integer> Query(Local<Name> key) {
     switch (state_) {
       case DECLARE:
         // Force declaration by returning that the
@@ -405,7 +397,7 @@
  public:
   ExistsInPrototypeContext() { InitializeIfNeeded(); }
  protected:
-  virtual v8::Handle<Integer> Query(Local<String> key) {
+  virtual v8::Handle<Integer> Query(Local<Name> key) {
     // Let it seem that the property exists in the prototype object.
     return Integer::New(isolate(), v8::None);
   }
@@ -464,7 +456,7 @@
 
 class AbsentInPrototypeContext: public DeclarationContext {
  protected:
-  virtual v8::Handle<Integer> Query(Local<String> key) {
+  virtual v8::Handle<Integer> Query(Local<Name> key) {
     // Let it seem that the property is absent in the prototype object.
     return Handle<Integer>();
   }
@@ -499,7 +491,7 @@
   }
 
  protected:
-  virtual v8::Handle<Integer> Query(Local<String> key) {
+  virtual v8::Handle<Integer> Query(Local<Name> key) {
     // Let it seem that the property exists in the hidden prototype object.
     return Integer::New(isolate(), v8::None);
   }
@@ -644,34 +636,212 @@
 }
 
 
-TEST(CrossScriptReferencesHarmony) {
+TEST(CrossScriptReferences_Simple) {
+  i::FLAG_harmony_scoping = true;
   i::FLAG_use_strict = true;
+
+  v8::Isolate* isolate = CcTest::isolate();
+  HandleScope scope(isolate);
+
+  {
+    SimpleContext context;
+    context.Check("let x = 1; x", EXPECT_RESULT, Number::New(isolate, 1));
+    context.Check("let x = 5; x", EXPECT_EXCEPTION);
+  }
+}
+
+
+TEST(CrossScriptReferences_Simple2) {
+  i::FLAG_harmony_scoping = true;
+  i::FLAG_use_strict = true;
+
+  v8::Isolate* isolate = CcTest::isolate();
+  HandleScope scope(isolate);
+
+  for (int k = 0; k < 100; k++) {
+    SimpleContext context;
+    bool cond = (k % 2) == 0;
+    if (cond) {
+      context.Check("let x = 1; x", EXPECT_RESULT, Number::New(isolate, 1));
+      context.Check("let z = 4; z", EXPECT_RESULT, Number::New(isolate, 4));
+    } else {
+      context.Check("let z = 1; z", EXPECT_RESULT, Number::New(isolate, 1));
+      context.Check("let x = 4; x", EXPECT_RESULT, Number::New(isolate, 4));
+    }
+    context.Check("let y = 2; x", EXPECT_RESULT,
+                  Number::New(isolate, cond ? 1 : 4));
+  }
+}
+
+
+TEST(CrossScriptReferencesHarmony) {
   i::FLAG_harmony_scoping = true;
   i::FLAG_harmony_modules = true;
 
   v8::Isolate* isolate = CcTest::isolate();
   HandleScope scope(isolate);
 
+  // Check that simple cross-script global scope access works.
   const char* decs[] = {
-    "var x = 1; x", "x", "this.x",
-    "function x() { return 1 }; x()", "x()", "this.x()",
-    "let x = 1; x", "x", "this.x",
-    "const x = 1; x", "x", "this.x",
-    "module x { export let a = 1 }; x.a", "x.a", "this.x.a",
+    "'use strict'; var x = 1; x", "x",
+    "'use strict'; function x() { return 1 }; x()", "x()",
+    "'use strict'; let x = 1; x", "x",
+    "'use strict'; const x = 1; x", "x",
+    "'use strict'; module x { export let a = 1 }; x.a", "x.a",
     NULL
   };
 
-  for (int i = 0; decs[i] != NULL; i += 3) {
+  for (int i = 0; decs[i] != NULL; i += 2) {
     SimpleContext context;
     context.Check(decs[i], EXPECT_RESULT, Number::New(isolate, 1));
     context.Check(decs[i+1], EXPECT_RESULT, Number::New(isolate, 1));
-    // TODO(rossberg): The current ES6 draft spec does not reflect lexical
-    // bindings on the global object. However, this will probably change, in
-    // which case we reactivate the following test.
-    if (i/3 < 2) {
-      context.Check(decs[i+2], EXPECT_RESULT, Number::New(isolate, 1));
-    }
   }
+
+  // Check that cross-script global scope access works with late declarations.
+  {
+    SimpleContext context;
+    context.Check("function d0() { return x0 }",  // dynamic lookup
+                  EXPECT_RESULT, Undefined(isolate));
+    context.Check("this.x0 = -1;"
+                  "d0()",
+                  EXPECT_RESULT, Number::New(isolate, -1));
+    context.Check("'use strict';"
+                  "function f0() { let y = 10; return x0 + y }"
+                  "function g0() { let y = 10; return eval('x0 + y') }"
+                  "function h0() { let y = 10; return (1,eval)('x0') + y }"
+                  "x0 + f0() + g0() + h0()",
+                  EXPECT_RESULT, Number::New(isolate, 26));
+
+    context.Check("'use strict';"
+                  "let x1 = 1;"
+                  "function f1() { let y = 10; return x1 + y }"
+                  "function g1() { let y = 10; return eval('x1 + y') }"
+                  "function h1() { let y = 10; return (1,eval)('x1') + y }"
+                  "function i1() { "
+                  "  let y = 10; return (typeof x2 === 'undefined' ? 0 : 2) + y"
+                  "}"
+                  "function j1() { let y = 10; return eval('x2 + y') }"
+                  "function k1() { let y = 10; return (1,eval)('x2') + y }"
+                  "function cl() { "
+                  "  let y = 10; "
+                  "  return { "
+                  "    f: function(){ return x1 + y },"
+                  "    g: function(){ return eval('x1 + y') },"
+                  "    h: function(){ return (1,eval)('x1') + y },"
+                  "    i: function(){"
+                  "      return (typeof x2 == 'undefined' ? 0 : 2) + y"
+                  "    },"
+                  "    j: function(){ return eval('x2 + y') },"
+                  "    k: function(){ return (1,eval)('x2') + y },"
+                  "  }"
+                  "}"
+                  "let o = cl();"
+                  "x1 + eval('x1') + (1,eval)('x1') + f1() + g1() + h1();",
+                  EXPECT_RESULT, Number::New(isolate, 36));
+    context.Check("x1 + eval('x1') + (1,eval)('x1') + f1() + g1() + h1();",
+                  EXPECT_RESULT, Number::New(isolate, 36));
+    context.Check("o.f() + o.g() + o.h();",
+                  EXPECT_RESULT, Number::New(isolate, 33));
+    context.Check("i1() + o.i();",
+                  EXPECT_RESULT, Number::New(isolate, 20));
+
+    context.Check("'use strict';"
+                  "let x2 = 2;"
+                  "function f2() { let y = 20; return x2 + y }"
+                  "function g2() { let y = 20; return eval('x2 + y') }"
+                  "function h2() { let y = 20; return (1,eval)('x2') + y }"
+                  "function i2() { let y = 20; return x1 + y }"
+                  "function j2() { let y = 20; return eval('x1 + y') }"
+                  "function k2() { let y = 20; return (1,eval)('x1') + y }"
+                  "x2 + eval('x2') + (1,eval)('x2') + f2() + g2() + h2();",
+                  EXPECT_RESULT, Number::New(isolate, 72));
+    context.Check("x1 + eval('x1') + (1,eval)('x1') + f1() + g1() + h1();",
+                  EXPECT_RESULT, Number::New(isolate, 36));
+    context.Check("i1() + j1() + k1();",
+                  EXPECT_RESULT, Number::New(isolate, 36));
+    context.Check("i2() + j2() + k2();",
+                  EXPECT_RESULT, Number::New(isolate, 63));
+    context.Check("o.f() + o.g() + o.h();",
+                  EXPECT_RESULT, Number::New(isolate, 33));
+    context.Check("o.i() + o.j() + o.k();",
+                  EXPECT_RESULT, Number::New(isolate, 36));
+    context.Check("i1() + o.i();",
+                  EXPECT_RESULT, Number::New(isolate, 24));
+
+    context.Check("'use strict';"
+                  "let x0 = 100;"
+                  "x0 + eval('x0') + (1,eval)('x0') + "
+                  "    d0() + f0() + g0() + h0();",
+                  EXPECT_RESULT, Number::New(isolate, 730));
+    context.Check("x0 + eval('x0') + (1,eval)('x0') + "
+                  "    d0() + f0() + g0() + h0();",
+                  EXPECT_RESULT, Number::New(isolate, 730));
+    context.Check("delete this.x0;"
+                  "x0 + eval('x0') + (1,eval)('x0') + "
+                  "    d0() + f0() + g0() + h0();",
+                  EXPECT_RESULT, Number::New(isolate, 730));
+    context.Check("this.x1 = 666;"
+                  "x1 + eval('x1') + (1,eval)('x1') + f1() + g1() + h1();",
+                  EXPECT_RESULT, Number::New(isolate, 36));
+    context.Check("delete this.x1;"
+                  "x1 + eval('x1') + (1,eval)('x1') + f1() + g1() + h1();",
+                  EXPECT_RESULT, Number::New(isolate, 36));
+  }
+
+  // Check that caching does respect scopes.
+  {
+    SimpleContext context;
+    const char* script1 = "(function(){ return y1 })()";
+    const char* script2 = "(function(){ return y2 })()";
+
+    context.Check(script1, EXPECT_EXCEPTION);
+    context.Check("this.y1 = 1; this.y2 = 2; 0;",
+                  EXPECT_RESULT, Number::New(isolate, 0));
+    context.Check(script1,
+                  EXPECT_RESULT, Number::New(isolate, 1));
+    context.Check("'use strict'; let y1 = 3; 0;",
+                  EXPECT_RESULT, Number::New(isolate, 0));
+    context.Check(script1,
+                  EXPECT_RESULT, Number::New(isolate, 3));
+    context.Check("y1 = 4;",
+                  EXPECT_RESULT, Number::New(isolate, 4));
+    context.Check(script1,
+                  EXPECT_RESULT, Number::New(isolate, 4));
+
+    context.Check(script2,
+                  EXPECT_RESULT, Number::New(isolate, 2));
+    context.Check("'use strict'; let y2 = 5; 0;",
+                  EXPECT_RESULT, Number::New(isolate, 0));
+    context.Check(script1,
+                  EXPECT_RESULT, Number::New(isolate, 4));
+    context.Check(script2,
+                  EXPECT_RESULT, Number::New(isolate, 5));
+  }
+}
+
+
+TEST(GlobalLexicalOSR) {
+  i::FLAG_use_strict = true;
+  i::FLAG_harmony_scoping = true;
+  i::FLAG_harmony_modules = true;
+
+  v8::Isolate* isolate = CcTest::isolate();
+  HandleScope scope(isolate);
+  SimpleContext context;
+
+  context.Check("'use strict';"
+                "let x = 1; x;",
+                EXPECT_RESULT, Number::New(isolate, 1));
+  context.Check("'use strict';"
+                "let y = 2*x;"
+                "++x;"
+                "let z = 0;"
+                "const limit = 100000;"
+                "for (var i = 0; i < limit; ++i) {"
+                "  z += x + y;"
+                "}"
+                "z;",
+                EXPECT_RESULT, Number::New(isolate, 400000));
 }
 
 
@@ -704,12 +874,280 @@
       SimpleContext context;
       context.Check(firsts[i], EXPECT_RESULT,
                     Number::New(CcTest::isolate(), 1));
-      // TODO(rossberg): All tests should actually be errors in Harmony,
-      // but we currently do not detect the cases where the first declaration
-      // is not lexical.
-      context.Check(seconds[j],
-                    i < 2 ? EXPECT_RESULT : EXPECT_ERROR,
-                    Number::New(CcTest::isolate(), 2));
+      bool success_case = i < 2 && j < 2;
+      Local<Value> success_result;
+      if (success_case) success_result = Number::New(CcTest::isolate(), 2);
+
+      context.Check(seconds[j], success_case ? EXPECT_RESULT : EXPECT_EXCEPTION,
+                    success_result);
     }
   }
 }
+
+
+TEST(CrossScriptDynamicLookup) {
+  i::FLAG_harmony_scoping = true;
+
+  HandleScope handle_scope(CcTest::isolate());
+
+  {
+    SimpleContext context;
+    Local<String> undefined_string = String::NewFromUtf8(
+        CcTest::isolate(), "undefined", String::kInternalizedString);
+    Local<String> number_string = String::NewFromUtf8(
+        CcTest::isolate(), "number", String::kInternalizedString);
+
+    context.Check(
+        "function f(o) { with(o) { return x; } }"
+        "function g(o) { with(o) { x = 15; } }"
+        "function h(o) { with(o) { return typeof x; } }",
+        EXPECT_RESULT, Undefined(CcTest::isolate()));
+    context.Check("h({})", EXPECT_RESULT, undefined_string);
+    context.Check(
+        "'use strict';"
+        "let x = 1;"
+        "f({})",
+        EXPECT_RESULT, Number::New(CcTest::isolate(), 1));
+    context.Check(
+        "'use strict';"
+        "g({});0",
+        EXPECT_RESULT, Number::New(CcTest::isolate(), 0));
+    context.Check("f({})", EXPECT_RESULT, Number::New(CcTest::isolate(), 15));
+    context.Check("h({})", EXPECT_RESULT, number_string);
+  }
+}
+
+
+TEST(CrossScriptGlobal) {
+  i::FLAG_harmony_scoping = true;
+
+  HandleScope handle_scope(CcTest::isolate());
+  {
+    SimpleContext context;
+
+    context.Check(
+        "var global = this;"
+        "global.x = 255;"
+        "x",
+        EXPECT_RESULT, Number::New(CcTest::isolate(), 255));
+    context.Check(
+        "'use strict';"
+        "let x = 1;"
+        "global.x",
+        EXPECT_RESULT, Number::New(CcTest::isolate(), 255));
+    context.Check("global.x = 15; x", EXPECT_RESULT,
+                  Number::New(CcTest::isolate(), 1));
+    context.Check("x = 221; global.x", EXPECT_RESULT,
+                  Number::New(CcTest::isolate(), 15));
+    context.Check(
+        "z = 15;"
+        "function f() { return z; };"
+        "for (var k = 0; k < 3; k++) { f(); }"
+        "f()",
+        EXPECT_RESULT, Number::New(CcTest::isolate(), 15));
+    context.Check(
+        "'use strict';"
+        "let z = 5; f()",
+        EXPECT_RESULT, Number::New(CcTest::isolate(), 5));
+    context.Check(
+        "function f() { konst = 10; return konst; };"
+        "f()",
+        EXPECT_RESULT, Number::New(CcTest::isolate(), 10));
+    context.Check(
+        "'use strict';"
+        "const konst = 255;"
+        "f()",
+        EXPECT_EXCEPTION);
+  }
+}
+
+
+TEST(CrossScriptStaticLookupUndeclared) {
+  i::FLAG_harmony_scoping = true;
+
+  HandleScope handle_scope(CcTest::isolate());
+
+  {
+    SimpleContext context;
+    Local<String> undefined_string = String::NewFromUtf8(
+        CcTest::isolate(), "undefined", String::kInternalizedString);
+    Local<String> number_string = String::NewFromUtf8(
+        CcTest::isolate(), "number", String::kInternalizedString);
+
+    context.Check(
+        "function f(o) { return x; }"
+        "function g(v) { x = v; }"
+        "function h(o) { return typeof x; }",
+        EXPECT_RESULT, Undefined(CcTest::isolate()));
+    context.Check("h({})", EXPECT_RESULT, undefined_string);
+    context.Check(
+        "'use strict';"
+        "let x = 1;"
+        "f({})",
+        EXPECT_RESULT, Number::New(CcTest::isolate(), 1));
+    context.Check(
+        "'use strict';"
+        "g(15);x",
+        EXPECT_RESULT, Number::New(CcTest::isolate(), 15));
+    context.Check("h({})", EXPECT_RESULT, number_string);
+    context.Check("f({})", EXPECT_RESULT, Number::New(CcTest::isolate(), 15));
+    context.Check("h({})", EXPECT_RESULT, number_string);
+  }
+}
+
+
+TEST(CrossScriptLoadICs) {
+  i::FLAG_harmony_scoping = true;
+  i::FLAG_allow_natives_syntax = true;
+
+  HandleScope handle_scope(CcTest::isolate());
+
+  {
+    SimpleContext context;
+    context.Check(
+        "x = 15;"
+        "function f() { return x; }"
+        "function g() { return x; }"
+        "f()",
+        EXPECT_RESULT, Number::New(CcTest::isolate(), 15));
+    context.Check(
+        "'use strict';"
+        "let x = 5;"
+        "f()",
+        EXPECT_RESULT, Number::New(CcTest::isolate(), 5));
+    for (int k = 0; k < 3; k++) {
+      context.Check("g()", EXPECT_RESULT, Number::New(CcTest::isolate(), 5));
+    }
+    for (int k = 0; k < 3; k++) {
+      context.Check("f()", EXPECT_RESULT, Number::New(CcTest::isolate(), 5));
+    }
+    context.Check("%OptimizeFunctionOnNextCall(g); g()", EXPECT_RESULT,
+                  Number::New(CcTest::isolate(), 5));
+    context.Check("%OptimizeFunctionOnNextCall(f); f()", EXPECT_RESULT,
+                  Number::New(CcTest::isolate(), 5));
+  }
+  {
+    SimpleContext context;
+    context.Check(
+        "x = 15;"
+        "function f() { return x; }"
+        "f()",
+        EXPECT_RESULT, Number::New(CcTest::isolate(), 15));
+    for (int k = 0; k < 3; k++) {
+      context.Check("f()", EXPECT_RESULT, Number::New(CcTest::isolate(), 15));
+    }
+    context.Check("%OptimizeFunctionOnNextCall(f); f()", EXPECT_RESULT,
+                  Number::New(CcTest::isolate(), 15));
+    context.Check(
+        "'use strict';"
+        "let x = 5;"
+        "f()",
+        EXPECT_RESULT, Number::New(CcTest::isolate(), 5));
+    for (int k = 0; k < 3; k++) {
+      context.Check("f()", EXPECT_RESULT, Number::New(CcTest::isolate(), 5));
+    }
+    context.Check("%OptimizeFunctionOnNextCall(f); f()", EXPECT_RESULT,
+                  Number::New(CcTest::isolate(), 5));
+  }
+}
+
+
+TEST(CrossScriptStoreICs) {
+  i::FLAG_harmony_scoping = true;
+  i::FLAG_allow_natives_syntax = true;
+
+  HandleScope handle_scope(CcTest::isolate());
+
+  {
+    SimpleContext context;
+    context.Check(
+        "var global = this;"
+        "x = 15;"
+        "function f(v) { x = v; }"
+        "function g(v) { x = v; }"
+        "f(10); x",
+        EXPECT_RESULT, Number::New(CcTest::isolate(), 10));
+    context.Check(
+        "'use strict';"
+        "let x = 5;"
+        "f(7); x",
+        EXPECT_RESULT, Number::New(CcTest::isolate(), 7));
+    context.Check("global.x", EXPECT_RESULT,
+                  Number::New(CcTest::isolate(), 10));
+    for (int k = 0; k < 3; k++) {
+      context.Check("g(31); x", EXPECT_RESULT,
+                    Number::New(CcTest::isolate(), 31));
+    }
+    context.Check("global.x", EXPECT_RESULT,
+                  Number::New(CcTest::isolate(), 10));
+    for (int k = 0; k < 3; k++) {
+      context.Check("f(32); x", EXPECT_RESULT,
+                    Number::New(CcTest::isolate(), 32));
+    }
+    context.Check("global.x", EXPECT_RESULT,
+                  Number::New(CcTest::isolate(), 10));
+    context.Check("%OptimizeFunctionOnNextCall(g); g(18); x", EXPECT_RESULT,
+                  Number::New(CcTest::isolate(), 18));
+    context.Check("global.x", EXPECT_RESULT,
+                  Number::New(CcTest::isolate(), 10));
+    context.Check("%OptimizeFunctionOnNextCall(f); f(33); x", EXPECT_RESULT,
+                  Number::New(CcTest::isolate(), 33));
+    context.Check("global.x", EXPECT_RESULT,
+                  Number::New(CcTest::isolate(), 10));
+  }
+  {
+    SimpleContext context;
+    context.Check(
+        "var global = this;"
+        "x = 15;"
+        "function f(v) { x = v; }"
+        "f(10); x",
+        EXPECT_RESULT, Number::New(CcTest::isolate(), 10));
+    for (int k = 0; k < 3; k++) {
+      context.Check("f(18); x", EXPECT_RESULT,
+                    Number::New(CcTest::isolate(), 18));
+    }
+    context.Check("%OptimizeFunctionOnNextCall(f); f(20); x", EXPECT_RESULT,
+                  Number::New(CcTest::isolate(), 20));
+    context.Check(
+        "'use strict';"
+        "let x = 5;"
+        "f(8); x",
+        EXPECT_RESULT, Number::New(CcTest::isolate(), 8));
+    context.Check("global.x", EXPECT_RESULT,
+                  Number::New(CcTest::isolate(), 20));
+    for (int k = 0; k < 3; k++) {
+      context.Check("f(13); x", EXPECT_RESULT,
+                    Number::New(CcTest::isolate(), 13));
+    }
+    context.Check("global.x", EXPECT_RESULT,
+                  Number::New(CcTest::isolate(), 20));
+    context.Check("%OptimizeFunctionOnNextCall(f); f(41); x", EXPECT_RESULT,
+                  Number::New(CcTest::isolate(), 41));
+    context.Check("global.x", EXPECT_RESULT,
+                  Number::New(CcTest::isolate(), 20));
+  }
+}
+
+
+TEST(CrossScriptAssignmentToConst) {
+  i::FLAG_harmony_scoping = true;
+  i::FLAG_allow_natives_syntax = true;
+
+  HandleScope handle_scope(CcTest::isolate());
+
+  {
+    SimpleContext context;
+
+    context.Check("function f() { x = 27; }", EXPECT_RESULT,
+                  Undefined(CcTest::isolate()));
+    context.Check("'use strict';const x = 1; x", EXPECT_RESULT,
+                  Number::New(CcTest::isolate(), 1));
+    context.Check("f();", EXPECT_EXCEPTION);
+    context.Check("x", EXPECT_RESULT, Number::New(CcTest::isolate(), 1));
+    context.Check("f();", EXPECT_EXCEPTION);
+    context.Check("x", EXPECT_RESULT, Number::New(CcTest::isolate(), 1));
+    context.Check("%OptimizeFunctionOnNextCall(f);f();", EXPECT_EXCEPTION);
+    context.Check("x", EXPECT_RESULT, Number::New(CcTest::isolate(), 1));
+  }
+}
diff --git a/test/cctest/test-disasm-arm.cc b/test/cctest/test-disasm-arm.cc
index c1f6ce2..095c636 100644
--- a/test/cctest/test-disasm-arm.cc
+++ b/test/cctest/test-disasm-arm.cc
@@ -410,16 +410,40 @@
             "e6843895       pkhbt r3, r4, r5, lsl #17");
     COMPARE(pkhtb(r3, r4, Operand(r5, ASR, 17)),
             "e68438d5       pkhtb r3, r4, r5, asr #17");
-    COMPARE(uxtb(r9, Operand(r10, ROR, 0)),
-            "e6ef907a       uxtb r9, r10");
-    COMPARE(uxtb(r3, Operand(r4, ROR, 8)),
-            "e6ef3474       uxtb r3, r4, ror #8");
-    COMPARE(uxtab(r3, r4, Operand(r5, ROR, 8)),
-            "e6e43475       uxtab r3, r4, r5, ror #8");
-    COMPARE(uxtb16(r3, Operand(r4, ROR, 8)),
-            "e6cf3474       uxtb16 r3, r4, ror #8");
+
+    COMPARE(sxtb(r1, r7, 0, eq), "06af1077       sxtbeq r1, r7");
+    COMPARE(sxtb(r0, r0, 8, ne), "16af0470       sxtbne r0, r0, ror #8");
+    COMPARE(sxtb(r9, r10, 16), "e6af987a       sxtb r9, r10, ror #16");
+    COMPARE(sxtb(r4, r3, 24), "e6af4c73       sxtb r4, r3, ror #24");
+
+    COMPARE(sxtab(r3, r4, r5), "e6a43075       sxtab r3, r4, r5");
+
+    COMPARE(sxth(r5, r0), "e6bf5070       sxth r5, r0");
+    COMPARE(sxth(r5, r9, 8), "e6bf5479       sxth r5, r9, ror #8");
+    COMPARE(sxth(r5, r9, 16, hi), "86bf5879       sxthhi r5, r9, ror #16");
+    COMPARE(sxth(r8, r9, 24, cc), "36bf8c79       sxthcc r8, r9, ror #24");
+
+    COMPARE(sxtah(r3, r4, r5, 16), "e6b43875       sxtah r3, r4, r5, ror #16");
+
+    COMPARE(uxtb(r9, r10), "e6ef907a       uxtb r9, r10");
+    COMPARE(uxtb(r3, r4, 8), "e6ef3474       uxtb r3, r4, ror #8");
+
+    COMPARE(uxtab(r3, r4, r5, 8), "e6e43475       uxtab r3, r4, r5, ror #8");
+
+    COMPARE(uxtb16(r3, r4, 8), "e6cf3474       uxtb16 r3, r4, ror #8");
+
+    COMPARE(uxth(r9, r10), "e6ff907a       uxth r9, r10");
+    COMPARE(uxth(r3, r4, 8), "e6ff3474       uxth r3, r4, ror #8");
+
+    COMPARE(uxtah(r3, r4, r5, 24), "e6f43c75       uxtah r3, r4, r5, ror #24");
   }
 
+  COMPARE(smmla(r0, r1, r2, r3), "e7503211       smmla r0, r1, r2, r3");
+  COMPARE(smmla(r10, r9, r8, r7), "e75a7819       smmla r10, r9, r8, r7");
+
+  COMPARE(smmul(r0, r1, r2), "e750f211       smmul r0, r1, r2");
+  COMPARE(smmul(r8, r9, r10), "e758fa19       smmul r8, r9, r10");
+
   VERIFY_RUN();
 }
 
@@ -680,6 +704,30 @@
 }
 
 
+TEST(ARMv8_vrintX_disasm) {
+  SET_UP();
+
+  if (CpuFeatures::IsSupported(ARMv8)) {
+    COMPARE(vrinta(d0, d0), "feb80b40       vrinta.f64.f64 d0, d0");
+    COMPARE(vrinta(d2, d3), "feb82b43       vrinta.f64.f64 d2, d3");
+
+    COMPARE(vrintp(d0, d0), "feba0b40       vrintp.f64.f64 d0, d0");
+    COMPARE(vrintp(d2, d3), "feba2b43       vrintp.f64.f64 d2, d3");
+
+    COMPARE(vrintn(d0, d0), "feb90b40       vrintn.f64.f64 d0, d0");
+    COMPARE(vrintn(d2, d3), "feb92b43       vrintn.f64.f64 d2, d3");
+
+    COMPARE(vrintm(d0, d0), "febb0b40       vrintm.f64.f64 d0, d0");
+    COMPARE(vrintm(d2, d3), "febb2b43       vrintm.f64.f64 d2, d3");
+
+    COMPARE(vrintz(d0, d0), "eeb60bc0       vrintz.f64.f64 d0, d0");
+    COMPARE(vrintz(d2, d3, ne), "1eb62bc3       vrintzne.f64.f64 d2, d3");
+  }
+
+  VERIFY_RUN();
+}
+
+
 TEST(Neon) {
   SET_UP();
 
diff --git a/test/cctest/test-disasm-arm64.cc b/test/cctest/test-disasm-arm64.cc
index fb01347..208f1f5 100644
--- a/test/cctest/test-disasm-arm64.cc
+++ b/test/cctest/test-disasm-arm64.cc
@@ -1408,6 +1408,10 @@
   COMPARE(frintn(s31, s30), "frintn s31, s30");
   COMPARE(frintn(d12, d13), "frintn d12, d13");
   COMPARE(frintn(d31, d30), "frintn d31, d30");
+  COMPARE(frintp(s10, s11), "frintp s10, s11");
+  COMPARE(frintp(s31, s30), "frintp s31, s30");
+  COMPARE(frintp(d12, d13), "frintp d12, d13");
+  COMPARE(frintp(d31, d30), "frintp d31, d30");
   COMPARE(frintz(s10, s11), "frintz s10, s11");
   COMPARE(frintz(s31, s30), "frintz s31, s30");
   COMPARE(frintz(d12, d13), "frintz d12, d13");
diff --git a/test/cctest/test-disasm-ia32.cc b/test/cctest/test-disasm-ia32.cc
index 49088f6..a2eaa15 100644
--- a/test/cctest/test-disasm-ia32.cc
+++ b/test/cctest/test-disasm-ia32.cc
@@ -51,7 +51,7 @@
   CcTest::InitializeVM();
   Isolate* isolate = CcTest::i_isolate();
   HandleScope scope(isolate);
-  v8::internal::byte buffer[2048];
+  v8::internal::byte buffer[4096];
   Assembler assm(isolate, buffer, sizeof buffer);
   DummyStaticFunction(NULL);  // just bloody use it (DELETE; debugging)
 
@@ -201,6 +201,12 @@
   __ rcl(edx, 7);
   __ rcr(edx, 1);
   __ rcr(edx, 7);
+  __ ror(edx, 1);
+  __ ror(edx, 6);
+  __ ror_cl(edx);
+  __ ror(Operand(ebx, ecx, times_4, 10000), 1);
+  __ ror(Operand(ebx, ecx, times_4, 10000), 6);
+  __ ror_cl(Operand(ebx, ecx, times_4, 10000));
   __ sar(edx, 1);
   __ sar(edx, 6);
   __ sar_cl(edx);
@@ -383,6 +389,8 @@
     // Move operation
     __ movaps(xmm0, xmm1);
     __ shufps(xmm0, xmm0, 0x0);
+    __ cvtsd2ss(xmm0, xmm1);
+    __ cvtsd2ss(xmm0, Operand(ebx, ecx, times_4, 10000));
 
     // logic operation
     __ andps(xmm0, xmm1);
@@ -393,6 +401,14 @@
     __ xorps(xmm0, Operand(ebx, ecx, times_4, 10000));
 
     // Arithmetic operation
+    __ addss(xmm1, xmm0);
+    __ addss(xmm1, Operand(ebx, ecx, times_4, 10000));
+    __ mulss(xmm1, xmm0);
+    __ mulss(xmm1, Operand(ebx, ecx, times_4, 10000));
+    __ subss(xmm1, xmm0);
+    __ subss(xmm1, Operand(ebx, ecx, times_4, 10000));
+    __ divss(xmm1, xmm0);
+    __ divss(xmm1, Operand(ebx, ecx, times_4, 10000));
     __ addps(xmm1, xmm0);
     __ addps(xmm1, Operand(ebx, ecx, times_4, 10000));
     __ subps(xmm1, xmm0);
@@ -401,10 +417,15 @@
     __ mulps(xmm1, Operand(ebx, ecx, times_4, 10000));
     __ divps(xmm1, xmm0);
     __ divps(xmm1, Operand(ebx, ecx, times_4, 10000));
+
+    __ ucomiss(xmm0, xmm1);
+    __ ucomiss(xmm0, Operand(ebx, ecx, times_4, 10000));
   }
   {
     __ cvttss2si(edx, Operand(ebx, ecx, times_4, 10000));
     __ cvtsi2sd(xmm1, Operand(ebx, ecx, times_4, 10000));
+    __ cvtss2sd(xmm1, Operand(ebx, ecx, times_4, 10000));
+    __ cvtss2sd(xmm1, xmm0);
     __ movsd(xmm1, Operand(ebx, ecx, times_4, 10000));
     __ movsd(Operand(ebx, ecx, times_4, 10000), xmm1);
     // 128 bit move instructions.
@@ -414,10 +435,13 @@
     __ movdqu(Operand(ebx, ecx, times_4, 10000), xmm0);
 
     __ addsd(xmm1, xmm0);
+    __ addsd(xmm1, Operand(ebx, ecx, times_4, 10000));
     __ mulsd(xmm1, xmm0);
+    __ mulsd(xmm1, Operand(ebx, ecx, times_4, 10000));
     __ subsd(xmm1, xmm0);
     __ subsd(xmm1, Operand(ebx, ecx, times_4, 10000));
     __ divsd(xmm1, xmm0);
+    __ divsd(xmm1, Operand(ebx, ecx, times_4, 10000));
     __ ucomisd(xmm0, xmm1);
     __ cmpltsd(xmm0, xmm1);
 
@@ -458,6 +482,83 @@
     }
   }
 
+  // AVX instruction
+  {
+    if (CpuFeatures::IsSupported(AVX)) {
+      CpuFeatureScope scope(&assm, AVX);
+      __ vaddsd(xmm0, xmm1, xmm2);
+      __ vaddsd(xmm0, xmm1, Operand(ebx, ecx, times_4, 10000));
+      __ vmulsd(xmm0, xmm1, xmm2);
+      __ vmulsd(xmm0, xmm1, Operand(ebx, ecx, times_4, 10000));
+      __ vsubsd(xmm0, xmm1, xmm2);
+      __ vsubsd(xmm0, xmm1, Operand(ebx, ecx, times_4, 10000));
+      __ vdivsd(xmm0, xmm1, xmm2);
+      __ vdivsd(xmm0, xmm1, Operand(ebx, ecx, times_4, 10000));
+    }
+  }
+
+  // FMA3 instruction
+  {
+    if (CpuFeatures::IsSupported(FMA3)) {
+      CpuFeatureScope scope(&assm, FMA3);
+      __ vfmadd132sd(xmm0, xmm1, xmm2);
+      __ vfmadd132sd(xmm0, xmm1, Operand(ebx, ecx, times_4, 10000));
+      __ vfmadd213sd(xmm0, xmm1, xmm2);
+      __ vfmadd213sd(xmm0, xmm1, Operand(ebx, ecx, times_4, 10000));
+      __ vfmadd231sd(xmm0, xmm1, xmm2);
+      __ vfmadd231sd(xmm0, xmm1, Operand(ebx, ecx, times_4, 10000));
+
+      __ vfmsub132sd(xmm0, xmm1, xmm2);
+      __ vfmsub132sd(xmm0, xmm1, Operand(ebx, ecx, times_4, 10000));
+      __ vfmsub213sd(xmm0, xmm1, xmm2);
+      __ vfmsub213sd(xmm0, xmm1, Operand(ebx, ecx, times_4, 10000));
+      __ vfmsub231sd(xmm0, xmm1, xmm2);
+      __ vfmsub231sd(xmm0, xmm1, Operand(ebx, ecx, times_4, 10000));
+
+      __ vfnmadd132sd(xmm0, xmm1, xmm2);
+      __ vfnmadd132sd(xmm0, xmm1, Operand(ebx, ecx, times_4, 10000));
+      __ vfnmadd213sd(xmm0, xmm1, xmm2);
+      __ vfnmadd213sd(xmm0, xmm1, Operand(ebx, ecx, times_4, 10000));
+      __ vfnmadd231sd(xmm0, xmm1, xmm2);
+      __ vfnmadd231sd(xmm0, xmm1, Operand(ebx, ecx, times_4, 10000));
+
+      __ vfnmsub132sd(xmm0, xmm1, xmm2);
+      __ vfnmsub132sd(xmm0, xmm1, Operand(ebx, ecx, times_4, 10000));
+      __ vfnmsub213sd(xmm0, xmm1, xmm2);
+      __ vfnmsub213sd(xmm0, xmm1, Operand(ebx, ecx, times_4, 10000));
+      __ vfnmsub231sd(xmm0, xmm1, xmm2);
+      __ vfnmsub231sd(xmm0, xmm1, Operand(ebx, ecx, times_4, 10000));
+
+      __ vfmadd132ss(xmm0, xmm1, xmm2);
+      __ vfmadd132ss(xmm0, xmm1, Operand(ebx, ecx, times_4, 10000));
+      __ vfmadd213ss(xmm0, xmm1, xmm2);
+      __ vfmadd213ss(xmm0, xmm1, Operand(ebx, ecx, times_4, 10000));
+      __ vfmadd231ss(xmm0, xmm1, xmm2);
+      __ vfmadd231ss(xmm0, xmm1, Operand(ebx, ecx, times_4, 10000));
+
+      __ vfmsub132ss(xmm0, xmm1, xmm2);
+      __ vfmsub132ss(xmm0, xmm1, Operand(ebx, ecx, times_4, 10000));
+      __ vfmsub213ss(xmm0, xmm1, xmm2);
+      __ vfmsub213ss(xmm0, xmm1, Operand(ebx, ecx, times_4, 10000));
+      __ vfmsub231ss(xmm0, xmm1, xmm2);
+      __ vfmsub231ss(xmm0, xmm1, Operand(ebx, ecx, times_4, 10000));
+
+      __ vfnmadd132ss(xmm0, xmm1, xmm2);
+      __ vfnmadd132ss(xmm0, xmm1, Operand(ebx, ecx, times_4, 10000));
+      __ vfnmadd213ss(xmm0, xmm1, xmm2);
+      __ vfnmadd213ss(xmm0, xmm1, Operand(ebx, ecx, times_4, 10000));
+      __ vfnmadd231ss(xmm0, xmm1, xmm2);
+      __ vfnmadd231ss(xmm0, xmm1, Operand(ebx, ecx, times_4, 10000));
+
+      __ vfnmsub132ss(xmm0, xmm1, xmm2);
+      __ vfnmsub132ss(xmm0, xmm1, Operand(ebx, ecx, times_4, 10000));
+      __ vfnmsub213ss(xmm0, xmm1, xmm2);
+      __ vfnmsub213ss(xmm0, xmm1, Operand(ebx, ecx, times_4, 10000));
+      __ vfnmsub231ss(xmm0, xmm1, xmm2);
+      __ vfnmsub231ss(xmm0, xmm1, Operand(ebx, ecx, times_4, 10000));
+    }
+  }
+
   // xchg.
   {
     __ xchg(eax, eax);
diff --git a/test/cctest/test-disasm-x64.cc b/test/cctest/test-disasm-x64.cc
index e756ce2..6cd58ec 100644
--- a/test/cctest/test-disasm-x64.cc
+++ b/test/cctest/test-disasm-x64.cc
@@ -51,7 +51,7 @@
   CcTest::InitializeVM();
   Isolate* isolate = CcTest::i_isolate();
   HandleScope scope(isolate);
-  v8::internal::byte buffer[2048];
+  v8::internal::byte buffer[4096];
   Assembler assm(isolate, buffer, sizeof buffer);
   DummyStaticFunction(NULL);  // just bloody use it (DELETE; debugging)
 
@@ -117,6 +117,26 @@
   __ imulq(rdx, rcx);
   __ shld(rdx, rcx);
   __ shrd(rdx, rcx);
+  __ shlq(Operand(rdi, rax, times_4, 100), Immediate(1));
+  __ shlq(Operand(rdi, rax, times_4, 100), Immediate(6));
+  __ shlq(Operand(r15, 0), Immediate(1));
+  __ shlq(Operand(r15, 0), Immediate(6));
+  __ shlq_cl(Operand(r15, 0));
+  __ shlq_cl(Operand(r15, 0));
+  __ shlq_cl(Operand(rdi, rax, times_4, 100));
+  __ shlq_cl(Operand(rdi, rax, times_4, 100));
+  __ shlq(rdx, Immediate(1));
+  __ shlq(rdx, Immediate(6));
+  __ shll(Operand(rdi, rax, times_4, 100), Immediate(1));
+  __ shll(Operand(rdi, rax, times_4, 100), Immediate(6));
+  __ shll(Operand(r15, 0), Immediate(1));
+  __ shll(Operand(r15, 0), Immediate(6));
+  __ shll_cl(Operand(r15, 0));
+  __ shll_cl(Operand(r15, 0));
+  __ shll_cl(Operand(rdi, rax, times_4, 100));
+  __ shll_cl(Operand(rdi, rax, times_4, 100));
+  __ shll(rdx, Immediate(1));
+  __ shll(rdx, Immediate(6));
   __ bts(Operand(rdx, 0), rcx);
   __ bts(Operand(rbx, rcx, times_4, 0), rcx);
   __ nop();
@@ -159,14 +179,22 @@
 
   __ nop();
   __ idivq(rdx);
-  __ mul(rdx);
+  __ mull(rdx);
+  __ mulq(rdx);
   __ negq(rdx);
   __ notq(rdx);
   __ testq(Operand(rbx, rcx, times_4, 10000), rdx);
 
-  __ imulq(rdx, Operand(rbx, rcx, times_4, 10000));
   __ imulq(rdx, rcx, Immediate(12));
   __ imulq(rdx, rcx, Immediate(1000));
+  __ imulq(rdx, Operand(rbx, rcx, times_4, 10000));
+  __ imulq(rdx, Operand(rbx, rcx, times_4, 10000), Immediate(12));
+  __ imulq(rdx, Operand(rbx, rcx, times_4, 10000), Immediate(1000));
+  __ imull(r15, rcx, Immediate(12));
+  __ imull(r15, rcx, Immediate(1000));
+  __ imull(r15, Operand(rbx, rcx, times_4, 10000));
+  __ imull(r15, Operand(rbx, rcx, times_4, 10000), Immediate(12));
+  __ imull(r15, Operand(rbx, rcx, times_4, 10000), Immediate(1000));
 
   __ incq(rdx);
   __ incq(Operand(rbx, rcx, times_4, 10000));
@@ -353,6 +381,8 @@
     // Move operation
     __ cvttss2si(rdx, Operand(rbx, rcx, times_4, 10000));
     __ cvttss2si(rdx, xmm1);
+    __ cvtsd2ss(xmm0, xmm1);
+    __ cvtsd2ss(xmm0, Operand(rbx, rcx, times_4, 10000));
     __ movaps(xmm0, xmm1);
 
     // logic operation
@@ -364,6 +394,14 @@
     __ xorps(xmm0, Operand(rbx, rcx, times_4, 10000));
 
     // Arithmetic operation
+    __ addss(xmm1, xmm0);
+    __ addss(xmm1, Operand(rbx, rcx, times_4, 10000));
+    __ mulss(xmm1, xmm0);
+    __ mulss(xmm1, Operand(rbx, rcx, times_4, 10000));
+    __ subss(xmm1, xmm0);
+    __ subss(xmm1, Operand(rbx, rcx, times_4, 10000));
+    __ divss(xmm1, xmm0);
+    __ divss(xmm1, Operand(rbx, rcx, times_4, 10000));
     __ addps(xmm1, xmm0);
     __ addps(xmm1, Operand(rbx, rcx, times_4, 10000));
     __ subps(xmm1, xmm0);
@@ -372,6 +410,9 @@
     __ mulps(xmm1, Operand(rbx, rcx, times_4, 10000));
     __ divps(xmm1, xmm0);
     __ divps(xmm1, Operand(rbx, rcx, times_4, 10000));
+
+    __ ucomiss(xmm0, xmm1);
+    __ ucomiss(xmm0, Operand(rbx, rcx, times_4, 10000));
   }
   // SSE 2 instructions
   {
@@ -379,6 +420,8 @@
     __ cvttsd2si(rdx, xmm1);
     __ cvttsd2siq(rdx, xmm1);
     __ cvttsd2siq(rdx, Operand(rbx, rcx, times_4, 10000));
+    __ cvtqsi2sd(xmm1, Operand(rbx, rcx, times_4, 10000));
+    __ cvtqsi2sd(xmm1, rdx);
     __ movsd(xmm1, Operand(rbx, rcx, times_4, 10000));
     __ movsd(Operand(rbx, rcx, times_4, 10000), xmm1);
     // 128 bit move instructions.
@@ -386,12 +429,23 @@
     __ movdqa(Operand(rbx, rcx, times_4, 10000), xmm0);
 
     __ addsd(xmm1, xmm0);
+    __ addsd(xmm1, Operand(rbx, rcx, times_4, 10000));
     __ mulsd(xmm1, xmm0);
+    __ mulsd(xmm1, Operand(rbx, rcx, times_4, 10000));
     __ subsd(xmm1, xmm0);
+    __ subsd(xmm1, Operand(rbx, rcx, times_4, 10000));
     __ divsd(xmm1, xmm0);
+    __ divsd(xmm1, Operand(rbx, rcx, times_4, 10000));
     __ ucomisd(xmm0, xmm1);
 
     __ andpd(xmm0, xmm1);
+
+    __ pslld(xmm0, 6);
+    __ psrld(xmm0, 6);
+    __ psllq(xmm0, 6);
+    __ psrlq(xmm0, 6);
+
+    __ pcmpeqd(xmm1, xmm0);
   }
 
   // cmov.
@@ -421,6 +475,89 @@
     }
   }
 
+  // AVX instruction
+  {
+    if (CpuFeatures::IsSupported(AVX)) {
+      CpuFeatureScope scope(&assm, AVX);
+      __ vaddsd(xmm0, xmm1, xmm2);
+      __ vaddsd(xmm0, xmm1, Operand(rbx, rcx, times_4, 10000));
+      __ vmulsd(xmm0, xmm1, xmm2);
+      __ vmulsd(xmm0, xmm1, Operand(rbx, rcx, times_4, 10000));
+      __ vsubsd(xmm0, xmm1, xmm2);
+      __ vsubsd(xmm0, xmm1, Operand(rbx, rcx, times_4, 10000));
+      __ vdivsd(xmm0, xmm1, xmm2);
+      __ vdivsd(xmm0, xmm1, Operand(rbx, rcx, times_4, 10000));
+    }
+  }
+
+  // FMA3 instruction
+  {
+    if (CpuFeatures::IsSupported(FMA3)) {
+      CpuFeatureScope scope(&assm, FMA3);
+      __ vfmadd132sd(xmm0, xmm1, xmm2);
+      __ vfmadd132sd(xmm0, xmm1, Operand(rbx, rcx, times_4, 10000));
+      __ vfmadd213sd(xmm0, xmm1, xmm2);
+      __ vfmadd213sd(xmm0, xmm1, Operand(rbx, rcx, times_4, 10000));
+      __ vfmadd231sd(xmm0, xmm1, xmm2);
+      __ vfmadd231sd(xmm0, xmm1, Operand(rbx, rcx, times_4, 10000));
+
+      __ vfmadd132sd(xmm9, xmm10, xmm11);
+      __ vfmadd132sd(xmm9, xmm10, Operand(r9, r11, times_4, 10000));
+      __ vfmadd213sd(xmm9, xmm10, xmm11);
+      __ vfmadd213sd(xmm9, xmm10, Operand(r9, r11, times_4, 10000));
+      __ vfmadd231sd(xmm9, xmm10, xmm11);
+      __ vfmadd231sd(xmm9, xmm10, Operand(r9, r11, times_4, 10000));
+
+      __ vfmsub132sd(xmm0, xmm1, xmm2);
+      __ vfmsub132sd(xmm0, xmm1, Operand(rbx, rcx, times_4, 10000));
+      __ vfmsub213sd(xmm0, xmm1, xmm2);
+      __ vfmsub213sd(xmm0, xmm1, Operand(rbx, rcx, times_4, 10000));
+      __ vfmsub231sd(xmm0, xmm1, xmm2);
+      __ vfmsub231sd(xmm0, xmm1, Operand(rbx, rcx, times_4, 10000));
+
+      __ vfnmadd132sd(xmm0, xmm1, xmm2);
+      __ vfnmadd132sd(xmm0, xmm1, Operand(rbx, rcx, times_4, 10000));
+      __ vfnmadd213sd(xmm0, xmm1, xmm2);
+      __ vfnmadd213sd(xmm0, xmm1, Operand(rbx, rcx, times_4, 10000));
+      __ vfnmadd231sd(xmm0, xmm1, xmm2);
+      __ vfnmadd231sd(xmm0, xmm1, Operand(rbx, rcx, times_4, 10000));
+
+      __ vfnmsub132sd(xmm0, xmm1, xmm2);
+      __ vfnmsub132sd(xmm0, xmm1, Operand(rbx, rcx, times_4, 10000));
+      __ vfnmsub213sd(xmm0, xmm1, xmm2);
+      __ vfnmsub213sd(xmm0, xmm1, Operand(rbx, rcx, times_4, 10000));
+      __ vfnmsub231sd(xmm0, xmm1, xmm2);
+      __ vfnmsub231sd(xmm0, xmm1, Operand(rbx, rcx, times_4, 10000));
+
+      __ vfmadd132ss(xmm0, xmm1, xmm2);
+      __ vfmadd132ss(xmm0, xmm1, Operand(rbx, rcx, times_4, 10000));
+      __ vfmadd213ss(xmm0, xmm1, xmm2);
+      __ vfmadd213ss(xmm0, xmm1, Operand(rbx, rcx, times_4, 10000));
+      __ vfmadd231ss(xmm0, xmm1, xmm2);
+      __ vfmadd231ss(xmm0, xmm1, Operand(rbx, rcx, times_4, 10000));
+
+      __ vfmsub132ss(xmm0, xmm1, xmm2);
+      __ vfmsub132ss(xmm0, xmm1, Operand(rbx, rcx, times_4, 10000));
+      __ vfmsub213ss(xmm0, xmm1, xmm2);
+      __ vfmsub213ss(xmm0, xmm1, Operand(rbx, rcx, times_4, 10000));
+      __ vfmsub231ss(xmm0, xmm1, xmm2);
+      __ vfmsub231ss(xmm0, xmm1, Operand(rbx, rcx, times_4, 10000));
+
+      __ vfnmadd132ss(xmm0, xmm1, xmm2);
+      __ vfnmadd132ss(xmm0, xmm1, Operand(rbx, rcx, times_4, 10000));
+      __ vfnmadd213ss(xmm0, xmm1, xmm2);
+      __ vfnmadd213ss(xmm0, xmm1, Operand(rbx, rcx, times_4, 10000));
+      __ vfnmadd231ss(xmm0, xmm1, xmm2);
+      __ vfnmadd231ss(xmm0, xmm1, Operand(rbx, rcx, times_4, 10000));
+
+      __ vfnmsub132ss(xmm0, xmm1, xmm2);
+      __ vfnmsub132ss(xmm0, xmm1, Operand(rbx, rcx, times_4, 10000));
+      __ vfnmsub213ss(xmm0, xmm1, xmm2);
+      __ vfnmsub213ss(xmm0, xmm1, Operand(rbx, rcx, times_4, 10000));
+      __ vfnmsub231ss(xmm0, xmm1, xmm2);
+      __ vfnmsub231ss(xmm0, xmm1, Operand(rbx, rcx, times_4, 10000));
+    }
+  }
   // xchg.
   {
     __ xchgq(rax, rax);
diff --git a/test/cctest/test-disasm-x87.cc b/test/cctest/test-disasm-x87.cc
index 6cd33e5..e9b0dc5 100644
--- a/test/cctest/test-disasm-x87.cc
+++ b/test/cctest/test-disasm-x87.cc
@@ -201,6 +201,12 @@
   __ rcl(edx, 7);
   __ rcr(edx, 1);
   __ rcr(edx, 7);
+  __ ror(edx, 1);
+  __ ror(edx, 6);
+  __ ror_cl(edx);
+  __ ror(Operand(ebx, ecx, times_4, 10000), 1);
+  __ ror(Operand(ebx, ecx, times_4, 10000), 6);
+  __ ror_cl(Operand(ebx, ecx, times_4, 10000));
   __ sar(edx, 1);
   __ sar(edx, 6);
   __ sar_cl(edx);
diff --git a/test/cctest/test-feedback-vector.cc b/test/cctest/test-feedback-vector.cc
new file mode 100644
index 0000000..fa2f195
--- /dev/null
+++ b/test/cctest/test-feedback-vector.cc
@@ -0,0 +1,308 @@
+// 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.
+
+#include "src/v8.h"
+#include "test/cctest/cctest.h"
+
+#include "src/api.h"
+#include "src/debug.h"
+#include "src/execution.h"
+#include "src/factory.h"
+#include "src/global-handles.h"
+#include "src/macro-assembler.h"
+#include "src/objects.h"
+
+using namespace v8::internal;
+
+namespace {
+
+TEST(VectorStructure) {
+  LocalContext context;
+  v8::HandleScope scope(context->GetIsolate());
+  Isolate* isolate = CcTest::i_isolate();
+  Factory* factory = isolate->factory();
+
+  // Empty vectors are the empty fixed array.
+  FeedbackVectorSpec empty;
+  Handle<TypeFeedbackVector> vector = factory->NewTypeFeedbackVector(empty);
+  CHECK(Handle<FixedArray>::cast(vector)
+            .is_identical_to(factory->empty_fixed_array()));
+  // Which can nonetheless be queried.
+  CHECK_EQ(0, vector->ic_with_type_info_count());
+  CHECK_EQ(0, vector->ic_generic_count());
+  CHECK_EQ(0, vector->Slots());
+  CHECK_EQ(0, vector->ICSlots());
+
+  FeedbackVectorSpec one_slot(1, 0);
+  vector = factory->NewTypeFeedbackVector(one_slot);
+  CHECK_EQ(1, vector->Slots());
+  CHECK_EQ(0, vector->ICSlots());
+
+  FeedbackVectorSpec one_icslot(0, 1);
+  if (FLAG_vector_ics) {
+    one_icslot.SetKind(0, Code::CALL_IC);
+  }
+  vector = factory->NewTypeFeedbackVector(one_icslot);
+  CHECK_EQ(0, vector->Slots());
+  CHECK_EQ(1, vector->ICSlots());
+
+  FeedbackVectorSpec spec(3, 5);
+  if (FLAG_vector_ics) {
+    for (int i = 0; i < 5; i++) spec.SetKind(i, Code::CALL_IC);
+  }
+  vector = factory->NewTypeFeedbackVector(spec);
+  CHECK_EQ(3, vector->Slots());
+  CHECK_EQ(5, vector->ICSlots());
+
+  int metadata_length = vector->ic_metadata_length();
+  if (!FLAG_vector_ics) {
+    CHECK_EQ(0, metadata_length);
+  } else {
+    CHECK(metadata_length > 0);
+  }
+
+  int index = vector->GetIndex(FeedbackVectorSlot(0));
+
+  CHECK_EQ(TypeFeedbackVector::kReservedIndexCount + metadata_length, index);
+  CHECK(FeedbackVectorSlot(0) == vector->ToSlot(index));
+
+  index = vector->GetIndex(FeedbackVectorICSlot(0));
+  CHECK_EQ(index,
+           TypeFeedbackVector::kReservedIndexCount + metadata_length + 3);
+  CHECK(FeedbackVectorICSlot(0) == vector->ToICSlot(index));
+
+  CHECK_EQ(TypeFeedbackVector::kReservedIndexCount + metadata_length + 3 + 5,
+           vector->length());
+}
+
+
+// IC slots need an encoding to recognize what is in there.
+TEST(VectorICMetadata) {
+  LocalContext context;
+  v8::HandleScope scope(context->GetIsolate());
+  if (!FLAG_vector_ics) {
+    // If FLAG_vector_ics is false, we only store CALL_ICs in the vector, so
+    // there is no need for metadata to describe the slots.
+    return;
+  }
+  Isolate* isolate = CcTest::i_isolate();
+  Factory* factory = isolate->factory();
+
+  FeedbackVectorSpec spec(10, 3 * 10);
+  // Set metadata.
+  for (int i = 0; i < 30; i++) {
+    Code::Kind kind;
+    if (i % 3 == 0) {
+      kind = Code::CALL_IC;
+    } else if (i % 3 == 1) {
+      kind = Code::LOAD_IC;
+    } else {
+      kind = Code::KEYED_LOAD_IC;
+    }
+    spec.SetKind(i, kind);
+  }
+
+  Handle<TypeFeedbackVector> vector = factory->NewTypeFeedbackVector(spec);
+  CHECK_EQ(10, vector->Slots());
+  CHECK_EQ(3 * 10, vector->ICSlots());
+
+  // Meanwhile set some feedback values and type feedback values to
+  // verify the data structure remains intact.
+  vector->change_ic_with_type_info_count(100);
+  vector->change_ic_generic_count(3333);
+  vector->Set(FeedbackVectorSlot(0), *vector);
+
+  // Verify the metadata is correctly set up from the spec.
+  for (int i = 0; i < 30; i++) {
+    Code::Kind kind = vector->GetKind(FeedbackVectorICSlot(i));
+    if (i % 3 == 0) {
+      CHECK_EQ(Code::CALL_IC, kind);
+    } else if (i % 3 == 1) {
+      CHECK_EQ(Code::LOAD_IC, kind);
+    } else {
+      CHECK_EQ(Code::KEYED_LOAD_IC, kind);
+    }
+  }
+}
+
+
+TEST(VectorSlotClearing) {
+  LocalContext context;
+  v8::HandleScope scope(context->GetIsolate());
+  Isolate* isolate = CcTest::i_isolate();
+  Factory* factory = isolate->factory();
+
+  // We only test clearing FeedbackVectorSlots, not FeedbackVectorICSlots.
+  // The reason is that FeedbackVectorICSlots need a full code environment
+  // to fully test (See VectorICProfilerStatistics test below).
+  FeedbackVectorSpec spec(5, 0);
+  Handle<TypeFeedbackVector> vector = factory->NewTypeFeedbackVector(spec);
+
+  // Fill with information
+  vector->Set(FeedbackVectorSlot(0), Smi::FromInt(1));
+  vector->Set(FeedbackVectorSlot(1), *factory->fixed_array_map());
+  Handle<AllocationSite> site = factory->NewAllocationSite();
+  vector->Set(FeedbackVectorSlot(2), *site);
+
+  vector->ClearSlots(NULL);
+
+  // The feedback vector slots are cleared. AllocationSites are granted
+  // an exemption from clearing, as are smis.
+  CHECK_EQ(Smi::FromInt(1), vector->Get(FeedbackVectorSlot(0)));
+  CHECK_EQ(*TypeFeedbackVector::UninitializedSentinel(isolate),
+           vector->Get(FeedbackVectorSlot(1)));
+  CHECK(vector->Get(FeedbackVectorSlot(2))->IsAllocationSite());
+}
+
+
+TEST(VectorICProfilerStatistics) {
+  if (i::FLAG_always_opt) return;
+  CcTest::InitializeVM();
+  LocalContext context;
+  v8::HandleScope scope(context->GetIsolate());
+  Isolate* isolate = CcTest::i_isolate();
+  Heap* heap = isolate->heap();
+
+  // Make sure function f has a call that uses a type feedback slot.
+  CompileRun(
+      "function fun() {};"
+      "function f(a) { a(); } f(fun);");
+  Handle<JSFunction> f = v8::Utils::OpenHandle(
+      *v8::Handle<v8::Function>::Cast(CcTest::global()->Get(v8_str("f"))));
+  // There should be one IC.
+  Code* code = f->shared()->code();
+  TypeFeedbackInfo* feedback_info =
+      TypeFeedbackInfo::cast(code->type_feedback_info());
+  CHECK_EQ(1, feedback_info->ic_total_count());
+  CHECK_EQ(0, feedback_info->ic_with_type_info_count());
+  CHECK_EQ(0, feedback_info->ic_generic_count());
+  TypeFeedbackVector* feedback_vector = f->shared()->feedback_vector();
+  CHECK_EQ(1, feedback_vector->ic_with_type_info_count());
+  CHECK_EQ(0, feedback_vector->ic_generic_count());
+
+  // Now send the information generic.
+  CompileRun("f(Object);");
+  feedback_vector = f->shared()->feedback_vector();
+  CHECK_EQ(0, feedback_vector->ic_with_type_info_count());
+  CHECK_EQ(1, feedback_vector->ic_generic_count());
+
+  // A collection will make the site uninitialized again.
+  heap->CollectAllGarbage(i::Heap::kNoGCFlags);
+  feedback_vector = f->shared()->feedback_vector();
+  CHECK_EQ(0, feedback_vector->ic_with_type_info_count());
+  CHECK_EQ(0, feedback_vector->ic_generic_count());
+
+  // The Array function is special. A call to array remains monomorphic
+  // and isn't cleared by gc because an AllocationSite is being held.
+  CompileRun("f(Array);");
+  feedback_vector = f->shared()->feedback_vector();
+  CHECK_EQ(1, feedback_vector->ic_with_type_info_count());
+  CHECK_EQ(0, feedback_vector->ic_generic_count());
+
+  int ic_slot = 0;
+  CHECK(
+      feedback_vector->Get(FeedbackVectorICSlot(ic_slot))->IsAllocationSite());
+  heap->CollectAllGarbage(i::Heap::kNoGCFlags);
+  feedback_vector = f->shared()->feedback_vector();
+  CHECK_EQ(1, feedback_vector->ic_with_type_info_count());
+  CHECK_EQ(0, feedback_vector->ic_generic_count());
+  CHECK(
+      feedback_vector->Get(FeedbackVectorICSlot(ic_slot))->IsAllocationSite());
+}
+
+
+TEST(VectorCallICStates) {
+  if (i::FLAG_always_opt) return;
+  CcTest::InitializeVM();
+  LocalContext context;
+  v8::HandleScope scope(context->GetIsolate());
+  Isolate* isolate = CcTest::i_isolate();
+  Heap* heap = isolate->heap();
+
+  // Make sure function f has a call that uses a type feedback slot.
+  CompileRun(
+      "function foo() { return 17; }"
+      "function f(a) { a(); } f(foo);");
+  Handle<JSFunction> f = v8::Utils::OpenHandle(
+      *v8::Handle<v8::Function>::Cast(CcTest::global()->Get(v8_str("f"))));
+  // There should be one IC.
+  Handle<TypeFeedbackVector> feedback_vector =
+      Handle<TypeFeedbackVector>(f->shared()->feedback_vector(), isolate);
+  FeedbackVectorICSlot slot(0);
+  CallICNexus nexus(feedback_vector, slot);
+  CHECK_EQ(MONOMORPHIC, nexus.StateFromFeedback());
+  // CallIC doesn't return map feedback.
+  CHECK_EQ(NULL, nexus.FindFirstMap());
+
+  CompileRun("f(function() { return 16; })");
+  CHECK_EQ(GENERIC, nexus.StateFromFeedback());
+
+  // After a collection, state should be reset to UNINITIALIZED.
+  heap->CollectAllGarbage(i::Heap::kNoGCFlags);
+  CHECK_EQ(UNINITIALIZED, nexus.StateFromFeedback());
+
+  // Array is special. It will remain monomorphic across gcs and it contains an
+  // AllocationSite.
+  CompileRun("f(Array)");
+  CHECK_EQ(MONOMORPHIC, nexus.StateFromFeedback());
+  CHECK(feedback_vector->Get(FeedbackVectorICSlot(slot))->IsAllocationSite());
+
+  heap->CollectAllGarbage(i::Heap::kNoGCFlags);
+  CHECK_EQ(MONOMORPHIC, nexus.StateFromFeedback());
+}
+
+
+TEST(VectorLoadICStates) {
+  if (i::FLAG_always_opt || !i::FLAG_vector_ics) return;
+  CcTest::InitializeVM();
+  LocalContext context;
+  v8::HandleScope scope(context->GetIsolate());
+  Isolate* isolate = CcTest::i_isolate();
+  Heap* heap = isolate->heap();
+
+  // Make sure function f has a call that uses a type feedback slot.
+  CompileRun(
+      "var o = { foo: 3 };"
+      "function f(a) { return a.foo; } f(o);");
+  Handle<JSFunction> f = v8::Utils::OpenHandle(
+      *v8::Handle<v8::Function>::Cast(CcTest::global()->Get(v8_str("f"))));
+  // There should be one IC.
+  Handle<TypeFeedbackVector> feedback_vector =
+      Handle<TypeFeedbackVector>(f->shared()->feedback_vector(), isolate);
+  FeedbackVectorICSlot slot(0);
+  LoadICNexus nexus(feedback_vector, slot);
+  CHECK_EQ(PREMONOMORPHIC, nexus.StateFromFeedback());
+
+  CompileRun("f(o)");
+  CHECK_EQ(MONOMORPHIC, nexus.StateFromFeedback());
+  // Verify that the monomorphic map is the one we expect.
+  Handle<JSObject> o = v8::Utils::OpenHandle(
+      *v8::Handle<v8::Object>::Cast(CcTest::global()->Get(v8_str("o"))));
+  CHECK_EQ(o->map(), nexus.FindFirstMap());
+
+  // Now go polymorphic.
+  CompileRun("f({ blarg: 3, foo: 2 })");
+  CHECK_EQ(POLYMORPHIC, nexus.StateFromFeedback());
+
+  CompileRun(
+      "delete o.foo;"
+      "f(o)");
+  CHECK_EQ(POLYMORPHIC, nexus.StateFromFeedback());
+
+  CompileRun("f({ blarg: 3, torino: 10, foo: 2 })");
+  CHECK_EQ(POLYMORPHIC, nexus.StateFromFeedback());
+  MapHandleList maps;
+  nexus.FindAllMaps(&maps);
+  CHECK_EQ(4, maps.length());
+
+  // Finally driven megamorphic.
+  CompileRun("f({ blarg: 3, gran: 3, torino: 10, foo: 2 })");
+  CHECK_EQ(MEGAMORPHIC, nexus.StateFromFeedback());
+  CHECK_EQ(NULL, nexus.FindFirstMap());
+
+  // After a collection, state should not be reset to PREMONOMORPHIC.
+  heap->CollectAllGarbage(i::Heap::kNoGCFlags);
+  CHECK_EQ(MEGAMORPHIC, nexus.StateFromFeedback());
+}
+}
diff --git a/test/cctest/test-func-name-inference.cc b/test/cctest/test-func-name-inference.cc
index bc503b5..7f3dafc 100644
--- a/test/cctest/test-func-name-inference.cc
+++ b/test/cctest/test-func-name-inference.cc
@@ -30,7 +30,7 @@
 
 #include "src/api.h"
 #include "src/debug.h"
-#include "src/runtime.h"
+#include "src/string-search.h"
 #include "test/cctest/cctest.h"
 
 
@@ -46,13 +46,13 @@
 using ::v8::internal::SmartArrayPointer;
 using ::v8::internal::SharedFunctionInfo;
 using ::v8::internal::String;
+using ::v8::internal::Vector;
 
 
 static void CheckFunctionName(v8::Handle<v8::Script> script,
                               const char* func_pos_src,
                               const char* ref_inferred_name) {
   Isolate* isolate = CcTest::i_isolate();
-  Factory* factory = isolate->factory();
 
   // Get script source.
   Handle<Object> obj = v8::Utils::OpenHandle(*script);
@@ -69,12 +69,14 @@
   Handle<String> script_src(String::cast(i_script->source()));
 
   // Find the position of a given func source substring in the source.
-  Handle<String> func_pos_str =
-      factory->NewStringFromAsciiChecked(func_pos_src);
-  int func_pos = Runtime::StringMatch(isolate,
-                                      script_src,
-                                      func_pos_str,
-                                      0);
+  int func_pos;
+  {
+    i::DisallowHeapAllocation no_gc;
+    Vector<const uint8_t> func_pos_str = i::OneByteVector(func_pos_src);
+    String::FlatContent script_content = script_src->GetFlatContent();
+    func_pos = SearchString(isolate, script_content.ToOneByteVector(),
+                            func_pos_str, 0);
+  }
   CHECK_NE(0, func_pos);
 
   // Obtain SharedFunctionInfo for the function.
diff --git a/test/cctest/test-heap-profiler.cc b/test/cctest/test-heap-profiler.cc
index 8f9b484..94a5be4 100644
--- a/test/cctest/test-heap-profiler.cc
+++ b/test/cctest/test-heap-profiler.cc
@@ -890,9 +890,10 @@
 }  // namespace
 
 TEST(HeapSnapshotJSONSerialization) {
+  v8::Isolate* isolate = CcTest::isolate();
   LocalContext env;
-  v8::HandleScope scope(env->GetIsolate());
-  v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler();
+  v8::HandleScope scope(isolate);
+  v8::HeapProfiler* heap_profiler = isolate->GetHeapProfiler();
 
 #define STRING_LITERAL_FOR_TEST \
   "\"String \\n\\r\\u0008\\u0081\\u0101\\u0801\\u8001\""
@@ -923,7 +924,7 @@
 
   // Verify that snapshot object has required fields.
   v8::Local<v8::Object> parsed_snapshot =
-      env->Global()->Get(v8_str("parsed"))->ToObject();
+      env->Global()->Get(v8_str("parsed"))->ToObject(isolate);
   CHECK(parsed_snapshot->Has(v8_str("snapshot")));
   CHECK(parsed_snapshot->Has(v8_str("nodes")));
   CHECK(parsed_snapshot->Has(v8_str("edges")));
@@ -979,17 +980,18 @@
       "  \"s\", property_type)");
   CHECK(!string_obj_pos_val.IsEmpty());
   int string_obj_pos =
-      static_cast<int>(string_obj_pos_val->ToNumber()->Value());
+      static_cast<int>(string_obj_pos_val->ToNumber(isolate)->Value());
   v8::Local<v8::Object> nodes_array =
-      parsed_snapshot->Get(v8_str("nodes"))->ToObject();
+      parsed_snapshot->Get(v8_str("nodes"))->ToObject(isolate);
   int string_index = static_cast<int>(
-      nodes_array->Get(string_obj_pos + 1)->ToNumber()->Value());
+      nodes_array->Get(string_obj_pos + 1)->ToNumber(isolate)->Value());
   CHECK_GT(string_index, 0);
   v8::Local<v8::Object> strings_array =
-      parsed_snapshot->Get(v8_str("strings"))->ToObject();
-  v8::Local<v8::String> string = strings_array->Get(string_index)->ToString();
+      parsed_snapshot->Get(v8_str("strings"))->ToObject(isolate);
+  v8::Local<v8::String> string =
+      strings_array->Get(string_index)->ToString(isolate);
   v8::Local<v8::String> ref_string =
-      CompileRun(STRING_LITERAL_FOR_TEST)->ToString();
+      CompileRun(STRING_LITERAL_FOR_TEST)->ToString(isolate);
 #undef STRING_LITERAL_FOR_TEST
   CHECK_EQ(*v8::String::Utf8Value(ref_string),
            *v8::String::Utf8Value(string));
@@ -1719,9 +1721,6 @@
   const v8::HeapGraphNode* native_context =
       GetProperty(global, v8::HeapGraphEdge::kInternal, "native_context");
   CHECK_NE(NULL, native_context);
-  const v8::HeapGraphNode* global_context =
-      GetProperty(global, v8::HeapGraphEdge::kInternal, "global_context");
-  CHECK_NE(NULL, global_context);
   const v8::HeapGraphNode* global_proxy =
       GetProperty(global, v8::HeapGraphEdge::kInternal, "global_proxy");
   CHECK_NE(NULL, global_proxy);
@@ -1917,6 +1916,47 @@
 }
 
 
+TEST(FastCaseRedefinedAccessors) {
+  LocalContext env;
+  v8::HandleScope scope(env->GetIsolate());
+  v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler();
+
+  CompileRun(
+      "var obj1 = {};\n"
+      "Object.defineProperty(obj1, 'prop', { "
+      "  get: function() { return 42; },\n"
+      "  set: function(value) { return this.prop_ = value; },\n"
+      "  configurable: true,\n"
+      "  enumerable: true,\n"
+      "});\n"
+      "Object.defineProperty(obj1, 'prop', { "
+      "  get: function() { return 153; },\n"
+      "  set: function(value) { return this.prop_ = value; },\n"
+      "  configurable: true,\n"
+      "  enumerable: true,\n"
+      "});\n");
+  v8::Local<v8::Object> js_global =
+      env->Global()->GetPrototype().As<v8::Object>();
+  i::Handle<i::JSObject> js_obj1 =
+      v8::Utils::OpenHandle(*js_global->Get(v8_str("obj1")).As<v8::Object>());
+  USE(js_obj1);
+
+  const v8::HeapSnapshot* snapshot =
+      heap_profiler->TakeHeapSnapshot(v8_str("fastCaseAccessors"));
+  CHECK(ValidateSnapshot(snapshot));
+  const v8::HeapGraphNode* global = GetGlobalObject(snapshot);
+  CHECK_NE(NULL, global);
+  const v8::HeapGraphNode* obj1 =
+      GetProperty(global, v8::HeapGraphEdge::kProperty, "obj1");
+  CHECK_NE(NULL, obj1);
+  const v8::HeapGraphNode* func;
+  func = GetProperty(obj1, v8::HeapGraphEdge::kProperty, "get prop");
+  CHECK_NE(NULL, func);
+  func = GetProperty(obj1, v8::HeapGraphEdge::kProperty, "set prop");
+  CHECK_NE(NULL, func);
+}
+
+
 TEST(SlowCaseAccessors) {
   LocalContext env;
   v8::HandleScope scope(env->GetIsolate());
@@ -1952,9 +1992,10 @@
 
 
 TEST(HiddenPropertiesFastCase) {
+  v8::Isolate* isolate = CcTest::isolate();
   LocalContext env;
-  v8::HandleScope scope(env->GetIsolate());
-  v8::HeapProfiler* heap_profiler = env->GetIsolate()->GetHeapProfiler();
+  v8::HandleScope scope(isolate);
+  v8::HeapProfiler* heap_profiler = isolate->GetHeapProfiler();
 
   CompileRun(
       "function C(x) { this.a = this; this.b = x; }\n"
@@ -1973,7 +2014,7 @@
   v8::Handle<v8::Value> cHandle =
       env->Global()->Get(v8::String::NewFromUtf8(env->GetIsolate(), "c"));
   CHECK(!cHandle.IsEmpty() && cHandle->IsObject());
-  cHandle->ToObject()->SetHiddenValue(v8_str("key"), v8_str("val"));
+  cHandle->ToObject(isolate)->SetHiddenValue(v8_str("key"), v8_str("val"));
 
   snapshot = heap_profiler->TakeHeapSnapshot(
       v8_str("HiddenPropertiesFastCase2"));
diff --git a/test/cctest/test-heap.cc b/test/cctest/test-heap.cc
index e526761..f8a7df2 100644
--- a/test/cctest/test-heap.cc
+++ b/test/cctest/test-heap.cc
@@ -1375,6 +1375,98 @@
 }
 
 
+TEST(CompilationCacheCachingBehavior) {
+  // If we do not flush code, or have the compilation cache turned off, this
+  // test is invalid.
+  if (!FLAG_flush_code || !FLAG_flush_code_incrementally ||
+      !FLAG_compilation_cache) {
+    return;
+  }
+  CcTest::InitializeVM();
+  Isolate* isolate = CcTest::i_isolate();
+  Factory* factory = isolate->factory();
+  Heap* heap = isolate->heap();
+  CompilationCache* compilation_cache = isolate->compilation_cache();
+
+  v8::HandleScope scope(CcTest::isolate());
+  const char* raw_source =
+      "function foo() {"
+      "  var x = 42;"
+      "  var y = 42;"
+      "  var z = x + y;"
+      "};"
+      "foo()";
+  Handle<String> source = factory->InternalizeUtf8String(raw_source);
+  Handle<Context> native_context = isolate->native_context();
+
+  {
+    v8::HandleScope scope(CcTest::isolate());
+    CompileRun(raw_source);
+  }
+
+  // On first compilation, only a hash is inserted in the code cache. We can't
+  // find that value.
+  MaybeHandle<SharedFunctionInfo> info = compilation_cache->LookupScript(
+      source, Handle<Object>(), 0, 0, true, native_context);
+  CHECK(info.is_null());
+
+  {
+    v8::HandleScope scope(CcTest::isolate());
+    CompileRun(raw_source);
+  }
+
+  // On second compilation, the hash is replaced by a real cache entry mapping
+  // the source to the shared function info containing the code.
+  info = compilation_cache->LookupScript(source, Handle<Object>(), 0, 0, true,
+                                         native_context);
+  CHECK(!info.is_null());
+
+  heap->CollectAllGarbage(Heap::kNoGCFlags);
+
+  // On second compilation, the hash is replaced by a real cache entry mapping
+  // the source to the shared function info containing the code.
+  info = compilation_cache->LookupScript(source, Handle<Object>(), 0, 0, true,
+                                         native_context);
+  CHECK(!info.is_null());
+
+  while (!info.ToHandleChecked()->code()->IsOld()) {
+    info.ToHandleChecked()->code()->MakeOlder(NO_MARKING_PARITY);
+  }
+
+  heap->CollectAllGarbage(Heap::kNoGCFlags);
+  // Ensure code aging cleared the entry from the cache.
+  info = compilation_cache->LookupScript(source, Handle<Object>(), 0, 0, true,
+                                         native_context);
+  CHECK(info.is_null());
+
+  {
+    v8::HandleScope scope(CcTest::isolate());
+    CompileRun(raw_source);
+  }
+
+  // On first compilation, only a hash is inserted in the code cache. We can't
+  // find that value.
+  info = compilation_cache->LookupScript(source, Handle<Object>(), 0, 0, true,
+                                         native_context);
+  CHECK(info.is_null());
+
+  for (int i = 0; i < CompilationCacheTable::kHashGenerations; i++) {
+    compilation_cache->MarkCompactPrologue();
+  }
+
+  {
+    v8::HandleScope scope(CcTest::isolate());
+    CompileRun(raw_source);
+  }
+
+  // If we aged the cache before caching the script, ensure that we didn't cache
+  // on next compilation.
+  info = compilation_cache->LookupScript(source, Handle<Object>(), 0, 0, true,
+                                         native_context);
+  CHECK(info.is_null());
+}
+
+
 // Count the number of native contexts in the weak list of native contexts.
 int CountNativeContexts() {
   int count = 0;
@@ -1487,7 +1579,7 @@
   }
 
   // Force compilation cache cleanup.
-  CcTest::heap()->NotifyContextDisposed();
+  CcTest::heap()->NotifyContextDisposed(true);
   CcTest::heap()->CollectAllGarbage(Heap::kNoGCFlags);
 
   // Dispose the native contexts one by one.
@@ -1602,6 +1694,64 @@
 }
 
 
+TEST(TestSizeOfRegExpCode) {
+  if (!FLAG_regexp_optimization) return;
+
+  v8::V8::Initialize();
+
+  Isolate* isolate = CcTest::i_isolate();
+  HandleScope scope(isolate);
+
+  LocalContext context;
+
+  // Adjust source below and this check to match
+  // RegExpImple::kRegExpTooLargeToOptimize.
+  DCHECK_EQ(i::RegExpImpl::kRegExpTooLargeToOptimize, 10 * KB);
+
+  // Compile a regexp that is much larger if we are using regexp optimizations.
+  CompileRun(
+      "var reg_exp_source = '(?:a|bc|def|ghij|klmno|pqrstu)';"
+      "var half_size_reg_exp;"
+      "while (reg_exp_source.length < 10 * 1024) {"
+      "  half_size_reg_exp = reg_exp_source;"
+      "  reg_exp_source = reg_exp_source + reg_exp_source;"
+      "}"
+      // Flatten string.
+      "reg_exp_source.match(/f/);");
+
+  // Get initial heap size after several full GCs, which will stabilize
+  // the heap size and return with sweeping finished completely.
+  CcTest::heap()->CollectAllGarbage(Heap::kNoGCFlags);
+  CcTest::heap()->CollectAllGarbage(Heap::kNoGCFlags);
+  CcTest::heap()->CollectAllGarbage(Heap::kNoGCFlags);
+  CcTest::heap()->CollectAllGarbage(Heap::kNoGCFlags);
+  CcTest::heap()->CollectAllGarbage(Heap::kNoGCFlags);
+  MarkCompactCollector* collector = CcTest::heap()->mark_compact_collector();
+  if (collector->sweeping_in_progress()) {
+    collector->EnsureSweepingCompleted();
+  }
+  int initial_size = static_cast<int>(CcTest::heap()->SizeOfObjects());
+
+  CompileRun("'foo'.match(reg_exp_source);");
+  CcTest::heap()->CollectAllGarbage(Heap::kNoGCFlags);
+  int size_with_regexp = static_cast<int>(CcTest::heap()->SizeOfObjects());
+
+  CompileRun("'foo'.match(half_size_reg_exp);");
+  CcTest::heap()->CollectAllGarbage(Heap::kNoGCFlags);
+  int size_with_optimized_regexp =
+      static_cast<int>(CcTest::heap()->SizeOfObjects());
+
+  int size_of_regexp_code = size_with_regexp - initial_size;
+
+  CHECK_LE(size_of_regexp_code, 1 * MB);
+
+  // Small regexp is half the size, but compiles to more than twice the code
+  // due to the optimization steps.
+  CHECK_GE(size_with_optimized_regexp,
+           size_with_regexp + size_of_regexp_code * 2);
+}
+
+
 TEST(TestSizeOfObjects) {
   v8::V8::Initialize();
 
@@ -2183,6 +2333,48 @@
 }
 
 
+TEST(IdleNotificationFinishMarking) {
+  i::FLAG_allow_natives_syntax = true;
+  CcTest::InitializeVM();
+  SimulateFullSpace(CcTest::heap()->old_pointer_space());
+  IncrementalMarking* marking = CcTest::heap()->incremental_marking();
+  marking->Abort();
+  marking->Start();
+
+  CHECK_EQ(CcTest::heap()->gc_count(), 0);
+
+  // TODO(hpayer): We cannot write proper unit test right now for heap.
+  // The ideal test would call kMaxIdleMarkingDelayCounter to test the
+  // marking delay counter.
+
+  // Perform a huge incremental marking step but don't complete marking.
+  intptr_t bytes_processed = 0;
+  do {
+    bytes_processed =
+        marking->Step(1 * MB, IncrementalMarking::NO_GC_VIA_STACK_GUARD,
+                      IncrementalMarking::FORCE_MARKING,
+                      IncrementalMarking::DO_NOT_FORCE_COMPLETION);
+    CHECK(!marking->IsIdleMarkingDelayCounterLimitReached());
+  } while (bytes_processed);
+
+  // The next invocations of incremental marking are not going to complete
+  // marking
+  // since the completion threshold is not reached
+  for (size_t i = 0; i < IncrementalMarking::kMaxIdleMarkingDelayCounter - 2;
+       i++) {
+    marking->Step(1 * MB, IncrementalMarking::NO_GC_VIA_STACK_GUARD,
+                  IncrementalMarking::FORCE_MARKING,
+                  IncrementalMarking::DO_NOT_FORCE_COMPLETION);
+    CHECK(!marking->IsIdleMarkingDelayCounterLimitReached());
+  }
+
+  // The next idle notification has to finish incremental marking.
+  const int kLongIdleTime = 1000000;
+  CcTest::isolate()->IdleNotification(kLongIdleTime);
+  CHECK_EQ(CcTest::heap()->gc_count(), 1);
+}
+
+
 // Test that HAllocateObject will always return an object in new-space.
 TEST(OptimizedAllocationAlwaysInNewSpace) {
   i::FLAG_allow_natives_syntax = true;
@@ -2204,7 +2396,8 @@
       "f(1); f(2); f(3);"
       "%OptimizeFunctionOnNextCall(f);"
       "f(4);");
-  CHECK_EQ(4, res->ToObject()->GetRealNamedProperty(v8_str("x"))->Int32Value());
+  CHECK_EQ(
+      4, res.As<v8::Object>()->GetRealNamedProperty(v8_str("x"))->Int32Value());
 
   Handle<JSObject> o =
       v8::Utils::OpenHandle(*v8::Handle<v8::Object>::Cast(res));
@@ -2342,12 +2535,21 @@
   FieldIndex idx1 = FieldIndex::ForPropertyIndex(o->map(), 0);
   FieldIndex idx2 = FieldIndex::ForPropertyIndex(o->map(), 1);
   CHECK(CcTest::heap()->InOldPointerSpace(o->RawFastPropertyAt(idx1)));
-  CHECK(CcTest::heap()->InOldDataSpace(o->RawFastPropertyAt(idx2)));
+  if (!o->IsUnboxedDoubleField(idx2)) {
+    CHECK(CcTest::heap()->InOldDataSpace(o->RawFastPropertyAt(idx2)));
+  } else {
+    CHECK_EQ(1.1, o->RawFastDoublePropertyAt(idx2));
+  }
 
   JSObject* inner_object =
       reinterpret_cast<JSObject*>(o->RawFastPropertyAt(idx1));
   CHECK(CcTest::heap()->InOldPointerSpace(inner_object));
-  CHECK(CcTest::heap()->InOldDataSpace(inner_object->RawFastPropertyAt(idx1)));
+  if (!inner_object->IsUnboxedDoubleField(idx1)) {
+    CHECK(
+        CcTest::heap()->InOldDataSpace(inner_object->RawFastPropertyAt(idx1)));
+  } else {
+    CHECK_EQ(2.2, inner_object->RawFastDoublePropertyAt(idx1));
+  }
   CHECK(CcTest::heap()->InOldPointerSpace(
       inner_object->RawFastPropertyAt(idx2)));
 }
@@ -2806,6 +3008,7 @@
              "root = new F");
   root = GetByName("root");
   AddPropertyTo(2, root, "funny");
+  CcTest::heap()->CollectGarbage(NEW_SPACE);
 
   // Count number of live transitions after marking.  Note that one transition
   // is left, because 'o' still holds an instance of one transition target.
@@ -2832,6 +3035,7 @@
 
   root = GetByName("root");
   AddPropertyTo(2, root, "funny");
+  CcTest::heap()->CollectGarbage(NEW_SPACE);
 
   // Count number of live transitions after marking.  Note that one transition
   // is left, because 'o' still holds an instance of one transition target.
@@ -3076,7 +3280,7 @@
 
   OFStream os(stdout);
   g->shared()->Print(os);
-  os << endl;
+  os << std::endl;
 }
 #endif  // OBJECT_PRINT
 
@@ -3147,22 +3351,20 @@
 
   Handle<TypeFeedbackVector> feedback_vector(f->shared()->feedback_vector());
 
-  int expected_length = FLAG_vector_ics ? 4 : 2;
-  CHECK_EQ(expected_length, feedback_vector->length());
-  for (int i = 0; i < expected_length; i++) {
-    if ((i % 2) == 1) {
-      CHECK(feedback_vector->get(i)->IsJSFunction());
-    }
-  }
+  int expected_slots = 2;
+  CHECK_EQ(expected_slots, feedback_vector->ICSlots());
+  int slot1 = 0;
+  int slot2 = 1;
+  CHECK(feedback_vector->Get(FeedbackVectorICSlot(slot1))->IsJSFunction());
+  CHECK(feedback_vector->Get(FeedbackVectorICSlot(slot2))->IsJSFunction());
 
   SimulateIncrementalMarking(CcTest::heap());
   CcTest::heap()->CollectAllGarbage(Heap::kNoGCFlags);
 
-  CHECK_EQ(expected_length, feedback_vector->length());
-  for (int i = 0; i < expected_length; i++) {
-    CHECK_EQ(feedback_vector->get(i),
-             *TypeFeedbackVector::UninitializedSentinel(CcTest::i_isolate()));
-  }
+  CHECK_EQ(feedback_vector->Get(FeedbackVectorICSlot(slot1)),
+           *TypeFeedbackVector::UninitializedSentinel(CcTest::i_isolate()));
+  CHECK_EQ(feedback_vector->Get(FeedbackVectorICSlot(slot2)),
+           *TypeFeedbackVector::UninitializedSentinel(CcTest::i_isolate()));
 }
 
 
@@ -3181,6 +3383,25 @@
 }
 
 
+static void CheckVectorIC(Handle<JSFunction> f, int ic_slot_index,
+                          InlineCacheState desired_state) {
+  Handle<TypeFeedbackVector> vector =
+      Handle<TypeFeedbackVector>(f->shared()->feedback_vector());
+  FeedbackVectorICSlot slot(ic_slot_index);
+  LoadICNexus nexus(vector, slot);
+  CHECK(nexus.StateFromFeedback() == desired_state);
+}
+
+
+static void CheckVectorICCleared(Handle<JSFunction> f, int ic_slot_index) {
+  Handle<TypeFeedbackVector> vector =
+      Handle<TypeFeedbackVector>(f->shared()->feedback_vector());
+  FeedbackVectorICSlot slot(ic_slot_index);
+  LoadICNexus nexus(vector, slot);
+  CHECK(IC::IsCleared(&nexus));
+}
+
+
 TEST(IncrementalMarkingPreservesMonomorphicIC) {
   if (i::FLAG_always_opt) return;
   CcTest::InitializeVM();
@@ -3196,13 +3417,23 @@
               CcTest::global()->Get(v8_str("f"))));
 
   Code* ic_before = FindFirstIC(f->shared()->code(), Code::LOAD_IC);
-  CHECK(ic_before->ic_state() == MONOMORPHIC);
+  if (FLAG_vector_ics) {
+    CheckVectorIC(f, 0, MONOMORPHIC);
+    CHECK(ic_before->ic_state() == DEFAULT);
+  } else {
+    CHECK(ic_before->ic_state() == MONOMORPHIC);
+  }
 
   SimulateIncrementalMarking(CcTest::heap());
   CcTest::heap()->CollectAllGarbage(Heap::kNoGCFlags);
 
   Code* ic_after = FindFirstIC(f->shared()->code(), Code::LOAD_IC);
-  CHECK(ic_after->ic_state() == MONOMORPHIC);
+  if (FLAG_vector_ics) {
+    CheckVectorIC(f, 0, MONOMORPHIC);
+    CHECK(ic_after->ic_state() == DEFAULT);
+  } else {
+    CHECK(ic_after->ic_state() == MONOMORPHIC);
+  }
 }
 
 
@@ -3228,7 +3459,12 @@
               CcTest::global()->Get(v8_str("f"))));
 
   Code* ic_before = FindFirstIC(f->shared()->code(), Code::LOAD_IC);
-  CHECK(ic_before->ic_state() == MONOMORPHIC);
+  if (FLAG_vector_ics) {
+    CheckVectorIC(f, 0, MONOMORPHIC);
+    CHECK(ic_before->ic_state() == DEFAULT);
+  } else {
+    CHECK(ic_before->ic_state() == MONOMORPHIC);
+  }
 
   // Fire context dispose notification.
   CcTest::isolate()->ContextDisposedNotification();
@@ -3236,7 +3472,60 @@
   CcTest::heap()->CollectAllGarbage(Heap::kNoGCFlags);
 
   Code* ic_after = FindFirstIC(f->shared()->code(), Code::LOAD_IC);
-  CHECK(IC::IsCleared(ic_after));
+  if (FLAG_vector_ics) {
+    CheckVectorICCleared(f, 0);
+    CHECK(ic_after->ic_state() == DEFAULT);
+  } else {
+    CHECK(IC::IsCleared(ic_after));
+  }
+}
+
+
+TEST(IncrementalMarkingPreservesPolymorphicIC) {
+  if (i::FLAG_always_opt) return;
+  CcTest::InitializeVM();
+  v8::HandleScope scope(CcTest::isolate());
+  v8::Local<v8::Value> obj1, obj2;
+
+  {
+    LocalContext env;
+    CompileRun("function fun() { this.x = 1; }; var obj = new fun();");
+    obj1 = env->Global()->Get(v8_str("obj"));
+  }
+
+  {
+    LocalContext env;
+    CompileRun("function fun() { this.x = 2; }; var obj = new fun();");
+    obj2 = env->Global()->Get(v8_str("obj"));
+  }
+
+  // Prepare function f that contains a polymorphic IC for objects
+  // originating from two different native contexts.
+  CcTest::global()->Set(v8_str("obj1"), obj1);
+  CcTest::global()->Set(v8_str("obj2"), obj2);
+  CompileRun("function f(o) { return o.x; } f(obj1); f(obj1); f(obj2);");
+  Handle<JSFunction> f = v8::Utils::OpenHandle(
+      *v8::Handle<v8::Function>::Cast(CcTest::global()->Get(v8_str("f"))));
+
+  Code* ic_before = FindFirstIC(f->shared()->code(), Code::LOAD_IC);
+  if (FLAG_vector_ics) {
+    CheckVectorIC(f, 0, POLYMORPHIC);
+    CHECK(ic_before->ic_state() == DEFAULT);
+  } else {
+    CHECK(ic_before->ic_state() == POLYMORPHIC);
+  }
+
+  // Fire context dispose notification.
+  SimulateIncrementalMarking(CcTest::heap());
+  CcTest::heap()->CollectAllGarbage(Heap::kNoGCFlags);
+
+  Code* ic_after = FindFirstIC(f->shared()->code(), Code::LOAD_IC);
+  if (FLAG_vector_ics) {
+    CheckVectorIC(f, 0, POLYMORPHIC);
+    CHECK(ic_after->ic_state() == DEFAULT);
+  } else {
+    CHECK(ic_after->ic_state() == POLYMORPHIC);
+  }
 }
 
 
@@ -3269,7 +3558,12 @@
               CcTest::global()->Get(v8_str("f"))));
 
   Code* ic_before = FindFirstIC(f->shared()->code(), Code::LOAD_IC);
-  CHECK(ic_before->ic_state() == POLYMORPHIC);
+  if (FLAG_vector_ics) {
+    CheckVectorIC(f, 0, POLYMORPHIC);
+    CHECK(ic_before->ic_state() == DEFAULT);
+  } else {
+    CHECK(ic_before->ic_state() == POLYMORPHIC);
+  }
 
   // Fire context dispose notification.
   CcTest::isolate()->ContextDisposedNotification();
@@ -3277,7 +3571,12 @@
   CcTest::heap()->CollectAllGarbage(Heap::kNoGCFlags);
 
   Code* ic_after = FindFirstIC(f->shared()->code(), Code::LOAD_IC);
-  CHECK(IC::IsCleared(ic_after));
+  if (FLAG_vector_ics) {
+    CheckVectorICCleared(f, 0);
+    CHECK(ic_before->ic_state() == DEFAULT);
+  } else {
+    CHECK(IC::IsCleared(ic_after));
+  }
 }
 
 
@@ -4021,8 +4320,9 @@
                "bar%d();"
                "bar%d();"
                "bar%d();"
-               "%%OptimizeFunctionOnNextCall(bar%d);"
-               "bar%d();", i, i, i, i, i, i, i, i);
+               "%%OptimizeFwunctionOnNextCall(bar%d);"
+               "bar%d();",
+               i, i, i, i, i, i, i, i);
       CompileRun(source.start());
     }
     heap->CollectAllGarbage(i::Heap::kNoGCFlags);
@@ -4154,7 +4454,7 @@
   v8::Persistent<v8::Object> garbage;
   {
     v8::HandleScope scope(isolate);
-    garbage.Reset(isolate, CompileRun(source)->ToObject());
+    garbage.Reset(isolate, CompileRun(source)->ToObject(isolate));
   }
   weak_ic_cleared = false;
   garbage.SetWeak(static_cast<void*>(&garbage), &ClearWeakIC);
@@ -4181,6 +4481,25 @@
 }
 
 
+TEST(WeakMapInPolymorphicLoadIC) {
+  CheckWeakness(
+      "function loadIC(obj) {"
+      "  return obj.name;"
+      "}"
+      " (function() {"
+      "   var proto = {'name' : 'weak'};"
+      "   var obj = Object.create(proto);"
+      "   loadIC(obj);"
+      "   loadIC(obj);"
+      "   loadIC(obj);"
+      "   var poly = Object.create(proto);"
+      "   poly.x = true;"
+      "   loadIC(poly);"
+      "   return proto;"
+      " })();");
+}
+
+
 TEST(WeakMapInMonomorphicKeyedLoadIC) {
   CheckWeakness("function keyedLoadIC(obj, field) {"
                 "  return obj[field];"
@@ -4196,6 +4515,25 @@
 }
 
 
+TEST(WeakMapInPolymorphicKeyedLoadIC) {
+  CheckWeakness(
+      "function keyedLoadIC(obj, field) {"
+      "  return obj[field];"
+      "}"
+      " (function() {"
+      "   var proto = {'name' : 'weak'};"
+      "   var obj = Object.create(proto);"
+      "   keyedLoadIC(obj, 'name');"
+      "   keyedLoadIC(obj, 'name');"
+      "   keyedLoadIC(obj, 'name');"
+      "   var poly = Object.create(proto);"
+      "   poly.x = true;"
+      "   keyedLoadIC(poly, 'name');"
+      "   return proto;"
+      " })();");
+}
+
+
 TEST(WeakMapInMonomorphicStoreIC) {
   CheckWeakness("function storeIC(obj, value) {"
                 "  obj.name = value;"
@@ -4211,6 +4549,25 @@
 }
 
 
+TEST(WeakMapInPolymorphicStoreIC) {
+  CheckWeakness(
+      "function storeIC(obj, value) {"
+      "  obj.name = value;"
+      "}"
+      " (function() {"
+      "   var proto = {'name' : 'weak'};"
+      "   var obj = Object.create(proto);"
+      "   storeIC(obj, 'x');"
+      "   storeIC(obj, 'x');"
+      "   storeIC(obj, 'x');"
+      "   var poly = Object.create(proto);"
+      "   poly.x = true;"
+      "   storeIC(poly, 'x');"
+      "   return proto;"
+      " })();");
+}
+
+
 TEST(WeakMapInMonomorphicKeyedStoreIC) {
   CheckWeakness("function keyedStoreIC(obj, field, value) {"
                 "  obj[field] = value;"
@@ -4226,6 +4583,25 @@
 }
 
 
+TEST(WeakMapInPolymorphicKeyedStoreIC) {
+  CheckWeakness(
+      "function keyedStoreIC(obj, field, value) {"
+      "  obj[field] = value;"
+      "}"
+      " (function() {"
+      "   var proto = {'name' : 'weak'};"
+      "   var obj = Object.create(proto);"
+      "   keyedStoreIC(obj, 'x');"
+      "   keyedStoreIC(obj, 'x');"
+      "   keyedStoreIC(obj, 'x');"
+      "   var poly = Object.create(proto);"
+      "   poly.x = true;"
+      "   keyedStoreIC(poly, 'x');"
+      "   return proto;"
+      " })();");
+}
+
+
 TEST(WeakMapInMonomorphicCompareNilIC) {
   CheckWeakness("function compareNilIC(obj) {"
                 "  return obj == null;"
@@ -4241,6 +4617,160 @@
 }
 
 
+Handle<JSFunction> GetFunctionByName(Isolate* isolate, const char* name) {
+  Handle<String> str = isolate->factory()->InternalizeUtf8String(name);
+  Handle<Object> obj =
+      Object::GetProperty(isolate->global_object(), str).ToHandleChecked();
+  return Handle<JSFunction>::cast(obj);
+}
+
+
+void CheckIC(Code* code, Code::Kind kind, InlineCacheState state) {
+  Code* ic = FindFirstIC(code, kind);
+  CHECK(ic->is_inline_cache_stub());
+  CHECK(ic->ic_state() == state);
+}
+
+
+TEST(MonomorphicStaysMonomorphicAfterGC) {
+  if (FLAG_always_opt) return;
+  // TODO(mvstanton): vector ics need weak support!
+  if (FLAG_vector_ics) return;
+  CcTest::InitializeVM();
+  Isolate* isolate = CcTest::i_isolate();
+  Heap* heap = isolate->heap();
+  v8::HandleScope scope(CcTest::isolate());
+  CompileRun(
+      "function loadIC(obj) {"
+      "  return obj.name;"
+      "}"
+      "function testIC() {"
+      "  var proto = {'name' : 'weak'};"
+      "  var obj = Object.create(proto);"
+      "  loadIC(obj);"
+      "  loadIC(obj);"
+      "  loadIC(obj);"
+      "  return proto;"
+      "};");
+  Handle<JSFunction> loadIC = GetFunctionByName(isolate, "loadIC");
+  {
+    v8::HandleScope scope(CcTest::isolate());
+    CompileRun("(testIC())");
+  }
+  heap->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
+  CheckIC(loadIC->code(), Code::LOAD_IC, MONOMORPHIC);
+  {
+    v8::HandleScope scope(CcTest::isolate());
+    CompileRun("(testIC())");
+  }
+  CheckIC(loadIC->code(), Code::LOAD_IC, MONOMORPHIC);
+}
+
+
+TEST(PolymorphicStaysPolymorphicAfterGC) {
+  if (FLAG_always_opt) return;
+  // TODO(mvstanton): vector ics need weak support!
+  if (FLAG_vector_ics) return;
+  CcTest::InitializeVM();
+  Isolate* isolate = CcTest::i_isolate();
+  Heap* heap = isolate->heap();
+  v8::HandleScope scope(CcTest::isolate());
+  CompileRun(
+      "function loadIC(obj) {"
+      "  return obj.name;"
+      "}"
+      "function testIC() {"
+      "  var proto = {'name' : 'weak'};"
+      "  var obj = Object.create(proto);"
+      "  loadIC(obj);"
+      "  loadIC(obj);"
+      "  loadIC(obj);"
+      "  var poly = Object.create(proto);"
+      "  poly.x = true;"
+      "  loadIC(poly);"
+      "  return proto;"
+      "};");
+  Handle<JSFunction> loadIC = GetFunctionByName(isolate, "loadIC");
+  {
+    v8::HandleScope scope(CcTest::isolate());
+    CompileRun("(testIC())");
+  }
+  heap->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask);
+  CheckIC(loadIC->code(), Code::LOAD_IC, POLYMORPHIC);
+  {
+    v8::HandleScope scope(CcTest::isolate());
+    CompileRun("(testIC())");
+  }
+  CheckIC(loadIC->code(), Code::LOAD_IC, POLYMORPHIC);
+}
+
+
+TEST(WeakCell) {
+  CcTest::InitializeVM();
+  Isolate* isolate = CcTest::i_isolate();
+  v8::internal::Heap* heap = CcTest::heap();
+  v8::internal::Factory* factory = isolate->factory();
+
+  HandleScope outer_scope(isolate);
+  Handle<WeakCell> weak_cell1;
+  {
+    HandleScope inner_scope(isolate);
+    Handle<HeapObject> value = factory->NewFixedArray(1, NOT_TENURED);
+    weak_cell1 = inner_scope.CloseAndEscape(factory->NewWeakCell(value));
+  }
+
+  Handle<FixedArray> survivor = factory->NewFixedArray(1, NOT_TENURED);
+  Handle<WeakCell> weak_cell2;
+  {
+    HandleScope inner_scope(isolate);
+    weak_cell2 = inner_scope.CloseAndEscape(factory->NewWeakCell(survivor));
+  }
+  CHECK(weak_cell1->value()->IsFixedArray());
+  CHECK_EQ(*survivor, weak_cell2->value());
+  heap->CollectGarbage(NEW_SPACE);
+  CHECK(weak_cell1->value()->IsFixedArray());
+  CHECK_EQ(*survivor, weak_cell2->value());
+  heap->CollectGarbage(NEW_SPACE);
+  CHECK(weak_cell1->value()->IsFixedArray());
+  CHECK_EQ(*survivor, weak_cell2->value());
+  heap->CollectAllAvailableGarbage();
+  CHECK(weak_cell1->cleared());
+  CHECK_EQ(*survivor, weak_cell2->value());
+}
+
+
+TEST(WeakCellsWithIncrementalMarking) {
+  CcTest::InitializeVM();
+  Isolate* isolate = CcTest::i_isolate();
+  v8::internal::Heap* heap = CcTest::heap();
+  v8::internal::Factory* factory = isolate->factory();
+
+  const int N = 16;
+  HandleScope outer_scope(isolate);
+  Handle<FixedArray> survivor = factory->NewFixedArray(1, NOT_TENURED);
+  Handle<WeakCell> weak_cells[N];
+
+  for (int i = 0; i < N; i++) {
+    HandleScope inner_scope(isolate);
+    Handle<HeapObject> value =
+        i == 0 ? survivor : factory->NewFixedArray(1, NOT_TENURED);
+    Handle<WeakCell> weak_cell = factory->NewWeakCell(value);
+    CHECK(weak_cell->value()->IsFixedArray());
+    IncrementalMarking* marking = heap->incremental_marking();
+    if (marking->IsStopped()) marking->Start();
+    marking->Step(128, IncrementalMarking::NO_GC_VIA_STACK_GUARD);
+    heap->CollectGarbage(NEW_SPACE);
+    CHECK(weak_cell->value()->IsFixedArray());
+    weak_cells[i] = inner_scope.CloseAndEscape(weak_cell);
+  }
+  heap->CollectAllGarbage(Heap::kNoGCFlags);
+  CHECK_EQ(*survivor, weak_cells[0]->value());
+  for (int i = 1; i < N; i++) {
+    CHECK(weak_cells[i]->cleared());
+  }
+}
+
+
 #ifdef DEBUG
 TEST(AddInstructionChangesNewSpacePromotion) {
   i::FLAG_allow_natives_syntax = true;
@@ -4320,7 +4850,7 @@
   CcTest::InitializeVM();
   v8::Isolate* isolate = CcTest::isolate();
   v8::HandleScope hscope(isolate);
-  v8::Handle<v8::ObjectTemplate> global =v8::ObjectTemplate::New(isolate);
+  v8::Handle<v8::ObjectTemplate> global = v8::ObjectTemplate::New(isolate);
   global->Set(v8::String::NewFromUtf8(isolate, "interrupt"),
               v8::FunctionTemplate::New(isolate, RequestInterrupt));
   v8::Local<v8::Context> context = v8::Context::New(isolate, NULL, global);
@@ -4333,7 +4863,7 @@
       "eval('function f() {' + locals + 'return function() { return v0; }; }');"
       "interrupt();"  // This triggers a fake stack overflow in f.
       "f()()");
-  CHECK_EQ(42.0, result->ToNumber()->Value());
+  CHECK_EQ(42.0, result->ToNumber(isolate)->Value());
 }
 
 
@@ -4502,6 +5032,63 @@
 }
 
 
+TEST(Regress3631) {
+  i::FLAG_expose_gc = true;
+  CcTest::InitializeVM();
+  v8::HandleScope scope(CcTest::isolate());
+  Isolate* isolate = CcTest::i_isolate();
+  Heap* heap = isolate->heap();
+  IncrementalMarking* marking = CcTest::heap()->incremental_marking();
+  v8::Local<v8::Value> result = CompileRun(
+      "var weak_map = new WeakMap();"
+      "var future_keys = [];"
+      "for (var i = 0; i < 50; i++) {"
+      "  var key = {'k' : i + 0.1};"
+      "  weak_map.set(key, 1);"
+      "  future_keys.push({'x' : i + 0.2});"
+      "}"
+      "weak_map");
+  if (marking->IsStopped()) {
+    marking->Start();
+  }
+  // Incrementally mark the backing store.
+  Handle<JSObject> obj =
+      v8::Utils::OpenHandle(*v8::Handle<v8::Object>::Cast(result));
+  Handle<JSWeakCollection> weak_map(reinterpret_cast<JSWeakCollection*>(*obj));
+  while (!Marking::IsBlack(
+             Marking::MarkBitFrom(HeapObject::cast(weak_map->table()))) &&
+         !marking->IsStopped()) {
+    marking->Step(MB, IncrementalMarking::NO_GC_VIA_STACK_GUARD);
+  }
+  // Stash the backing store in a handle.
+  Handle<Object> save(weak_map->table(), isolate);
+  // The following line will update the backing store.
+  CompileRun(
+      "for (var i = 0; i < 50; i++) {"
+      "  weak_map.set(future_keys[i], i);"
+      "}");
+  heap->incremental_marking()->set_should_hurry(true);
+  heap->CollectGarbage(OLD_POINTER_SPACE);
+}
+
+
+TEST(Regress442710) {
+  CcTest::InitializeVM();
+  Isolate* isolate = CcTest::i_isolate();
+  Heap* heap = isolate->heap();
+  Factory* factory = isolate->factory();
+
+  HandleScope sc(isolate);
+  Handle<GlobalObject> global(CcTest::i_isolate()->context()->global_object());
+  Handle<JSArray> array = factory->NewJSArray(2);
+
+  Handle<String> name = factory->InternalizeUtf8String("testArray");
+  JSReceiver::SetProperty(global, name, array, SLOPPY).Check();
+  CompileRun("testArray[0] = 1; testArray[1] = 2; testArray.shift();");
+  heap->CollectGarbage(OLD_POINTER_SPACE);
+}
+
+
 #ifdef DEBUG
 TEST(PathTracer) {
   CcTest::InitializeVM();
diff --git a/test/cctest/test-lockers.cc b/test/cctest/test-lockers.cc
index ed315ce..dc5404e 100644
--- a/test/cctest/test-lockers.cc
+++ b/test/cctest/test-lockers.cc
@@ -141,6 +141,7 @@
 
   void Join() {
     semaphore_.Wait();
+    thread_.Join();
   }
 
   virtual void Run() = 0;
diff --git a/test/cctest/test-log-stack-tracer.cc b/test/cctest/test-log-stack-tracer.cc
index 334a201..714ad69 100644
--- a/test/cctest/test-log-stack-tracer.cc
+++ b/test/cctest/test-log-stack-tracer.cc
@@ -235,9 +235,9 @@
 
 static void CFuncDoTrace(byte dummy_parameter) {
   Address fp;
-#ifdef __GNUC__
+#if V8_HAS_BUILTIN_FRAME_ADDRESS
   fp = reinterpret_cast<Address>(__builtin_frame_address(0));
-#elif defined _MSC_VER
+#elif V8_CC_MSVC
   // Approximate a frame pointer address. We compile without base pointers,
   // so we can't trust ebp/rbp.
   fp = &dummy_parameter - 2 * sizeof(void*);  // NOLINT
diff --git a/test/cctest/test-log.cc b/test/cctest/test-log.cc
index 482f89f..eee3e13 100644
--- a/test/cctest/test-log.cc
+++ b/test/cctest/test-log.cc
@@ -42,6 +42,7 @@
 #include "src/natives.h"
 #include "src/utils.h"
 #include "src/v8threads.h"
+#include "src/version.h"
 #include "src/vm-state-inl.h"
 #include "test/cctest/cctest.h"
 
@@ -477,10 +478,9 @@
         isolate, log.start(), v8::String::kNormalString, log.length());
     initialize_logger.env()->Global()->Set(v8_str("_log"), log_str);
 
-    i::Vector<const unsigned char> source = TestSources::GetScriptsSource();
+    i::Vector<const char> source = TestSources::GetScriptsSource();
     v8::Handle<v8::String> source_str = v8::String::NewFromUtf8(
-        isolate, reinterpret_cast<const char*>(source.start()),
-        v8::String::kNormalString, source.length());
+        isolate, source.start(), v8::String::kNormalString, source.length());
     v8::TryCatch try_catch;
     v8::Handle<v8::Script> script = CompileWithOrigin(source_str, "");
     if (script.IsEmpty()) {
@@ -496,7 +496,7 @@
     }
     // The result either be a "true" literal or problem description.
     if (!result->IsTrue()) {
-      v8::Local<v8::String> s = result->ToString();
+      v8::Local<v8::String> s = result->ToString(isolate);
       i::ScopedVector<char> data(s->Utf8Length() + 1);
       CHECK_NE(NULL, data.start());
       s->WriteUtf8(data.start());
@@ -508,3 +508,23 @@
   }
   isolate->Dispose();
 }
+
+
+TEST(LogVersion) {
+  v8::Isolate* isolate;
+  {
+    ScopedLoggerInitializer initialize_logger;
+    isolate = initialize_logger.isolate();
+    bool exists = false;
+    i::Vector<const char> log(
+        i::ReadFile(initialize_logger.StopLoggingGetTempFile(), &exists, true));
+    CHECK(exists);
+    i::EmbeddedVector<char, 100> ref_data;
+    i::SNPrintF(ref_data, "v8-version,%d,%d,%d,%d,%d", i::Version::GetMajor(),
+                i::Version::GetMinor(), i::Version::GetBuild(),
+                i::Version::GetPatch(), i::Version::IsCandidate());
+    CHECK_NE(NULL, StrNStr(log.start(), ref_data.start(), log.length()));
+    log.Dispose();
+  }
+  isolate->Dispose();
+}
diff --git a/test/cctest/test-mark-compact.cc b/test/cctest/test-mark-compact.cc
index c7d6531..64d995d 100644
--- a/test/cctest/test-mark-compact.cc
+++ b/test/cctest/test-mark-compact.cc
@@ -446,7 +446,7 @@
     bool write_permission = (buffer[position++] == 'w');
     CHECK(buffer[position] == '-' || buffer[position] == 'x');
     bool execute_permission = (buffer[position++] == 'x');
-    CHECK(buffer[position] == '-' || buffer[position] == 'p');
+    CHECK(buffer[position] == 's' || buffer[position] == 'p');
     bool private_mapping = (buffer[position++] == 'p');
     CHECK_EQ(buffer[position++], ' ');
     uintptr_t offset = ReadLong(buffer, &position, 16);
diff --git a/test/cctest/test-object-observe.cc b/test/cctest/test-object-observe.cc
index d208a26..2766a4f 100644
--- a/test/cctest/test-object-observe.cc
+++ b/test/cctest/test-object-observe.cc
@@ -130,6 +130,59 @@
 }
 
 
+TEST(DeliveryCallbackThrows) {
+  HandleScope scope(CcTest::isolate());
+  LocalContext context(CcTest::isolate());
+  CompileRun(
+      "var obj = {};"
+      "var ordering = [];"
+      "function observer1() { ordering.push(1); };"
+      "function observer2() { ordering.push(2); };"
+      "function observer_throws() {"
+      "  ordering.push(0);"
+      "  throw new Error();"
+      "  ordering.push(-1);"
+      "};"
+      "Object.observe(obj, observer_throws.bind());"
+      "Object.observe(obj, observer1);"
+      "Object.observe(obj, observer_throws.bind());"
+      "Object.observe(obj, observer2);"
+      "Object.observe(obj, observer_throws.bind());"
+      "obj.foo = 'bar';");
+  CHECK_EQ(5, CompileRun("ordering.length")->Int32Value());
+  CHECK_EQ(0, CompileRun("ordering[0]")->Int32Value());
+  CHECK_EQ(1, CompileRun("ordering[1]")->Int32Value());
+  CHECK_EQ(0, CompileRun("ordering[2]")->Int32Value());
+  CHECK_EQ(2, CompileRun("ordering[3]")->Int32Value());
+  CHECK_EQ(0, CompileRun("ordering[4]")->Int32Value());
+}
+
+
+TEST(DeliveryChangesMutationInCallback) {
+  HandleScope scope(CcTest::isolate());
+  LocalContext context(CcTest::isolate());
+  CompileRun(
+      "var obj = {};"
+      "var ordering = [];"
+      "function observer1(records) {"
+      "  ordering.push(100 + records.length);"
+      "  records.push(11);"
+      "  records.push(22);"
+      "};"
+      "function observer2(records) {"
+      "  ordering.push(200 + records.length);"
+      "  records.push(33);"
+      "  records.push(44);"
+      "};"
+      "Object.observe(obj, observer1);"
+      "Object.observe(obj, observer2);"
+      "obj.foo = 'bar';");
+  CHECK_EQ(2, CompileRun("ordering.length")->Int32Value());
+  CHECK_EQ(101, CompileRun("ordering[0]")->Int32Value());
+  CHECK_EQ(201, CompileRun("ordering[1]")->Int32Value());
+}
+
+
 TEST(DeliveryOrderingReentrant) {
   HandleScope scope(CcTest::isolate());
   LocalContext context(CcTest::isolate());
@@ -709,3 +762,76 @@
   CcTest::isolate()->ContextDisposedNotification();
   CheckSurvivingGlobalObjectsCount(1);
 }
+
+
+static void ObserverCallback(const FunctionCallbackInfo<Value>& args) {
+  *static_cast<int*>(Handle<External>::Cast(args.Data())->Value()) =
+      Handle<Array>::Cast(args[0])->Length();
+}
+
+
+TEST(ObjectObserveCallsCppFunction) {
+  Isolate* isolate = CcTest::isolate();
+  HandleScope scope(isolate);
+  LocalContext context(isolate);
+  int numRecordsSent = 0;
+  Handle<Function> observer =
+      Function::New(CcTest::isolate(), ObserverCallback,
+                    External::New(isolate, &numRecordsSent));
+  context->Global()->Set(String::NewFromUtf8(CcTest::isolate(), "observer"),
+                         observer);
+  CompileRun(
+      "var obj = {};"
+      "Object.observe(obj, observer);"
+      "obj.foo = 1;"
+      "obj.bar = 2;");
+  CHECK_EQ(2, numRecordsSent);
+}
+
+
+TEST(ObjectObserveCallsFunctionTemplateInstance) {
+  Isolate* isolate = CcTest::isolate();
+  HandleScope scope(isolate);
+  LocalContext context(isolate);
+  int numRecordsSent = 0;
+  Handle<FunctionTemplate> tmpl = FunctionTemplate::New(
+      isolate, ObserverCallback, External::New(isolate, &numRecordsSent));
+  context->Global()->Set(String::NewFromUtf8(CcTest::isolate(), "observer"),
+                         tmpl->GetFunction());
+  CompileRun(
+      "var obj = {};"
+      "Object.observe(obj, observer);"
+      "obj.foo = 1;"
+      "obj.bar = 2;");
+  CHECK_EQ(2, numRecordsSent);
+}
+
+
+static void AccessorGetter(Local<String> property,
+                           const PropertyCallbackInfo<Value>& info) {
+  info.GetReturnValue().Set(Integer::New(info.GetIsolate(), 42));
+}
+
+
+static void AccessorSetter(Local<String> property, Local<Value> value,
+                           const PropertyCallbackInfo<void>& info) {
+  info.GetReturnValue().SetUndefined();
+}
+
+
+TEST(APIAccessorsShouldNotNotify) {
+  Isolate* isolate = CcTest::isolate();
+  HandleScope handle_scope(isolate);
+  LocalContext context(isolate);
+  Handle<Object> object = Object::New(isolate);
+  object->SetAccessor(String::NewFromUtf8(isolate, "accessor"), &AccessorGetter,
+                      &AccessorSetter);
+  context->Global()->Set(String::NewFromUtf8(isolate, "obj"), object);
+  CompileRun(
+      "var records = null;"
+      "Object.observe(obj, function(r) { records = r });"
+      "obj.accessor = 43;");
+  CHECK(CompileRun("records")->IsNull());
+  CompileRun("Object.defineProperty(obj, 'accessor', { value: 44 });");
+  CHECK(CompileRun("records")->IsNull());
+}
diff --git a/test/cctest/test-ostreams.cc b/test/cctest/test-ostreams.cc
deleted file mode 100644
index c83f96d..0000000
--- a/test/cctest/test-ostreams.cc
+++ /dev/null
@@ -1,148 +0,0 @@
-// 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.
-
-#include <string.h>
-#include <limits>
-
-#include "include/v8stdint.h"
-#include "src/ostreams.h"
-#include "test/cctest/cctest.h"
-
-using namespace v8::internal;
-
-
-TEST(OStringStreamConstructor) {
-  OStringStream oss;
-  const size_t expected_size = 0;
-  CHECK(expected_size == oss.size());
-  CHECK_GT(oss.capacity(), 0);
-  CHECK_NE(NULL, oss.data());
-  CHECK_EQ("", oss.c_str());
-}
-
-
-#define TEST_STRING            \
-  "Ash nazg durbatuluk, "      \
-  "ash nazg gimbatul, "        \
-  "ash nazg thrakatuluk, "     \
-  "agh burzum-ishi krimpatul."
-
-TEST(OStringStreamGrow) {
-  OStringStream oss;
-  const int repeat = 30;
-  size_t len = strlen(TEST_STRING);
-  for (int i = 0; i < repeat; ++i) {
-    oss.write(TEST_STRING, len);
-  }
-  const char* expected =
-      TEST_STRING TEST_STRING TEST_STRING TEST_STRING TEST_STRING
-      TEST_STRING TEST_STRING TEST_STRING TEST_STRING TEST_STRING
-      TEST_STRING TEST_STRING TEST_STRING TEST_STRING TEST_STRING
-      TEST_STRING TEST_STRING TEST_STRING TEST_STRING TEST_STRING
-      TEST_STRING TEST_STRING TEST_STRING TEST_STRING TEST_STRING
-      TEST_STRING TEST_STRING TEST_STRING TEST_STRING TEST_STRING;
-  const size_t expected_len = len * repeat;
-  CHECK(expected_len == oss.size());
-  CHECK_GT(oss.capacity(), 0);
-  CHECK_EQ(0, strncmp(expected, oss.data(), expected_len));
-  CHECK_EQ(expected, oss.c_str());
-}
-
-
-template <class T>
-static void check(const char* expected, T value) {
-  OStringStream oss;
-  oss << value << " " << hex << value;
-  CHECK_EQ(expected, oss.c_str());
-}
-
-
-TEST(NumericFormatting) {
-  check<bool>("0 0", false);
-  check<bool>("1 1", true);
-
-  check<int16_t>("-12345 cfc7", -12345);
-  check<int16_t>("-32768 8000", std::numeric_limits<int16_t>::min());
-  check<int16_t>("32767 7fff", std::numeric_limits<int16_t>::max());
-
-  check<uint16_t>("34567 8707", 34567);
-  check<uint16_t>("0 0", std::numeric_limits<uint16_t>::min());
-  check<uint16_t>("65535 ffff", std::numeric_limits<uint16_t>::max());
-
-  check<int32_t>("-1234567 ffed2979", -1234567);
-  check<int32_t>("-2147483648 80000000", std::numeric_limits<int32_t>::min());
-  check<int32_t>("2147483647 7fffffff", std::numeric_limits<int32_t>::max());
-
-  check<uint32_t>("3456789 34bf15", 3456789);
-  check<uint32_t>("0 0", std::numeric_limits<uint32_t>::min());
-  check<uint32_t>("4294967295 ffffffff", std::numeric_limits<uint32_t>::max());
-
-  check<int64_t>("-1234567 ffffffffffed2979", -1234567);
-  check<int64_t>("-9223372036854775808 8000000000000000",
-                 std::numeric_limits<int64_t>::min());
-  check<int64_t>("9223372036854775807 7fffffffffffffff",
-                 std::numeric_limits<int64_t>::max());
-
-  check<uint64_t>("3456789 34bf15", 3456789);
-  check<uint64_t>("0 0", std::numeric_limits<uint64_t>::min());
-  check<uint64_t>("18446744073709551615 ffffffffffffffff",
-                  std::numeric_limits<uint64_t>::max());
-
-  check<float>("0 0", 0.0f);
-  check<float>("123 123", 123.0f);
-  check<float>("-0.5 -0.5", -0.5f);
-  check<float>("1.25 1.25", 1.25f);
-  check<float>("0.0625 0.0625", 6.25e-2f);
-
-  check<double>("0 0", 0.0);
-  check<double>("123 123", 123.0);
-  check<double>("-0.5 -0.5", -0.5);
-  check<double>("1.25 1.25", 1.25);
-  check<double>("0.0625 0.0625", 6.25e-2);
-}
-
-
-TEST(CharacterOutput) {
-  check<char>("a a", 'a');
-  check<signed char>("B B", 'B');
-  check<unsigned char>("9 9", '9');
-  check<const char*>("bye bye", "bye");
-
-  OStringStream os;
-  os.put('H').write("ello", 4);
-  CHECK_EQ("Hello", os.c_str());
-}
-
-
-TEST(Manipulators) {
-  OStringStream os;
-  os << 123 << hex << 123 << endl << 123 << dec << 123 << 123;
-  CHECK_EQ("1237b\n7b123123", os.c_str());
-}
-
-
-class MiscStuff {
- public:
-  MiscStuff(int i, double d, const char* s) : i_(i), d_(d), s_(s) { }
-
- private:
-  friend OStream& operator<<(OStream& os, const MiscStuff& m);
-
-  int i_;
-  double d_;
-  const char* s_;
-};
-
-
-OStream& operator<<(OStream& os, const MiscStuff& m) {
-  return os << "{i:" << m.i_ << ", d:" << m.d_ << ", s:'" << m.s_ << "'}";
-}
-
-
-TEST(CustomOutput) {
-  OStringStream os;
-  MiscStuff m(123, 4.5, "Hurz!");
-  os << m;
-  CHECK_EQ("{i:123, d:4.5, s:'Hurz!'}", os.c_str());
-}
diff --git a/test/cctest/test-parsing.cc b/test/cctest/test-parsing.cc
index 72f2298..08caeab 100644
--- a/test/cctest/test-parsing.cc
+++ b/test/cctest/test-parsing.cc
@@ -31,6 +31,8 @@
 
 #include "src/v8.h"
 
+#include "src/ast.h"
+#include "src/ast-numbering.h"
 #include "src/ast-value-factory.h"
 #include "src/compiler.h"
 #include "src/execution.h"
@@ -317,8 +319,8 @@
 
     i::PreParser preparser(&scanner, &log, stack_limit);
     preparser.set_allow_lazy(true);
-    preparser.set_allow_natives_syntax(true);
-    preparser.set_allow_arrow_functions(true);
+    preparser.set_allow_natives(true);
+    preparser.set_allow_harmony_arrow_functions(true);
     i::PreParser::PreParseResult result = preparser.PreParseProgram();
     CHECK_EQ(i::PreParser::kPreParseSuccess, result);
     CHECK(!log.HasError());
@@ -452,14 +454,14 @@
   i::PreParser::PreParseResult result = preparser.PreParseProgram();
   CHECK_EQ(i::PreParser::kPreParseSuccess, result);
   i::ScriptData* sd = log.GetScriptData();
-  i::ParseData pd(sd);
-  pd.Initialize();
+  i::ParseData* pd = i::ParseData::FromCachedData(sd);
+  pd->Initialize();
 
   int first_function =
       static_cast<int>(strstr(program, "function") - program);
   int first_lbrace = first_function + i::StrLength("function () ");
   CHECK_EQ('{', program[first_lbrace]);
-  i::FunctionEntry entry1 = pd.GetFunctionEntry(first_lbrace);
+  i::FunctionEntry entry1 = pd->GetFunctionEntry(first_lbrace);
   CHECK(!entry1.is_valid());
 
   int second_function =
@@ -467,10 +469,11 @@
   int second_lbrace =
       second_function + i::StrLength("function () ");
   CHECK_EQ('{', program[second_lbrace]);
-  i::FunctionEntry entry2 = pd.GetFunctionEntry(second_lbrace);
+  i::FunctionEntry entry2 = pd->GetFunctionEntry(second_lbrace);
   CHECK(entry2.is_valid());
   CHECK_EQ('}', program[entry2.end_pos() - 1]);
   delete sd;
+  delete pd;
 }
 
 
@@ -496,7 +499,7 @@
 
   i::PreParser preparser(&scanner, &log, stack_limit);
   preparser.set_allow_lazy(true);
-  preparser.set_allow_arrow_functions(true);
+  preparser.set_allow_harmony_arrow_functions(true);
   i::PreParser::PreParseResult result = preparser.PreParseProgram();
   CHECK_EQ(i::PreParser::kPreParseStackOverflow, result);
 }
@@ -917,6 +920,142 @@
 }
 
 
+TEST(ScopeUsesArgumentsSuperThis) {
+  static const struct {
+    const char* prefix;
+    const char* suffix;
+  } surroundings[] = {
+    { "function f() {", "}" },
+    { "var f = () => {", "}" },
+  };
+
+  enum Expected {
+    NONE = 0,
+    ARGUMENTS = 1,
+    SUPER_PROPERTY = 2,
+    SUPER_CONSTRUCTOR_CALL = 4,
+    THIS = 8,
+    INNER_ARGUMENTS = 16,
+    INNER_SUPER_PROPERTY = 32,
+    INNER_SUPER_CONSTRUCTOR_CALL = 64,
+    INNER_THIS = 128
+  };
+
+  static const struct {
+    const char* body;
+    int expected;
+  } source_data[] = {
+        {"", NONE},
+        {"return this", THIS},
+        {"return arguments", ARGUMENTS},
+        {"return super()", SUPER_CONSTRUCTOR_CALL},
+        {"return super.x", SUPER_PROPERTY},
+        {"return arguments[0]", ARGUMENTS},
+        {"return this + arguments[0]", ARGUMENTS | THIS},
+        {"return this + arguments[0] + super.x",
+         ARGUMENTS | SUPER_PROPERTY | THIS},
+        {"return x => this + x", INNER_THIS},
+        {"return x => super() + x", INNER_SUPER_CONSTRUCTOR_CALL},
+        {"this.foo = 42;", THIS},
+        {"this.foo();", THIS},
+        {"if (foo()) { this.f() }", THIS},
+        {"if (foo()) { super.f() }", SUPER_PROPERTY},
+        {"if (arguments.length) { this.f() }", ARGUMENTS | THIS},
+        {"while (true) { this.f() }", THIS},
+        {"while (true) { super.f() }", SUPER_PROPERTY},
+        {"if (true) { while (true) this.foo(arguments) }", ARGUMENTS | THIS},
+        // Multiple nesting levels must work as well.
+        {"while (true) { while (true) { while (true) return this } }", THIS},
+        {"while (true) { while (true) { while (true) return super() } }",
+         SUPER_CONSTRUCTOR_CALL},
+        {"if (1) { return () => { while (true) new this() } }", INNER_THIS},
+        {"if (1) { return () => { while (true) new super() } }", NONE},
+        {"if (1) { return () => { while (true) new new super() } }", NONE},
+        // Note that propagation of the inner_uses_this() value does not
+        // cross boundaries of normal functions onto parent scopes.
+        {"return function (x) { return this + x }", NONE},
+        {"return function (x) { return super() + x }", NONE},
+        {"var x = function () { this.foo = 42 };", NONE},
+        {"var x = function () { super.foo = 42 };", NONE},
+        {"if (1) { return function () { while (true) new this() } }", NONE},
+        {"if (1) { return function () { while (true) new super() } }", NONE},
+        {"return function (x) { return () => this }", NONE},
+        {"return function (x) { return () => super() }", NONE},
+        // Flags must be correctly set when using block scoping.
+        {"\"use strict\"; while (true) { let x; this, arguments; }",
+         INNER_ARGUMENTS | INNER_THIS},
+        {"\"use strict\"; while (true) { let x; this, super(), arguments; }",
+         INNER_ARGUMENTS | INNER_SUPER_CONSTRUCTOR_CALL | INNER_THIS},
+        {"\"use strict\"; if (foo()) { let x; this.f() }", INNER_THIS},
+        {"\"use strict\"; if (foo()) { let x; super.f() }",
+         INNER_SUPER_PROPERTY},
+        {"\"use strict\"; if (1) {"
+         "  let x; return function () { return this + super() + arguments }"
+         "}",
+         NONE},
+    };
+
+  i::Isolate* isolate = CcTest::i_isolate();
+  i::Factory* factory = isolate->factory();
+
+  v8::HandleScope handles(CcTest::isolate());
+  v8::Handle<v8::Context> context = v8::Context::New(CcTest::isolate());
+  v8::Context::Scope context_scope(context);
+
+  isolate->stack_guard()->SetStackLimit(i::GetCurrentStackPosition() -
+                                        128 * 1024);
+
+  for (unsigned j = 0; j < arraysize(surroundings); ++j) {
+    for (unsigned i = 0; i < arraysize(source_data); ++i) {
+      int kProgramByteSize = i::StrLength(surroundings[j].prefix) +
+                             i::StrLength(surroundings[j].suffix) +
+                             i::StrLength(source_data[i].body);
+      i::ScopedVector<char> program(kProgramByteSize + 1);
+      i::SNPrintF(program, "%s%s%s", surroundings[j].prefix,
+                  source_data[i].body, surroundings[j].suffix);
+      i::Handle<i::String> source =
+          factory->NewStringFromUtf8(i::CStrVector(program.start()))
+              .ToHandleChecked();
+      i::Handle<i::Script> script = factory->NewScript(source);
+      i::CompilationInfoWithZone info(script);
+      i::Parser::ParseInfo parse_info = {isolate->stack_guard()->real_climit(),
+                                         isolate->heap()->HashSeed(),
+                                         isolate->unicode_cache()};
+      i::Parser parser(&info, &parse_info);
+      parser.set_allow_harmony_arrow_functions(true);
+      parser.set_allow_harmony_classes(true);
+      parser.set_allow_harmony_scoping(true);
+      info.MarkAsGlobal();
+      parser.Parse();
+      CHECK(i::Rewriter::Rewrite(&info));
+      CHECK(i::Scope::Analyze(&info));
+      CHECK(info.function() != NULL);
+
+      i::Scope* script_scope = info.function()->scope();
+      CHECK(script_scope->is_script_scope());
+      CHECK_EQ(1, script_scope->inner_scopes()->length());
+
+      i::Scope* scope = script_scope->inner_scopes()->at(0);
+      CHECK_EQ((source_data[i].expected & ARGUMENTS) != 0,
+               scope->uses_arguments());
+      CHECK_EQ((source_data[i].expected & SUPER_PROPERTY) != 0,
+               scope->uses_super_property());
+      CHECK_EQ((source_data[i].expected & SUPER_CONSTRUCTOR_CALL) != 0,
+               scope->uses_super_constructor_call());
+      CHECK_EQ((source_data[i].expected & THIS) != 0, scope->uses_this());
+      CHECK_EQ((source_data[i].expected & INNER_ARGUMENTS) != 0,
+               scope->inner_uses_arguments());
+      CHECK_EQ((source_data[i].expected & INNER_SUPER_PROPERTY) != 0,
+               scope->inner_uses_super_property());
+      CHECK_EQ((source_data[i].expected & INNER_SUPER_CONSTRUCTOR_CALL) != 0,
+               scope->inner_uses_super_constructor_call());
+      CHECK_EQ((source_data[i].expected & INNER_THIS) != 0,
+               scope->inner_uses_this());
+    }
+  }
+}
+
+
 TEST(ScopePositions) {
   v8::internal::FLAG_harmony_scoping = true;
 
@@ -974,11 +1113,10 @@
       "    infunction;\n"
       "  }", "\n"
       "  more;", i::FUNCTION_SCOPE, i::SLOPPY },
-    // TODO(aperez): Change to use i::ARROW_SCOPE when implemented
     { "  start;\n", "(a,b) => a + b", "; more;",
-      i::FUNCTION_SCOPE, i::SLOPPY },
+      i::ARROW_SCOPE, i::SLOPPY },
     { "  start;\n", "(a,b) => { return a+b; }", "\nmore;",
-      i::FUNCTION_SCOPE, i::SLOPPY },
+      i::ARROW_SCOPE, i::SLOPPY },
     { "  start;\n"
       "  (function fun", "(a,b) { infunction; }", ")();",
       i::FUNCTION_SCOPE, i::SLOPPY },
@@ -1137,7 +1275,7 @@
     i::Parser parser(&info, &parse_info);
     parser.set_allow_lazy(true);
     parser.set_allow_harmony_scoping(true);
-    parser.set_allow_arrow_functions(true);
+    parser.set_allow_harmony_arrow_functions(true);
     info.MarkAsGlobal();
     info.SetStrictMode(source_data[i].strict_mode);
     parser.Parse();
@@ -1145,7 +1283,7 @@
 
     // Check scope types and positions.
     i::Scope* scope = info.function()->scope();
-    CHECK(scope->is_global_scope());
+    CHECK(scope->is_script_scope());
     CHECK_EQ(scope->start_position(), 0);
     CHECK_EQ(scope->end_position(), kProgramSize);
     CHECK_EQ(scope->inner_scopes()->length(), 1);
@@ -1211,13 +1349,16 @@
 
 enum ParserFlag {
   kAllowLazy,
-  kAllowNativesSyntax,
+  kAllowNatives,
   kAllowHarmonyScoping,
-  kAllowModules,
+  kAllowHarmonyModules,
   kAllowHarmonyNumericLiterals,
-  kAllowArrowFunctions,
-  kAllowClasses,
-  kAllowHarmonyObjectLiterals
+  kAllowHarmonyArrowFunctions,
+  kAllowHarmonyClasses,
+  kAllowHarmonyObjectLiterals,
+  kAllowHarmonyTemplates,
+  kAllowHarmonySloppy,
+  kAllowHarmonyUnicode
 };
 
 
@@ -1231,15 +1372,19 @@
 void SetParserFlags(i::ParserBase<Traits>* parser,
                     i::EnumSet<ParserFlag> flags) {
   parser->set_allow_lazy(flags.Contains(kAllowLazy));
-  parser->set_allow_natives_syntax(flags.Contains(kAllowNativesSyntax));
+  parser->set_allow_natives(flags.Contains(kAllowNatives));
   parser->set_allow_harmony_scoping(flags.Contains(kAllowHarmonyScoping));
-  parser->set_allow_modules(flags.Contains(kAllowModules));
+  parser->set_allow_harmony_modules(flags.Contains(kAllowHarmonyModules));
   parser->set_allow_harmony_numeric_literals(
       flags.Contains(kAllowHarmonyNumericLiterals));
   parser->set_allow_harmony_object_literals(
       flags.Contains(kAllowHarmonyObjectLiterals));
-  parser->set_allow_arrow_functions(flags.Contains(kAllowArrowFunctions));
-  parser->set_allow_classes(flags.Contains(kAllowClasses));
+  parser->set_allow_harmony_arrow_functions(
+      flags.Contains(kAllowHarmonyArrowFunctions));
+  parser->set_allow_harmony_classes(flags.Contains(kAllowHarmonyClasses));
+  parser->set_allow_harmony_templates(flags.Contains(kAllowHarmonyTemplates));
+  parser->set_allow_harmony_sloppy(flags.Contains(kAllowHarmonySloppy));
+  parser->set_allow_harmony_unicode(flags.Contains(kAllowHarmonyUnicode));
 }
 
 
@@ -1250,6 +1395,8 @@
   i::Factory* factory = isolate->factory();
 
   uintptr_t stack_limit = isolate->stack_guard()->real_climit();
+  int preparser_materialized_literals = -1;
+  int parser_materialized_literals = -2;
 
   // Preparse the data.
   i::CompleteParserRecorder log;
@@ -1259,7 +1406,8 @@
     i::PreParser preparser(&scanner, &log, stack_limit);
     SetParserFlags(&preparser, flags);
     scanner.Initialize(&stream);
-    i::PreParser::PreParseResult result = preparser.PreParseProgram();
+    i::PreParser::PreParseResult result = preparser.PreParseProgram(
+        &preparser_materialized_literals);
     CHECK_EQ(i::PreParser::kPreParseSuccess, result);
   }
 
@@ -1278,6 +1426,9 @@
     info.MarkAsGlobal();
     parser.Parse();
     function = info.function();
+    if (function) {
+      parser_materialized_literals = function->materialized_literal_count();
+    }
   }
 
   // Check that preparsing fails iff parsing fails.
@@ -1343,6 +1494,15 @@
         "However, parser and preparser succeeded",
         source->ToCString().get());
     CHECK(false);
+  } else if (preparser_materialized_literals != parser_materialized_literals) {
+    v8::base::OS::Print(
+        "Preparser materialized literals (%d) differ from Parser materialized "
+        "literals (%d) on:\n"
+        "\t%s\n"
+        "However, parser and preparser succeeded",
+        preparser_materialized_literals, parser_materialized_literals,
+        source->ToCString().get());
+    CHECK(false);
   }
 }
 
@@ -1352,7 +1512,9 @@
                     size_t varying_flags_length,
                     ParserSyncTestResult result = kSuccessOrError,
                     const ParserFlag* always_true_flags = NULL,
-                    size_t always_true_flags_length = 0) {
+                    size_t always_true_flags_length = 0,
+                    const ParserFlag* always_false_flags = NULL,
+                    size_t always_false_flags_length = 0) {
   i::Handle<i::String> str =
       CcTest::i_isolate()->factory()->NewStringFromAsciiChecked(source);
   for (int bits = 0; bits < (1 << varying_flags_length); bits++) {
@@ -1365,6 +1527,10 @@
          ++flag_index) {
       flags.Add(always_true_flags[flag_index]);
     }
+    for (size_t flag_index = 0; flag_index < always_false_flags_length;
+         ++flag_index) {
+      flags.Remove(always_false_flags[flag_index]);
+    }
     TestParserSyncWithFlags(str, flags, result);
   }
 }
@@ -1399,7 +1565,7 @@
     "if (false) {} else ;",
     "if (false) {} else {}",
     "if (false) {} else 12",
-    "if (false) ;"
+    "if (false) ;",
     "if (false) {}",
     "if (false) 12",
     "do {} while (false)",
@@ -1419,8 +1585,8 @@
     "with ({}) ;",
     "with ({}) {}",
     "with ({}) 12",
-    "switch ({}) { default: }"
-    "label3: "
+    "switch ({}) { default: }",
+    "label3: ",
     "throw",
     "throw  12",
     "throw\n12",
@@ -1447,16 +1613,6 @@
   CcTest::i_isolate()->stack_guard()->SetStackLimit(
       i::GetCurrentStackPosition() - 128 * 1024);
 
-  static const ParserFlag flags1[] = {
-    kAllowArrowFunctions,
-    kAllowClasses,
-    kAllowHarmonyNumericLiterals,
-    kAllowHarmonyObjectLiterals,
-    kAllowHarmonyScoping,
-    kAllowLazy,
-    kAllowModules,
-  };
-
   for (int i = 0; context_data[i][0] != NULL; ++i) {
     for (int j = 0; statement_data[j] != NULL; ++j) {
       for (int k = 0; termination_data[k] != NULL; ++k) {
@@ -1476,7 +1632,7 @@
             termination_data[k],
             context_data[i][1]);
         CHECK(length == kProgramSize);
-        TestParserSync(program.start(), flags1, arraysize(flags1));
+        TestParserSync(program.start(), NULL, 0);
       }
     }
   }
@@ -1488,7 +1644,7 @@
   TestParserSync("0o1234", flags2, arraysize(flags2));
   TestParserSync("0b1011", flags2, arraysize(flags2));
 
-  static const ParserFlag flags3[] = { kAllowNativesSyntax };
+  static const ParserFlag flags3[] = { kAllowNatives };
   TestParserSync("%DebugPrint(123)", flags3, arraysize(flags3));
 }
 
@@ -1522,7 +1678,9 @@
                        const ParserFlag* flags = NULL,
                        int flags_len = 0,
                        const ParserFlag* always_true_flags = NULL,
-                       int always_true_flags_len = 0) {
+                       int always_true_len = 0,
+                       const ParserFlag* always_false_flags = NULL,
+                       int always_false_len = 0) {
   v8::HandleScope handles(CcTest::isolate());
   v8::Handle<v8::Context> context = v8::Context::New(CcTest::isolate());
   v8::Context::Scope context_scope(context);
@@ -1530,36 +1688,32 @@
   CcTest::i_isolate()->stack_guard()->SetStackLimit(
       i::GetCurrentStackPosition() - 128 * 1024);
 
+  // Experimental feature flags should not go here; pass the flags as
+  // always_true_flags if the test needs them.
   static const ParserFlag default_flags[] = {
-    kAllowArrowFunctions,
-    kAllowClasses,
-    kAllowHarmonyNumericLiterals,
-    kAllowHarmonyObjectLiterals,
-    kAllowHarmonyScoping,
     kAllowLazy,
-    kAllowModules,
-    kAllowNativesSyntax,
+    kAllowNatives,
   };
   ParserFlag* generated_flags = NULL;
   if (flags == NULL) {
     flags = default_flags;
     flags_len = arraysize(default_flags);
-    if (always_true_flags != NULL) {
-      // Remove always_true_flags from default_flags.
-      CHECK(always_true_flags_len < flags_len);
-      generated_flags = new ParserFlag[flags_len - always_true_flags_len];
+    if (always_true_flags != NULL || always_false_flags != NULL) {
+      // Remove always_true/false_flags from default_flags (if present).
+      CHECK((always_true_flags != NULL) == (always_true_len > 0));
+      CHECK((always_false_flags != NULL) == (always_false_len > 0));
+      generated_flags = new ParserFlag[flags_len + always_true_len];
       int flag_index = 0;
       for (int i = 0; i < flags_len; ++i) {
         bool use_flag = true;
-        for (int j = 0; j < always_true_flags_len; ++j) {
-          if (flags[i] == always_true_flags[j]) {
-            use_flag = false;
-            break;
-          }
+        for (int j = 0; use_flag && j < always_true_len; ++j) {
+          if (flags[i] == always_true_flags[j]) use_flag = false;
+        }
+        for (int j = 0; use_flag && j < always_false_len; ++j) {
+          if (flags[i] == always_false_flags[j]) use_flag = false;
         }
         if (use_flag) generated_flags[flag_index++] = flags[i];
       }
-      CHECK(flag_index == flags_len - always_true_flags_len);
       flags_len = flag_index;
       flags = generated_flags;
     }
@@ -1584,7 +1738,9 @@
                      flags_len,
                      result,
                      always_true_flags,
-                     always_true_flags_len);
+                     always_true_len,
+                     always_false_flags,
+                     always_false_len);
     }
   }
   delete[] generated_flags;
@@ -1691,45 +1847,70 @@
     NULL
   };
 
-  static const ParserFlag always_flags[] = {kAllowArrowFunctions};
+  static const ParserFlag always_flags[] = {kAllowHarmonyArrowFunctions};
   RunParserSyncTest(context_data, statement_data, kSuccess, NULL, 0,
                     always_flags, arraysize(always_flags));
 }
 
 
+#define FUTURE_STRICT_RESERVED_WORDS(V) \
+  V(implements)                         \
+  V(interface)                          \
+  V(let)                                \
+  V(package)                            \
+  V(private)                            \
+  V(protected)                          \
+  V(public)                             \
+  V(static)                             \
+  V(yield)
+
+
+#define LIMITED_FUTURE_STRICT_RESERVED_WORDS(V) \
+  V(implements)                                 \
+  V(let)                                        \
+  V(static)                                     \
+  V(yield)
+
+
+#define FUTURE_STRICT_RESERVED_STATEMENTS(NAME) \
+  "var " #NAME ";",                             \
+  "var foo, " #NAME ";",                        \
+  "try { } catch (" #NAME ") { }",              \
+  "function " #NAME "() { }",                   \
+  "(function " #NAME "() { })",                 \
+  "function foo(" #NAME ") { }",                \
+  "function foo(bar, " #NAME ") { }",           \
+  #NAME " = 1;",                                \
+  #NAME " += 1;",                               \
+  "var foo = " #NAME " = 1;",                   \
+  "++" #NAME ";",                               \
+  #NAME " ++;",
+
+
 TEST(ErrorsFutureStrictReservedWords) {
   // Tests that both preparsing and parsing produce the right kind of errors for
   // using future strict reserved words as identifiers. Without the strict mode,
   // it's ok to use future strict reserved words as identifiers. With the strict
   // mode, it isn't.
   const char* context_data[][2] = {
-    { "\"use strict\";", "" },
     { "function test_func() {\"use strict\"; ", "}"},
     { "() => { \"use strict\"; ", "}" },
     { NULL, NULL }
   };
 
-  const char* statement_data[] = {
-    "var interface;",
-    "var foo, interface;",
-    "try { } catch (interface) { }",
-    "function interface() { }",
-    "function foo(interface) { }",
-    "function foo(bar, interface) { }",
-    "interface = 1;",
-    "var foo = interface = 1;",
-    "++interface;",
-    "interface++;",
-    "var yield = 13;",
+  const char* statement_data[] {
+    LIMITED_FUTURE_STRICT_RESERVED_WORDS(FUTURE_STRICT_RESERVED_STATEMENTS)
     NULL
   };
 
-  static const ParserFlag always_flags[] = {kAllowArrowFunctions};
-  RunParserSyncTest(context_data, statement_data, kError, NULL, 0, always_flags,
-                    arraysize(always_flags));
+  RunParserSyncTest(context_data, statement_data, kError);
+  RunParserSyncTest(context_data, statement_data, kError);
 }
 
 
+#undef LIMITED_FUTURE_STRICT_RESERVED_WORDS
+
+
 TEST(NoErrorsFutureStrictReservedWords) {
   const char* context_data[][2] = {
     { "", "" },
@@ -1739,23 +1920,18 @@
   };
 
   const char* statement_data[] = {
-    "var interface;",
-    "var foo, interface;",
-    "try { } catch (interface) { }",
-    "function interface() { }",
-    "function foo(interface) { }",
-    "function foo(bar, interface) { }",
-    "interface = 1;",
-    "var foo = interface = 1;",
-    "++interface;",
-    "interface++;",
-    "var yield = 13;",
+    FUTURE_STRICT_RESERVED_WORDS(FUTURE_STRICT_RESERVED_STATEMENTS)
     NULL
   };
 
-  static const ParserFlag always_flags[] = {kAllowArrowFunctions};
+  static const ParserFlag always_flags[] = {kAllowHarmonyArrowFunctions};
   RunParserSyncTest(context_data, statement_data, kSuccess, NULL, 0,
                     always_flags, arraysize(always_flags));
+
+  static const ParserFlag classes_flags[] = {
+      kAllowHarmonyArrowFunctions, kAllowHarmonyClasses, kAllowHarmonyScoping};
+  RunParserSyncTest(context_data, statement_data, kSuccess, NULL, 0,
+                    classes_flags, arraysize(classes_flags));
 }
 
 
@@ -2135,12 +2311,13 @@
     { NULL, NULL }
   };
 
+#define LABELLED_WHILE(NAME) #NAME ": while (true) { break " #NAME "; }",
   const char* statement_data[] = {
     "super: while(true) { break super; }",
-    "interface: while(true) { break interface; }",
-    "yield: while(true) { break yield; }",
+    FUTURE_STRICT_RESERVED_WORDS(LABELLED_WHILE)
     NULL
   };
+#undef LABELLED_WHILE
 
   RunParserSyncTest(context_data, statement_data, kError);
 }
@@ -2165,7 +2342,28 @@
     NULL
   };
 
-  static const ParserFlag always_flags[] = {kAllowArrowFunctions};
+  static const ParserFlag always_flags[] = {kAllowHarmonyArrowFunctions};
+  RunParserSyncTest(context_data, statement_data, kSuccess, NULL, 0,
+                    always_flags, arraysize(always_flags));
+}
+
+
+TEST(NoErrorsFutureStrictReservedAsLabelsSloppy) {
+  const char* context_data[][2] = {
+    { "", ""},
+    { "function test_func() {", "}" },
+    { "() => {", "}" },
+    { NULL, NULL }
+  };
+
+#define LABELLED_WHILE(NAME) #NAME ": while (true) { break " #NAME "; }",
+  const char* statement_data[] {
+    FUTURE_STRICT_RESERVED_WORDS(LABELLED_WHILE)
+    NULL
+  };
+#undef LABELLED_WHILE
+
+  static const ParserFlag always_flags[] = {kAllowHarmonyArrowFunctions};
   RunParserSyncTest(context_data, statement_data, kSuccess, NULL, 0,
                     always_flags, arraysize(always_flags));
 }
@@ -2285,17 +2483,18 @@
     i::ScriptData* sd = NULL;
     info.SetCachedData(&sd, v8::ScriptCompiler::kProduceParserCache);
     i::Parser::Parse(&info, true);
-    i::ParseData pd(sd);
+    i::ParseData* pd = i::ParseData::FromCachedData(sd);
 
-    if (pd.FunctionCount() != test_cases[i].functions) {
+    if (pd->FunctionCount() != test_cases[i].functions) {
       v8::base::OS::Print(
           "Expected preparse data for program:\n"
           "\t%s\n"
           "to contain %d functions, however, received %d functions.\n",
-          program, test_cases[i].functions, pd.FunctionCount());
+          program, test_cases[i].functions, pd->FunctionCount());
       CHECK(false);
     }
     delete sd;
+    delete pd;
   }
 }
 
@@ -2416,9 +2615,9 @@
     NULL
   };
 
-  // This test requires kAllowNativesSyntax to succeed.
+  // This test requires kAllowNatives to succeed.
   static const ParserFlag always_true_flags[] = {
-    kAllowNativesSyntax
+    kAllowNatives
   };
 
   RunParserSyncTest(context_data, statement_data, kSuccess, NULL, 0,
@@ -2904,11 +3103,11 @@
   const i::AstRawString* name = avf.GetOneByteString("result");
   i::Handle<i::String> str = name->string();
   CHECK(str->IsInternalizedString());
-  i::Scope* global_scope =
-      new (&zone) i::Scope(NULL, i::GLOBAL_SCOPE, &avf, &zone);
-  global_scope->Initialize();
-  i::Scope* s = i::Scope::DeserializeScopeChain(context, global_scope, &zone);
-  DCHECK(s != global_scope);
+  i::Scope* script_scope =
+      new (&zone) i::Scope(NULL, i::SCRIPT_SCOPE, &avf, &zone);
+  script_scope->Initialize();
+  i::Scope* s = i::Scope::DeserializeScopeChain(context, script_scope, &zone);
+  DCHECK(s != script_scope);
   DCHECK(name != NULL);
 
   // Get result from h's function context (that is f's context)
@@ -2951,11 +3150,11 @@
   i::AstValueFactory avf(&zone, isolate->heap()->HashSeed());
   avf.Internalize(isolate);
 
-  i::Scope* global_scope =
-      new (&zone) i::Scope(NULL, i::GLOBAL_SCOPE, &avf, &zone);
-  global_scope->Initialize();
-  i::Scope* s = i::Scope::DeserializeScopeChain(context, global_scope, &zone);
-  DCHECK(s != global_scope);
+  i::Scope* script_scope =
+      new (&zone) i::Scope(NULL, i::SCRIPT_SCOPE, &avf, &zone);
+  script_scope->Initialize();
+  i::Scope* s = i::Scope::DeserializeScopeChain(context, script_scope, &zone);
+  DCHECK(s != script_scope);
   const i::AstRawString* name_x = avf.GetOneByteString("x");
 
   // Get result from f's function context (that is g's outer context)
@@ -2998,11 +3197,11 @@
   i::AstValueFactory avf(&zone, isolate->heap()->HashSeed());
   avf.Internalize(isolate);
 
-  i::Scope* global_scope =
-      new (&zone) i::Scope(NULL, i::GLOBAL_SCOPE, &avf, &zone);
-  global_scope->Initialize();
-  i::Scope* s = i::Scope::DeserializeScopeChain(context, global_scope, &zone);
-  DCHECK(s != global_scope);
+  i::Scope* script_scope =
+      new (&zone) i::Scope(NULL, i::SCRIPT_SCOPE, &avf, &zone);
+  script_scope->Initialize();
+  i::Scope* s = i::Scope::DeserializeScopeChain(context, script_scope, &zone);
+  DCHECK(s != script_scope);
   const i::AstRawString* name_x = avf.GetOneByteString("x");
   const i::AstRawString* name_f = avf.GetOneByteString("f");
   const i::AstRawString* name_y = avf.GetOneByteString("y");
@@ -3156,8 +3355,7 @@
           i::Parser parser(&info, &parse_info);
           parser.set_allow_harmony_scoping(true);
           CHECK(parser.Parse());
-          CHECK(i::Rewriter::Rewrite(&info));
-          CHECK(i::Scope::Analyze(&info));
+          CHECK(i::Compiler::Analyze(&info));
           CHECK(info.function() != NULL);
 
           i::Scope* scope = info.function()->scope();
@@ -3304,7 +3502,7 @@
 
   // The test is quite slow, so run it with a reduced set of flags.
   static const ParserFlag flags[] = {kAllowLazy, kAllowHarmonyScoping};
-  static const ParserFlag always_flags[] = { kAllowArrowFunctions };
+  static const ParserFlag always_flags[] = { kAllowHarmonyArrowFunctions };
   RunParserSyncTest(context_data, statement_data, kError, flags,
                     arraysize(flags), always_flags, arraysize(always_flags));
 }
@@ -3358,7 +3556,7 @@
     NULL
   };
 
-  static const ParserFlag always_flags[] = {kAllowArrowFunctions};
+  static const ParserFlag always_flags[] = {kAllowHarmonyArrowFunctions};
   RunParserSyncTest(context_data, statement_data, kSuccess, NULL, 0,
                     always_flags, arraysize(always_flags));
 }
@@ -3383,7 +3581,7 @@
     "z.super",  // Ok, property lookup.
     NULL};
 
-  static const ParserFlag always_flags[] = {kAllowClasses};
+  static const ParserFlag always_flags[] = {kAllowHarmonyClasses};
   RunParserSyncTest(context_data, statement_data, kSuccess, NULL, 0,
                     always_flags, arraysize(always_flags));
 }
@@ -3402,7 +3600,7 @@
     "f(super)",
     NULL};
 
-  static const ParserFlag always_flags[] = {kAllowClasses};
+  static const ParserFlag always_flags[] = {kAllowHarmonyClasses};
   RunParserSyncTest(context_data, statement_data, kError, NULL, 0,
                     always_flags, arraysize(always_flags));
 }
@@ -3585,7 +3783,8 @@
     "class name extends class base {} {}",
     NULL};
 
-  static const ParserFlag always_flags[] = {kAllowClasses};
+  static const ParserFlag always_flags[] = {
+      kAllowHarmonyClasses, kAllowHarmonySloppy};
   RunParserSyncTest(context_data, class_data, kSuccess, NULL, 0,
                     always_flags, arraysize(always_flags));
 }
@@ -3604,7 +3803,8 @@
     "class name extends class base {} {}",
     NULL};
 
-  static const ParserFlag always_flags[] = {kAllowClasses};
+  static const ParserFlag always_flags[] = {
+      kAllowHarmonyClasses, kAllowHarmonySloppy};
   RunParserSyncTest(context_data, statement_data, kSuccess, NULL, 0,
                     always_flags, arraysize(always_flags));
 }
@@ -3648,8 +3848,9 @@
     NULL};
 
   static const ParserFlag always_flags[] = {
-    kAllowClasses,
-    kAllowHarmonyObjectLiterals
+    kAllowHarmonyClasses,
+    kAllowHarmonyObjectLiterals,
+    kAllowHarmonySloppy
   };
   RunParserSyncTest(context_data, class_body_data, kSuccess, NULL, 0,
                     always_flags, arraysize(always_flags));
@@ -3706,8 +3907,9 @@
     NULL};
 
   static const ParserFlag always_flags[] = {
-    kAllowClasses,
-    kAllowHarmonyObjectLiterals
+    kAllowHarmonyClasses,
+    kAllowHarmonyObjectLiterals,
+    kAllowHarmonySloppy
   };
   RunParserSyncTest(context_data, name_data, kSuccess, NULL, 0,
                     always_flags, arraysize(always_flags));
@@ -3737,8 +3939,9 @@
     NULL};
 
   static const ParserFlag always_flags[] = {
-    kAllowClasses,
-    kAllowHarmonyObjectLiterals
+    kAllowHarmonyClasses,
+    kAllowHarmonyObjectLiterals,
+    kAllowHarmonySloppy
   };
   RunParserSyncTest(context_data, class_data, kError, NULL, 0,
                     always_flags, arraysize(always_flags));
@@ -3774,8 +3977,9 @@
     NULL};
 
   static const ParserFlag always_flags[] = {
-    kAllowClasses,
-    kAllowHarmonyNumericLiterals
+    kAllowHarmonyClasses,
+    kAllowHarmonyNumericLiterals,
+    kAllowHarmonySloppy
   };
   RunParserSyncTest(context_data, class_data, kError, NULL, 0,
                     always_flags, arraysize(always_flags));
@@ -3804,8 +4008,9 @@
     NULL};
 
   static const ParserFlag always_flags[] = {
-    kAllowClasses,
-    kAllowHarmonyObjectLiterals
+    kAllowHarmonyClasses,
+    kAllowHarmonyObjectLiterals,
+    kAllowHarmonySloppy
   };
   RunParserSyncTest(context_data, class_name, kError, NULL, 0,
                     always_flags, arraysize(always_flags));
@@ -3837,8 +4042,9 @@
     NULL};
 
   static const ParserFlag always_flags[] = {
-    kAllowClasses,
-    kAllowHarmonyObjectLiterals
+    kAllowHarmonyClasses,
+    kAllowHarmonyObjectLiterals,
+    kAllowHarmonySloppy
   };
   RunParserSyncTest(context_data, class_name, kError, NULL, 0,
                     always_flags, arraysize(always_flags));
@@ -3855,11 +4061,19 @@
     "static get prototype() {}",
     "static set prototype(_) {}",
     "static *prototype() {}",
+    "static 'prototype'() {}",
+    "static *'prototype'() {}",
+    "static prot\\u006ftype() {}",
+    "static 'prot\\u006ftype'() {}",
+    "static get 'prot\\u006ftype'() {}",
+    "static set 'prot\\u006ftype'(_) {}",
+    "static *'prot\\u006ftype'() {}",
     NULL};
 
   static const ParserFlag always_flags[] = {
-    kAllowClasses,
-    kAllowHarmonyObjectLiterals
+    kAllowHarmonyClasses,
+    kAllowHarmonyObjectLiterals,
+    kAllowHarmonySloppy
   };
   RunParserSyncTest(context_data, class_body_data, kError, NULL, 0,
                     always_flags, arraysize(always_flags));
@@ -3875,11 +4089,19 @@
     "get constructor() {}",
     "get constructor(_) {}",
     "*constructor() {}",
+    "get 'constructor'() {}",
+    "*'constructor'() {}",
+    "get c\\u006fnstructor() {}",
+    "*c\\u006fnstructor() {}",
+    "get 'c\\u006fnstructor'() {}",
+    "get 'c\\u006fnstructor'(_) {}",
+    "*'c\\u006fnstructor'() {}",
     NULL};
 
   static const ParserFlag always_flags[] = {
-    kAllowClasses,
-    kAllowHarmonyObjectLiterals
+    kAllowHarmonyClasses,
+    kAllowHarmonyObjectLiterals,
+    kAllowHarmonySloppy
   };
   RunParserSyncTest(context_data, class_body_data, kError, NULL, 0,
                     always_flags, arraysize(always_flags));
@@ -3900,8 +4122,9 @@
     NULL};
 
   static const ParserFlag always_flags[] = {
-    kAllowClasses,
-    kAllowHarmonyObjectLiterals
+    kAllowHarmonyClasses,
+    kAllowHarmonyObjectLiterals,
+    kAllowHarmonySloppy
   };
   RunParserSyncTest(context_data, class_body_data, kSuccess, NULL, 0,
                     always_flags, arraysize(always_flags));
@@ -3909,9 +4132,6 @@
 
 
 TEST(ClassMultipleConstructorErrors) {
-  // We currently do not allow any duplicate properties in class bodies. This
-  // test ensures that when we change that we still throw on duplicate
-  // constructors.
   const char* context_data[][2] = {{"class C {", "}"},
                                    {"(class {", "});"},
                                    {NULL, NULL}};
@@ -3921,17 +4141,16 @@
     NULL};
 
   static const ParserFlag always_flags[] = {
-    kAllowClasses,
-    kAllowHarmonyObjectLiterals
+    kAllowHarmonyClasses,
+    kAllowHarmonyObjectLiterals,
+    kAllowHarmonySloppy
   };
   RunParserSyncTest(context_data, class_body_data, kError, NULL, 0,
                     always_flags, arraysize(always_flags));
 }
 
 
-// TODO(arv): We should allow duplicate property names.
-// https://code.google.com/p/v8/issues/detail?id=3570
-DISABLED_TEST(ClassMultiplePropertyNamesNoErrors) {
+TEST(ClassMultiplePropertyNamesNoErrors) {
   const char* context_data[][2] = {{"class C {", "}"},
                                    {"(class {", "});"},
                                    {NULL, NULL}};
@@ -3940,11 +4159,14 @@
     "constructor() {}; static constructor() {}",
     "m() {}; static m() {}",
     "m() {}; m() {}",
+    "static m() {}; static m() {}",
+    "get m() {}; set m(_) {}; get m() {}; set m(_) {};",
     NULL};
 
   static const ParserFlag always_flags[] = {
-    kAllowClasses,
-    kAllowHarmonyObjectLiterals
+    kAllowHarmonyClasses,
+    kAllowHarmonyObjectLiterals,
+    kAllowHarmonySloppy
   };
   RunParserSyncTest(context_data, class_body_data, kSuccess, NULL, 0,
                     always_flags, arraysize(always_flags));
@@ -3963,9 +4185,422 @@
     NULL};
 
   static const ParserFlag always_flags[] = {
-    kAllowClasses,
-    kAllowHarmonyObjectLiterals
+    kAllowHarmonyClasses,
+    kAllowHarmonyObjectLiterals,
+    kAllowHarmonySloppy
   };
   RunParserSyncTest(context_data, class_body_data, kError, NULL, 0,
                     always_flags, arraysize(always_flags));
 }
+
+
+TEST(ObjectLiteralPropertyShorthandKeywordsError) {
+  const char* context_data[][2] = {{"({", "});"},
+                                   {"'use strict'; ({", "});"},
+                                   {NULL, NULL}};
+
+  const char* name_data[] = {
+    "break",
+    "case",
+    "catch",
+    "class",
+    "const",
+    "continue",
+    "debugger",
+    "default",
+    "delete",
+    "do",
+    "else",
+    "enum",
+    "export",
+    "extends",
+    "false",
+    "finally",
+    "for",
+    "function",
+    "if",
+    "import",
+    "in",
+    "instanceof",
+    "new",
+    "null",
+    "return",
+    "super",
+    "switch",
+    "this",
+    "throw",
+    "true",
+    "try",
+    "typeof",
+    "var",
+    "void",
+    "while",
+    "with",
+    NULL
+  };
+
+  static const ParserFlag always_flags[] = {kAllowHarmonyObjectLiterals};
+  RunParserSyncTest(context_data, name_data, kError, NULL, 0,
+                    always_flags, arraysize(always_flags));
+}
+
+
+TEST(ObjectLiteralPropertyShorthandStrictKeywords) {
+  const char* context_data[][2] = {{"({", "});"},
+                                   {NULL, NULL}};
+
+  const char* name_data[] = {
+    "implements",
+    "interface",
+    "let",
+    "package",
+    "private",
+    "protected",
+    "public",
+    "static",
+    "yield",
+    NULL
+  };
+
+  static const ParserFlag always_flags[] = {kAllowHarmonyObjectLiterals};
+  RunParserSyncTest(context_data, name_data, kSuccess, NULL, 0,
+                    always_flags, arraysize(always_flags));
+
+  const char* context_strict_data[][2] = {{"'use strict'; ({", "});"},
+                                          {NULL, NULL}};
+  RunParserSyncTest(context_strict_data, name_data, kError, NULL, 0,
+                    always_flags, arraysize(always_flags));
+}
+
+
+TEST(ObjectLiteralPropertyShorthandError) {
+  const char* context_data[][2] = {{"({", "});"},
+                                   {"'use strict'; ({", "});"},
+                                   {NULL, NULL}};
+
+  const char* name_data[] = {
+    "1",
+    "1.2",
+    "0",
+    "0.1",
+    "1.0",
+    "1e1",
+    "0x1",
+    "\"s\"",
+    "'s'",
+    NULL
+  };
+
+  static const ParserFlag always_flags[] = {kAllowHarmonyObjectLiterals};
+  RunParserSyncTest(context_data, name_data, kError, NULL, 0,
+                    always_flags, arraysize(always_flags));
+}
+
+
+TEST(ObjectLiteralPropertyShorthandYieldInGeneratorError) {
+  const char* context_data[][2] = {{"", ""},
+                                   {NULL, NULL}};
+
+  const char* name_data[] = {
+    "function* g() { ({yield}); }",
+    NULL
+  };
+
+  static const ParserFlag always_flags[] = {kAllowHarmonyObjectLiterals};
+  RunParserSyncTest(context_data, name_data, kError, NULL, 0,
+                    always_flags, arraysize(always_flags));
+}
+
+
+TEST(ConstParsingInForIn) {
+  const char* context_data[][2] = {{"'use strict';", ""},
+                                   {"function foo(){ 'use strict';", "}"},
+                                   {NULL, NULL}};
+
+  const char* data[] = {
+      "for(const x = 1; ; ) {}",
+      "for(const x = 1, y = 2;;){}",
+      "for(const x in [1,2,3]) {}",
+      "for(const x of [1,2,3]) {}",
+      NULL};
+  static const ParserFlag always_flags[] = {kAllowHarmonyScoping};
+  RunParserSyncTest(context_data, data, kSuccess, NULL, 0, always_flags,
+                    arraysize(always_flags));
+}
+
+
+TEST(ConstParsingInForInError) {
+  const char* context_data[][2] = {{"'use strict';", ""},
+                                   {"function foo(){ 'use strict';", "}"},
+                                   {NULL, NULL}};
+
+  const char* data[] = {
+      "for(const x,y = 1; ; ) {}",
+      "for(const x = 4 in [1,2,3]) {}",
+      "for(const x = 4, y in [1,2,3]) {}",
+      "for(const x = 4 of [1,2,3]) {}",
+      "for(const x = 4, y of [1,2,3]) {}",
+      "for(const x = 1, y = 2 in []) {}",
+      "for(const x,y in []) {}",
+      "for(const x = 1, y = 2 of []) {}",
+      "for(const x,y of []) {}",
+      NULL};
+  static const ParserFlag always_flags[] = {kAllowHarmonyScoping};
+  RunParserSyncTest(context_data, data, kError, NULL, 0, always_flags,
+                    arraysize(always_flags));
+}
+
+
+TEST(InvalidUnicodeEscapes) {
+  const char* context_data[][2] = {{"", ""},
+                                   {"'use strict';", ""},
+                                   {NULL, NULL}};
+  const char* data[] = {
+    "var foob\\u123r = 0;",
+    "var \\u123roo = 0;",
+    "\"foob\\u123rr\"",
+    // No escapes allowed in regexp flags
+    "/regex/\\u0069g",
+    "/regex/\\u006g",
+    // Braces gone wrong
+    "var foob\\u{c481r = 0;",
+    "var foob\\uc481}r = 0;",
+    "var \\u{0052oo = 0;",
+    "var \\u0052}oo = 0;",
+    "\"foob\\u{c481r\"",
+    "var foob\\u{}ar = 0;",
+    // Too high value for the unicode escape
+    "\"\\u{110000}\"",
+    // Not an unicode escape
+    "var foob\\v1234r = 0;",
+    "var foob\\U1234r = 0;",
+    "var foob\\v{1234}r = 0;",
+    "var foob\\U{1234}r = 0;",
+    NULL};
+  static const ParserFlag always_flags[] = {kAllowHarmonyUnicode};
+  RunParserSyncTest(context_data, data, kError, NULL, 0, always_flags,
+                    arraysize(always_flags));
+}
+
+
+TEST(UnicodeEscapes) {
+  const char* context_data[][2] = {{"", ""},
+                                   {"'use strict';", ""},
+                                   {NULL, NULL}};
+  const char* data[] = {
+    // Identifier starting with escape
+    "var \\u0052oo = 0;",
+    "var \\u{0052}oo = 0;",
+    "var \\u{52}oo = 0;",
+    "var \\u{00000000052}oo = 0;",
+    // Identifier with an escape but not starting with an escape
+    "var foob\\uc481r = 0;",
+    "var foob\\u{c481}r = 0;",
+    // String with an escape
+    "\"foob\\uc481r\"",
+    "\"foob\\{uc481}r\"",
+    // This character is a valid unicode character, representable as a surrogate
+    // pair, not representable as 4 hex digits.
+    "\"foo\\u{10e6d}\"",
+    // Max value for the unicode escape
+    "\"\\u{10ffff}\"",
+    NULL};
+  static const ParserFlag always_flags[] = {kAllowHarmonyUnicode};
+  RunParserSyncTest(context_data, data, kSuccess, NULL, 0, always_flags,
+                    arraysize(always_flags));
+}
+
+
+TEST(ScanTemplateLiterals) {
+  const char* context_data[][2] = {{"'use strict';", ""},
+                                   {"function foo(){ 'use strict';"
+                                    "  var a, b, c; return ", "}"},
+                                   {NULL, NULL}};
+
+  const char* data[] = {
+      "``",
+      "`no-subst-template`",
+      "`template-head${a}`",
+      "`${a}`",
+      "`${a}template-tail`",
+      "`template-head${a}template-tail`",
+      "`${a}${b}${c}`",
+      "`a${a}b${b}c${c}`",
+      "`${a}a${b}b${c}c`",
+      "`foo\n\nbar\r\nbaz`",
+      "`foo\n\n${  bar  }\r\nbaz`",
+      "`foo${a /* comment */}`",
+      "`foo${a // comment\n}`",
+      "`foo${a \n}`",
+      "`foo${a \r\n}`",
+      "`foo${a \r}`",
+      "`foo${/* comment */ a}`",
+      "`foo${// comment\na}`",
+      "`foo${\n a}`",
+      "`foo${\r\n a}`",
+      "`foo${\r a}`",
+      "`foo${'a' in a}`",
+      NULL};
+  static const ParserFlag always_flags[] = {kAllowHarmonyTemplates};
+  RunParserSyncTest(context_data, data, kSuccess, NULL, 0, always_flags,
+                    arraysize(always_flags));
+}
+
+
+TEST(ScanTaggedTemplateLiterals) {
+  const char* context_data[][2] = {{"'use strict';", ""},
+                                   {"function foo(){ 'use strict';"
+                                    "  function tag() {}"
+                                    "  var a, b, c; return ", "}"},
+                                   {NULL, NULL}};
+
+  const char* data[] = {
+      "tag ``",
+      "tag `no-subst-template`",
+      "tag`template-head${a}`",
+      "tag `${a}`",
+      "tag `${a}template-tail`",
+      "tag   `template-head${a}template-tail`",
+      "tag\n`${a}${b}${c}`",
+      "tag\r\n`a${a}b${b}c${c}`",
+      "tag    `${a}a${b}b${c}c`",
+      "tag\t`foo\n\nbar\r\nbaz`",
+      "tag\r`foo\n\n${  bar  }\r\nbaz`",
+      "tag`foo${a /* comment */}`",
+      "tag`foo${a // comment\n}`",
+      "tag`foo${a \n}`",
+      "tag`foo${a \r\n}`",
+      "tag`foo${a \r}`",
+      "tag`foo${/* comment */ a}`",
+      "tag`foo${// comment\na}`",
+      "tag`foo${\n a}`",
+      "tag`foo${\r\n a}`",
+      "tag`foo${\r a}`",
+      "tag`foo${'a' in a}`",
+      NULL};
+  static const ParserFlag always_flags[] = {kAllowHarmonyTemplates};
+  RunParserSyncTest(context_data, data, kSuccess, NULL, 0, always_flags,
+                    arraysize(always_flags));
+}
+
+
+TEST(TemplateMaterializedLiterals) {
+  const char* context_data[][2] = {
+    {
+      "'use strict';\n"
+      "function tag() {}\n"
+      "var a, b, c;\n"
+      "(", ")"
+    },
+    {NULL, NULL}
+  };
+
+  const char* data[] = {
+    "tag``",
+    "tag`a`",
+    "tag`a${1}b`",
+    "tag`a${1}b${2}c`",
+    "``",
+    "`a`",
+    "`a${1}b`",
+    "`a${1}b${2}c`",
+    NULL
+  };
+
+  static const ParserFlag always_flags[] = {kAllowHarmonyTemplates};
+  RunParserSyncTest(context_data, data, kSuccess, NULL, 0, always_flags,
+                    arraysize(always_flags));
+}
+
+
+TEST(ScanUnterminatedTemplateLiterals) {
+  const char* context_data[][2] = {{"'use strict';", ""},
+                                   {"function foo(){ 'use strict';"
+                                    "  var a, b, c; return ", "}"},
+                                   {NULL, NULL}};
+
+  const char* data[] = {
+      "`no-subst-template",
+      "`template-head${a}",
+      "`${a}template-tail",
+      "`template-head${a}template-tail",
+      "`${a}${b}${c}",
+      "`a${a}b${b}c${c}",
+      "`${a}a${b}b${c}c",
+      "`foo\n\nbar\r\nbaz",
+      "`foo\n\n${  bar  }\r\nbaz",
+      "`foo${a /* comment } */`",
+      "`foo${a /* comment } `*/",
+      "`foo${a // comment}`",
+      "`foo${a \n`",
+      "`foo${a \r\n`",
+      "`foo${a \r`",
+      "`foo${/* comment */ a`",
+      "`foo${// commenta}`",
+      "`foo${\n a`",
+      "`foo${\r\n a`",
+      "`foo${\r a`",
+      "`foo${fn(}`",
+      "`foo${1 if}`",
+      NULL};
+  static const ParserFlag always_flags[] = {kAllowHarmonyTemplates};
+  RunParserSyncTest(context_data, data, kError, NULL, 0, always_flags,
+                    arraysize(always_flags));
+}
+
+
+TEST(TemplateLiteralsIllegalTokens) {
+  const char* context_data[][2] = {{"'use strict';", ""},
+                                   {"function foo(){ 'use strict';"
+                                    "  var a, b, c; return ", "}"},
+                                   {NULL, NULL}};
+  const char* data[] = {
+      "`hello\\x`",
+      "`hello\\x${1}`",
+      "`hello${1}\\x`",
+      "`hello${1}\\x${2}`",
+      "`hello\\x\n`",
+      "`hello\\x\n${1}`",
+      "`hello${1}\\x\n`",
+      "`hello${1}\\x\n${2}`",
+      NULL};
+
+  static const ParserFlag always_flags[] = {kAllowHarmonyTemplates};
+  RunParserSyncTest(context_data, data, kError, NULL, 0, always_flags,
+                    arraysize(always_flags));
+}
+
+
+TEST(LexicalScopingSloppyMode) {
+  const char* context_data[][2] = {
+      {"", ""},
+      {"function f() {", "}"},
+      {"{", "}"},
+      {NULL, NULL}};
+  const char* bad_data[] = {
+    "let x = 1;",
+    "for(let x = 1;;){}",
+    "for(let x of []){}",
+    "for(let x in []){}",
+    "class C {}",
+    "class C extends D {}",
+    "(class {})",
+    "(class extends D {})",
+    "(class C {})",
+    "(class C extends D {})",
+    NULL};
+  static const ParserFlag always_true_flags[] = {
+      kAllowHarmonyScoping, kAllowHarmonyClasses};
+  static const ParserFlag always_false_flags[] = {kAllowHarmonySloppy};
+  RunParserSyncTest(context_data, bad_data, kError, NULL, 0,
+                    always_true_flags, arraysize(always_true_flags),
+                    always_false_flags, arraysize(always_false_flags));
+
+  const char* good_data[] = {
+    "let = 1;",
+    "for(let = 1;;){}",
+    NULL};
+  RunParserSyncTest(context_data, good_data, kSuccess, NULL, 0,
+                    always_true_flags, arraysize(always_true_flags),
+                    always_false_flags, arraysize(always_false_flags));
+}
diff --git a/test/cctest/test-platform.cc b/test/cctest/test-platform.cc
index 100a5a7..90926d1 100644
--- a/test/cctest/test-platform.cc
+++ b/test/cctest/test-platform.cc
@@ -2,7 +2,7 @@
 // Use of this source code is governed by a BSD-style license that can be
 // found in the LICENSE file.
 
-#include "include/v8stdint.h"
+#include <stdint.h>
 #include "src/base/build_config.h"
 #include "src/base/platform/platform.h"
 #include "test/cctest/cctest.h"
diff --git a/test/cctest/test-regexp.cc b/test/cctest/test-regexp.cc
index 9d1d52e..4a572c8 100644
--- a/test/cctest/test-regexp.cc
+++ b/test/cctest/test-regexp.cc
@@ -25,8 +25,8 @@
 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
-
-#include <stdlib.h>
+#include <cstdlib>
+#include <sstream>
 
 #include "src/v8.h"
 
@@ -103,9 +103,9 @@
       &reader, false, &result, &zone));
   CHECK(result.tree != NULL);
   CHECK(result.error.is_null());
-  OStringStream os;
+  std::ostringstream os;
   result.tree->Print(os, &zone);
-  CHECK_EQ(expected, os.c_str());
+  CHECK_EQ(expected, os.str().c_str());
 }
 
 
@@ -435,11 +435,11 @@
   // Check that we don't allow more than kMaxCapture captures
   const int kMaxCaptures = 1 << 16;  // Must match RegExpParser::kMaxCaptures.
   const char* kTooManyCaptures = "Too many captures";
-  OStringStream os;
+  std::ostringstream os;
   for (int i = 0; i <= kMaxCaptures; i++) {
     os << "()";
   }
-  ExpectError(os.c_str(), kTooManyCaptures);
+  ExpectError(os.str().c_str(), kTooManyCaptures);
 }
 
 
diff --git a/test/cctest/test-sampler-api.cc b/test/cctest/test-sampler-api.cc
new file mode 100644
index 0000000..2f6f92e
--- /dev/null
+++ b/test/cctest/test-sampler-api.cc
@@ -0,0 +1,245 @@
+// 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.
+//
+// Tests the sampling API in include/v8.h
+
+#include <map>
+#include <string>
+#include "include/v8.h"
+#include "src/simulator.h"
+#include "test/cctest/cctest.h"
+
+namespace {
+
+class Sample {
+ public:
+  enum { kFramesLimit = 255 };
+
+  Sample() {}
+
+  typedef const void* const* const_iterator;
+  const_iterator begin() const { return data_.start(); }
+  const_iterator end() const { return &data_[data_.length()]; }
+
+  int size() const { return data_.length(); }
+  v8::internal::Vector<void*>& data() { return data_; }
+
+ private:
+  v8::internal::EmbeddedVector<void*, kFramesLimit> data_;
+};
+
+
+#if defined(USE_SIMULATOR)
+class SimulatorHelper {
+ public:
+  inline bool Init(v8::Isolate* isolate) {
+    simulator_ = reinterpret_cast<v8::internal::Isolate*>(isolate)
+                     ->thread_local_top()
+                     ->simulator_;
+    // Check if there is active simulator.
+    return simulator_ != NULL;
+  }
+
+  inline void FillRegisters(v8::RegisterState* state) {
+#if V8_TARGET_ARCH_ARM
+    state->pc = reinterpret_cast<void*>(simulator_->get_pc());
+    state->sp = reinterpret_cast<void*>(
+        simulator_->get_register(v8::internal::Simulator::sp));
+    state->fp = reinterpret_cast<void*>(
+        simulator_->get_register(v8::internal::Simulator::r11));
+#elif V8_TARGET_ARCH_ARM64
+    if (simulator_->sp() == 0 || simulator_->fp() == 0) {
+      // It's possible that the simulator is interrupted while it is updating
+      // the sp or fp register. ARM64 simulator does this in two steps:
+      // first setting it to zero and then setting it to a new value.
+      // Bailout if sp/fp doesn't contain the new value.
+      return;
+    }
+    state->pc = reinterpret_cast<void*>(simulator_->pc());
+    state->sp = reinterpret_cast<void*>(simulator_->sp());
+    state->fp = reinterpret_cast<void*>(simulator_->fp());
+#elif V8_TARGET_ARCH_MIPS || V8_TARGET_ARCH_MIPS64
+    state->pc = reinterpret_cast<void*>(simulator_->get_pc());
+    state->sp = reinterpret_cast<void*>(
+        simulator_->get_register(v8::internal::Simulator::sp));
+    state->fp = reinterpret_cast<void*>(
+        simulator_->get_register(v8::internal::Simulator::fp));
+#endif
+  }
+
+ private:
+  v8::internal::Simulator* simulator_;
+};
+#endif  // USE_SIMULATOR
+
+
+class SamplingTestHelper {
+ public:
+  struct CodeEventEntry {
+    std::string name;
+    const void* code_start;
+    size_t code_len;
+  };
+  typedef std::map<const void*, CodeEventEntry> CodeEntries;
+
+  explicit SamplingTestHelper(const std::string& test_function)
+      : sample_is_taken_(false), isolate_(CcTest::isolate()) {
+    DCHECK_EQ(NULL, instance_);
+    instance_ = this;
+    v8::HandleScope scope(isolate_);
+    v8::Handle<v8::ObjectTemplate> global = v8::ObjectTemplate::New(isolate_);
+    global->Set(v8::String::NewFromUtf8(isolate_, "CollectSample"),
+                v8::FunctionTemplate::New(isolate_, CollectSample));
+    LocalContext env(isolate_, NULL, global);
+    isolate_->SetJitCodeEventHandler(v8::kJitCodeEventDefault,
+                                     JitCodeEventHandler);
+    v8::Script::Compile(
+        v8::String::NewFromUtf8(isolate_, test_function.c_str()))->Run();
+  }
+
+  ~SamplingTestHelper() {
+    isolate_->SetJitCodeEventHandler(v8::kJitCodeEventDefault, NULL);
+    instance_ = NULL;
+  }
+
+  Sample& sample() { return sample_; }
+
+  const CodeEventEntry* FindEventEntry(const void* address) {
+    CodeEntries::const_iterator it = code_entries_.upper_bound(address);
+    if (it == code_entries_.begin()) return NULL;
+    const CodeEventEntry& entry = (--it)->second;
+    const void* code_end =
+        static_cast<const uint8_t*>(entry.code_start) + entry.code_len;
+    return address < code_end ? &entry : NULL;
+  }
+
+ private:
+  static void CollectSample(const v8::FunctionCallbackInfo<v8::Value>& args) {
+    instance_->DoCollectSample();
+  }
+
+  static void JitCodeEventHandler(const v8::JitCodeEvent* event) {
+    instance_->DoJitCodeEventHandler(event);
+  }
+
+  // The JavaScript calls this function when on full stack depth.
+  void DoCollectSample() {
+    v8::RegisterState state;
+#if defined(USE_SIMULATOR)
+    SimulatorHelper simulator_helper;
+    if (!simulator_helper.Init(isolate_)) return;
+    simulator_helper.FillRegisters(&state);
+#else
+    state.pc = NULL;
+    state.fp = &state;
+    state.sp = &state;
+#endif
+    v8::SampleInfo info;
+    isolate_->GetStackSample(state, sample_.data().start(),
+                             static_cast<size_t>(sample_.size()), &info);
+    size_t frames_count = info.frames_count;
+    CHECK_LE(frames_count, static_cast<size_t>(sample_.size()));
+    sample_.data().Truncate(static_cast<int>(frames_count));
+    sample_is_taken_ = true;
+  }
+
+  void DoJitCodeEventHandler(const v8::JitCodeEvent* event) {
+    if (sample_is_taken_) return;
+    switch (event->type) {
+      case v8::JitCodeEvent::CODE_ADDED: {
+        CodeEventEntry entry;
+        entry.name = std::string(event->name.str, event->name.len);
+        entry.code_start = event->code_start;
+        entry.code_len = event->code_len;
+        code_entries_.insert(std::make_pair(entry.code_start, entry));
+        break;
+      }
+      case v8::JitCodeEvent::CODE_MOVED: {
+        CodeEntries::iterator it = code_entries_.find(event->code_start);
+        CHECK(it != code_entries_.end());
+        code_entries_.erase(it);
+        CodeEventEntry entry;
+        entry.name = std::string(event->name.str, event->name.len);
+        entry.code_start = event->new_code_start;
+        entry.code_len = event->code_len;
+        code_entries_.insert(std::make_pair(entry.code_start, entry));
+        break;
+      }
+      case v8::JitCodeEvent::CODE_REMOVED:
+        code_entries_.erase(event->code_start);
+        break;
+      default:
+        break;
+    }
+  }
+
+  Sample sample_;
+  bool sample_is_taken_;
+  v8::Isolate* isolate_;
+  CodeEntries code_entries_;
+
+  static SamplingTestHelper* instance_;
+};
+
+SamplingTestHelper* SamplingTestHelper::instance_;
+
+}  // namespace
+
+
+// A JavaScript function which takes stack depth
+// (minimum value 2) as an argument.
+// When at the bottom of the recursion,
+// the JavaScript code calls into C++ test code,
+// waiting for the sampler to take a sample.
+static const char* test_function =
+    "function func(depth) {"
+    "  if (depth == 2) CollectSample();"
+    "  else return func(depth - 1);"
+    "}";
+
+
+TEST(StackDepthIsConsistent) {
+  SamplingTestHelper helper(std::string(test_function) + "func(8);");
+  CHECK_EQ(8, helper.sample().size());
+}
+
+
+TEST(StackDepthDoesNotExceedMaxValue) {
+  SamplingTestHelper helper(std::string(test_function) + "func(300);");
+  CHECK_EQ(Sample::kFramesLimit, helper.sample().size());
+}
+
+
+// The captured sample should have three pc values.
+// They should fall in the range where the compiled code resides.
+// The expected stack is:
+// bottom of stack [{anon script}, outer, inner] top of stack
+//                              ^      ^       ^
+// sample.stack indices         2      1       0
+TEST(StackFramesConsistent) {
+  // Note: The arguments.callee stuff is there so that the
+  //       functions are not optimized away.
+  const char* test_script =
+      "function test_sampler_api_inner() {"
+      "  CollectSample();"
+      "  return arguments.callee.toString();"
+      "}"
+      "function test_sampler_api_outer() {"
+      "  return test_sampler_api_inner() + arguments.callee.toString();"
+      "}"
+      "test_sampler_api_outer();";
+
+  SamplingTestHelper helper(test_script);
+  Sample& sample = helper.sample();
+  CHECK_EQ(3, sample.size());
+
+  const SamplingTestHelper::CodeEventEntry* entry;
+  entry = helper.FindEventEntry(sample.begin()[0]);
+  CHECK_NE(NULL, entry);
+  CHECK(std::string::npos != entry->name.find("test_sampler_api_inner"));
+
+  entry = helper.FindEventEntry(sample.begin()[1]);
+  CHECK_NE(NULL, entry);
+  CHECK(std::string::npos != entry->name.find("test_sampler_api_outer"));
+}
diff --git a/test/cctest/test-serialize.cc b/test/cctest/test-serialize.cc
index 94b400e..45da250 100644
--- a/test/cctest/test-serialize.cc
+++ b/test/cctest/test-serialize.cc
@@ -37,7 +37,7 @@
 #include "src/heap/spaces.h"
 #include "src/natives.h"
 #include "src/objects.h"
-#include "src/runtime.h"
+#include "src/runtime/runtime.h"
 #include "src/scopeinfo.h"
 #include "src/serialize.h"
 #include "src/snapshot.h"
@@ -114,82 +114,27 @@
 }
 
 
-class FileByteSink : public SnapshotByteSink {
- public:
-  explicit FileByteSink(const char* snapshot_file) {
-    fp_ = v8::base::OS::FOpen(snapshot_file, "wb");
-    file_name_ = snapshot_file;
-    if (fp_ == NULL) {
-      PrintF("Unable to write to snapshot file \"%s\"\n", snapshot_file);
-      exit(1);
-    }
+void WritePayload(const Vector<const byte>& payload, const char* file_name) {
+  FILE* file = v8::base::OS::FOpen(file_name, "wb");
+  if (file == NULL) {
+    PrintF("Unable to write to snapshot file \"%s\"\n", file_name);
+    exit(1);
   }
-  virtual ~FileByteSink() {
-    if (fp_ != NULL) {
-      fclose(fp_);
-    }
+  size_t written = fwrite(payload.begin(), 1, payload.length(), file);
+  if (written != static_cast<size_t>(payload.length())) {
+    i::PrintF("Writing snapshot file failed.. Aborting.\n");
+    exit(1);
   }
-  virtual void Put(byte b, const char* description) {
-    if (fp_ != NULL) {
-      fputc(b, fp_);
-    }
-  }
-  virtual int Position() {
-    return ftell(fp_);
-  }
-  void WriteSpaceUsed(
-      int new_space_used,
-      int pointer_space_used,
-      int data_space_used,
-      int code_space_used,
-      int map_space_used,
-      int cell_space_used,
-      int property_cell_space_used);
-
- private:
-  FILE* fp_;
-  const char* file_name_;
-};
-
-
-void FileByteSink::WriteSpaceUsed(
-      int new_space_used,
-      int pointer_space_used,
-      int data_space_used,
-      int code_space_used,
-      int map_space_used,
-      int cell_space_used,
-      int property_cell_space_used) {
-  int file_name_length = StrLength(file_name_) + 10;
-  Vector<char> name = Vector<char>::New(file_name_length + 1);
-  SNPrintF(name, "%s.size", file_name_);
-  FILE* fp = v8::base::OS::FOpen(name.start(), "w");
-  name.Dispose();
-  fprintf(fp, "new %d\n", new_space_used);
-  fprintf(fp, "pointer %d\n", pointer_space_used);
-  fprintf(fp, "data %d\n", data_space_used);
-  fprintf(fp, "code %d\n", code_space_used);
-  fprintf(fp, "map %d\n", map_space_used);
-  fprintf(fp, "cell %d\n", cell_space_used);
-  fprintf(fp, "property cell %d\n", property_cell_space_used);
-  fclose(fp);
+  fclose(file);
 }
 
 
 static bool WriteToFile(Isolate* isolate, const char* snapshot_file) {
-  FileByteSink file(snapshot_file);
-  StartupSerializer ser(isolate, &file);
+  SnapshotByteSink sink;
+  StartupSerializer ser(isolate, &sink);
   ser.Serialize();
-
-  file.WriteSpaceUsed(
-      ser.CurrentAllocationAddress(NEW_SPACE),
-      ser.CurrentAllocationAddress(OLD_POINTER_SPACE),
-      ser.CurrentAllocationAddress(OLD_DATA_SPACE),
-      ser.CurrentAllocationAddress(CODE_SPACE),
-      ser.CurrentAllocationAddress(MAP_SPACE),
-      ser.CurrentAllocationAddress(CELL_SPACE),
-      ser.CurrentAllocationAddress(PROPERTY_CELL_SPACE));
-
+  SnapshotData snapshot_data(sink, ser);
+  WritePayload(snapshot_data.RawData(), snapshot_file);
   return true;
 }
 
@@ -206,7 +151,7 @@
   }
 
   Isolate* internal_isolate = reinterpret_cast<Isolate*>(isolate);
-  internal_isolate->heap()->CollectAllGarbage(Heap::kNoGCFlags, "serialize");
+  internal_isolate->heap()->CollectAllAvailableGarbage("serialize");
   WriteToFile(internal_isolate, FLAG_testing_serialization_file);
 }
 
@@ -237,51 +182,14 @@
 //----------------------------------------------------------------------------
 // Tests that the heap can be deserialized.
 
-
-static void ReserveSpaceForSnapshot(Deserializer* deserializer,
-                                    const char* file_name) {
-  int file_name_length = StrLength(file_name) + 10;
-  Vector<char> name = Vector<char>::New(file_name_length + 1);
-  SNPrintF(name, "%s.size", file_name);
-  FILE* fp = v8::base::OS::FOpen(name.start(), "r");
-  name.Dispose();
-  int new_size, pointer_size, data_size, code_size, map_size, cell_size,
-      property_cell_size;
-#ifdef _MSC_VER
-  // Avoid warning about unsafe fscanf from MSVC.
-  // Please note that this is only fine if %c and %s are not being used.
-#define fscanf fscanf_s
-#endif
-  CHECK_EQ(1, fscanf(fp, "new %d\n", &new_size));
-  CHECK_EQ(1, fscanf(fp, "pointer %d\n", &pointer_size));
-  CHECK_EQ(1, fscanf(fp, "data %d\n", &data_size));
-  CHECK_EQ(1, fscanf(fp, "code %d\n", &code_size));
-  CHECK_EQ(1, fscanf(fp, "map %d\n", &map_size));
-  CHECK_EQ(1, fscanf(fp, "cell %d\n", &cell_size));
-  CHECK_EQ(1, fscanf(fp, "property cell %d\n", &property_cell_size));
-#ifdef _MSC_VER
-#undef fscanf
-#endif
-  fclose(fp);
-  deserializer->set_reservation(NEW_SPACE, new_size);
-  deserializer->set_reservation(OLD_POINTER_SPACE, pointer_size);
-  deserializer->set_reservation(OLD_DATA_SPACE, data_size);
-  deserializer->set_reservation(CODE_SPACE, code_size);
-  deserializer->set_reservation(MAP_SPACE, map_size);
-  deserializer->set_reservation(CELL_SPACE, cell_size);
-  deserializer->set_reservation(PROPERTY_CELL_SPACE, property_cell_size);
-}
-
-
 v8::Isolate* InitializeFromFile(const char* snapshot_file) {
   int len;
   byte* str = ReadBytes(snapshot_file, &len);
   if (!str) return NULL;
   v8::Isolate* v8_isolate = NULL;
   {
-    SnapshotByteSource source(str, len);
-    Deserializer deserializer(&source);
-    ReserveSpaceForSnapshot(&deserializer, snapshot_file);
+    SnapshotData snapshot_data(Vector<const byte>(str, len));
+    Deserializer deserializer(&snapshot_data);
     Isolate* isolate = Isolate::NewForTesting();
     v8_isolate = reinterpret_cast<v8::Isolate*>(isolate);
     v8::Isolate::Scope isolate_scope(v8_isolate);
@@ -440,32 +348,23 @@
       }
       env.Reset();
 
-      FileByteSink startup_sink(startup_name.start());
+      SnapshotByteSink startup_sink;
       StartupSerializer startup_serializer(isolate, &startup_sink);
       startup_serializer.SerializeStrongReferences();
 
-      FileByteSink partial_sink(FLAG_testing_serialization_file);
-      PartialSerializer p_ser(isolate, &startup_serializer, &partial_sink);
-      p_ser.Serialize(&raw_foo);
+      SnapshotByteSink partial_sink;
+      PartialSerializer partial_serializer(isolate, &startup_serializer,
+                                           &partial_sink);
+      partial_serializer.Serialize(&raw_foo);
+
       startup_serializer.SerializeWeakReferences();
 
-      partial_sink.WriteSpaceUsed(
-          p_ser.CurrentAllocationAddress(NEW_SPACE),
-          p_ser.CurrentAllocationAddress(OLD_POINTER_SPACE),
-          p_ser.CurrentAllocationAddress(OLD_DATA_SPACE),
-          p_ser.CurrentAllocationAddress(CODE_SPACE),
-          p_ser.CurrentAllocationAddress(MAP_SPACE),
-          p_ser.CurrentAllocationAddress(CELL_SPACE),
-          p_ser.CurrentAllocationAddress(PROPERTY_CELL_SPACE));
+      SnapshotData startup_snapshot(startup_sink, startup_serializer);
+      SnapshotData partial_snapshot(partial_sink, partial_serializer);
 
-      startup_sink.WriteSpaceUsed(
-          startup_serializer.CurrentAllocationAddress(NEW_SPACE),
-          startup_serializer.CurrentAllocationAddress(OLD_POINTER_SPACE),
-          startup_serializer.CurrentAllocationAddress(OLD_DATA_SPACE),
-          startup_serializer.CurrentAllocationAddress(CODE_SPACE),
-          startup_serializer.CurrentAllocationAddress(MAP_SPACE),
-          startup_serializer.CurrentAllocationAddress(CELL_SPACE),
-          startup_serializer.CurrentAllocationAddress(PROPERTY_CELL_SPACE));
+      WritePayload(partial_snapshot.RawData(), FLAG_testing_serialization_file);
+      WritePayload(startup_snapshot.RawData(), startup_name.start());
+
       startup_name.Dispose();
     }
     v8_isolate->Exit();
@@ -494,9 +393,8 @@
       Isolate* isolate = reinterpret_cast<Isolate*>(v8_isolate);
       Object* root;
       {
-        SnapshotByteSource source(snapshot, snapshot_size);
-        Deserializer deserializer(&source);
-        ReserveSpaceForSnapshot(&deserializer, file_name);
+        SnapshotData snapshot_data(Vector<const byte>(snapshot, snapshot_size));
+        Deserializer deserializer(&snapshot_data);
         deserializer.DeserializePartial(isolate, &root);
         CHECK(root->IsString());
       }
@@ -506,9 +404,8 @@
 
       Object* root2;
       {
-        SnapshotByteSource source(snapshot, snapshot_size);
-        Deserializer deserializer(&source);
-        ReserveSpaceForSnapshot(&deserializer, file_name);
+        SnapshotData snapshot_data(Vector<const byte>(snapshot, snapshot_size));
+        Deserializer deserializer(&snapshot_data);
         deserializer.DeserializePartial(isolate, &root2);
         CHECK(root2->IsString());
         CHECK(*root_handle == root2);
@@ -563,32 +460,22 @@
 
       env.Reset();
 
-      FileByteSink startup_sink(startup_name.start());
+      SnapshotByteSink startup_sink;
       StartupSerializer startup_serializer(isolate, &startup_sink);
       startup_serializer.SerializeStrongReferences();
 
-      FileByteSink partial_sink(FLAG_testing_serialization_file);
-      PartialSerializer p_ser(isolate, &startup_serializer, &partial_sink);
-      p_ser.Serialize(&raw_context);
+      SnapshotByteSink partial_sink;
+      PartialSerializer partial_serializer(isolate, &startup_serializer,
+                                           &partial_sink);
+      partial_serializer.Serialize(&raw_context);
       startup_serializer.SerializeWeakReferences();
 
-      partial_sink.WriteSpaceUsed(
-          p_ser.CurrentAllocationAddress(NEW_SPACE),
-          p_ser.CurrentAllocationAddress(OLD_POINTER_SPACE),
-          p_ser.CurrentAllocationAddress(OLD_DATA_SPACE),
-          p_ser.CurrentAllocationAddress(CODE_SPACE),
-          p_ser.CurrentAllocationAddress(MAP_SPACE),
-          p_ser.CurrentAllocationAddress(CELL_SPACE),
-          p_ser.CurrentAllocationAddress(PROPERTY_CELL_SPACE));
+      SnapshotData startup_snapshot(startup_sink, startup_serializer);
+      SnapshotData partial_snapshot(partial_sink, partial_serializer);
 
-      startup_sink.WriteSpaceUsed(
-          startup_serializer.CurrentAllocationAddress(NEW_SPACE),
-          startup_serializer.CurrentAllocationAddress(OLD_POINTER_SPACE),
-          startup_serializer.CurrentAllocationAddress(OLD_DATA_SPACE),
-          startup_serializer.CurrentAllocationAddress(CODE_SPACE),
-          startup_serializer.CurrentAllocationAddress(MAP_SPACE),
-          startup_serializer.CurrentAllocationAddress(CELL_SPACE),
-          startup_serializer.CurrentAllocationAddress(PROPERTY_CELL_SPACE));
+      WritePayload(partial_snapshot.RawData(), FLAG_testing_serialization_file);
+      WritePayload(startup_snapshot.RawData(), startup_name.start());
+
       startup_name.Dispose();
     }
     v8_isolate->Dispose();
@@ -616,9 +503,8 @@
       Isolate* isolate = reinterpret_cast<Isolate*>(v8_isolate);
       Object* root;
       {
-        SnapshotByteSource source(snapshot, snapshot_size);
-        Deserializer deserializer(&source);
-        ReserveSpaceForSnapshot(&deserializer, file_name);
+        SnapshotData snapshot_data(Vector<const byte>(snapshot, snapshot_size));
+        Deserializer deserializer(&snapshot_data);
         deserializer.DeserializePartial(isolate, &root);
         CHECK(root->IsContext());
       }
@@ -628,9 +514,8 @@
 
       Object* root2;
       {
-        SnapshotByteSource source(snapshot, snapshot_size);
-        Deserializer deserializer(&source);
-        ReserveSpaceForSnapshot(&deserializer, file_name);
+        SnapshotData snapshot_data(Vector<const byte>(snapshot, snapshot_size));
+        Deserializer deserializer(&snapshot_data);
         deserializer.DeserializePartial(isolate, &root2);
         CHECK(root2->IsContext());
         CHECK(*root_handle != root2);
@@ -786,6 +671,432 @@
 }
 
 
+Vector<const uint8_t> ConstructSource(Vector<const uint8_t> head,
+                                      Vector<const uint8_t> body,
+                                      Vector<const uint8_t> tail, int repeats) {
+  int source_length = head.length() + body.length() * repeats + tail.length();
+  uint8_t* source = NewArray<uint8_t>(static_cast<size_t>(source_length));
+  CopyChars(source, head.start(), head.length());
+  for (int i = 0; i < repeats; i++) {
+    CopyChars(source + head.length() + i * body.length(), body.start(),
+              body.length());
+  }
+  CopyChars(source + head.length() + repeats * body.length(), tail.start(),
+            tail.length());
+  return Vector<const uint8_t>(const_cast<const uint8_t*>(source),
+                               source_length);
+}
+
+
+TEST(SerializeToplevelLargeCodeObject) {
+  FLAG_serialize_toplevel = true;
+  LocalContext context;
+  Isolate* isolate = CcTest::i_isolate();
+  isolate->compilation_cache()->Disable();  // Disable same-isolate code cache.
+
+  v8::HandleScope scope(CcTest::isolate());
+
+  Vector<const uint8_t> source =
+      ConstructSource(STATIC_CHAR_VECTOR("var j=1; try { if (j) throw 1;"),
+                      STATIC_CHAR_VECTOR("for(var i=0;i<1;i++)j++;"),
+                      STATIC_CHAR_VECTOR("} catch (e) { j=7; } j"), 10000);
+  Handle<String> source_str =
+      isolate->factory()->NewStringFromOneByte(source).ToHandleChecked();
+
+  Handle<JSObject> global(isolate->context()->global_object());
+  ScriptData* cache = NULL;
+
+  Handle<SharedFunctionInfo> orig = Compiler::CompileScript(
+      source_str, Handle<String>(), 0, 0, false,
+      Handle<Context>(isolate->native_context()), NULL, &cache,
+      v8::ScriptCompiler::kProduceCodeCache, NOT_NATIVES_CODE);
+
+  CHECK(isolate->heap()->InSpace(orig->code(), LO_SPACE));
+
+  Handle<SharedFunctionInfo> copy;
+  {
+    DisallowCompilation no_compile_expected(isolate);
+    copy = Compiler::CompileScript(
+        source_str, Handle<String>(), 0, 0, false,
+        Handle<Context>(isolate->native_context()), NULL, &cache,
+        v8::ScriptCompiler::kConsumeCodeCache, NOT_NATIVES_CODE);
+  }
+  CHECK_NE(*orig, *copy);
+
+  Handle<JSFunction> copy_fun =
+      isolate->factory()->NewFunctionFromSharedFunctionInfo(
+          copy, isolate->native_context());
+
+  Handle<Object> copy_result =
+      Execution::Call(isolate, copy_fun, global, 0, NULL).ToHandleChecked();
+
+  int result_int;
+  CHECK(copy_result->ToInt32(&result_int));
+  CHECK_EQ(7, result_int);
+
+  delete cache;
+  source.Dispose();
+}
+
+
+TEST(SerializeToplevelLargeStrings) {
+  FLAG_serialize_toplevel = true;
+  LocalContext context;
+  Isolate* isolate = CcTest::i_isolate();
+  Factory* f = isolate->factory();
+  isolate->compilation_cache()->Disable();  // Disable same-isolate code cache.
+
+  v8::HandleScope scope(CcTest::isolate());
+
+  Vector<const uint8_t> source_s = ConstructSource(
+      STATIC_CHAR_VECTOR("var s = \""), STATIC_CHAR_VECTOR("abcdef"),
+      STATIC_CHAR_VECTOR("\";"), 1000000);
+  Vector<const uint8_t> source_t = ConstructSource(
+      STATIC_CHAR_VECTOR("var t = \""), STATIC_CHAR_VECTOR("uvwxyz"),
+      STATIC_CHAR_VECTOR("\"; s + t"), 999999);
+  Handle<String> source_str =
+      f->NewConsString(f->NewStringFromOneByte(source_s).ToHandleChecked(),
+                       f->NewStringFromOneByte(source_t).ToHandleChecked())
+          .ToHandleChecked();
+
+  Handle<JSObject> global(isolate->context()->global_object());
+  ScriptData* cache = NULL;
+
+  Handle<SharedFunctionInfo> orig = Compiler::CompileScript(
+      source_str, Handle<String>(), 0, 0, false,
+      Handle<Context>(isolate->native_context()), NULL, &cache,
+      v8::ScriptCompiler::kProduceCodeCache, NOT_NATIVES_CODE);
+
+  Handle<SharedFunctionInfo> copy;
+  {
+    DisallowCompilation no_compile_expected(isolate);
+    copy = Compiler::CompileScript(
+        source_str, Handle<String>(), 0, 0, false,
+        Handle<Context>(isolate->native_context()), NULL, &cache,
+        v8::ScriptCompiler::kConsumeCodeCache, NOT_NATIVES_CODE);
+  }
+  CHECK_NE(*orig, *copy);
+
+  Handle<JSFunction> copy_fun =
+      isolate->factory()->NewFunctionFromSharedFunctionInfo(
+          copy, isolate->native_context());
+
+  Handle<Object> copy_result =
+      Execution::Call(isolate, copy_fun, global, 0, NULL).ToHandleChecked();
+
+  CHECK_EQ(6 * 1999999, Handle<String>::cast(copy_result)->length());
+  Handle<Object> property = JSObject::GetDataProperty(
+      isolate->global_object(), f->NewStringFromAsciiChecked("s"));
+  CHECK(isolate->heap()->InSpace(HeapObject::cast(*property), LO_SPACE));
+  property = JSObject::GetDataProperty(isolate->global_object(),
+                                       f->NewStringFromAsciiChecked("t"));
+  CHECK(isolate->heap()->InSpace(HeapObject::cast(*property), LO_SPACE));
+  // Make sure we do not serialize too much, e.g. include the source string.
+  CHECK_LT(cache->length(), 13000000);
+
+  delete cache;
+  source_s.Dispose();
+  source_t.Dispose();
+}
+
+
+TEST(SerializeToplevelThreeBigStrings) {
+  FLAG_serialize_toplevel = true;
+  LocalContext context;
+  Isolate* isolate = CcTest::i_isolate();
+  Factory* f = isolate->factory();
+  isolate->compilation_cache()->Disable();  // Disable same-isolate code cache.
+
+  v8::HandleScope scope(CcTest::isolate());
+
+  Vector<const uint8_t> source_a =
+      ConstructSource(STATIC_CHAR_VECTOR("var a = \""), STATIC_CHAR_VECTOR("a"),
+                      STATIC_CHAR_VECTOR("\";"), 700000);
+  Handle<String> source_a_str =
+      f->NewStringFromOneByte(source_a).ToHandleChecked();
+
+  Vector<const uint8_t> source_b =
+      ConstructSource(STATIC_CHAR_VECTOR("var b = \""), STATIC_CHAR_VECTOR("b"),
+                      STATIC_CHAR_VECTOR("\";"), 600000);
+  Handle<String> source_b_str =
+      f->NewStringFromOneByte(source_b).ToHandleChecked();
+
+  Vector<const uint8_t> source_c =
+      ConstructSource(STATIC_CHAR_VECTOR("var c = \""), STATIC_CHAR_VECTOR("c"),
+                      STATIC_CHAR_VECTOR("\";"), 500000);
+  Handle<String> source_c_str =
+      f->NewStringFromOneByte(source_c).ToHandleChecked();
+
+  Handle<String> source_str =
+      f->NewConsString(
+             f->NewConsString(source_a_str, source_b_str).ToHandleChecked(),
+             source_c_str).ToHandleChecked();
+
+  Handle<JSObject> global(isolate->context()->global_object());
+  ScriptData* cache = NULL;
+
+  Handle<SharedFunctionInfo> orig = Compiler::CompileScript(
+      source_str, Handle<String>(), 0, 0, false,
+      Handle<Context>(isolate->native_context()), NULL, &cache,
+      v8::ScriptCompiler::kProduceCodeCache, NOT_NATIVES_CODE);
+
+  Handle<SharedFunctionInfo> copy;
+  {
+    DisallowCompilation no_compile_expected(isolate);
+    copy = Compiler::CompileScript(
+        source_str, Handle<String>(), 0, 0, false,
+        Handle<Context>(isolate->native_context()), NULL, &cache,
+        v8::ScriptCompiler::kConsumeCodeCache, NOT_NATIVES_CODE);
+  }
+  CHECK_NE(*orig, *copy);
+
+  Handle<JSFunction> copy_fun =
+      isolate->factory()->NewFunctionFromSharedFunctionInfo(
+          copy, isolate->native_context());
+
+  USE(Execution::Call(isolate, copy_fun, global, 0, NULL));
+
+  CHECK_EQ(600000 + 700000, CompileRun("(a + b).length")->Int32Value());
+  CHECK_EQ(500000 + 600000, CompileRun("(b + c).length")->Int32Value());
+  Heap* heap = isolate->heap();
+  CHECK(heap->InSpace(
+      *v8::Utils::OpenHandle(*CompileRun("a")->ToString(CcTest::isolate())),
+      OLD_DATA_SPACE));
+  CHECK(heap->InSpace(
+      *v8::Utils::OpenHandle(*CompileRun("b")->ToString(CcTest::isolate())),
+      OLD_DATA_SPACE));
+  CHECK(heap->InSpace(
+      *v8::Utils::OpenHandle(*CompileRun("c")->ToString(CcTest::isolate())),
+      OLD_DATA_SPACE));
+
+  delete cache;
+  source_a.Dispose();
+  source_b.Dispose();
+  source_c.Dispose();
+}
+
+
+class SerializerOneByteResource
+    : public v8::String::ExternalOneByteStringResource {
+ public:
+  SerializerOneByteResource(const char* data, size_t length)
+      : data_(data), length_(length) {}
+  virtual const char* data() const { return data_; }
+  virtual size_t length() const { return length_; }
+
+ private:
+  const char* data_;
+  size_t length_;
+};
+
+
+class SerializerTwoByteResource : public v8::String::ExternalStringResource {
+ public:
+  SerializerTwoByteResource(const char* data, size_t length)
+      : data_(AsciiToTwoByteString(data)), length_(length) {}
+  ~SerializerTwoByteResource() { DeleteArray<const uint16_t>(data_); }
+
+  virtual const uint16_t* data() const { return data_; }
+  virtual size_t length() const { return length_; }
+
+ private:
+  const uint16_t* data_;
+  size_t length_;
+};
+
+
+TEST(SerializeToplevelExternalString) {
+  FLAG_serialize_toplevel = true;
+  LocalContext context;
+  Isolate* isolate = CcTest::i_isolate();
+  isolate->compilation_cache()->Disable();  // Disable same-isolate code cache.
+
+  v8::HandleScope scope(CcTest::isolate());
+
+  // Obtain external internalized one-byte string.
+  SerializerOneByteResource one_byte_resource("one_byte", 8);
+  Handle<String> one_byte_string =
+      isolate->factory()->NewStringFromAsciiChecked("one_byte");
+  one_byte_string = isolate->factory()->InternalizeString(one_byte_string);
+  one_byte_string->MakeExternal(&one_byte_resource);
+  CHECK(one_byte_string->IsExternalOneByteString());
+  CHECK(one_byte_string->IsInternalizedString());
+
+  // Obtain external internalized two-byte string.
+  SerializerTwoByteResource two_byte_resource("two_byte", 8);
+  Handle<String> two_byte_string =
+      isolate->factory()->NewStringFromAsciiChecked("two_byte");
+  two_byte_string = isolate->factory()->InternalizeString(two_byte_string);
+  two_byte_string->MakeExternal(&two_byte_resource);
+  CHECK(two_byte_string->IsExternalTwoByteString());
+  CHECK(two_byte_string->IsInternalizedString());
+
+  const char* source =
+      "var o = {}               \n"
+      "o.one_byte = 7;          \n"
+      "o.two_byte = 8;          \n"
+      "o.one_byte + o.two_byte; \n";
+  Handle<String> source_string = isolate->factory()
+                                     ->NewStringFromUtf8(CStrVector(source))
+                                     .ToHandleChecked();
+
+  Handle<JSObject> global(isolate->context()->global_object());
+  ScriptData* cache = NULL;
+
+  Handle<SharedFunctionInfo> orig = Compiler::CompileScript(
+      source_string, Handle<String>(), 0, 0, false,
+      Handle<Context>(isolate->native_context()), NULL, &cache,
+      v8::ScriptCompiler::kProduceCodeCache, NOT_NATIVES_CODE);
+
+  Handle<SharedFunctionInfo> copy;
+  {
+    DisallowCompilation no_compile_expected(isolate);
+    copy = Compiler::CompileScript(
+        source_string, Handle<String>(), 0, 0, false,
+        Handle<Context>(isolate->native_context()), NULL, &cache,
+        v8::ScriptCompiler::kConsumeCodeCache, NOT_NATIVES_CODE);
+  }
+  CHECK_NE(*orig, *copy);
+
+  Handle<JSFunction> copy_fun =
+      isolate->factory()->NewFunctionFromSharedFunctionInfo(
+          copy, isolate->native_context());
+
+  Handle<Object> copy_result =
+      Execution::Call(isolate, copy_fun, global, 0, NULL).ToHandleChecked();
+
+  CHECK_EQ(15.0f, copy_result->Number());
+
+  delete cache;
+}
+
+
+TEST(SerializeToplevelLargeExternalString) {
+  FLAG_serialize_toplevel = true;
+  LocalContext context;
+  Isolate* isolate = CcTest::i_isolate();
+  isolate->compilation_cache()->Disable();  // Disable same-isolate code cache.
+
+  Factory* f = isolate->factory();
+
+  v8::HandleScope scope(CcTest::isolate());
+
+  // Create a huge external internalized string to use as variable name.
+  Vector<const uint8_t> string =
+      ConstructSource(STATIC_CHAR_VECTOR(""), STATIC_CHAR_VECTOR("abcdef"),
+                      STATIC_CHAR_VECTOR(""), 999999);
+  Handle<String> name = f->NewStringFromOneByte(string).ToHandleChecked();
+  SerializerOneByteResource one_byte_resource(
+      reinterpret_cast<const char*>(string.start()), string.length());
+  name = f->InternalizeString(name);
+  name->MakeExternal(&one_byte_resource);
+  CHECK(name->IsExternalOneByteString());
+  CHECK(name->IsInternalizedString());
+  CHECK(isolate->heap()->InSpace(*name, LO_SPACE));
+
+  // Create the source, which is "var <literal> = 42; <literal>".
+  Handle<String> source_str =
+      f->NewConsString(
+             f->NewConsString(f->NewStringFromAsciiChecked("var "), name)
+                 .ToHandleChecked(),
+             f->NewConsString(f->NewStringFromAsciiChecked(" = 42; "), name)
+                 .ToHandleChecked()).ToHandleChecked();
+
+  Handle<JSObject> global(isolate->context()->global_object());
+  ScriptData* cache = NULL;
+
+  Handle<SharedFunctionInfo> orig = Compiler::CompileScript(
+      source_str, Handle<String>(), 0, 0, false,
+      Handle<Context>(isolate->native_context()), NULL, &cache,
+      v8::ScriptCompiler::kProduceCodeCache, NOT_NATIVES_CODE);
+
+  Handle<SharedFunctionInfo> copy;
+  {
+    DisallowCompilation no_compile_expected(isolate);
+    copy = Compiler::CompileScript(
+        source_str, Handle<String>(), 0, 0, false,
+        Handle<Context>(isolate->native_context()), NULL, &cache,
+        v8::ScriptCompiler::kConsumeCodeCache, NOT_NATIVES_CODE);
+  }
+  CHECK_NE(*orig, *copy);
+
+  Handle<JSFunction> copy_fun =
+      f->NewFunctionFromSharedFunctionInfo(copy, isolate->native_context());
+
+  Handle<Object> copy_result =
+      Execution::Call(isolate, copy_fun, global, 0, NULL).ToHandleChecked();
+
+  CHECK_EQ(42.0f, copy_result->Number());
+
+  delete cache;
+  string.Dispose();
+}
+
+
+TEST(SerializeToplevelExternalScriptName) {
+  FLAG_serialize_toplevel = true;
+  LocalContext context;
+  Isolate* isolate = CcTest::i_isolate();
+  isolate->compilation_cache()->Disable();  // Disable same-isolate code cache.
+
+  Factory* f = isolate->factory();
+
+  v8::HandleScope scope(CcTest::isolate());
+
+  const char* source =
+      "var a = [1, 2, 3, 4];"
+      "a.reduce(function(x, y) { return x + y }, 0)";
+
+  Handle<String> source_string =
+      f->NewStringFromUtf8(CStrVector(source)).ToHandleChecked();
+
+  const SerializerOneByteResource one_byte_resource("one_byte", 8);
+  Handle<String> name =
+      f->NewExternalStringFromOneByte(&one_byte_resource).ToHandleChecked();
+  CHECK(name->IsExternalOneByteString());
+  CHECK(!name->IsInternalizedString());
+
+  Handle<JSObject> global(isolate->context()->global_object());
+  ScriptData* cache = NULL;
+
+  Handle<SharedFunctionInfo> orig = Compiler::CompileScript(
+      source_string, name, 0, 0, false,
+      Handle<Context>(isolate->native_context()), NULL, &cache,
+      v8::ScriptCompiler::kProduceCodeCache, NOT_NATIVES_CODE);
+
+  Handle<SharedFunctionInfo> copy;
+  {
+    DisallowCompilation no_compile_expected(isolate);
+    copy = Compiler::CompileScript(
+        source_string, name, 0, 0, false,
+        Handle<Context>(isolate->native_context()), NULL, &cache,
+        v8::ScriptCompiler::kConsumeCodeCache, NOT_NATIVES_CODE);
+  }
+  CHECK_NE(*orig, *copy);
+
+  Handle<JSFunction> copy_fun =
+      f->NewFunctionFromSharedFunctionInfo(copy, isolate->native_context());
+
+  Handle<Object> copy_result =
+      Execution::Call(isolate, copy_fun, global, 0, NULL).ToHandleChecked();
+
+  CHECK_EQ(10.0f, copy_result->Number());
+
+  delete cache;
+}
+
+
+static bool toplevel_test_code_event_found = false;
+
+
+static void SerializerCodeEventListener(const v8::JitCodeEvent* event) {
+  if (event->type == v8::JitCodeEvent::CODE_ADDED &&
+      memcmp(event->name.str, "Script:~test", 12) == 0) {
+    toplevel_test_code_event_found = true;
+  }
+}
+
+
 TEST(SerializeToplevelIsolates) {
   FLAG_serialize_toplevel = true;
 
@@ -805,6 +1116,7 @@
     v8::Local<v8::UnboundScript> script = v8::ScriptCompiler::CompileUnbound(
         isolate1, &source, v8::ScriptCompiler::kProduceCodeCache);
     const v8::ScriptCompiler::CachedData* data = source.GetCachedData();
+    CHECK(data);
     // Persist cached data.
     uint8_t* buffer = NewArray<uint8_t>(data->length);
     MemCopy(buffer, data->data, data->length);
@@ -812,11 +1124,14 @@
         buffer, data->length, v8::ScriptCompiler::CachedData::BufferOwned);
 
     v8::Local<v8::Value> result = script->BindToCurrentContext()->Run();
-    CHECK(result->ToString()->Equals(v8_str("abcdef")));
+    CHECK(result->ToString(isolate1)->Equals(v8_str("abcdef")));
   }
   isolate1->Dispose();
 
   v8::Isolate* isolate2 = v8::Isolate::New();
+  isolate2->SetJitCodeEventHandler(v8::kJitCodeEventDefault,
+                                   SerializerCodeEventListener);
+  toplevel_test_code_event_found = false;
   {
     v8::Isolate::Scope iscope(isolate2);
     v8::HandleScope scope(isolate2);
@@ -832,8 +1147,125 @@
       script = v8::ScriptCompiler::CompileUnbound(
           isolate2, &source, v8::ScriptCompiler::kConsumeCodeCache);
     }
+    CHECK(!cache->rejected);
     v8::Local<v8::Value> result = script->BindToCurrentContext()->Run();
-    CHECK(result->ToString()->Equals(v8_str("abcdef")));
+    CHECK(result->ToString(isolate2)->Equals(v8_str("abcdef")));
+  }
+  DCHECK(toplevel_test_code_event_found);
+  isolate2->Dispose();
+}
+
+
+TEST(SerializeToplevelFlagChange) {
+  FLAG_serialize_toplevel = true;
+
+  const char* source = "function f() { return 'abc'; }; f() + 'def'";
+  v8::ScriptCompiler::CachedData* cache;
+
+  v8::Isolate* isolate1 = v8::Isolate::New();
+  {
+    v8::Isolate::Scope iscope(isolate1);
+    v8::HandleScope scope(isolate1);
+    v8::Local<v8::Context> context = v8::Context::New(isolate1);
+    v8::Context::Scope context_scope(context);
+
+    v8::Local<v8::String> source_str = v8_str(source);
+    v8::ScriptOrigin origin(v8_str("test"));
+    v8::ScriptCompiler::Source source(source_str, origin);
+    v8::Local<v8::UnboundScript> script = v8::ScriptCompiler::CompileUnbound(
+        isolate1, &source, v8::ScriptCompiler::kProduceCodeCache);
+    const v8::ScriptCompiler::CachedData* data = source.GetCachedData();
+    CHECK(data);
+    // Persist cached data.
+    uint8_t* buffer = NewArray<uint8_t>(data->length);
+    MemCopy(buffer, data->data, data->length);
+    cache = new v8::ScriptCompiler::CachedData(
+        buffer, data->length, v8::ScriptCompiler::CachedData::BufferOwned);
+
+    v8::Local<v8::Value> result = script->BindToCurrentContext()->Run();
+    CHECK(result->ToString(isolate1)->Equals(v8_str("abcdef")));
+  }
+  isolate1->Dispose();
+
+  v8::Isolate* isolate2 = v8::Isolate::New();
+  FLAG_allow_natives_syntax = true;  // Flag change should trigger cache reject.
+  {
+    v8::Isolate::Scope iscope(isolate2);
+    v8::HandleScope scope(isolate2);
+    v8::Local<v8::Context> context = v8::Context::New(isolate2);
+    v8::Context::Scope context_scope(context);
+
+    v8::Local<v8::String> source_str = v8_str(source);
+    v8::ScriptOrigin origin(v8_str("test"));
+    v8::ScriptCompiler::Source source(source_str, origin, cache);
+    v8::ScriptCompiler::CompileUnbound(isolate2, &source,
+                                       v8::ScriptCompiler::kConsumeCodeCache);
+    CHECK(cache->rejected);
+  }
+  isolate2->Dispose();
+}
+
+
+TEST(SerializeWithHarmonyScoping) {
+  FLAG_serialize_toplevel = true;
+  FLAG_harmony_scoping = true;
+
+  const char* source1 = "'use strict'; let x = 'X'";
+  const char* source2 = "'use strict'; let y = 'Y'";
+  const char* source3 = "'use strict'; x + y";
+
+  v8::ScriptCompiler::CachedData* cache;
+
+  v8::Isolate* isolate1 = v8::Isolate::New();
+  {
+    v8::Isolate::Scope iscope(isolate1);
+    v8::HandleScope scope(isolate1);
+    v8::Local<v8::Context> context = v8::Context::New(isolate1);
+    v8::Context::Scope context_scope(context);
+
+    CompileRun(source1);
+    CompileRun(source2);
+
+    v8::Local<v8::String> source_str = v8_str(source3);
+    v8::ScriptOrigin origin(v8_str("test"));
+    v8::ScriptCompiler::Source source(source_str, origin);
+    v8::Local<v8::UnboundScript> script = v8::ScriptCompiler::CompileUnbound(
+        isolate1, &source, v8::ScriptCompiler::kProduceCodeCache);
+    const v8::ScriptCompiler::CachedData* data = source.GetCachedData();
+    CHECK(data);
+    // Persist cached data.
+    uint8_t* buffer = NewArray<uint8_t>(data->length);
+    MemCopy(buffer, data->data, data->length);
+    cache = new v8::ScriptCompiler::CachedData(
+        buffer, data->length, v8::ScriptCompiler::CachedData::BufferOwned);
+
+    v8::Local<v8::Value> result = script->BindToCurrentContext()->Run();
+    CHECK(result->ToString(isolate1)->Equals(v8_str("XY")));
+  }
+  isolate1->Dispose();
+
+  v8::Isolate* isolate2 = v8::Isolate::New();
+  {
+    v8::Isolate::Scope iscope(isolate2);
+    v8::HandleScope scope(isolate2);
+    v8::Local<v8::Context> context = v8::Context::New(isolate2);
+    v8::Context::Scope context_scope(context);
+
+    // Reverse order of prior running scripts.
+    CompileRun(source2);
+    CompileRun(source1);
+
+    v8::Local<v8::String> source_str = v8_str(source3);
+    v8::ScriptOrigin origin(v8_str("test"));
+    v8::ScriptCompiler::Source source(source_str, origin, cache);
+    v8::Local<v8::UnboundScript> script;
+    {
+      DisallowCompilation no_compile(reinterpret_cast<Isolate*>(isolate2));
+      script = v8::ScriptCompiler::CompileUnbound(
+          isolate2, &source, v8::ScriptCompiler::kConsumeCodeCache);
+    }
+    v8::Local<v8::Value> result = script->BindToCurrentContext()->Run();
+    CHECK(result->ToString(isolate2)->Equals(v8_str("XY")));
   }
   isolate2->Dispose();
 }
diff --git a/test/cctest/test-spaces.cc b/test/cctest/test-spaces.cc
index d09c128..a84b867 100644
--- a/test/cctest/test-spaces.cc
+++ b/test/cctest/test-spaces.cc
@@ -27,6 +27,7 @@
 
 #include <stdlib.h>
 
+#include "src/base/platform/platform.h"
 #include "src/snapshot.h"
 #include "src/v8.h"
 #include "test/cctest/cctest.h"
@@ -212,11 +213,17 @@
   TestMemoryAllocatorScope test_allocator_scope(isolate, memory_allocator);
   CodeRange* code_range = new CodeRange(isolate);
   const size_t code_range_size = 4 * MB;
-  if (!code_range->SetUp(code_range_size)) return;
+  if (!code_range->SetUp(
+          code_range_size +
+          RoundUp(v8::base::OS::CommitPageSize() * kReservedCodeRangePages,
+                  MemoryChunk::kAlignment) +
+          v8::internal::MemoryAllocator::CodePageAreaSize())) {
+    return;
+  }
   Address address;
   size_t size;
-  address = code_range->AllocateRawMemory(code_range_size - MB,
-                                          code_range_size - MB, &size);
+  address = code_range->AllocateRawMemory(code_range_size - 2 * MB,
+                                          code_range_size - 2 * MB, &size);
   CHECK(address != NULL);
   Address null_address;
   size_t null_size;
@@ -450,3 +457,55 @@
   // No large objects required to perform the above steps.
   CHECK(isolate->heap()->lo_space()->IsEmpty());
 }
+
+
+static inline void FillCurrentPage(v8::internal::NewSpace* space) {
+  int new_linear_size = static_cast<int>(*space->allocation_limit_address() -
+                                         *space->allocation_top_address());
+  if (new_linear_size == 0) return;
+  v8::internal::AllocationResult allocation =
+      space->AllocateRaw(new_linear_size);
+  v8::internal::FreeListNode* node =
+      v8::internal::FreeListNode::cast(allocation.ToObjectChecked());
+  node->set_size(space->heap(), new_linear_size);
+}
+
+
+UNINITIALIZED_TEST(NewSpaceGrowsToTargetCapacity) {
+  FLAG_target_semi_space_size = 2;
+  if (FLAG_optimize_for_size) return;
+
+  v8::Isolate* isolate = v8::Isolate::New();
+  {
+    v8::Isolate::Scope isolate_scope(isolate);
+    v8::HandleScope handle_scope(isolate);
+    v8::Context::New(isolate)->Enter();
+
+    Isolate* i_isolate = reinterpret_cast<Isolate*>(isolate);
+
+    NewSpace* new_space = i_isolate->heap()->new_space();
+
+    // This test doesn't work if we start with a non-default new space
+    // configuration.
+    if (new_space->InitialTotalCapacity() == Page::kPageSize) {
+      CHECK(new_space->CommittedMemory() == new_space->InitialTotalCapacity());
+
+      // Fill up the first (and only) page of the semi space.
+      FillCurrentPage(new_space);
+
+      // Try to allocate out of the new space. A new page should be added and
+      // the
+      // allocation should succeed.
+      v8::internal::AllocationResult allocation = new_space->AllocateRaw(80);
+      CHECK(!allocation.IsRetry());
+      CHECK(new_space->CommittedMemory() == 2 * Page::kPageSize);
+
+      // Turn the allocation into a proper object so isolate teardown won't
+      // crash.
+      v8::internal::FreeListNode* node =
+          v8::internal::FreeListNode::cast(allocation.ToObjectChecked());
+      node->set_size(new_space->heap(), 80);
+    }
+  }
+  isolate->Dispose();
+}
diff --git a/test/cctest/test-strings.cc b/test/cctest/test-strings.cc
index ef13c4d..d1f23f7 100644
--- a/test/cctest/test-strings.cc
+++ b/test/cctest/test-strings.cc
@@ -37,6 +37,7 @@
 #include "src/api.h"
 #include "src/factory.h"
 #include "src/objects.h"
+#include "src/unicode-decoder.h"
 #include "test/cctest/cctest.h"
 
 // Adapted from http://en.wikipedia.org/wiki/Multiply-with-carry
@@ -356,10 +357,10 @@
 
 void AccumulateStatsWithOperator(
     ConsString* cons_string, ConsStringStats* stats) {
-  ConsStringIteratorOp op(cons_string);
+  ConsStringIterator iter(cons_string);
   String* string;
   int offset;
-  while (NULL != (string = op.Next(&offset))) {
+  while (NULL != (string = iter.Next(&offset))) {
     // Accumulate stats.
     CHECK_EQ(0, offset);
     stats->leaves_++;
@@ -523,13 +524,10 @@
 }
 
 
-static ConsStringIteratorOp cons_string_iterator_op_1;
-static ConsStringIteratorOp cons_string_iterator_op_2;
-
 static void Traverse(Handle<String> s1, Handle<String> s2) {
   int i = 0;
-  StringCharacterStream character_stream_1(*s1, &cons_string_iterator_op_1);
-  StringCharacterStream character_stream_2(*s2, &cons_string_iterator_op_2);
+  StringCharacterStream character_stream_1(*s1);
+  StringCharacterStream character_stream_2(*s2);
   while (character_stream_1.HasMore()) {
     CHECK(character_stream_2.HasMore());
     uint16_t c = character_stream_1.GetNext();
@@ -545,8 +543,8 @@
 
 static void TraverseFirst(Handle<String> s1, Handle<String> s2, int chars) {
   int i = 0;
-  StringCharacterStream character_stream_1(*s1, &cons_string_iterator_op_1);
-  StringCharacterStream character_stream_2(*s2, &cons_string_iterator_op_2);
+  StringCharacterStream character_stream_1(*s1);
+  StringCharacterStream character_stream_2(*s2);
   while (character_stream_1.HasMore() && i < chars) {
     CHECK(character_stream_2.HasMore());
     uint16_t c = character_stream_1.GetNext();
@@ -615,10 +613,8 @@
     if (offset < 0) offset = 0;
     // Want to test the offset == length case.
     if (offset > length) offset = length;
-    StringCharacterStream flat_stream(
-        flat_string, &cons_string_iterator_op_1, offset);
-    StringCharacterStream cons_stream(
-        cons_string, &cons_string_iterator_op_2, offset);
+    StringCharacterStream flat_stream(flat_string, offset);
+    StringCharacterStream cons_stream(cons_string, offset);
     for (int i = offset; i < length; i++) {
       uint16_t c = flat_string->Get(i);
       CHECK(flat_stream.HasMore());
@@ -634,14 +630,11 @@
 
 static inline void PrintStats(const ConsStringGenerationData& data) {
 #ifdef DEBUG
-printf(
-    "%s: [%d], %s: [%d], %s: [%d], %s: [%d], %s: [%d], %s: [%d]\n",
-    "leaves", data.stats_.leaves_,
-    "empty", data.stats_.empty_leaves_,
-    "chars", data.stats_.chars_,
-    "lefts", data.stats_.left_traversals_,
-    "rights", data.stats_.right_traversals_,
-    "early_terminations", data.early_terminations_);
+  printf("%s: [%u], %s: [%u], %s: [%u], %s: [%u], %s: [%u], %s: [%u]\n",
+         "leaves", data.stats_.leaves_, "empty", data.stats_.empty_leaves_,
+         "chars", data.stats_.chars_, "lefts", data.stats_.left_traversals_,
+         "rights", data.stats_.right_traversals_, "early_terminations",
+         data.early_terminations_);
 #endif
 }
 
@@ -1027,11 +1020,13 @@
   // into a two-byte external string.  Check that JSON.stringify works.
   v8::HandleScope handle_scope(CcTest::isolate());
   v8::Handle<v8::String> underlying =
-      CompileRun("var underlying = 'abcdefghijklmnopqrstuvwxyz';"
-                 "underlying")->ToString();
-  v8::Handle<v8::String> slice =
-      CompileRun("var slice = underlying.slice(1);"
-                 "slice")->ToString();
+      CompileRun(
+          "var underlying = 'abcdefghijklmnopqrstuvwxyz';"
+          "underlying")->ToString(CcTest::isolate());
+  v8::Handle<v8::String> slice = CompileRun(
+                                     "var slice = '';"
+                                     "slice = underlying.slice(1);"
+                                     "slice")->ToString(CcTest::isolate());
   CHECK(v8::Utils::OpenHandle(*slice)->IsSlicedString());
   CHECK(v8::Utils::OpenHandle(*underlying)->IsSeqOneByteString());
 
@@ -1089,7 +1084,7 @@
     CHECK_EQ(results[i]->IsNumber(), result->IsNumber());
     if (result->IsNumber()) {
       CHECK_EQ(Object::ToSmi(isolate, results[i]).ToHandleChecked()->value(),
-               result->ToInt32()->Value());
+               result->ToInt32(CcTest::isolate())->Value());
     }
   }
 }
@@ -1189,7 +1184,7 @@
   v8::Local<v8::Value> result;
   Handle<String> string;
   const char* init = "var str = 'abcdefghijklmnopqrstuvwxyz';";
-  const char* slice = "var slice = str.slice(1,-1); slice";
+  const char* slice = "var slice = ''; slice = str.slice(1,-1); slice";
   const char* slice_from_slice = "slice.slice(1,-1);";
 
   CompileRun(init);
@@ -1292,6 +1287,42 @@
 }
 
 
+namespace {
+
+int* global_use_counts = NULL;
+
+void MockUseCounterCallback(v8::Isolate* isolate,
+                            v8::Isolate::UseCounterFeature feature) {
+  ++global_use_counts[feature];
+}
+}
+
+
+TEST(CountBreakIterator) {
+  CcTest::InitializeVM();
+  v8::HandleScope scope(CcTest::isolate());
+  LocalContext context;
+  int use_counts[v8::Isolate::kUseCounterFeatureCount] = {};
+  global_use_counts = use_counts;
+  CcTest::isolate()->SetUseCounterCallback(MockUseCounterCallback);
+  CHECK_EQ(0, use_counts[v8::Isolate::kBreakIterator]);
+  v8::Local<v8::Value> result = CompileRun(
+      "(function() {"
+      "  if (!this.Intl) return 0;"
+      "  var iterator = Intl.v8BreakIterator(['en']);"
+      "  iterator.adoptText('Now is the time');"
+      "  iterator.next();"
+      "  return iterator.next();"
+      "})();");
+  CHECK(result->IsNumber());
+  int uses = result->ToInt32(CcTest::isolate())->Value() == 0 ? 0 : 1;
+  CHECK_EQ(uses, use_counts[v8::Isolate::kBreakIterator]);
+  // Make sure GC cleans up the break iterator, so we don't get a memory leak
+  // reported by ASAN.
+  CcTest::isolate()->LowMemoryNotification();
+}
+
+
 TEST(StringReplaceAtomTwoByteResult) {
   CcTest::InitializeVM();
   v8::HandleScope scope(CcTest::isolate());
diff --git a/test/cctest/test-transitions.cc b/test/cctest/test-transitions.cc
new file mode 100644
index 0000000..6bcdb35
--- /dev/null
+++ b/test/cctest/test-transitions.cc
@@ -0,0 +1,301 @@
+// 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.
+
+#include <stdlib.h>
+#include <utility>
+
+#include "src/v8.h"
+
+#include "src/compilation-cache.h"
+#include "src/execution.h"
+#include "src/factory.h"
+#include "src/global-handles.h"
+#include "test/cctest/cctest.h"
+
+using namespace v8::internal;
+
+
+//
+// Helper functions.
+//
+
+static void ConnectTransition(Handle<Map> parent,
+                              Handle<TransitionArray> transitions,
+                              Handle<Map> child) {
+  if (!parent->HasTransitionArray() || *transitions != parent->transitions()) {
+    parent->set_transitions(*transitions);
+  }
+  child->SetBackPointer(*parent);
+}
+
+
+static void CheckPropertyDetailsFieldsConsistency(PropertyType type,
+                                                  PropertyKind kind,
+                                                  PropertyLocation location) {
+  int type_value = PropertyDetails::TypeField::encode(type);
+  int kind_location_value = PropertyDetails::KindField::encode(kind) |
+                            PropertyDetails::LocationField::encode(location);
+  CHECK_EQ(type_value, kind_location_value);
+}
+
+
+TEST(PropertyDetailsFieldsConsistency) {
+  CheckPropertyDetailsFieldsConsistency(FIELD, DATA, IN_OBJECT);
+  CheckPropertyDetailsFieldsConsistency(CONSTANT, DATA, IN_DESCRIPTOR);
+  CheckPropertyDetailsFieldsConsistency(ACCESSOR_FIELD, ACCESSOR, IN_OBJECT);
+  CheckPropertyDetailsFieldsConsistency(CALLBACKS, ACCESSOR, IN_DESCRIPTOR);
+}
+
+
+TEST(TransitionArray_SimpleFieldTransitions) {
+  CcTest::InitializeVM();
+  v8::HandleScope scope(CcTest::isolate());
+  Isolate* isolate = CcTest::i_isolate();
+  Factory* factory = isolate->factory();
+
+  Handle<String> name1 = factory->InternalizeUtf8String("foo");
+  Handle<String> name2 = factory->InternalizeUtf8String("bar");
+  PropertyAttributes attributes = NONE;
+
+  Handle<Map> map0 = Map::Create(isolate, 0);
+  Handle<Map> map1 =
+      Map::CopyWithField(map0, name1, handle(HeapType::Any(), isolate),
+                         attributes, Representation::Tagged(),
+                         OMIT_TRANSITION).ToHandleChecked();
+  Handle<Map> map2 =
+      Map::CopyWithField(map0, name2, handle(HeapType::Any(), isolate),
+                         attributes, Representation::Tagged(),
+                         OMIT_TRANSITION).ToHandleChecked();
+
+  CHECK(!map0->HasTransitionArray());
+  Handle<TransitionArray> transitions = TransitionArray::Allocate(isolate, 0);
+  CHECK(transitions->IsFullTransitionArray());
+
+  int transition;
+  transitions =
+      transitions->Insert(map0, name1, map1, SIMPLE_PROPERTY_TRANSITION);
+  ConnectTransition(map0, transitions, map1);
+  CHECK(transitions->IsSimpleTransition());
+  transition = transitions->Search(DATA, *name1, attributes);
+  CHECK_EQ(TransitionArray::kSimpleTransitionIndex, transition);
+  CHECK_EQ(*name1, transitions->GetKey(transition));
+  CHECK_EQ(*map1, transitions->GetTarget(transition));
+
+  transitions =
+      transitions->Insert(map0, name2, map2, SIMPLE_PROPERTY_TRANSITION);
+  ConnectTransition(map0, transitions, map2);
+  CHECK(transitions->IsFullTransitionArray());
+
+  transition = transitions->Search(DATA, *name1, attributes);
+  CHECK_EQ(*name1, transitions->GetKey(transition));
+  CHECK_EQ(*map1, transitions->GetTarget(transition));
+
+  transition = transitions->Search(DATA, *name2, attributes);
+  CHECK_EQ(*name2, transitions->GetKey(transition));
+  CHECK_EQ(*map2, transitions->GetTarget(transition));
+
+  DCHECK(transitions->IsSortedNoDuplicates());
+}
+
+
+TEST(TransitionArray_FullFieldTransitions) {
+  CcTest::InitializeVM();
+  v8::HandleScope scope(CcTest::isolate());
+  Isolate* isolate = CcTest::i_isolate();
+  Factory* factory = isolate->factory();
+
+  Handle<String> name1 = factory->InternalizeUtf8String("foo");
+  Handle<String> name2 = factory->InternalizeUtf8String("bar");
+  PropertyAttributes attributes = NONE;
+
+  Handle<Map> map0 = Map::Create(isolate, 0);
+  Handle<Map> map1 =
+      Map::CopyWithField(map0, name1, handle(HeapType::Any(), isolate),
+                         attributes, Representation::Tagged(),
+                         OMIT_TRANSITION).ToHandleChecked();
+  Handle<Map> map2 =
+      Map::CopyWithField(map0, name2, handle(HeapType::Any(), isolate),
+                         attributes, Representation::Tagged(),
+                         OMIT_TRANSITION).ToHandleChecked();
+
+  CHECK(!map0->HasTransitionArray());
+  Handle<TransitionArray> transitions = TransitionArray::Allocate(isolate, 0);
+  CHECK(transitions->IsFullTransitionArray());
+
+  int transition;
+  transitions = transitions->Insert(map0, name1, map1, PROPERTY_TRANSITION);
+  ConnectTransition(map0, transitions, map1);
+  CHECK(transitions->IsFullTransitionArray());
+  transition = transitions->Search(DATA, *name1, attributes);
+  CHECK_EQ(*name1, transitions->GetKey(transition));
+  CHECK_EQ(*map1, transitions->GetTarget(transition));
+
+  transitions = transitions->Insert(map0, name2, map2, PROPERTY_TRANSITION);
+  ConnectTransition(map0, transitions, map2);
+  CHECK(transitions->IsFullTransitionArray());
+
+  transition = transitions->Search(DATA, *name1, attributes);
+  CHECK_EQ(*name1, transitions->GetKey(transition));
+  CHECK_EQ(*map1, transitions->GetTarget(transition));
+
+  transition = transitions->Search(DATA, *name2, attributes);
+  CHECK_EQ(*name2, transitions->GetKey(transition));
+  CHECK_EQ(*map2, transitions->GetTarget(transition));
+
+  DCHECK(transitions->IsSortedNoDuplicates());
+}
+
+
+TEST(TransitionArray_DifferentFieldNames) {
+  CcTest::InitializeVM();
+  v8::HandleScope scope(CcTest::isolate());
+  Isolate* isolate = CcTest::i_isolate();
+  Factory* factory = isolate->factory();
+
+  const int PROPS_COUNT = 10;
+  Handle<String> names[PROPS_COUNT];
+  Handle<Map> maps[PROPS_COUNT];
+  PropertyAttributes attributes = NONE;
+
+  Handle<Map> map0 = Map::Create(isolate, 0);
+  CHECK(!map0->HasTransitionArray());
+  Handle<TransitionArray> transitions = TransitionArray::Allocate(isolate, 0);
+  CHECK(transitions->IsFullTransitionArray());
+
+  for (int i = 0; i < PROPS_COUNT; i++) {
+    EmbeddedVector<char, 64> buffer;
+    SNPrintF(buffer, "prop%d", i);
+    Handle<String> name = factory->InternalizeUtf8String(buffer.start());
+    Handle<Map> map =
+        Map::CopyWithField(map0, name, handle(HeapType::Any(), isolate),
+                           attributes, Representation::Tagged(),
+                           OMIT_TRANSITION).ToHandleChecked();
+    names[i] = name;
+    maps[i] = map;
+
+    transitions = transitions->Insert(map0, name, map, PROPERTY_TRANSITION);
+    ConnectTransition(map0, transitions, map);
+  }
+
+  for (int i = 0; i < PROPS_COUNT; i++) {
+    int transition = transitions->Search(DATA, *names[i], attributes);
+    CHECK_EQ(*names[i], transitions->GetKey(transition));
+    CHECK_EQ(*maps[i], transitions->GetTarget(transition));
+  }
+
+  DCHECK(transitions->IsSortedNoDuplicates());
+}
+
+
+TEST(TransitionArray_SameFieldNamesDifferentAttributesSimple) {
+  CcTest::InitializeVM();
+  v8::HandleScope scope(CcTest::isolate());
+  Isolate* isolate = CcTest::i_isolate();
+  Factory* factory = isolate->factory();
+
+  Handle<Map> map0 = Map::Create(isolate, 0);
+  CHECK(!map0->HasTransitionArray());
+  Handle<TransitionArray> transitions = TransitionArray::Allocate(isolate, 0);
+  CHECK(transitions->IsFullTransitionArray());
+
+  const int ATTRS_COUNT = (READ_ONLY | DONT_ENUM | DONT_DELETE) + 1;
+  STATIC_ASSERT(ATTRS_COUNT == 8);
+  Handle<Map> attr_maps[ATTRS_COUNT];
+  Handle<String> name = factory->InternalizeUtf8String("foo");
+
+  // Add transitions for same field name but different attributes.
+  for (int i = 0; i < ATTRS_COUNT; i++) {
+    PropertyAttributes attributes = static_cast<PropertyAttributes>(i);
+
+    Handle<Map> map =
+        Map::CopyWithField(map0, name, handle(HeapType::Any(), isolate),
+                           attributes, Representation::Tagged(),
+                           OMIT_TRANSITION).ToHandleChecked();
+    attr_maps[i] = map;
+
+    transitions = transitions->Insert(map0, name, map, PROPERTY_TRANSITION);
+    ConnectTransition(map0, transitions, map);
+  }
+
+  // Ensure that transitions for |name| field are valid.
+  for (int i = 0; i < ATTRS_COUNT; i++) {
+    PropertyAttributes attributes = static_cast<PropertyAttributes>(i);
+
+    int transition = transitions->Search(DATA, *name, attributes);
+    CHECK_EQ(*name, transitions->GetKey(transition));
+    CHECK_EQ(*attr_maps[i], transitions->GetTarget(transition));
+  }
+
+  DCHECK(transitions->IsSortedNoDuplicates());
+}
+
+
+TEST(TransitionArray_SameFieldNamesDifferentAttributes) {
+  CcTest::InitializeVM();
+  v8::HandleScope scope(CcTest::isolate());
+  Isolate* isolate = CcTest::i_isolate();
+  Factory* factory = isolate->factory();
+
+  const int PROPS_COUNT = 10;
+  Handle<String> names[PROPS_COUNT];
+  Handle<Map> maps[PROPS_COUNT];
+
+  Handle<Map> map0 = Map::Create(isolate, 0);
+  CHECK(!map0->HasTransitionArray());
+  Handle<TransitionArray> transitions = TransitionArray::Allocate(isolate, 0);
+  CHECK(transitions->IsFullTransitionArray());
+
+  // Some number of fields.
+  for (int i = 0; i < PROPS_COUNT; i++) {
+    EmbeddedVector<char, 64> buffer;
+    SNPrintF(buffer, "prop%d", i);
+    Handle<String> name = factory->InternalizeUtf8String(buffer.start());
+    Handle<Map> map =
+        Map::CopyWithField(map0, name, handle(HeapType::Any(), isolate), NONE,
+                           Representation::Tagged(),
+                           OMIT_TRANSITION).ToHandleChecked();
+    names[i] = name;
+    maps[i] = map;
+
+    transitions = transitions->Insert(map0, name, map, PROPERTY_TRANSITION);
+    ConnectTransition(map0, transitions, map);
+  }
+
+  const int ATTRS_COUNT = (READ_ONLY | DONT_ENUM | DONT_DELETE) + 1;
+  STATIC_ASSERT(ATTRS_COUNT == 8);
+  Handle<Map> attr_maps[ATTRS_COUNT];
+  Handle<String> name = factory->InternalizeUtf8String("foo");
+
+  // Add transitions for same field name but different attributes.
+  for (int i = 0; i < ATTRS_COUNT; i++) {
+    PropertyAttributes attributes = static_cast<PropertyAttributes>(i);
+
+    Handle<Map> map =
+        Map::CopyWithField(map0, name, handle(HeapType::Any(), isolate),
+                           attributes, Representation::Tagged(),
+                           OMIT_TRANSITION).ToHandleChecked();
+    attr_maps[i] = map;
+
+    transitions = transitions->Insert(map0, name, map, PROPERTY_TRANSITION);
+    ConnectTransition(map0, transitions, map);
+  }
+
+  // Ensure that transitions for |name| field are valid.
+  for (int i = 0; i < ATTRS_COUNT; i++) {
+    PropertyAttributes attributes = static_cast<PropertyAttributes>(i);
+
+    int transition = transitions->Search(DATA, *name, attributes);
+    CHECK_EQ(*name, transitions->GetKey(transition));
+    CHECK_EQ(*attr_maps[i], transitions->GetTarget(transition));
+  }
+
+  // Ensure that info about the other fields still valid.
+  for (int i = 0; i < PROPS_COUNT; i++) {
+    int transition = transitions->Search(DATA, *names[i], NONE);
+    CHECK_EQ(*names[i], transitions->GetKey(transition));
+    CHECK_EQ(*maps[i], transitions->GetTarget(transition));
+  }
+
+  DCHECK(transitions->IsSortedNoDuplicates());
+}
diff --git a/test/cctest/test-types.cc b/test/cctest/test-types.cc
index 0cd2472..ebef527 100644
--- a/test/cctest/test-types.cc
+++ b/test/cctest/test-types.cc
@@ -8,12 +8,27 @@
 #include "src/isolate-inl.h"
 #include "src/types.h"
 #include "test/cctest/cctest.h"
+#include "test/cctest/types-fuzz.h"
 
 using namespace v8::internal;
 
+
 // Testing auxiliaries (breaking the Type abstraction).
+
+
+static bool IsInteger(double x) {
+  return nearbyint(x) == x && !i::IsMinusZero(x);  // Allows for infinities.
+}
+
+
+static bool IsInteger(i::Object* x) {
+  return x->IsNumber() && IsInteger(x->Number());
+}
+
+
 typedef uint32_t bitset;
 
+
 struct ZoneRep {
   typedef void* Struct;
 
@@ -76,262 +91,6 @@
 };
 
 
-template<class Type, class TypeHandle, class Region>
-class Types {
- public:
-  Types(Region* region, Isolate* isolate)
-      : region_(region), rng_(isolate->random_number_generator()) {
-    #define DECLARE_TYPE(name, value) \
-      name = Type::name(region); \
-      types.push_back(name);
-    PROPER_BITSET_TYPE_LIST(DECLARE_TYPE)
-    #undef DECLARE_TYPE
-
-    object_map = isolate->factory()->NewMap(
-        JS_OBJECT_TYPE, JSObject::kHeaderSize);
-    array_map = isolate->factory()->NewMap(
-        JS_ARRAY_TYPE, JSArray::kSize);
-    number_map = isolate->factory()->NewMap(
-        HEAP_NUMBER_TYPE, HeapNumber::kSize);
-    uninitialized_map = isolate->factory()->uninitialized_map();
-    ObjectClass = Type::Class(object_map, region);
-    ArrayClass = Type::Class(array_map, region);
-    NumberClass = Type::Class(number_map, region);
-    UninitializedClass = Type::Class(uninitialized_map, region);
-
-    maps.push_back(object_map);
-    maps.push_back(array_map);
-    maps.push_back(uninitialized_map);
-    for (MapVector::iterator it = maps.begin(); it != maps.end(); ++it) {
-      types.push_back(Type::Class(*it, region));
-    }
-
-    smi = handle(Smi::FromInt(666), isolate);
-    signed32 = isolate->factory()->NewHeapNumber(0x40000000);
-    object1 = isolate->factory()->NewJSObjectFromMap(object_map);
-    object2 = isolate->factory()->NewJSObjectFromMap(object_map);
-    array = isolate->factory()->NewJSArray(20);
-    uninitialized = isolate->factory()->uninitialized_value();
-    SmiConstant = Type::Constant(smi, region);
-    Signed32Constant = Type::Constant(signed32, region);
-    ObjectConstant1 = Type::Constant(object1, region);
-    ObjectConstant2 = Type::Constant(object2, region);
-    ArrayConstant = Type::Constant(array, region);
-    UninitializedConstant = Type::Constant(uninitialized, region);
-
-    values.push_back(smi);
-    values.push_back(signed32);
-    values.push_back(object1);
-    values.push_back(object2);
-    values.push_back(array);
-    values.push_back(uninitialized);
-    for (ValueVector::iterator it = values.begin(); it != values.end(); ++it) {
-      types.push_back(Type::Constant(*it, region));
-    }
-
-    integers.push_back(isolate->factory()->NewNumber(-V8_INFINITY));
-    integers.push_back(isolate->factory()->NewNumber(+V8_INFINITY));
-    integers.push_back(isolate->factory()->NewNumber(-rng_->NextInt(10)));
-    integers.push_back(isolate->factory()->NewNumber(+rng_->NextInt(10)));
-    for (int i = 0; i < 10; ++i) {
-      double x = rng_->NextInt();
-      integers.push_back(isolate->factory()->NewNumber(x));
-      x *= rng_->NextInt();
-      if (!IsMinusZero(x)) integers.push_back(isolate->factory()->NewNumber(x));
-    }
-
-    NumberArray = Type::Array(Number, region);
-    StringArray = Type::Array(String, region);
-    AnyArray = Type::Array(Any, region);
-
-    SignedFunction1 = Type::Function(SignedSmall, SignedSmall, region);
-    NumberFunction1 = Type::Function(Number, Number, region);
-    NumberFunction2 = Type::Function(Number, Number, Number, region);
-    MethodFunction = Type::Function(String, Object, 0, region);
-
-    for (int i = 0; i < 30; ++i) {
-      types.push_back(Fuzz());
-    }
-  }
-
-  Handle<i::Map> object_map;
-  Handle<i::Map> array_map;
-  Handle<i::Map> number_map;
-  Handle<i::Map> uninitialized_map;
-
-  Handle<i::Smi> smi;
-  Handle<i::HeapNumber> signed32;
-  Handle<i::JSObject> object1;
-  Handle<i::JSObject> object2;
-  Handle<i::JSArray> array;
-  Handle<i::Oddball> uninitialized;
-
-  #define DECLARE_TYPE(name, value) TypeHandle name;
-  BITSET_TYPE_LIST(DECLARE_TYPE)
-  #undef DECLARE_TYPE
-
-  TypeHandle ObjectClass;
-  TypeHandle ArrayClass;
-  TypeHandle NumberClass;
-  TypeHandle UninitializedClass;
-
-  TypeHandle SmiConstant;
-  TypeHandle Signed32Constant;
-  TypeHandle ObjectConstant1;
-  TypeHandle ObjectConstant2;
-  TypeHandle ArrayConstant;
-  TypeHandle UninitializedConstant;
-
-  TypeHandle NumberArray;
-  TypeHandle StringArray;
-  TypeHandle AnyArray;
-
-  TypeHandle SignedFunction1;
-  TypeHandle NumberFunction1;
-  TypeHandle NumberFunction2;
-  TypeHandle MethodFunction;
-
-  typedef std::vector<TypeHandle> TypeVector;
-  typedef std::vector<Handle<i::Map> > MapVector;
-  typedef std::vector<Handle<i::Object> > ValueVector;
-
-  TypeVector types;
-  MapVector maps;
-  ValueVector values;
-  ValueVector integers;  // "Integer" values used for range limits.
-
-  TypeHandle Of(Handle<i::Object> value) {
-    return Type::Of(value, region_);
-  }
-
-  TypeHandle NowOf(Handle<i::Object> value) {
-    return Type::NowOf(value, region_);
-  }
-
-  TypeHandle Class(Handle<i::Map> map) {
-    return Type::Class(map, region_);
-  }
-
-  TypeHandle Constant(Handle<i::Object> value) {
-    return Type::Constant(value, region_);
-  }
-
-  TypeHandle Range(Handle<i::Object> min, Handle<i::Object> max) {
-    return Type::Range(min, max, region_);
-  }
-
-  TypeHandle Context(TypeHandle outer) {
-    return Type::Context(outer, region_);
-  }
-
-  TypeHandle Array1(TypeHandle element) {
-    return Type::Array(element, region_);
-  }
-
-  TypeHandle Function0(TypeHandle result, TypeHandle receiver) {
-    return Type::Function(result, receiver, 0, region_);
-  }
-
-  TypeHandle Function1(TypeHandle result, TypeHandle receiver, TypeHandle arg) {
-    TypeHandle type = Type::Function(result, receiver, 1, region_);
-    type->AsFunction()->InitParameter(0, arg);
-    return type;
-  }
-
-  TypeHandle Function2(TypeHandle result, TypeHandle arg1, TypeHandle arg2) {
-    return Type::Function(result, arg1, arg2, region_);
-  }
-
-  TypeHandle Union(TypeHandle t1, TypeHandle t2) {
-    return Type::Union(t1, t2, region_);
-  }
-  TypeHandle Intersect(TypeHandle t1, TypeHandle t2) {
-    return Type::Intersect(t1, t2, region_);
-  }
-
-  template<class Type2, class TypeHandle2>
-  TypeHandle Convert(TypeHandle2 t) {
-    return Type::template Convert<Type2>(t, region_);
-  }
-
-  TypeHandle Random() {
-    return types[rng_->NextInt(static_cast<int>(types.size()))];
-  }
-
-  TypeHandle Fuzz(int depth = 4) {
-    switch (rng_->NextInt(depth == 0 ? 3 : 20)) {
-      case 0: {  // bitset
-        int n = 0
-        #define COUNT_BITSET_TYPES(type, value) + 1
-        PROPER_BITSET_TYPE_LIST(COUNT_BITSET_TYPES)
-        #undef COUNT_BITSET_TYPES
-        ;
-        int i = rng_->NextInt(n);
-        #define PICK_BITSET_TYPE(type, value) \
-          if (i-- == 0) return Type::type(region_);
-        PROPER_BITSET_TYPE_LIST(PICK_BITSET_TYPE)
-        #undef PICK_BITSET_TYPE
-        UNREACHABLE();
-      }
-      case 1: {  // class
-        int i = rng_->NextInt(static_cast<int>(maps.size()));
-        return Type::Class(maps[i], region_);
-      }
-      case 2: {  // constant
-        int i = rng_->NextInt(static_cast<int>(values.size()));
-        return Type::Constant(values[i], region_);
-      }
-      case 3: {  // range
-        int i = rng_->NextInt(static_cast<int>(integers.size()));
-        int j = rng_->NextInt(static_cast<int>(integers.size()));
-        i::Handle<i::Object> min = integers[i];
-        i::Handle<i::Object> max = integers[j];
-        if (min->Number() > max->Number()) std::swap(min, max);
-        return Type::Range(min, max, region_);
-      }
-      case 4: {  // context
-        int depth = rng_->NextInt(3);
-        TypeHandle type = Type::Internal(region_);
-        for (int i = 0; i < depth; ++i) type = Type::Context(type, region_);
-        return type;
-      }
-      case 5: {  // array
-        TypeHandle element = Fuzz(depth / 2);
-        return Type::Array(element, region_);
-      }
-      case 6:
-      case 7: {  // function
-        TypeHandle result = Fuzz(depth / 2);
-        TypeHandle receiver = Fuzz(depth / 2);
-        int arity = rng_->NextInt(3);
-        TypeHandle type = Type::Function(result, receiver, arity, region_);
-        for (int i = 0; i < type->AsFunction()->Arity(); ++i) {
-          TypeHandle parameter = Fuzz(depth / 2);
-          type->AsFunction()->InitParameter(i, parameter);
-        }
-        return type;
-      }
-      default: {  // union
-        int n = rng_->NextInt(10);
-        TypeHandle type = None;
-        for (int i = 0; i < n; ++i) {
-          TypeHandle operand = Fuzz(depth - 1);
-          type = Type::Union(type, operand, region_);
-        }
-        return type;
-      }
-    }
-    UNREACHABLE();
-  }
-
-  Region* region() { return region_; }
-
- private:
-  Region* region_;
-  v8::base::RandomNumberGenerator* rng_;
-};
-
-
 template<class Type, class TypeHandle, class Region, class Rep>
 struct Tests : Rep {
   typedef Types<Type, TypeHandle, Region> TypesInstance;
@@ -535,39 +294,55 @@
     CHECK(T.Constant(fac->NewNumber(0))->Is(T.UnsignedSmall));
     CHECK(T.Constant(fac->NewNumber(1))->Is(T.UnsignedSmall));
     CHECK(T.Constant(fac->NewNumber(0x3fffffff))->Is(T.UnsignedSmall));
-    CHECK(T.Constant(fac->NewNumber(-1))->Is(T.OtherSignedSmall));
-    CHECK(T.Constant(fac->NewNumber(-0x3fffffff))->Is(T.OtherSignedSmall));
-    CHECK(T.Constant(fac->NewNumber(-0x40000000))->Is(T.OtherSignedSmall));
+    CHECK(T.Constant(fac->NewNumber(-1))->Is(T.NegativeSignedSmall));
+    CHECK(T.Constant(fac->NewNumber(-0x3fffffff))->Is(T.NegativeSignedSmall));
+    CHECK(T.Constant(fac->NewNumber(-0x40000000))->Is(T.NegativeSignedSmall));
     if (SmiValuesAre31Bits()) {
-      CHECK(T.Constant(fac->NewNumber(0x40000000))->Is(T.OtherUnsigned31));
-      CHECK(T.Constant(fac->NewNumber(0x7fffffff))->Is(T.OtherUnsigned31));
-      CHECK(T.Constant(fac->NewNumber(-0x40000001))->Is(T.OtherSigned32));
-      CHECK(T.Constant(fac->NewNumber(-0x7fffffff))->Is(T.OtherSigned32));
-      CHECK(T.Constant(fac->NewNumber(-0x7fffffff-1))->Is(T.OtherSigned32));
+      CHECK(T.Constant(fac->NewNumber(0x40000000))->Is(T.NonNegativeSigned32));
+      CHECK(!T.Constant(fac->NewNumber(0x40000000))->Is(T.UnsignedSmall));
+      CHECK(T.Constant(fac->NewNumber(0x7fffffff))->Is(T.NonNegativeSigned32));
+      CHECK(!T.Constant(fac->NewNumber(0x7fffffff))->Is(T.UnsignedSmall));
+      CHECK(T.Constant(fac->NewNumber(-0x40000001))->Is(T.NegativeSigned32));
+      CHECK(
+          !T.Constant(fac->NewNumber(-0x40000001))->Is(T.NegativeSignedSmall));
+      CHECK(T.Constant(fac->NewNumber(-0x7fffffff))->Is(T.NegativeSigned32));
+      CHECK(!T.Constant(fac->NewNumber(-0x7fffffff - 1))
+                 ->Is(T.NegativeSignedSmall));
     } else {
       CHECK(SmiValuesAre32Bits());
       CHECK(T.Constant(fac->NewNumber(0x40000000))->Is(T.UnsignedSmall));
       CHECK(T.Constant(fac->NewNumber(0x7fffffff))->Is(T.UnsignedSmall));
-      CHECK(!T.Constant(fac->NewNumber(0x40000000))->Is(T.OtherUnsigned31));
-      CHECK(!T.Constant(fac->NewNumber(0x7fffffff))->Is(T.OtherUnsigned31));
-      CHECK(T.Constant(fac->NewNumber(-0x40000001))->Is(T.OtherSignedSmall));
-      CHECK(T.Constant(fac->NewNumber(-0x7fffffff))->Is(T.OtherSignedSmall));
-      CHECK(T.Constant(fac->NewNumber(-0x7fffffff-1))->Is(T.OtherSignedSmall));
-      CHECK(!T.Constant(fac->NewNumber(-0x40000001))->Is(T.OtherSigned32));
-      CHECK(!T.Constant(fac->NewNumber(-0x7fffffff))->Is(T.OtherSigned32));
-      CHECK(!T.Constant(fac->NewNumber(-0x7fffffff-1))->Is(T.OtherSigned32));
+      CHECK(T.Constant(fac->NewNumber(0x40000000))->Is(T.NonNegativeSigned32));
+      CHECK(T.Constant(fac->NewNumber(0x7fffffff))->Is(T.NonNegativeSigned32));
+      CHECK(T.Constant(fac->NewNumber(-0x40000001))->Is(T.NegativeSignedSmall));
+      CHECK(T.Constant(fac->NewNumber(-0x7fffffff))->Is(T.NegativeSignedSmall));
+      CHECK(T.Constant(fac->NewNumber(-0x7fffffff - 1))
+                ->Is(T.NegativeSignedSmall));
+      CHECK(T.Constant(fac->NewNumber(-0x40000001))->Is(T.NegativeSigned32));
+      CHECK(T.Constant(fac->NewNumber(-0x7fffffff))->Is(T.NegativeSigned32));
+      CHECK(
+          T.Constant(fac->NewNumber(-0x7fffffff - 1))->Is(T.NegativeSigned32));
     }
-    CHECK(T.Constant(fac->NewNumber(0x80000000u))->Is(T.OtherUnsigned32));
-    CHECK(T.Constant(fac->NewNumber(0xffffffffu))->Is(T.OtherUnsigned32));
-    CHECK(T.Constant(fac->NewNumber(0xffffffffu+1.0))->Is(T.OtherNumber));
-    CHECK(T.Constant(fac->NewNumber(-0x7fffffff-2.0))->Is(T.OtherNumber));
-    CHECK(T.Constant(fac->NewNumber(0.1))->Is(T.OtherNumber));
-    CHECK(T.Constant(fac->NewNumber(-10.1))->Is(T.OtherNumber));
-    CHECK(T.Constant(fac->NewNumber(10e60))->Is(T.OtherNumber));
+    CHECK(T.Constant(fac->NewNumber(0x80000000u))->Is(T.Unsigned32));
+    CHECK(!T.Constant(fac->NewNumber(0x80000000u))->Is(T.NonNegativeSigned32));
+    CHECK(T.Constant(fac->NewNumber(0xffffffffu))->Is(T.Unsigned32));
+    CHECK(!T.Constant(fac->NewNumber(0xffffffffu))->Is(T.NonNegativeSigned32));
+    CHECK(T.Constant(fac->NewNumber(0xffffffffu + 1.0))->Is(T.PlainNumber));
+    CHECK(!T.Constant(fac->NewNumber(0xffffffffu + 1.0))->Is(T.Integral32));
+    CHECK(T.Constant(fac->NewNumber(-0x7fffffff - 2.0))->Is(T.PlainNumber));
+    CHECK(!T.Constant(fac->NewNumber(-0x7fffffff - 2.0))->Is(T.Integral32));
+    CHECK(T.Constant(fac->NewNumber(0.1))->Is(T.PlainNumber));
+    CHECK(!T.Constant(fac->NewNumber(0.1))->Is(T.Integral32));
+    CHECK(T.Constant(fac->NewNumber(-10.1))->Is(T.PlainNumber));
+    CHECK(!T.Constant(fac->NewNumber(-10.1))->Is(T.Integral32));
+    CHECK(T.Constant(fac->NewNumber(10e60))->Is(T.PlainNumber));
+    CHECK(!T.Constant(fac->NewNumber(10e60))->Is(T.Integral32));
     CHECK(T.Constant(fac->NewNumber(-1.0*0.0))->Is(T.MinusZero));
     CHECK(T.Constant(fac->NewNumber(v8::base::OS::nan_value()))->Is(T.NaN));
-    CHECK(T.Constant(fac->NewNumber(V8_INFINITY))->Is(T.OtherNumber));
-    CHECK(T.Constant(fac->NewNumber(-V8_INFINITY))->Is(T.OtherNumber));
+    CHECK(T.Constant(fac->NewNumber(V8_INFINITY))->Is(T.PlainNumber));
+    CHECK(!T.Constant(fac->NewNumber(V8_INFINITY))->Is(T.Integral32));
+    CHECK(T.Constant(fac->NewNumber(-V8_INFINITY))->Is(T.PlainNumber));
+    CHECK(!T.Constant(fac->NewNumber(-V8_INFINITY))->Is(T.Integral32));
   }
 
   void Range() {
@@ -598,11 +373,11 @@
     // Range(min1, max1) = Range(min2, max2) <=> min1 = min2 /\ max1 = max2
     for (ValueIterator i1 = T.integers.begin();
         i1 != T.integers.end(); ++i1) {
-      for (ValueIterator j1 = T.integers.begin();
+      for (ValueIterator j1 = i1;
           j1 != T.integers.end(); ++j1) {
         for (ValueIterator i2 = T.integers.begin();
             i2 != T.integers.end(); ++i2) {
-          for (ValueIterator j2 = T.integers.begin();
+          for (ValueIterator j2 = i2;
               j2 != T.integers.end(); ++j2) {
             i::Handle<i::Object> min1 = *i1;
             i::Handle<i::Object> max1 = *j1;
@@ -619,6 +394,33 @@
     }
   }
 
+  void Context() {
+    // Constructor
+    for (int i = 0; i < 20; ++i) {
+      TypeHandle type = T.Random();
+      TypeHandle context = T.Context(type);
+      CHECK(context->Iscontext());
+    }
+
+    // Attributes
+    for (int i = 0; i < 20; ++i) {
+      TypeHandle type = T.Random();
+      TypeHandle context = T.Context(type);
+      CheckEqual(type, context->AsContext()->Outer());
+    }
+
+    // Functionality & Injectivity: Context(T1) = Context(T2) iff T1 = T2
+    for (int i = 0; i < 20; ++i) {
+      for (int j = 0; j < 20; ++j) {
+        TypeHandle type1 = T.Random();
+        TypeHandle type2 = T.Random();
+        TypeHandle context1 = T.Context(type1);
+        TypeHandle context2 = T.Context(type2);
+        CHECK(Equal(context1, context2) == Equal(type1, type2));
+      }
+    }
+  }
+
   void Array() {
     // Constructor
     for (int i = 0; i < 20; ++i) {
@@ -803,6 +605,66 @@
     }
   }
 
+  void MinMax() {
+    Factory* fac = isolate->factory();
+
+    // If b is regular numeric bitset, then Range(b->Min(), b->Max())->Is(b).
+    // TODO(neis): Need to ignore representation for this to be true.
+    /*
+    for (TypeIterator it = T.types.begin(); it != T.types.end(); ++it) {
+      TypeHandle type = *it;
+      if (this->IsBitset(type) && type->Is(T.Number) &&
+          !type->Is(T.None) && !type->Is(T.NaN)) {
+        TypeHandle range = T.Range(
+            isolate->factory()->NewNumber(type->Min()),
+            isolate->factory()->NewNumber(type->Max()));
+        CHECK(range->Is(type));
+      }
+    }
+    */
+
+    // If b is regular numeric bitset, then b->Min() and b->Max() are integers.
+    for (TypeIterator it = T.types.begin(); it != T.types.end(); ++it) {
+      TypeHandle type = *it;
+      if (this->IsBitset(type) && type->Is(T.Number) && !type->Is(T.NaN)) {
+        CHECK(IsInteger(type->Min()) && IsInteger(type->Max()));
+      }
+    }
+
+    // If b1 and b2 are regular numeric bitsets with b1->Is(b2), then
+    // b1->Min() >= b2->Min() and b1->Max() <= b2->Max().
+    for (TypeIterator it1 = T.types.begin(); it1 != T.types.end(); ++it1) {
+      for (TypeIterator it2 = T.types.begin(); it2 != T.types.end(); ++it2) {
+        TypeHandle type1 = *it1;
+        TypeHandle type2 = *it2;
+        if (this->IsBitset(type1) && type1->Is(type2) && type2->Is(T.Number) &&
+            !type1->Is(T.NaN) && !type2->Is(T.NaN)) {
+          CHECK(type1->Min() >= type2->Min());
+          CHECK(type1->Max() <= type2->Max());
+        }
+      }
+    }
+
+    // Lub(Range(x,y))->Min() <= x and y <= Lub(Range(x,y))->Max()
+    for (TypeIterator it = T.types.begin(); it != T.types.end(); ++it) {
+      TypeHandle type = *it;
+      if (type->IsRange()) {
+        TypeHandle lub = Rep::BitsetType::New(
+            Rep::BitsetType::Lub(type), T.region());
+        CHECK(lub->Min() <= type->Min() && type->Max() <= lub->Max());
+      }
+    }
+
+    // Rangification: If T->Is(Range(-inf,+inf)) and !T->Is(None), then
+    // T->Is(Range(T->Min(), T->Max())).
+    for (TypeIterator it = T.types.begin(); it != T.types.end(); ++it) {
+      TypeHandle type = *it;
+      CHECK(!(type->Is(T.Integer) && !type->Is(T.None)) ||
+            type->Is(T.Range(fac->NewNumber(type->Min()),
+                             fac->NewNumber(type->Max()))));
+    }
+  }
+
   void BitsetGlb() {
     // Lower: (T->BitsetGlb())->Is(T)
     for (TypeIterator it = T.types.begin(); it != T.types.end(); ++it) {
@@ -871,7 +733,7 @@
     }
   }
 
-  void Is() {
+  void Is1() {
     // Least Element (Bottom): None->Is(T)
     for (TypeIterator it = T.types.begin(); it != T.types.end(); ++it) {
       TypeHandle type = *it;
@@ -923,6 +785,26 @@
       }
     }
 
+    // (In-)Compatibilities.
+    for (TypeIterator i = T.types.begin(); i != T.types.end(); ++i) {
+      for (TypeIterator j = T.types.begin(); j != T.types.end(); ++j) {
+        TypeHandle type1 = *i;
+        TypeHandle type2 = *j;
+        CHECK(!type1->Is(type2) || this->IsBitset(type2) ||
+              this->IsUnion(type2) || this->IsUnion(type1) ||
+              (type1->IsClass() && type2->IsClass()) ||
+              (type1->IsConstant() && type2->IsConstant()) ||
+              (type1->IsConstant() && type2->IsRange()) ||
+              (type1->IsRange() && type2->IsRange()) ||
+              (type1->IsContext() && type2->IsContext()) ||
+              (type1->IsArray() && type2->IsArray()) ||
+              (type1->IsFunction() && type2->IsFunction()) ||
+              type1->Equals(T.None));
+      }
+    }
+  }
+
+  void Is2() {
     // Class(M1)->Is(Class(M2)) iff M1 = M2
     for (MapIterator mt1 = T.maps.begin(); mt1 != T.maps.end(); ++mt1) {
       for (MapIterator mt2 = T.maps.begin(); mt2 != T.maps.end(); ++mt2) {
@@ -934,26 +816,14 @@
       }
     }
 
-    // Constant(V1)->Is(Constant(V2)) iff V1 = V2
-    for (ValueIterator vt1 = T.values.begin(); vt1 != T.values.end(); ++vt1) {
-      for (ValueIterator vt2 = T.values.begin(); vt2 != T.values.end(); ++vt2) {
-        Handle<i::Object> value1 = *vt1;
-        Handle<i::Object> value2 = *vt2;
-        TypeHandle const_type1 = T.Constant(value1);
-        TypeHandle const_type2 = T.Constant(value2);
-        CHECK(const_type1->Is(const_type2) == (*value1 == *value2));
-      }
-    }
-
-    // Range(min1, max1)->Is(Range(min2, max2)) iff
-    // min1 >= min2 /\ max1 <= max2
+    // Range(X1, Y1)->Is(Range(X2, Y2)) iff X1 >= X2 /\ Y1 <= Y2
     for (ValueIterator i1 = T.integers.begin();
         i1 != T.integers.end(); ++i1) {
-      for (ValueIterator j1 = T.integers.begin();
+      for (ValueIterator j1 = i1;
           j1 != T.integers.end(); ++j1) {
         for (ValueIterator i2 = T.integers.begin();
              i2 != T.integers.end(); ++i2) {
-          for (ValueIterator j2 = T.integers.begin();
+          for (ValueIterator j2 = i2;
                j2 != T.integers.end(); ++j2) {
             i::Handle<i::Object> min1 = *i1;
             i::Handle<i::Object> max1 = *j1;
@@ -964,13 +834,24 @@
             TypeHandle type1 = T.Range(min1, max1);
             TypeHandle type2 = T.Range(min2, max2);
             CHECK(type1->Is(type2) ==
-                (min2->Number() <= min1->Number() &&
+                (min1->Number() >= min2->Number() &&
                  max1->Number() <= max2->Number()));
           }
         }
       }
     }
 
+    // Constant(V1)->Is(Constant(V2)) iff V1 = V2
+    for (ValueIterator vt1 = T.values.begin(); vt1 != T.values.end(); ++vt1) {
+      for (ValueIterator vt2 = T.values.begin(); vt2 != T.values.end(); ++vt2) {
+        Handle<i::Object> value1 = *vt1;
+        Handle<i::Object> value2 = *vt2;
+        TypeHandle const_type1 = T.Constant(value1);
+        TypeHandle const_type2 = T.Constant(value2);
+        CHECK(const_type1->Is(const_type2) == (*value1 == *value2));
+      }
+    }
+
     // Context(T1)->Is(Context(T2)) iff T1 = T2
     for (TypeIterator it1 = T.types.begin(); it1 != T.types.end(); ++it1) {
       for (TypeIterator it2 = T.types.begin(); it2 != T.types.end(); ++it2) {
@@ -1007,25 +888,45 @@
       }
     }
 
-    // (In-)Compatibilities.
-    for (TypeIterator i = T.types.begin(); i != T.types.end(); ++i) {
-      for (TypeIterator j = T.types.begin(); j != T.types.end(); ++j) {
-        TypeHandle type1 = *i;
-        TypeHandle type2 = *j;
-        CHECK(!type1->Is(type2) || this->IsBitset(type2) ||
-              this->IsUnion(type2) || this->IsUnion(type1) ||
-              (type1->IsClass() && type2->IsClass()) ||
-              (type1->IsConstant() && type2->IsConstant()) ||
-              (type1->IsConstant() && type2->IsRange()) ||
-              (type1->IsRange() && type2->IsRange()) ||
-              (type1->IsContext() && type2->IsContext()) ||
-              (type1->IsArray() && type2->IsArray()) ||
-              (type1->IsFunction() && type2->IsFunction()) ||
-              type1->Equals(T.None));
+
+    // Range-specific subtyping
+
+    // If IsInteger(v) then Constant(v)->Is(Range(v, v)).
+    for (TypeIterator it = T.types.begin(); it != T.types.end(); ++it) {
+      TypeHandle type = *it;
+      if (type->IsConstant() && IsInteger(*type->AsConstant()->Value())) {
+        CHECK(type->Is(
+            T.Range(type->AsConstant()->Value(), type->AsConstant()->Value())));
       }
     }
 
-    // Basic types
+    // If Constant(x)->Is(Range(min,max)) then IsInteger(v) and min <= x <= max.
+    for (TypeIterator it1 = T.types.begin(); it1 != T.types.end(); ++it1) {
+      for (TypeIterator it2 = T.types.begin(); it2 != T.types.end(); ++it2) {
+        TypeHandle type1 = *it1;
+        TypeHandle type2 = *it2;
+        if (type1->IsConstant() && type2->IsRange() && type1->Is(type2)) {
+          double x = type1->AsConstant()->Value()->Number();
+          double min = type2->AsRange()->Min()->Number();
+          double max = type2->AsRange()->Max()->Number();
+          CHECK(IsInteger(x) && min <= x && x <= max);
+        }
+      }
+    }
+
+    // Lub(Range(x,y))->Is(T.Union(T.Integral32, T.OtherNumber))
+    for (TypeIterator it = T.types.begin(); it != T.types.end(); ++it) {
+      TypeHandle type = *it;
+      if (type->IsRange()) {
+        TypeHandle lub = Rep::BitsetType::New(
+            Rep::BitsetType::Lub(type), T.region());
+        CHECK(lub->Is(T.PlainNumber));
+      }
+    }
+
+
+    // Subtyping between concrete basic types
+
     CheckUnordered(T.Boolean, T.Null);
     CheckUnordered(T.Undefined, T.Null);
     CheckUnordered(T.Boolean, T.Undefined);
@@ -1049,12 +950,12 @@
 
     CheckSub(T.Object, T.Receiver);
     CheckSub(T.Array, T.Object);
-    CheckSub(T.Function, T.Object);
     CheckSub(T.Proxy, T.Receiver);
     CheckUnordered(T.Object, T.Proxy);
-    CheckUnordered(T.Array, T.Function);
 
-    // Structural types
+
+    // Subtyping between concrete structural types
+
     CheckSub(T.ObjectClass, T.Object);
     CheckSub(T.ArrayClass, T.Object);
     CheckSub(T.ArrayClass, T.Array);
@@ -1086,7 +987,7 @@
     CheckSub(T.NumberArray, T.Object);
     CheckUnordered(T.StringArray, T.AnyArray);
 
-    CheckSub(T.MethodFunction, T.Function);
+    CheckSub(T.MethodFunction, T.Object);
     CheckSub(T.NumberFunction1, T.Object);
     CheckUnordered(T.SignedFunction1, T.NumberFunction1);
     CheckUnordered(T.NumberFunction1, T.NumberFunction2);
@@ -1372,10 +1273,8 @@
     CheckDisjoint(T.InternalizedString, T.Symbol);
     CheckOverlap(T.Object, T.Receiver);
     CheckOverlap(T.Array, T.Object);
-    CheckOverlap(T.Function, T.Object);
     CheckOverlap(T.Proxy, T.Receiver);
     CheckDisjoint(T.Object, T.Proxy);
-    CheckDisjoint(T.Array, T.Function);
 
     // Structural types
     CheckOverlap(T.ObjectClass, T.Object);
@@ -1399,7 +1298,7 @@
     CheckOverlap(T.NumberArray, T.Array);
     CheckDisjoint(T.NumberArray, T.AnyArray);
     CheckDisjoint(T.NumberArray, T.StringArray);
-    CheckOverlap(T.MethodFunction, T.Function);
+    CheckOverlap(T.MethodFunction, T.Object);
     CheckDisjoint(T.SignedFunction1, T.NumberFunction1);
     CheckDisjoint(T.SignedFunction1, T.NumberFunction2);
     CheckDisjoint(T.NumberFunction1, T.NumberFunction2);
@@ -1443,7 +1342,9 @@
     }
 
     // Associativity: Union(T1, Union(T2, T3)) = Union(Union(T1, T2), T3)
-    // This does NOT hold!
+    // This does NOT hold!  For example:
+    // (Unsigned32 \/ Range(0,5)) \/ Range(-5,0) = Unsigned32 \/ Range(-5,0)
+    // Unsigned32 \/ (Range(0,5) \/ Range(-5,0)) = Unsigned32 \/ Range(-5,5)
     /*
     for (TypeIterator it1 = T.types.begin(); it1 != T.types.end(); ++it1) {
       for (TypeIterator it2 = T.types.begin(); it2 != T.types.end(); ++it2) {
@@ -1483,7 +1384,9 @@
     }
 
     // Monotonicity: T1->Is(T2) implies Union(T1, T3)->Is(Union(T2, T3))
-    // This does NOT hold.
+    // This does NOT hold.  For example:
+    // Range(-5,-1) <= Signed32
+    // Range(-5,-1) \/ Range(1,5) = Range(-5,5) </= Signed32 \/ Range(1,5)
     /*
     for (TypeIterator it1 = T.types.begin(); it1 != T.types.end(); ++it1) {
       for (TypeIterator it2 = T.types.begin(); it2 != T.types.end(); ++it2) {
@@ -1502,8 +1405,10 @@
 
   void Union2() {
     // Monotonicity: T1->Is(T3) and T2->Is(T3) implies Union(T1, T2)->Is(T3)
-    // This does NOT hold.  TODO(neis): Could fix this by splitting
-    // OtherNumber into a negative and a positive part.
+    // This does NOT hold.  For example:
+    // Range(-2^33, -2^33) <= OtherNumber
+    // Range(2^33, 2^33) <= OtherNumber
+    // Range(-2^33, 2^33) </= OtherNumber
     /*
     for (TypeIterator it1 = T.types.begin(); it1 != T.types.end(); ++it1) {
       for (TypeIterator it2 = T.types.begin(); it2 != T.types.end(); ++it2) {
@@ -1523,7 +1428,7 @@
     // Monotonicity: T1->Is(T2) or T1->Is(T3) implies T1->Is(Union(T2, T3))
     for (TypeIterator it1 = T.types.begin(); it1 != T.types.end(); ++it1) {
       for (TypeIterator it2 = T.types.begin(); it2 != T.types.end(); ++it2) {
-        for (TypeIterator it3 = T.types.begin(); it3 != T.types.end(); ++it3) {
+        for (TypeIterator it3 = it2; it3 != T.types.end(); ++it3) {
           TypeHandle type1 = *it1;
           TypeHandle type2 = *it2;
           TypeHandle type3 = *it3;
@@ -1563,11 +1468,11 @@
     CheckDisjoint(T.Union(T.NumberArray, T.String), T.Number);
 
     // Bitset-function
-    CHECK(this->IsBitset(T.Union(T.MethodFunction, T.Function)));
+    CHECK(this->IsBitset(T.Union(T.MethodFunction, T.Object)));
     CHECK(this->IsUnion(T.Union(T.NumberFunction1, T.Number)));
 
-    CheckEqual(T.Union(T.MethodFunction, T.Function), T.Function);
-    CheckUnordered(T.Union(T.NumberFunction1, T.String), T.Function);
+    CheckEqual(T.Union(T.MethodFunction, T.Object), T.Object);
+    CheckUnordered(T.Union(T.NumberFunction1, T.String), T.Object);
     CheckOverlap(T.Union(T.NumberFunction2, T.String), T.Object);
     CheckDisjoint(T.Union(T.NumberFunction1, T.String), T.Number);
 
@@ -1635,7 +1540,7 @@
     CheckEqual(
         T.Union(T.NumberFunction1, T.NumberFunction2),
         T.Union(T.NumberFunction2, T.NumberFunction1));
-    CheckSub(T.Union(T.SignedFunction1, T.MethodFunction), T.Function);
+    CheckSub(T.Union(T.SignedFunction1, T.MethodFunction), T.Object);
 
     // Union-union
     CheckEqual(
@@ -1685,7 +1590,11 @@
 
     // Associativity:
     // Intersect(T1, Intersect(T2, T3)) = Intersect(Intersect(T1, T2), T3)
-    // This does NOT hold.
+    // This does NOT hold.  For example:
+    // (Class(..stringy1..) /\ Class(..stringy2..)) /\ Constant(..string..) =
+    // None
+    // Class(..stringy1..) /\ (Class(..stringy2..) /\ Constant(..string..)) =
+    // Constant(..string..)
     /*
     for (TypeIterator it1 = T.types.begin(); it1 != T.types.end(); ++it1) {
       for (TypeIterator it2 = T.types.begin(); it2 != T.types.end(); ++it2) {
@@ -1704,7 +1613,11 @@
     */
 
     // Join: Intersect(T1, T2)->Is(T1) and Intersect(T1, T2)->Is(T2)
-    // This does NOT hold.  Not even the disjunction.
+    // This does NOT hold.  For example:
+    // Class(..stringy..) /\ Constant(..string..) = Constant(..string..)
+    // Currently, not even the disjunction holds:
+    // Class(Internal/TaggedPtr) /\ (Any/Untagged \/ Context(..)) =
+    // Class(Internal/TaggedPtr) \/ Context(..)
     /*
     for (TypeIterator it1 = T.types.begin(); it1 != T.types.end(); ++it1) {
       for (TypeIterator it2 = T.types.begin(); it2 != T.types.end(); ++it2) {
@@ -1728,7 +1641,10 @@
     }
 
     // Monotonicity: T1->Is(T2) implies Intersect(T1, T3)->Is(Intersect(T2, T3))
-    // This does NOT hold.
+    // This does NOT hold.  For example:
+    // Class(OtherObject/TaggedPtr) <= Any/TaggedPtr
+    // Class(OtherObject/TaggedPtr) /\ Any/UntaggedInt1 = Class(..)
+    // Any/TaggedPtr /\ Any/UntaggedInt1 = None
     /*
     for (TypeIterator it1 = T.types.begin(); it1 != T.types.end(); ++it1) {
       for (TypeIterator it2 = T.types.begin(); it2 != T.types.end(); ++it2) {
@@ -1745,7 +1661,10 @@
     */
 
     // Monotonicity: T1->Is(T3) or T2->Is(T3) implies Intersect(T1, T2)->Is(T3)
-    // This does NOT hold.
+    // This does NOT hold.  For example:
+    // Class(..stringy..) <= Class(..stringy..)
+    // Class(..stringy..) /\ Constant(..string..) = Constant(..string..)
+    // Constant(..string..) </= Class(..stringy..)
     /*
     for (TypeIterator it1 = T.types.begin(); it1 != T.types.end(); ++it1) {
       for (TypeIterator it2 = T.types.begin(); it2 != T.types.end(); ++it2) {
@@ -1762,8 +1681,6 @@
     */
 
     // Monotonicity: T1->Is(T2) and T1->Is(T3) implies T1->Is(Intersect(T2, T3))
-    // This does NOT hold.
-    /*
     for (TypeIterator it1 = T.types.begin(); it1 != T.types.end(); ++it1) {
       for (TypeIterator it2 = T.types.begin(); it2 != T.types.end(); ++it2) {
         for (TypeIterator it3 = T.types.begin(); it3 != T.types.end(); ++it3) {
@@ -1776,7 +1693,6 @@
         }
       }
     }
-    */
 
     // Bitset-class
     CheckEqual(T.Intersect(T.ObjectClass, T.Object), T.ObjectClass);
@@ -1785,11 +1701,11 @@
 
     // Bitset-array
     CheckEqual(T.Intersect(T.NumberArray, T.Object), T.NumberArray);
-    CheckEqual(T.Intersect(T.AnyArray, T.Function), T.None);
+    CheckEqual(T.Intersect(T.AnyArray, T.Proxy), T.None);
 
     // Bitset-function
     CheckEqual(T.Intersect(T.MethodFunction, T.Object), T.MethodFunction);
-    CheckEqual(T.Intersect(T.NumberFunction1, T.Array), T.None);
+    CheckEqual(T.Intersect(T.NumberFunction1, T.Proxy), T.None);
 
     // Bitset-union
     CheckEqual(
@@ -1880,7 +1796,11 @@
 
   void Distributivity() {
     // Union(T1, Intersect(T2, T3)) = Intersect(Union(T1, T2), Union(T1, T3))
-    // This does NOT hold.
+    // This does NOT hold.  For example:
+    // Untagged \/ (Untagged /\ Class(../Tagged)) = Untagged \/ Class(../Tagged)
+    // (Untagged \/ Untagged) /\ (Untagged \/ Class(../Tagged)) =
+    // Untagged /\ (Untagged \/ Class(../Tagged)) = Untagged
+    // because Untagged <= Untagged \/ Class(../Tagged)
     /*
     for (TypeIterator it1 = T.types.begin(); it1 != T.types.end(); ++it1) {
       for (TypeIterator it2 = T.types.begin(); it2 != T.types.end(); ++it2) {
@@ -1900,7 +1820,10 @@
     */
 
     // Intersect(T1, Union(T2, T3)) = Union(Intersect(T1, T2), Intersect(T1,T3))
-    // This does NOT hold.
+    // This does NOT hold.  For example:
+    // Untagged /\ (Untagged \/ Class(../Tagged)) = Untagged
+    // (Untagged /\ Untagged) \/ (Untagged /\ Class(../Tagged)) =
+    // Untagged \/ Class(../Tagged)
     /*
     for (TypeIterator it1 = T.types.begin(); it1 != T.types.end(); ++it1) {
       for (TypeIterator it2 = T.types.begin(); it2 != T.types.end(); ++it2) {
@@ -1920,6 +1843,32 @@
     */
   }
 
+  void GetRange() {
+    // GetRange(Range(a, b)) = Range(a, b).
+    for (TypeIterator it1 = T.types.begin(); it1 != T.types.end(); ++it1) {
+      TypeHandle type1 = *it1;
+      if (type1->IsRange()) {
+        typename Type::RangeType* range = type1->GetRange();
+        CHECK(type1->Min() == range->Min()->Number());
+        CHECK(type1->Max() == range->Max()->Number());
+      }
+    }
+
+    // GetRange(Union(Constant(x), Range(min,max))) == Range(min, max).
+    for (TypeIterator it1 = T.types.begin(); it1 != T.types.end(); ++it1) {
+      for (TypeIterator it2 = T.types.begin(); it2 != T.types.end(); ++it2) {
+        TypeHandle type1 = *it1;
+        TypeHandle type2 = *it2;
+        if (type1->IsConstant() && type2->IsRange()) {
+          TypeHandle u = T.Union(type1, type2);
+
+          CHECK(type2->Min() == u->GetRange()->Min()->Number());
+          CHECK(type2->Max() == u->GetRange()->Max()->Number());
+        }
+      }
+    }
+  }
+
   template<class Type2, class TypeHandle2, class Region2, class Rep2>
   void Convert() {
     Types<Type2, TypeHandle2, Region2> T2(
@@ -2012,6 +1961,13 @@
 }
 
 
+TEST(MinMax) {
+  CcTest::InitializeVM();
+  ZoneTests().MinMax();
+  HeapTests().MinMax();
+}
+
+
 TEST(BitsetGlb) {
   CcTest::InitializeVM();
   ZoneTests().BitsetGlb();
@@ -2026,10 +1982,17 @@
 }
 
 
-TEST(Is) {
+TEST(Is1) {
   CcTest::InitializeVM();
-  ZoneTests().Is();
-  HeapTests().Is();
+  ZoneTests().Is1();
+  HeapTests().Is1();
+}
+
+
+TEST(Is2) {
+  CcTest::InitializeVM();
+  ZoneTests().Is2();
+  HeapTests().Is2();
 }
 
 
@@ -2098,13 +2061,18 @@
 }
 
 
-/*
 TEST(Distributivity) {
   CcTest::InitializeVM();
   ZoneTests().Distributivity();
   HeapTests().Distributivity();
 }
-*/
+
+
+TEST(GetRange) {
+  CcTest::InitializeVM();
+  ZoneTests().GetRange();
+  HeapTests().GetRange();
+}
 
 
 TEST(Convert) {
diff --git a/test/cctest/test-unboxed-doubles.cc b/test/cctest/test-unboxed-doubles.cc
new file mode 100644
index 0000000..a12bf47
--- /dev/null
+++ b/test/cctest/test-unboxed-doubles.cc
@@ -0,0 +1,1162 @@
+// 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.
+
+#include <stdlib.h>
+#include <utility>
+
+#include "src/v8.h"
+
+#include "src/compilation-cache.h"
+#include "src/execution.h"
+#include "src/factory.h"
+#include "src/global-handles.h"
+#include "src/ic/ic.h"
+#include "src/macro-assembler.h"
+#include "test/cctest/cctest.h"
+
+using namespace v8::base;
+using namespace v8::internal;
+
+#if (V8_DOUBLE_FIELDS_UNBOXING)
+
+
+static double GetDoubleFieldValue(JSObject* obj, FieldIndex field_index) {
+  if (obj->IsUnboxedDoubleField(field_index)) {
+    return obj->RawFastDoublePropertyAt(field_index);
+  } else {
+    Object* value = obj->RawFastPropertyAt(field_index);
+    DCHECK(value->IsMutableHeapNumber());
+    return HeapNumber::cast(value)->value();
+  }
+}
+
+const int kNumberOfBits = 32;
+
+
+enum TestPropertyKind {
+  PROP_CONSTANT,
+  PROP_SMI,
+  PROP_DOUBLE,
+  PROP_TAGGED,
+  PROP_KIND_NUMBER
+};
+
+static Representation representations[PROP_KIND_NUMBER] = {
+    Representation::None(), Representation::Smi(), Representation::Double(),
+    Representation::Tagged()};
+
+
+static Handle<DescriptorArray> CreateDescriptorArray(Isolate* isolate,
+                                                     TestPropertyKind* props,
+                                                     int kPropsCount) {
+  Factory* factory = isolate->factory();
+
+  Handle<String> func_name = factory->InternalizeUtf8String("func");
+  Handle<JSFunction> func = factory->NewFunction(func_name);
+
+  Handle<DescriptorArray> descriptors =
+      DescriptorArray::Allocate(isolate, 0, kPropsCount);
+
+  int next_field_offset = 0;
+  for (int i = 0; i < kPropsCount; i++) {
+    EmbeddedVector<char, 64> buffer;
+    SNPrintF(buffer, "prop%d", i);
+    Handle<String> name = factory->InternalizeUtf8String(buffer.start());
+
+    TestPropertyKind kind = props[i];
+
+    if (kind == PROP_CONSTANT) {
+      ConstantDescriptor d(name, func, NONE);
+      descriptors->Append(&d);
+
+    } else {
+      FieldDescriptor f(name, next_field_offset, NONE, representations[kind]);
+      next_field_offset += f.GetDetails().field_width_in_words();
+      descriptors->Append(&f);
+    }
+  }
+  return descriptors;
+}
+
+
+TEST(LayoutDescriptorBasicFast) {
+  CcTest::InitializeVM();
+  v8::HandleScope scope(CcTest::isolate());
+
+  LayoutDescriptor* layout_desc = LayoutDescriptor::FastPointerLayout();
+
+  CHECK(!layout_desc->IsSlowLayout());
+  CHECK(layout_desc->IsFastPointerLayout());
+  CHECK_EQ(kSmiValueSize, layout_desc->capacity());
+
+  for (int i = 0; i < kSmiValueSize + 13; i++) {
+    CHECK_EQ(true, layout_desc->IsTagged(i));
+  }
+  CHECK_EQ(true, layout_desc->IsTagged(-1));
+  CHECK_EQ(true, layout_desc->IsTagged(-12347));
+  CHECK_EQ(true, layout_desc->IsTagged(15635));
+  CHECK(layout_desc->IsFastPointerLayout());
+
+  for (int i = 0; i < kSmiValueSize; i++) {
+    layout_desc = layout_desc->SetTaggedForTesting(i, false);
+    CHECK_EQ(false, layout_desc->IsTagged(i));
+    layout_desc = layout_desc->SetTaggedForTesting(i, true);
+    CHECK_EQ(true, layout_desc->IsTagged(i));
+  }
+  CHECK(layout_desc->IsFastPointerLayout());
+
+  int sequence_length;
+  CHECK_EQ(true, layout_desc->IsTagged(0, std::numeric_limits<int>::max(),
+                                       &sequence_length));
+  CHECK_EQ(std::numeric_limits<int>::max(), sequence_length);
+
+  CHECK_EQ(true, layout_desc->IsTagged(0, 7, &sequence_length));
+  CHECK_EQ(7, sequence_length);
+}
+
+
+TEST(LayoutDescriptorBasicSlow) {
+  CcTest::InitializeVM();
+  Isolate* isolate = CcTest::i_isolate();
+  v8::HandleScope scope(CcTest::isolate());
+
+  Handle<LayoutDescriptor> layout_descriptor;
+  const int kPropsCount = kSmiValueSize * 3;
+  TestPropertyKind props[kPropsCount];
+  for (int i = 0; i < kPropsCount; i++) {
+    // All properties tagged.
+    props[i] = PROP_TAGGED;
+  }
+
+  {
+    Handle<DescriptorArray> descriptors =
+        CreateDescriptorArray(isolate, props, kPropsCount);
+
+    Handle<Map> map = Map::Create(isolate, kPropsCount);
+
+    layout_descriptor = LayoutDescriptor::New(map, descriptors, kPropsCount);
+    CHECK_EQ(LayoutDescriptor::FastPointerLayout(), *layout_descriptor);
+    CHECK_EQ(kSmiValueSize, layout_descriptor->capacity());
+    map->InitializeDescriptors(*descriptors, *layout_descriptor);
+    DCHECK(layout_descriptor->IsConsistentWithMap(*map));
+  }
+
+  props[0] = PROP_DOUBLE;
+  props[kPropsCount - 1] = PROP_DOUBLE;
+
+  Handle<DescriptorArray> descriptors =
+      CreateDescriptorArray(isolate, props, kPropsCount);
+
+  {
+    int inobject_properties = kPropsCount - 1;
+    Handle<Map> map = Map::Create(isolate, inobject_properties);
+
+    // Should be fast as the only double property is the first one.
+    layout_descriptor = LayoutDescriptor::New(map, descriptors, kPropsCount);
+    CHECK_NE(LayoutDescriptor::FastPointerLayout(), *layout_descriptor);
+    CHECK(!layout_descriptor->IsSlowLayout());
+    CHECK(!layout_descriptor->IsFastPointerLayout());
+
+    CHECK_EQ(false, layout_descriptor->IsTagged(0));
+    for (int i = 1; i < kPropsCount; i++) {
+      CHECK_EQ(true, layout_descriptor->IsTagged(i));
+    }
+    map->InitializeDescriptors(*descriptors, *layout_descriptor);
+    DCHECK(layout_descriptor->IsConsistentWithMap(*map));
+  }
+
+  {
+    int inobject_properties = kPropsCount;
+    Handle<Map> map = Map::Create(isolate, inobject_properties);
+
+    layout_descriptor = LayoutDescriptor::New(map, descriptors, kPropsCount);
+    CHECK_NE(LayoutDescriptor::FastPointerLayout(), *layout_descriptor);
+    CHECK(layout_descriptor->IsSlowLayout());
+    CHECK(!layout_descriptor->IsFastPointerLayout());
+    CHECK(layout_descriptor->capacity() > kSmiValueSize);
+
+    CHECK_EQ(false, layout_descriptor->IsTagged(0));
+    CHECK_EQ(false, layout_descriptor->IsTagged(kPropsCount - 1));
+    for (int i = 1; i < kPropsCount - 1; i++) {
+      CHECK_EQ(true, layout_descriptor->IsTagged(i));
+    }
+
+    map->InitializeDescriptors(*descriptors, *layout_descriptor);
+    DCHECK(layout_descriptor->IsConsistentWithMap(*map));
+
+    // Here we have truly slow layout descriptor, so play with the bits.
+    CHECK_EQ(true, layout_descriptor->IsTagged(-1));
+    CHECK_EQ(true, layout_descriptor->IsTagged(-12347));
+    CHECK_EQ(true, layout_descriptor->IsTagged(15635));
+
+    LayoutDescriptor* layout_desc = *layout_descriptor;
+    // Play with the bits but leave it in consistent state with map at the end.
+    for (int i = 1; i < kPropsCount - 1; i++) {
+      layout_desc = layout_desc->SetTaggedForTesting(i, false);
+      CHECK_EQ(false, layout_desc->IsTagged(i));
+      layout_desc = layout_desc->SetTaggedForTesting(i, true);
+      CHECK_EQ(true, layout_desc->IsTagged(i));
+    }
+    CHECK(layout_desc->IsSlowLayout());
+    CHECK(!layout_desc->IsFastPointerLayout());
+
+    DCHECK(layout_descriptor->IsConsistentWithMap(*map));
+  }
+}
+
+
+static void TestLayoutDescriptorQueries(int layout_descriptor_length,
+                                        int* bit_flip_positions,
+                                        int max_sequence_length) {
+  Handle<LayoutDescriptor> layout_descriptor = LayoutDescriptor::NewForTesting(
+      CcTest::i_isolate(), layout_descriptor_length);
+  layout_descriptor_length = layout_descriptor->capacity();
+  LayoutDescriptor* layout_desc = *layout_descriptor;
+
+  {
+    // Fill in the layout descriptor.
+    int cur_bit_flip_index = 0;
+    bool tagged = true;
+    for (int i = 0; i < layout_descriptor_length; i++) {
+      if (i == bit_flip_positions[cur_bit_flip_index]) {
+        tagged = !tagged;
+        ++cur_bit_flip_index;
+        CHECK(i < bit_flip_positions[cur_bit_flip_index]);  // check test data
+      }
+      layout_desc = layout_desc->SetTaggedForTesting(i, tagged);
+    }
+  }
+
+  if (layout_desc->IsFastPointerLayout()) {
+    return;
+  }
+
+  {
+    // Check queries.
+    int cur_bit_flip_index = 0;
+    bool tagged = true;
+    for (int i = 0; i < layout_descriptor_length; i++) {
+      if (i == bit_flip_positions[cur_bit_flip_index]) {
+        tagged = !tagged;
+        ++cur_bit_flip_index;
+      }
+      CHECK_EQ(tagged, layout_desc->IsTagged(i));
+
+      int next_bit_flip_position = bit_flip_positions[cur_bit_flip_index];
+      int expected_sequence_length;
+      if (next_bit_flip_position < layout_desc->capacity()) {
+        expected_sequence_length = next_bit_flip_position - i;
+      } else {
+        expected_sequence_length = tagged ? std::numeric_limits<int>::max()
+                                          : (layout_desc->capacity() - i);
+      }
+      expected_sequence_length =
+          Min(expected_sequence_length, max_sequence_length);
+      int sequence_length;
+      CHECK_EQ(tagged,
+               layout_desc->IsTagged(i, max_sequence_length, &sequence_length));
+      CHECK(sequence_length > 0);
+
+      CHECK_EQ(expected_sequence_length, sequence_length);
+    }
+
+    int sequence_length;
+    CHECK_EQ(true,
+             layout_desc->IsTagged(layout_descriptor_length,
+                                   max_sequence_length, &sequence_length));
+    CHECK_EQ(max_sequence_length, sequence_length);
+  }
+}
+
+
+static void TestLayoutDescriptorQueriesFast(int max_sequence_length) {
+  {
+    LayoutDescriptor* layout_desc = LayoutDescriptor::FastPointerLayout();
+    int sequence_length;
+    for (int i = 0; i < kNumberOfBits; i++) {
+      CHECK_EQ(true,
+               layout_desc->IsTagged(i, max_sequence_length, &sequence_length));
+      CHECK(sequence_length > 0);
+      CHECK_EQ(max_sequence_length, sequence_length);
+    }
+  }
+
+  {
+    int bit_flip_positions[] = {1000};
+    TestLayoutDescriptorQueries(kSmiValueSize, bit_flip_positions,
+                                max_sequence_length);
+  }
+
+  {
+    int bit_flip_positions[] = {0, 1000};
+    TestLayoutDescriptorQueries(kSmiValueSize, bit_flip_positions,
+                                max_sequence_length);
+  }
+
+  {
+    int bit_flip_positions[kNumberOfBits + 1];
+    for (int i = 0; i <= kNumberOfBits; i++) {
+      bit_flip_positions[i] = i;
+    }
+    TestLayoutDescriptorQueries(kSmiValueSize, bit_flip_positions,
+                                max_sequence_length);
+  }
+
+  {
+    int bit_flip_positions[] = {3, 7, 8, 10, 15, 21, 30, 1000};
+    TestLayoutDescriptorQueries(kSmiValueSize, bit_flip_positions,
+                                max_sequence_length);
+  }
+
+  {
+    int bit_flip_positions[] = {0,  1,  2,  3,  5,  7,  9,
+                                12, 15, 18, 22, 26, 29, 1000};
+    TestLayoutDescriptorQueries(kSmiValueSize, bit_flip_positions,
+                                max_sequence_length);
+  }
+}
+
+
+TEST(LayoutDescriptorQueriesFastLimited7) {
+  CcTest::InitializeVM();
+  v8::HandleScope scope(CcTest::isolate());
+
+  TestLayoutDescriptorQueriesFast(7);
+}
+
+
+TEST(LayoutDescriptorQueriesFastLimited13) {
+  CcTest::InitializeVM();
+  v8::HandleScope scope(CcTest::isolate());
+
+  TestLayoutDescriptorQueriesFast(13);
+}
+
+
+TEST(LayoutDescriptorQueriesFastUnlimited) {
+  CcTest::InitializeVM();
+  v8::HandleScope scope(CcTest::isolate());
+
+  TestLayoutDescriptorQueriesFast(std::numeric_limits<int>::max());
+}
+
+
+static void TestLayoutDescriptorQueriesSlow(int max_sequence_length) {
+  {
+    int bit_flip_positions[] = {10000};
+    TestLayoutDescriptorQueries(kMaxNumberOfDescriptors, bit_flip_positions,
+                                max_sequence_length);
+  }
+
+  {
+    int bit_flip_positions[] = {0, 10000};
+    TestLayoutDescriptorQueries(kMaxNumberOfDescriptors, bit_flip_positions,
+                                max_sequence_length);
+  }
+
+  {
+    int bit_flip_positions[kMaxNumberOfDescriptors + 1];
+    for (int i = 0; i < kMaxNumberOfDescriptors; i++) {
+      bit_flip_positions[i] = i;
+    }
+    bit_flip_positions[kMaxNumberOfDescriptors] = 10000;
+    TestLayoutDescriptorQueries(kMaxNumberOfDescriptors, bit_flip_positions,
+                                max_sequence_length);
+  }
+
+  {
+    int bit_flip_positions[] = {3,  7,  8,  10, 15,  21,   30,
+                                37, 54, 80, 99, 383, 10000};
+    TestLayoutDescriptorQueries(kMaxNumberOfDescriptors, bit_flip_positions,
+                                max_sequence_length);
+  }
+
+  {
+    int bit_flip_positions[] = {0,   10,  20,  30,  50,  70,  90,
+                                120, 150, 180, 220, 260, 290, 10000};
+    TestLayoutDescriptorQueries(kMaxNumberOfDescriptors, bit_flip_positions,
+                                max_sequence_length);
+  }
+
+  {
+    int bit_flip_positions[kMaxNumberOfDescriptors + 1];
+    int cur = 0;
+    for (int i = 0; i < kMaxNumberOfDescriptors; i++) {
+      bit_flip_positions[i] = cur;
+      cur = (cur + 1) * 2;
+    }
+    CHECK(cur < 10000);
+    bit_flip_positions[kMaxNumberOfDescriptors] = 10000;
+    TestLayoutDescriptorQueries(kMaxNumberOfDescriptors, bit_flip_positions,
+                                max_sequence_length);
+  }
+
+  {
+    int bit_flip_positions[kMaxNumberOfDescriptors + 1];
+    int cur = 3;
+    for (int i = 0; i < kMaxNumberOfDescriptors; i++) {
+      bit_flip_positions[i] = cur;
+      cur = (cur + 1) * 2;
+    }
+    CHECK(cur < 10000);
+    bit_flip_positions[kMaxNumberOfDescriptors] = 10000;
+    TestLayoutDescriptorQueries(kMaxNumberOfDescriptors, bit_flip_positions,
+                                max_sequence_length);
+  }
+}
+
+
+TEST(LayoutDescriptorQueriesSlowLimited7) {
+  CcTest::InitializeVM();
+  v8::HandleScope scope(CcTest::isolate());
+
+  TestLayoutDescriptorQueriesSlow(7);
+}
+
+
+TEST(LayoutDescriptorQueriesSlowLimited13) {
+  CcTest::InitializeVM();
+  v8::HandleScope scope(CcTest::isolate());
+
+  TestLayoutDescriptorQueriesSlow(13);
+}
+
+
+TEST(LayoutDescriptorQueriesSlowLimited42) {
+  CcTest::InitializeVM();
+  v8::HandleScope scope(CcTest::isolate());
+
+  TestLayoutDescriptorQueriesSlow(42);
+}
+
+
+TEST(LayoutDescriptorQueriesSlowUnlimited) {
+  CcTest::InitializeVM();
+  v8::HandleScope scope(CcTest::isolate());
+
+  TestLayoutDescriptorQueriesSlow(std::numeric_limits<int>::max());
+}
+
+
+TEST(LayoutDescriptorCreateNewFast) {
+  CcTest::InitializeVM();
+  Isolate* isolate = CcTest::i_isolate();
+  v8::HandleScope scope(CcTest::isolate());
+
+  Handle<LayoutDescriptor> layout_descriptor;
+  TestPropertyKind props[] = {
+      PROP_CONSTANT,
+      PROP_TAGGED,  // field #0
+      PROP_CONSTANT,
+      PROP_DOUBLE,  // field #1
+      PROP_CONSTANT,
+      PROP_TAGGED,  // field #2
+      PROP_CONSTANT,
+  };
+  const int kPropsCount = arraysize(props);
+
+  Handle<DescriptorArray> descriptors =
+      CreateDescriptorArray(isolate, props, kPropsCount);
+
+  {
+    Handle<Map> map = Map::Create(isolate, 0);
+    layout_descriptor = LayoutDescriptor::New(map, descriptors, kPropsCount);
+    CHECK_EQ(LayoutDescriptor::FastPointerLayout(), *layout_descriptor);
+    map->InitializeDescriptors(*descriptors, *layout_descriptor);
+    DCHECK(layout_descriptor->IsConsistentWithMap(*map));
+  }
+
+  {
+    Handle<Map> map = Map::Create(isolate, 1);
+    layout_descriptor = LayoutDescriptor::New(map, descriptors, kPropsCount);
+    CHECK_EQ(LayoutDescriptor::FastPointerLayout(), *layout_descriptor);
+    map->InitializeDescriptors(*descriptors, *layout_descriptor);
+    DCHECK(layout_descriptor->IsConsistentWithMap(*map));
+  }
+
+  {
+    Handle<Map> map = Map::Create(isolate, 2);
+    layout_descriptor = LayoutDescriptor::New(map, descriptors, kPropsCount);
+    CHECK_NE(LayoutDescriptor::FastPointerLayout(), *layout_descriptor);
+    CHECK(!layout_descriptor->IsSlowLayout());
+    CHECK_EQ(true, layout_descriptor->IsTagged(0));
+    CHECK_EQ(false, layout_descriptor->IsTagged(1));
+    CHECK_EQ(true, layout_descriptor->IsTagged(2));
+    CHECK_EQ(true, layout_descriptor->IsTagged(125));
+    map->InitializeDescriptors(*descriptors, *layout_descriptor);
+    DCHECK(layout_descriptor->IsConsistentWithMap(*map));
+  }
+}
+
+
+TEST(LayoutDescriptorCreateNewSlow) {
+  CcTest::InitializeVM();
+  Isolate* isolate = CcTest::i_isolate();
+  v8::HandleScope scope(CcTest::isolate());
+
+  Handle<LayoutDescriptor> layout_descriptor;
+  const int kPropsCount = kSmiValueSize * 3;
+  TestPropertyKind props[kPropsCount];
+  for (int i = 0; i < kPropsCount; i++) {
+    props[i] = static_cast<TestPropertyKind>(i % PROP_KIND_NUMBER);
+  }
+
+  Handle<DescriptorArray> descriptors =
+      CreateDescriptorArray(isolate, props, kPropsCount);
+
+  {
+    Handle<Map> map = Map::Create(isolate, 0);
+    layout_descriptor = LayoutDescriptor::New(map, descriptors, kPropsCount);
+    CHECK_EQ(LayoutDescriptor::FastPointerLayout(), *layout_descriptor);
+    map->InitializeDescriptors(*descriptors, *layout_descriptor);
+    DCHECK(layout_descriptor->IsConsistentWithMap(*map));
+  }
+
+  {
+    Handle<Map> map = Map::Create(isolate, 1);
+    layout_descriptor = LayoutDescriptor::New(map, descriptors, kPropsCount);
+    CHECK_EQ(LayoutDescriptor::FastPointerLayout(), *layout_descriptor);
+    map->InitializeDescriptors(*descriptors, *layout_descriptor);
+    DCHECK(layout_descriptor->IsConsistentWithMap(*map));
+  }
+
+  {
+    Handle<Map> map = Map::Create(isolate, 2);
+    layout_descriptor = LayoutDescriptor::New(map, descriptors, kPropsCount);
+    CHECK_NE(LayoutDescriptor::FastPointerLayout(), *layout_descriptor);
+    CHECK(!layout_descriptor->IsSlowLayout());
+    CHECK_EQ(true, layout_descriptor->IsTagged(0));
+    CHECK_EQ(false, layout_descriptor->IsTagged(1));
+    CHECK_EQ(true, layout_descriptor->IsTagged(2));
+    CHECK_EQ(true, layout_descriptor->IsTagged(125));
+    map->InitializeDescriptors(*descriptors, *layout_descriptor);
+    DCHECK(layout_descriptor->IsConsistentWithMap(*map));
+  }
+
+  {
+    int inobject_properties = kPropsCount / 2;
+    Handle<Map> map = Map::Create(isolate, inobject_properties);
+    layout_descriptor = LayoutDescriptor::New(map, descriptors, kPropsCount);
+    CHECK_NE(LayoutDescriptor::FastPointerLayout(), *layout_descriptor);
+    CHECK(layout_descriptor->IsSlowLayout());
+    for (int i = 0; i < inobject_properties; i++) {
+      // PROP_DOUBLE has index 1 among FIELD properties.
+      const bool tagged = (i % (PROP_KIND_NUMBER - 1)) != 1;
+      CHECK_EQ(tagged, layout_descriptor->IsTagged(i));
+    }
+    // Every property after inobject_properties must be tagged.
+    for (int i = inobject_properties; i < kPropsCount; i++) {
+      CHECK_EQ(true, layout_descriptor->IsTagged(i));
+    }
+    map->InitializeDescriptors(*descriptors, *layout_descriptor);
+    DCHECK(layout_descriptor->IsConsistentWithMap(*map));
+
+    // Now test LayoutDescriptor::cast_gc_safe().
+    Handle<LayoutDescriptor> layout_descriptor_copy =
+        LayoutDescriptor::New(map, descriptors, kPropsCount);
+
+    LayoutDescriptor* layout_desc = *layout_descriptor;
+    CHECK_EQ(layout_desc, LayoutDescriptor::cast(layout_desc));
+    CHECK_EQ(layout_desc, LayoutDescriptor::cast_gc_safe(layout_desc));
+    CHECK(layout_descriptor->IsFixedTypedArrayBase());
+    // Now make it look like a forwarding pointer to layout_descriptor_copy.
+    MapWord map_word = layout_desc->map_word();
+    CHECK(!map_word.IsForwardingAddress());
+    layout_desc->set_map_word(
+        MapWord::FromForwardingAddress(*layout_descriptor_copy));
+    CHECK(layout_desc->map_word().IsForwardingAddress());
+    CHECK_EQ(*layout_descriptor_copy,
+             LayoutDescriptor::cast_gc_safe(layout_desc));
+
+    // Restore it back.
+    layout_desc->set_map_word(map_word);
+    CHECK_EQ(layout_desc, LayoutDescriptor::cast(layout_desc));
+  }
+}
+
+
+static Handle<LayoutDescriptor> TestLayoutDescriptorAppend(
+    Isolate* isolate, int inobject_properties, TestPropertyKind* props,
+    int kPropsCount) {
+  Factory* factory = isolate->factory();
+
+  Handle<String> func_name = factory->InternalizeUtf8String("func");
+  Handle<JSFunction> func = factory->NewFunction(func_name);
+
+  Handle<DescriptorArray> descriptors =
+      DescriptorArray::Allocate(isolate, 0, kPropsCount);
+
+  Handle<Map> map = Map::Create(isolate, inobject_properties);
+  map->InitializeDescriptors(*descriptors,
+                             LayoutDescriptor::FastPointerLayout());
+
+  int next_field_offset = 0;
+  for (int i = 0; i < kPropsCount; i++) {
+    EmbeddedVector<char, 64> buffer;
+    SNPrintF(buffer, "prop%d", i);
+    Handle<String> name = factory->InternalizeUtf8String(buffer.start());
+
+    Handle<LayoutDescriptor> layout_descriptor;
+    TestPropertyKind kind = props[i];
+    if (kind == PROP_CONSTANT) {
+      ConstantDescriptor d(name, func, NONE);
+      layout_descriptor = LayoutDescriptor::Append(map, d.GetDetails());
+      descriptors->Append(&d);
+
+    } else {
+      FieldDescriptor f(name, next_field_offset, NONE, representations[kind]);
+      int field_width_in_words = f.GetDetails().field_width_in_words();
+      next_field_offset += field_width_in_words;
+      layout_descriptor = LayoutDescriptor::Append(map, f.GetDetails());
+      descriptors->Append(&f);
+
+      int field_index = f.GetDetails().field_index();
+      bool is_inobject = field_index < map->inobject_properties();
+      for (int bit = 0; bit < field_width_in_words; bit++) {
+        CHECK_EQ(is_inobject && (kind == PROP_DOUBLE),
+                 !layout_descriptor->IsTagged(field_index + bit));
+      }
+      CHECK(layout_descriptor->IsTagged(next_field_offset));
+    }
+    map->InitializeDescriptors(*descriptors, *layout_descriptor);
+  }
+  Handle<LayoutDescriptor> layout_descriptor(map->layout_descriptor(), isolate);
+  DCHECK(layout_descriptor->IsConsistentWithMap(*map));
+  return layout_descriptor;
+}
+
+
+TEST(LayoutDescriptorAppend) {
+  CcTest::InitializeVM();
+  Isolate* isolate = CcTest::i_isolate();
+  v8::HandleScope scope(CcTest::isolate());
+
+  Handle<LayoutDescriptor> layout_descriptor;
+  const int kPropsCount = kSmiValueSize * 3;
+  TestPropertyKind props[kPropsCount];
+  for (int i = 0; i < kPropsCount; i++) {
+    props[i] = static_cast<TestPropertyKind>(i % PROP_KIND_NUMBER);
+  }
+
+  layout_descriptor =
+      TestLayoutDescriptorAppend(isolate, 0, props, kPropsCount);
+  CHECK(!layout_descriptor->IsSlowLayout());
+
+  layout_descriptor =
+      TestLayoutDescriptorAppend(isolate, 13, props, kPropsCount);
+  CHECK(!layout_descriptor->IsSlowLayout());
+
+  layout_descriptor =
+      TestLayoutDescriptorAppend(isolate, kSmiValueSize, props, kPropsCount);
+  CHECK(!layout_descriptor->IsSlowLayout());
+
+  layout_descriptor = TestLayoutDescriptorAppend(isolate, kSmiValueSize * 2,
+                                                 props, kPropsCount);
+  CHECK(layout_descriptor->IsSlowLayout());
+
+  layout_descriptor =
+      TestLayoutDescriptorAppend(isolate, kPropsCount, props, kPropsCount);
+  CHECK(layout_descriptor->IsSlowLayout());
+}
+
+
+TEST(LayoutDescriptorAppendAllDoubles) {
+  CcTest::InitializeVM();
+  Isolate* isolate = CcTest::i_isolate();
+  v8::HandleScope scope(CcTest::isolate());
+
+  Handle<LayoutDescriptor> layout_descriptor;
+  const int kPropsCount = kSmiValueSize * 3;
+  TestPropertyKind props[kPropsCount];
+  for (int i = 0; i < kPropsCount; i++) {
+    props[i] = PROP_DOUBLE;
+  }
+
+  layout_descriptor =
+      TestLayoutDescriptorAppend(isolate, 0, props, kPropsCount);
+  CHECK(!layout_descriptor->IsSlowLayout());
+
+  layout_descriptor =
+      TestLayoutDescriptorAppend(isolate, 13, props, kPropsCount);
+  CHECK(!layout_descriptor->IsSlowLayout());
+
+  layout_descriptor =
+      TestLayoutDescriptorAppend(isolate, kSmiValueSize, props, kPropsCount);
+  CHECK(!layout_descriptor->IsSlowLayout());
+
+  layout_descriptor = TestLayoutDescriptorAppend(isolate, kSmiValueSize + 1,
+                                                 props, kPropsCount);
+  CHECK(layout_descriptor->IsSlowLayout());
+
+  layout_descriptor = TestLayoutDescriptorAppend(isolate, kSmiValueSize * 2,
+                                                 props, kPropsCount);
+  CHECK(layout_descriptor->IsSlowLayout());
+
+  layout_descriptor =
+      TestLayoutDescriptorAppend(isolate, kPropsCount, props, kPropsCount);
+  CHECK(layout_descriptor->IsSlowLayout());
+
+  {
+    // Ensure layout descriptor switches into slow mode at the right moment.
+    layout_descriptor =
+        TestLayoutDescriptorAppend(isolate, kPropsCount, props, kSmiValueSize);
+    CHECK(!layout_descriptor->IsSlowLayout());
+
+    layout_descriptor = TestLayoutDescriptorAppend(isolate, kPropsCount, props,
+                                                   kSmiValueSize + 1);
+    CHECK(layout_descriptor->IsSlowLayout());
+  }
+}
+
+
+static Handle<LayoutDescriptor> TestLayoutDescriptorAppendIfFastOrUseFull(
+    Isolate* isolate, int inobject_properties,
+    Handle<DescriptorArray> descriptors, int number_of_descriptors) {
+  Handle<Map> map = Map::Create(isolate, inobject_properties);
+
+  Handle<LayoutDescriptor> full_layout_descriptor = LayoutDescriptor::New(
+      map, descriptors, descriptors->number_of_descriptors());
+
+  int nof = 0;
+  bool switched_to_slow_mode = false;
+
+  for (int i = 0; i < number_of_descriptors; i++) {
+    PropertyDetails details = descriptors->GetDetails(i);
+
+    // This method calls LayoutDescriptor::AppendIfFastOrUseFull() internally
+    // and does all the required map-descriptors related book keeping.
+    map = Map::CopyInstallDescriptorsForTesting(map, i, descriptors,
+                                                full_layout_descriptor);
+
+    LayoutDescriptor* layout_desc = map->layout_descriptor();
+
+    if (layout_desc->IsSlowLayout()) {
+      switched_to_slow_mode = true;
+      CHECK_EQ(*full_layout_descriptor, layout_desc);
+    } else {
+      CHECK(!switched_to_slow_mode);
+      if (details.type() == FIELD) {
+        nof++;
+        int field_index = details.field_index();
+        int field_width_in_words = details.field_width_in_words();
+
+        bool is_inobject = field_index < map->inobject_properties();
+        for (int bit = 0; bit < field_width_in_words; bit++) {
+          CHECK_EQ(is_inobject && details.representation().IsDouble(),
+                   !layout_desc->IsTagged(field_index + bit));
+        }
+        CHECK(layout_desc->IsTagged(field_index + field_width_in_words));
+      }
+    }
+    DCHECK(map->layout_descriptor()->IsConsistentWithMap(*map));
+  }
+
+  Handle<LayoutDescriptor> layout_descriptor(map->GetLayoutDescriptor(),
+                                             isolate);
+  DCHECK(layout_descriptor->IsConsistentWithMap(*map));
+  return layout_descriptor;
+}
+
+
+TEST(LayoutDescriptorAppendIfFastOrUseFull) {
+  CcTest::InitializeVM();
+  Isolate* isolate = CcTest::i_isolate();
+  v8::HandleScope scope(CcTest::isolate());
+
+  Handle<LayoutDescriptor> layout_descriptor;
+  const int kPropsCount = kSmiValueSize * 3;
+  TestPropertyKind props[kPropsCount];
+  for (int i = 0; i < kPropsCount; i++) {
+    props[i] = static_cast<TestPropertyKind>(i % PROP_KIND_NUMBER);
+  }
+  Handle<DescriptorArray> descriptors =
+      CreateDescriptorArray(isolate, props, kPropsCount);
+
+  layout_descriptor = TestLayoutDescriptorAppendIfFastOrUseFull(
+      isolate, 0, descriptors, kPropsCount);
+  CHECK(!layout_descriptor->IsSlowLayout());
+
+  layout_descriptor = TestLayoutDescriptorAppendIfFastOrUseFull(
+      isolate, 13, descriptors, kPropsCount);
+  CHECK(!layout_descriptor->IsSlowLayout());
+
+  layout_descriptor = TestLayoutDescriptorAppendIfFastOrUseFull(
+      isolate, kSmiValueSize, descriptors, kPropsCount);
+  CHECK(!layout_descriptor->IsSlowLayout());
+
+  layout_descriptor = TestLayoutDescriptorAppendIfFastOrUseFull(
+      isolate, kSmiValueSize * 2, descriptors, kPropsCount);
+  CHECK(layout_descriptor->IsSlowLayout());
+
+  layout_descriptor = TestLayoutDescriptorAppendIfFastOrUseFull(
+      isolate, kPropsCount, descriptors, kPropsCount);
+  CHECK(layout_descriptor->IsSlowLayout());
+}
+
+
+TEST(LayoutDescriptorAppendIfFastOrUseFullAllDoubles) {
+  CcTest::InitializeVM();
+  Isolate* isolate = CcTest::i_isolate();
+  v8::HandleScope scope(CcTest::isolate());
+
+  Handle<LayoutDescriptor> layout_descriptor;
+  const int kPropsCount = kSmiValueSize * 3;
+  TestPropertyKind props[kPropsCount];
+  for (int i = 0; i < kPropsCount; i++) {
+    props[i] = PROP_DOUBLE;
+  }
+  Handle<DescriptorArray> descriptors =
+      CreateDescriptorArray(isolate, props, kPropsCount);
+
+  layout_descriptor = TestLayoutDescriptorAppendIfFastOrUseFull(
+      isolate, 0, descriptors, kPropsCount);
+  CHECK(!layout_descriptor->IsSlowLayout());
+
+  layout_descriptor = TestLayoutDescriptorAppendIfFastOrUseFull(
+      isolate, 13, descriptors, kPropsCount);
+  CHECK(!layout_descriptor->IsSlowLayout());
+
+  layout_descriptor = TestLayoutDescriptorAppendIfFastOrUseFull(
+      isolate, kSmiValueSize, descriptors, kPropsCount);
+  CHECK(!layout_descriptor->IsSlowLayout());
+
+  layout_descriptor = TestLayoutDescriptorAppendIfFastOrUseFull(
+      isolate, kSmiValueSize + 1, descriptors, kPropsCount);
+  CHECK(layout_descriptor->IsSlowLayout());
+
+  layout_descriptor = TestLayoutDescriptorAppendIfFastOrUseFull(
+      isolate, kSmiValueSize * 2, descriptors, kPropsCount);
+  CHECK(layout_descriptor->IsSlowLayout());
+
+  layout_descriptor = TestLayoutDescriptorAppendIfFastOrUseFull(
+      isolate, kPropsCount, descriptors, kPropsCount);
+  CHECK(layout_descriptor->IsSlowLayout());
+
+  {
+    // Ensure layout descriptor switches into slow mode at the right moment.
+    layout_descriptor = TestLayoutDescriptorAppendIfFastOrUseFull(
+        isolate, kPropsCount, descriptors, kSmiValueSize);
+    CHECK(!layout_descriptor->IsSlowLayout());
+
+    layout_descriptor = TestLayoutDescriptorAppendIfFastOrUseFull(
+        isolate, kPropsCount, descriptors, kSmiValueSize + 1);
+    CHECK(layout_descriptor->IsSlowLayout());
+  }
+}
+
+
+TEST(Regress436816) {
+  CcTest::InitializeVM();
+  Isolate* isolate = CcTest::i_isolate();
+  Factory* factory = isolate->factory();
+  v8::HandleScope scope(CcTest::isolate());
+
+  const int kPropsCount = kSmiValueSize * 3;
+  TestPropertyKind props[kPropsCount];
+  for (int i = 0; i < kPropsCount; i++) {
+    props[i] = PROP_DOUBLE;
+  }
+  Handle<DescriptorArray> descriptors =
+      CreateDescriptorArray(isolate, props, kPropsCount);
+
+  Handle<Map> map = Map::Create(isolate, kPropsCount);
+  Handle<LayoutDescriptor> layout_descriptor =
+      LayoutDescriptor::New(map, descriptors, kPropsCount);
+  map->InitializeDescriptors(*descriptors, *layout_descriptor);
+
+  Handle<JSObject> object = factory->NewJSObjectFromMap(map, TENURED);
+
+  Address fake_address = reinterpret_cast<Address>(~kHeapObjectTagMask);
+  HeapObject* fake_object = HeapObject::FromAddress(fake_address);
+  CHECK(fake_object->IsHeapObject());
+
+  double boom_value = bit_cast<double>(fake_object);
+  for (int i = 0; i < kPropsCount; i++) {
+    FieldIndex index = FieldIndex::ForDescriptor(*map, i);
+    CHECK(map->IsUnboxedDoubleField(index));
+    object->RawFastDoublePropertyAtPut(index, boom_value);
+  }
+  CHECK(object->HasFastProperties());
+  CHECK(!object->map()->HasFastPointerLayout());
+
+  Handle<Map> normalized_map =
+      Map::Normalize(map, KEEP_INOBJECT_PROPERTIES, "testing");
+  JSObject::MigrateToMap(object, normalized_map);
+  CHECK(!object->HasFastProperties());
+  CHECK(object->map()->HasFastPointerLayout());
+
+  // Trigger GCs and heap verification.
+  CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
+}
+
+
+TEST(DoScavenge) {
+  CcTest::InitializeVM();
+  Isolate* isolate = CcTest::i_isolate();
+  Factory* factory = isolate->factory();
+  v8::HandleScope scope(CcTest::isolate());
+
+  CompileRun(
+      "function A() {"
+      "  this.x = 42.5;"
+      "  this.o = {};"
+      "};"
+      "var o = new A();");
+
+  Handle<String> obj_name = factory->InternalizeUtf8String("o");
+
+  Handle<Object> obj_value =
+      Object::GetProperty(isolate->global_object(), obj_name).ToHandleChecked();
+  CHECK(obj_value->IsJSObject());
+  Handle<JSObject> obj = Handle<JSObject>::cast(obj_value);
+
+  {
+    // Ensure the object is properly set up.
+    Map* map = obj->map();
+    DescriptorArray* descriptors = map->instance_descriptors();
+    CHECK(map->NumberOfOwnDescriptors() == 2);
+    CHECK(descriptors->GetDetails(0).representation().IsDouble());
+    CHECK(descriptors->GetDetails(1).representation().IsHeapObject());
+    FieldIndex field_index = FieldIndex::ForDescriptor(map, 0);
+    CHECK(field_index.is_inobject() && field_index.is_double());
+    CHECK_EQ(FLAG_unbox_double_fields, map->IsUnboxedDoubleField(field_index));
+    CHECK_EQ(42.5, GetDoubleFieldValue(*obj, field_index));
+  }
+  CHECK(isolate->heap()->new_space()->Contains(*obj));
+
+  // Trigger GCs so that the newly allocated object moves to old gen.
+  CcTest::heap()->CollectGarbage(i::NEW_SPACE);  // in survivor space now
+
+  // Create temp object in the new space.
+  Handle<JSArray> temp = factory->NewJSArray(FAST_ELEMENTS, NOT_TENURED);
+  CHECK(isolate->heap()->new_space()->Contains(*temp));
+
+  // Construct a double value that looks like a pointer to the new space object
+  // and store it into the obj.
+  Address fake_object = reinterpret_cast<Address>(*temp) + kPointerSize;
+  double boom_value = bit_cast<double>(fake_object);
+
+  FieldIndex field_index = FieldIndex::ForDescriptor(obj->map(), 0);
+  Handle<HeapNumber> boom_number = factory->NewHeapNumber(boom_value, MUTABLE);
+  obj->FastPropertyAtPut(field_index, *boom_number);
+
+  // Now the object moves to old gen and it has a double field that looks like
+  // a pointer to a from semi-space.
+  CcTest::heap()->CollectGarbage(i::NEW_SPACE);  // in old gen now
+
+  CHECK(isolate->heap()->old_pointer_space()->Contains(*obj));
+
+  CHECK_EQ(boom_value, GetDoubleFieldValue(*obj, field_index));
+}
+
+
+static void TestLayoutDescriptorHelper(Isolate* isolate,
+                                       int inobject_properties,
+                                       Handle<DescriptorArray> descriptors,
+                                       int number_of_descriptors) {
+  Handle<Map> map = Map::Create(isolate, inobject_properties);
+
+  Handle<LayoutDescriptor> layout_descriptor = LayoutDescriptor::New(
+      map, descriptors, descriptors->number_of_descriptors());
+  map->InitializeDescriptors(*descriptors, *layout_descriptor);
+  DCHECK(layout_descriptor->IsConsistentWithMap(*map));
+
+  LayoutDescriptorHelper helper(*map);
+  bool all_fields_tagged = true;
+
+  int instance_size = map->instance_size();
+
+  int end_offset = instance_size * 2;
+  int first_non_tagged_field_offset = end_offset;
+  for (int i = 0; i < number_of_descriptors; i++) {
+    PropertyDetails details = descriptors->GetDetails(i);
+    if (details.type() != FIELD) continue;
+    FieldIndex index = FieldIndex::ForDescriptor(*map, i);
+    if (!index.is_inobject()) continue;
+    all_fields_tagged &= !details.representation().IsDouble();
+    bool expected_tagged = !index.is_double();
+    if (!expected_tagged) {
+      first_non_tagged_field_offset =
+          Min(first_non_tagged_field_offset, index.offset());
+    }
+
+    int end_of_region_offset;
+    CHECK_EQ(expected_tagged, helper.IsTagged(index.offset()));
+    CHECK_EQ(expected_tagged, helper.IsTagged(index.offset(), instance_size,
+                                              &end_of_region_offset));
+    CHECK(end_of_region_offset > 0);
+    CHECK(end_of_region_offset % kPointerSize == 0);
+    CHECK(end_of_region_offset <= instance_size);
+
+    for (int offset = index.offset(); offset < end_of_region_offset;
+         offset += kPointerSize) {
+      CHECK_EQ(expected_tagged, helper.IsTagged(index.offset()));
+    }
+    if (end_of_region_offset < instance_size) {
+      CHECK_EQ(!expected_tagged, helper.IsTagged(end_of_region_offset));
+    } else {
+      CHECK_EQ(true, helper.IsTagged(end_of_region_offset));
+    }
+  }
+
+  for (int offset = 0; offset < JSObject::kHeaderSize; offset += kPointerSize) {
+    // Header queries
+    CHECK_EQ(true, helper.IsTagged(offset));
+    int end_of_region_offset;
+    CHECK_EQ(true, helper.IsTagged(offset, end_offset, &end_of_region_offset));
+    CHECK_EQ(first_non_tagged_field_offset, end_of_region_offset);
+
+    // Out of bounds queries
+    CHECK_EQ(true, helper.IsTagged(offset + instance_size));
+  }
+
+  CHECK_EQ(all_fields_tagged, helper.all_fields_tagged());
+}
+
+
+TEST(LayoutDescriptorHelperMixed) {
+  CcTest::InitializeVM();
+  Isolate* isolate = CcTest::i_isolate();
+  v8::HandleScope scope(CcTest::isolate());
+
+  Handle<LayoutDescriptor> layout_descriptor;
+  const int kPropsCount = kSmiValueSize * 3;
+  TestPropertyKind props[kPropsCount];
+  for (int i = 0; i < kPropsCount; i++) {
+    props[i] = static_cast<TestPropertyKind>(i % PROP_KIND_NUMBER);
+  }
+  Handle<DescriptorArray> descriptors =
+      CreateDescriptorArray(isolate, props, kPropsCount);
+
+  TestLayoutDescriptorHelper(isolate, 0, descriptors, kPropsCount);
+
+  TestLayoutDescriptorHelper(isolate, 13, descriptors, kPropsCount);
+
+  TestLayoutDescriptorHelper(isolate, kSmiValueSize, descriptors, kPropsCount);
+
+  TestLayoutDescriptorHelper(isolate, kSmiValueSize * 2, descriptors,
+                             kPropsCount);
+
+  TestLayoutDescriptorHelper(isolate, kPropsCount, descriptors, kPropsCount);
+}
+
+
+TEST(LayoutDescriptorHelperAllTagged) {
+  CcTest::InitializeVM();
+  Isolate* isolate = CcTest::i_isolate();
+  v8::HandleScope scope(CcTest::isolate());
+
+  Handle<LayoutDescriptor> layout_descriptor;
+  const int kPropsCount = kSmiValueSize * 3;
+  TestPropertyKind props[kPropsCount];
+  for (int i = 0; i < kPropsCount; i++) {
+    props[i] = PROP_TAGGED;
+  }
+  Handle<DescriptorArray> descriptors =
+      CreateDescriptorArray(isolate, props, kPropsCount);
+
+  TestLayoutDescriptorHelper(isolate, 0, descriptors, kPropsCount);
+
+  TestLayoutDescriptorHelper(isolate, 13, descriptors, kPropsCount);
+
+  TestLayoutDescriptorHelper(isolate, kSmiValueSize, descriptors, kPropsCount);
+
+  TestLayoutDescriptorHelper(isolate, kSmiValueSize * 2, descriptors,
+                             kPropsCount);
+
+  TestLayoutDescriptorHelper(isolate, kPropsCount, descriptors, kPropsCount);
+}
+
+
+TEST(LayoutDescriptorHelperAllDoubles) {
+  CcTest::InitializeVM();
+  Isolate* isolate = CcTest::i_isolate();
+  v8::HandleScope scope(CcTest::isolate());
+
+  Handle<LayoutDescriptor> layout_descriptor;
+  const int kPropsCount = kSmiValueSize * 3;
+  TestPropertyKind props[kPropsCount];
+  for (int i = 0; i < kPropsCount; i++) {
+    props[i] = PROP_DOUBLE;
+  }
+  Handle<DescriptorArray> descriptors =
+      CreateDescriptorArray(isolate, props, kPropsCount);
+
+  TestLayoutDescriptorHelper(isolate, 0, descriptors, kPropsCount);
+
+  TestLayoutDescriptorHelper(isolate, 13, descriptors, kPropsCount);
+
+  TestLayoutDescriptorHelper(isolate, kSmiValueSize, descriptors, kPropsCount);
+
+  TestLayoutDescriptorHelper(isolate, kSmiValueSize * 2, descriptors,
+                             kPropsCount);
+
+  TestLayoutDescriptorHelper(isolate, kPropsCount, descriptors, kPropsCount);
+}
+
+
+TEST(StoreBufferScanOnScavenge) {
+  CcTest::InitializeVM();
+  Isolate* isolate = CcTest::i_isolate();
+  Factory* factory = isolate->factory();
+  v8::HandleScope scope(CcTest::isolate());
+
+  CompileRun(
+      "function A() {"
+      "  this.x = 42.5;"
+      "  this.o = {};"
+      "};"
+      "var o = new A();");
+
+  Handle<String> obj_name = factory->InternalizeUtf8String("o");
+
+  Handle<Object> obj_value =
+      Object::GetProperty(isolate->global_object(), obj_name).ToHandleChecked();
+  CHECK(obj_value->IsJSObject());
+  Handle<JSObject> obj = Handle<JSObject>::cast(obj_value);
+
+  {
+    // Ensure the object is properly set up.
+    Map* map = obj->map();
+    DescriptorArray* descriptors = map->instance_descriptors();
+    CHECK(map->NumberOfOwnDescriptors() == 2);
+    CHECK(descriptors->GetDetails(0).representation().IsDouble());
+    CHECK(descriptors->GetDetails(1).representation().IsHeapObject());
+    FieldIndex field_index = FieldIndex::ForDescriptor(map, 0);
+    CHECK(field_index.is_inobject() && field_index.is_double());
+    CHECK_EQ(FLAG_unbox_double_fields, map->IsUnboxedDoubleField(field_index));
+    CHECK_EQ(42.5, GetDoubleFieldValue(*obj, field_index));
+  }
+  CHECK(isolate->heap()->new_space()->Contains(*obj));
+
+  // Trigger GCs so that the newly allocated object moves to old gen.
+  CcTest::heap()->CollectGarbage(i::NEW_SPACE);  // in survivor space now
+  CcTest::heap()->CollectGarbage(i::NEW_SPACE);  // in old gen now
+
+  CHECK(isolate->heap()->old_pointer_space()->Contains(*obj));
+
+  // Create temp object in the new space.
+  Handle<JSArray> temp = factory->NewJSArray(FAST_ELEMENTS, NOT_TENURED);
+  CHECK(isolate->heap()->new_space()->Contains(*temp));
+
+  // Construct a double value that looks like a pointer to the new space object
+  // and store it into the obj.
+  Address fake_object = reinterpret_cast<Address>(*temp) + kPointerSize;
+  double boom_value = bit_cast<double>(fake_object);
+
+  FieldIndex field_index = FieldIndex::ForDescriptor(obj->map(), 0);
+  Handle<HeapNumber> boom_number = factory->NewHeapNumber(boom_value, MUTABLE);
+  obj->FastPropertyAtPut(field_index, *boom_number);
+
+  // Enforce scan on scavenge for the obj's page.
+  MemoryChunk* chunk = MemoryChunk::FromAddress(obj->address());
+  chunk->set_scan_on_scavenge(true);
+
+  // Trigger GCs and force evacuation. Should not crash there.
+  CcTest::heap()->CollectAllGarbage(i::Heap::kNoGCFlags);
+
+  CHECK_EQ(boom_value, GetDoubleFieldValue(*obj, field_index));
+}
+
+#endif
diff --git a/test/cctest/test-utils.cc b/test/cctest/test-utils.cc
index 9ea8b2b..05a12f5 100644
--- a/test/cctest/test-utils.cc
+++ b/test/cctest/test-utils.cc
@@ -76,6 +76,47 @@
 }
 
 
+TEST(BitSetComputer) {
+  typedef BitSetComputer<bool, 1, kSmiValueSize, uint32_t> BoolComputer;
+  CHECK_EQ(0, BoolComputer::word_count(0));
+  CHECK_EQ(1, BoolComputer::word_count(8));
+  CHECK_EQ(2, BoolComputer::word_count(50));
+  CHECK_EQ(0, BoolComputer::index(0, 8));
+  CHECK_EQ(100, BoolComputer::index(100, 8));
+  CHECK_EQ(1, BoolComputer::index(0, 40));
+  uint32_t data = 0;
+  data = BoolComputer::encode(data, 1, true);
+  data = BoolComputer::encode(data, 4, true);
+  CHECK_EQ(true, BoolComputer::decode(data, 1));
+  CHECK_EQ(true, BoolComputer::decode(data, 4));
+  CHECK_EQ(false, BoolComputer::decode(data, 0));
+  CHECK_EQ(false, BoolComputer::decode(data, 2));
+  CHECK_EQ(false, BoolComputer::decode(data, 3));
+
+  // Lets store 2 bits per item with 3000 items and verify the values are
+  // correct.
+  typedef BitSetComputer<unsigned char, 2, 8, unsigned char> TwoBits;
+  const int words = 750;
+  CHECK_EQ(words, TwoBits::word_count(3000));
+  const int offset = 10;
+  Vector<unsigned char> buffer = Vector<unsigned char>::New(offset + words);
+  memset(buffer.start(), 0, sizeof(unsigned char) * buffer.length());
+  for (int i = 0; i < words; i++) {
+    const int index = TwoBits::index(offset, i);
+    unsigned char data = buffer[index];
+    data = TwoBits::encode(data, i, i % 4);
+    buffer[index] = data;
+  }
+
+  for (int i = 0; i < words; i++) {
+    const int index = TwoBits::index(offset, i);
+    unsigned char data = buffer[index];
+    CHECK_EQ(i % 4, TwoBits::decode(data, i));
+  }
+  buffer.Dispose();
+}
+
+
 TEST(SNPrintF) {
   // Make sure that strings that are truncated because of too small
   // buffers are zero-terminated anyway.
@@ -222,8 +263,6 @@
 }
 
 
-// TODO(svenpanne) Unconditionally test this when our infrastructure is fixed.
-#if !V8_OS_NACL
 TEST(CPlusPlus11Features) {
   struct S {
     bool x;
@@ -256,4 +295,3 @@
     j += 11;
   }
 }
-#endif
diff --git a/test/cctest/test-weakmaps.cc b/test/cctest/test-weakmaps.cc
index bb412a8..6c19cb8 100644
--- a/test/cctest/test-weakmaps.cc
+++ b/test/cctest/test-weakmaps.cc
@@ -97,19 +97,20 @@
   }
   CHECK(!global_handles->IsWeak(key.location()));
 
-  // Put entry into weak map.
+  // Put two chained entries into weak map.
   {
     HandleScope scope(isolate);
-    PutIntoWeakMap(weakmap,
-                   Handle<JSObject>(JSObject::cast(*key)),
-                   Handle<Smi>(Smi::FromInt(23), isolate));
+    Handle<Map> map = factory->NewMap(JS_OBJECT_TYPE, JSObject::kHeaderSize);
+    Handle<JSObject> object = factory->NewJSObjectFromMap(map);
+    PutIntoWeakMap(weakmap, Handle<JSObject>(JSObject::cast(*key)), object);
+    PutIntoWeakMap(weakmap, object, Handle<Smi>(Smi::FromInt(23), isolate));
   }
-  CHECK_EQ(1, ObjectHashTable::cast(weakmap->table())->NumberOfElements());
+  CHECK_EQ(2, ObjectHashTable::cast(weakmap->table())->NumberOfElements());
 
   // Force a full GC.
   heap->CollectAllGarbage(false);
   CHECK_EQ(0, NumberOfWeakCalls);
-  CHECK_EQ(1, ObjectHashTable::cast(weakmap->table())->NumberOfElements());
+  CHECK_EQ(2, ObjectHashTable::cast(weakmap->table())->NumberOfElements());
   CHECK_EQ(
       0, ObjectHashTable::cast(weakmap->table())->NumberOfDeletedElements());
 
@@ -128,14 +129,14 @@
   // weak references whereas the second one will also clear weak maps.
   heap->CollectAllGarbage(false);
   CHECK_EQ(1, NumberOfWeakCalls);
-  CHECK_EQ(1, ObjectHashTable::cast(weakmap->table())->NumberOfElements());
+  CHECK_EQ(2, ObjectHashTable::cast(weakmap->table())->NumberOfElements());
   CHECK_EQ(
       0, ObjectHashTable::cast(weakmap->table())->NumberOfDeletedElements());
   heap->CollectAllGarbage(false);
   CHECK_EQ(1, NumberOfWeakCalls);
   CHECK_EQ(0, ObjectHashTable::cast(weakmap->table())->NumberOfElements());
-  CHECK_EQ(
-      1, ObjectHashTable::cast(weakmap->table())->NumberOfDeletedElements());
+  CHECK_EQ(2,
+           ObjectHashTable::cast(weakmap->table())->NumberOfDeletedElements());
 }
 
 
diff --git a/test/cctest/trace-extension.cc b/test/cctest/trace-extension.cc
index 8f390e4..0a1ff87 100644
--- a/test/cctest/trace-extension.cc
+++ b/test/cctest/trace-extension.cc
@@ -91,7 +91,8 @@
   // sp is only used to define stack high bound
   regs.sp =
       reinterpret_cast<Address>(trace_env.sample) - 10240;
-  trace_env.sample->Init(CcTest::i_isolate(), regs);
+  trace_env.sample->Init(CcTest::i_isolate(), regs,
+                         TickSample::kSkipCEntryFrame);
 }
 
 
diff --git a/test/cctest/types-fuzz.h b/test/cctest/types-fuzz.h
new file mode 100644
index 0000000..4eac64c
--- /dev/null
+++ b/test/cctest/types-fuzz.h
@@ -0,0 +1,311 @@
+// 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.
+
+#ifndef V8_TEST_CCTEST_TYPES_H_
+#define V8_TEST_CCTEST_TYPES_H_
+
+#include "src/v8.h"
+
+namespace v8 {
+namespace internal {
+
+
+template<class Type, class TypeHandle, class Region>
+class Types {
+ public:
+  Types(Region* region, Isolate* isolate)
+      : region_(region), rng_(isolate->random_number_generator()) {
+    #define DECLARE_TYPE(name, value) \
+      name = Type::name(region);      \
+      types.push_back(name);
+    PROPER_BITSET_TYPE_LIST(DECLARE_TYPE)
+    #undef DECLARE_TYPE
+
+    object_map = isolate->factory()->NewMap(
+        JS_OBJECT_TYPE, JSObject::kHeaderSize);
+    array_map = isolate->factory()->NewMap(
+        JS_ARRAY_TYPE, JSArray::kSize);
+    number_map = isolate->factory()->NewMap(
+        HEAP_NUMBER_TYPE, HeapNumber::kSize);
+    uninitialized_map = isolate->factory()->uninitialized_map();
+    ObjectClass = Type::Class(object_map, region);
+    ArrayClass = Type::Class(array_map, region);
+    NumberClass = Type::Class(number_map, region);
+    UninitializedClass = Type::Class(uninitialized_map, region);
+
+    maps.push_back(object_map);
+    maps.push_back(array_map);
+    maps.push_back(uninitialized_map);
+    for (MapVector::iterator it = maps.begin(); it != maps.end(); ++it) {
+      types.push_back(Type::Class(*it, region));
+    }
+
+    smi = handle(Smi::FromInt(666), isolate);
+    signed32 = isolate->factory()->NewHeapNumber(0x40000000);
+    object1 = isolate->factory()->NewJSObjectFromMap(object_map);
+    object2 = isolate->factory()->NewJSObjectFromMap(object_map);
+    array = isolate->factory()->NewJSArray(20);
+    uninitialized = isolate->factory()->uninitialized_value();
+    SmiConstant = Type::Constant(smi, region);
+    Signed32Constant = Type::Constant(signed32, region);
+    ObjectConstant1 = Type::Constant(object1, region);
+    ObjectConstant2 = Type::Constant(object2, region);
+    ArrayConstant = Type::Constant(array, region);
+    UninitializedConstant = Type::Constant(uninitialized, region);
+
+    values.push_back(smi);
+    values.push_back(signed32);
+    values.push_back(object1);
+    values.push_back(object2);
+    values.push_back(array);
+    values.push_back(uninitialized);
+    for (ValueVector::iterator it = values.begin(); it != values.end(); ++it) {
+      types.push_back(Type::Constant(*it, region));
+    }
+
+    integers.push_back(isolate->factory()->NewNumber(-V8_INFINITY));
+    integers.push_back(isolate->factory()->NewNumber(+V8_INFINITY));
+    integers.push_back(isolate->factory()->NewNumber(-rng_->NextInt(10)));
+    integers.push_back(isolate->factory()->NewNumber(+rng_->NextInt(10)));
+    for (int i = 0; i < 10; ++i) {
+      double x = rng_->NextInt();
+      integers.push_back(isolate->factory()->NewNumber(x));
+      x *= rng_->NextInt();
+      if (!IsMinusZero(x)) integers.push_back(isolate->factory()->NewNumber(x));
+    }
+
+    Integer = Type::Range(isolate->factory()->NewNumber(-V8_INFINITY),
+                          isolate->factory()->NewNumber(+V8_INFINITY), region);
+
+    NumberArray = Type::Array(Number, region);
+    StringArray = Type::Array(String, region);
+    AnyArray = Type::Array(Any, region);
+
+    SignedFunction1 = Type::Function(SignedSmall, SignedSmall, region);
+    NumberFunction1 = Type::Function(Number, Number, region);
+    NumberFunction2 = Type::Function(Number, Number, Number, region);
+    MethodFunction = Type::Function(String, Object, 0, region);
+
+    for (int i = 0; i < 30; ++i) {
+      types.push_back(Fuzz());
+    }
+  }
+
+  Handle<i::Map> object_map;
+  Handle<i::Map> array_map;
+  Handle<i::Map> number_map;
+  Handle<i::Map> uninitialized_map;
+
+  Handle<i::Smi> smi;
+  Handle<i::HeapNumber> signed32;
+  Handle<i::JSObject> object1;
+  Handle<i::JSObject> object2;
+  Handle<i::JSArray> array;
+  Handle<i::Oddball> uninitialized;
+
+  #define DECLARE_TYPE(name, value) TypeHandle name;
+  PROPER_BITSET_TYPE_LIST(DECLARE_TYPE)
+  #undef DECLARE_TYPE
+
+  TypeHandle ObjectClass;
+  TypeHandle ArrayClass;
+  TypeHandle NumberClass;
+  TypeHandle UninitializedClass;
+
+  TypeHandle SmiConstant;
+  TypeHandle Signed32Constant;
+  TypeHandle ObjectConstant1;
+  TypeHandle ObjectConstant2;
+  TypeHandle ArrayConstant;
+  TypeHandle UninitializedConstant;
+
+  TypeHandle Integer;
+
+  TypeHandle NumberArray;
+  TypeHandle StringArray;
+  TypeHandle AnyArray;
+
+  TypeHandle SignedFunction1;
+  TypeHandle NumberFunction1;
+  TypeHandle NumberFunction2;
+  TypeHandle MethodFunction;
+
+  typedef std::vector<TypeHandle> TypeVector;
+  typedef std::vector<Handle<i::Map> > MapVector;
+  typedef std::vector<Handle<i::Object> > ValueVector;
+
+  TypeVector types;
+  MapVector maps;
+  ValueVector values;
+  ValueVector integers;  // "Integer" values used for range limits.
+
+  TypeHandle Of(Handle<i::Object> value) {
+    return Type::Of(value, region_);
+  }
+
+  TypeHandle NowOf(Handle<i::Object> value) {
+    return Type::NowOf(value, region_);
+  }
+
+  TypeHandle Class(Handle<i::Map> map) {
+    return Type::Class(map, region_);
+  }
+
+  TypeHandle Constant(Handle<i::Object> value) {
+    return Type::Constant(value, region_);
+  }
+
+  TypeHandle Range(Handle<i::Object> min, Handle<i::Object> max) {
+    return Type::Range(min, max, region_);
+  }
+
+  TypeHandle Context(TypeHandle outer) {
+    return Type::Context(outer, region_);
+  }
+
+  TypeHandle Array1(TypeHandle element) {
+    return Type::Array(element, region_);
+  }
+
+  TypeHandle Function0(TypeHandle result, TypeHandle receiver) {
+    return Type::Function(result, receiver, 0, region_);
+  }
+
+  TypeHandle Function1(TypeHandle result, TypeHandle receiver, TypeHandle arg) {
+    TypeHandle type = Type::Function(result, receiver, 1, region_);
+    type->AsFunction()->InitParameter(0, arg);
+    return type;
+  }
+
+  TypeHandle Function2(TypeHandle result, TypeHandle arg1, TypeHandle arg2) {
+    return Type::Function(result, arg1, arg2, region_);
+  }
+
+  TypeHandle Union(TypeHandle t1, TypeHandle t2) {
+    return Type::Union(t1, t2, region_);
+  }
+  TypeHandle Intersect(TypeHandle t1, TypeHandle t2) {
+    return Type::Intersect(t1, t2, region_);
+  }
+
+  template<class Type2, class TypeHandle2>
+  TypeHandle Convert(TypeHandle2 t) {
+    return Type::template Convert<Type2>(t, region_);
+  }
+
+  TypeHandle Random() {
+    return types[rng_->NextInt(static_cast<int>(types.size()))];
+  }
+
+  TypeHandle Fuzz(int depth = 4) {
+    switch (rng_->NextInt(depth == 0 ? 3 : 20)) {
+      case 0: {  // bitset
+        #define COUNT_BITSET_TYPES(type, value) + 1
+        int n = 0 PROPER_BITSET_TYPE_LIST(COUNT_BITSET_TYPES);
+        #undef COUNT_BITSET_TYPES
+        // Pick a bunch of named bitsets and return their intersection.
+        TypeHandle result = Type::Any(region_);
+        for (int i = 0, m = 1 + rng_->NextInt(3); i < m; ++i) {
+          int j = rng_->NextInt(n);
+          #define PICK_BITSET_TYPE(type, value) \
+            if (j-- == 0) { \
+              TypeHandle tmp = Type::Intersect( \
+                  result, Type::type(region_), region_); \
+              if (tmp->Is(Type::None()) && i != 0) { \
+                break; \
+              } else { \
+                result = tmp; \
+                continue; \
+              } \
+            }
+          PROPER_BITSET_TYPE_LIST(PICK_BITSET_TYPE)
+          #undef PICK_BITSET_TYPE
+        }
+        return result;
+      }
+      case 1: {  // class
+        int i = rng_->NextInt(static_cast<int>(maps.size()));
+        return Type::Class(maps[i], region_);
+      }
+      case 2: {  // constant
+        int i = rng_->NextInt(static_cast<int>(values.size()));
+        return Type::Constant(values[i], region_);
+      }
+      case 3: {  // range
+        int i = rng_->NextInt(static_cast<int>(integers.size()));
+        int j = rng_->NextInt(static_cast<int>(integers.size()));
+        i::Handle<i::Object> min = integers[i];
+        i::Handle<i::Object> max = integers[j];
+        if (min->Number() > max->Number()) std::swap(min, max);
+        return Type::Range(min, max, region_);
+      }
+      case 4: {  // context
+        int depth = rng_->NextInt(3);
+        TypeHandle type = Type::Internal(region_);
+        for (int i = 0; i < depth; ++i) type = Type::Context(type, region_);
+        return type;
+      }
+      case 5: {  // array
+        TypeHandle element = Fuzz(depth / 2);
+        return Type::Array(element, region_);
+      }
+      case 6:
+      case 7: {  // function
+        TypeHandle result = Fuzz(depth / 2);
+        TypeHandle receiver = Fuzz(depth / 2);
+        int arity = rng_->NextInt(3);
+        TypeHandle type = Type::Function(result, receiver, arity, region_);
+        for (int i = 0; i < type->AsFunction()->Arity(); ++i) {
+          TypeHandle parameter = Fuzz(depth / 2);
+          type->AsFunction()->InitParameter(i, parameter);
+        }
+        return type;
+      }
+      default: {  // union
+        int n = rng_->NextInt(10);
+        TypeHandle type = None;
+        for (int i = 0; i < n; ++i) {
+          TypeHandle operand = Fuzz(depth - 1);
+          type = Type::Union(type, operand, region_);
+        }
+        return type;
+      }
+    }
+    UNREACHABLE();
+  }
+
+  Region* region() { return region_; }
+
+ private:
+  Region* region_;
+  v8::base::RandomNumberGenerator* rng_;
+};
+
+
+} }  // namespace v8::internal
+
+#endif