Version 3.15.7

Activated code aging by default.

Included more information in --prof log.

Removed eager sweeping for lazy swept spaces. Try to find in SlowAllocateRaw a bounded number of times a big enough memory slot. (issue 2194)

Performance and stability improvements on all platforms.

git-svn-id: http://v8.googlecode.com/svn/trunk@13101 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
diff --git a/ChangeLog b/ChangeLog
index 77b198e..c102910 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,16 @@
+2012-11-30: Version 3.15.7
+
+        Activated code aging by default.
+
+        Included more information in --prof log.
+
+        Removed eager sweeping for lazy swept spaces. Try to find in
+        SlowAllocateRaw a bounded number of times a big enough memory slot.
+        (issue 2194)
+
+        Performance and stability improvements on all platforms.
+
+
 2012-11-26: Version 3.15.6
 
         Ensure double arrays are filled with holes when extended from
diff --git a/src/api.cc b/src/api.cc
index 5351b96..39741f5 100644
--- a/src/api.cc
+++ b/src/api.cc
@@ -1237,7 +1237,7 @@
 
 void FunctionTemplate::ReadOnlyPrototype() {
   i::Isolate* isolate = Utils::OpenHandle(this)->GetIsolate();
-  if (IsDeadCheck(isolate, "v8::FunctionTemplate::SetPrototypeAttributes()")) {
+  if (IsDeadCheck(isolate, "v8::FunctionTemplate::ReadOnlyPrototype()")) {
     return;
   }
   ENTER_V8(isolate);
diff --git a/src/arm/codegen-arm.cc b/src/arm/codegen-arm.cc
index 689de9f..0470035 100644
--- a/src/arm/codegen-arm.cc
+++ b/src/arm/codegen-arm.cc
@@ -615,29 +615,6 @@
 }
 
 
-byte* Code::FindPlatformCodeAgeSequence() {
-  byte* start = instruction_start();
-  uint32_t young_length;
-  byte* young_sequence = GetNoCodeAgeSequence(&young_length);
-  if (!memcmp(start, young_sequence, young_length) ||
-      Memory::uint32_at(start) == kCodeAgePatchFirstInstruction) {
-    return start;
-  } else {
-    byte* start_after_strict = NULL;
-    if (kind() == FUNCTION) {
-      start_after_strict = start + kSizeOfFullCodegenStrictModePrologue;
-    } else {
-      ASSERT(kind() == OPTIMIZED_FUNCTION);
-      start_after_strict = start + kSizeOfOptimizedStrictModePrologue;
-    }
-    ASSERT(!memcmp(start_after_strict, young_sequence, young_length) ||
-           Memory::uint32_at(start_after_strict) ==
-           kCodeAgePatchFirstInstruction);
-    return start_after_strict;
-  }
-}
-
-
 bool Code::IsYoungSequence(byte* sequence) {
   uint32_t young_length;
   byte* young_sequence = GetNoCodeAgeSequence(&young_length);
diff --git a/src/arm/codegen-arm.h b/src/arm/codegen-arm.h
index 7ca2c8d..8f0033e 100644
--- a/src/arm/codegen-arm.h
+++ b/src/arm/codegen-arm.h
@@ -34,9 +34,6 @@
 namespace v8 {
 namespace internal {
 
-static const int kSizeOfFullCodegenStrictModePrologue = 16;
-static const int kSizeOfOptimizedStrictModePrologue = 16;
-
 // Forward declarations
 class CompilationInfo;
 
diff --git a/src/arm/full-codegen-arm.cc b/src/arm/full-codegen-arm.cc
index 9c69e8e..7cb402e 100644
--- a/src/arm/full-codegen-arm.cc
+++ b/src/arm/full-codegen-arm.cc
@@ -149,15 +149,12 @@
   // function calls.
   if (!info->is_classic_mode() || info->is_native()) {
     Label ok;
-    Label begin;
-    __ bind(&begin);
     __ cmp(r5, Operand(0));
     __ b(eq, &ok);
     int receiver_offset = info->scope()->num_parameters() * kPointerSize;
     __ LoadRoot(r2, Heap::kUndefinedValueRootIndex);
     __ str(r2, MemOperand(sp, receiver_offset));
     __ bind(&ok);
-    ASSERT_EQ(kSizeOfFullCodegenStrictModePrologue, ok.pos() - begin.pos());
   }
 
   // Open a frame scope to indicate that there is a frame on the stack.  The
@@ -167,6 +164,7 @@
 
   int locals_count = info->scope()->num_stack_slots();
 
+  info->set_prologue_offset(masm_->pc_offset());
   // The following four instructions must remain together and unmodified for
   // code aging to work properly.
   __ stm(db_w, sp, r1.bit() | cp.bit() | fp.bit() | lr.bit());
diff --git a/src/arm/lithium-codegen-arm.cc b/src/arm/lithium-codegen-arm.cc
index 6ff4cab..39e239a 100644
--- a/src/arm/lithium-codegen-arm.cc
+++ b/src/arm/lithium-codegen-arm.cc
@@ -138,17 +138,16 @@
   // function calls.
   if (!info_->is_classic_mode() || info_->is_native()) {
     Label ok;
-    Label begin;
-    __ bind(&begin);
     __ cmp(r5, Operand(0));
     __ b(eq, &ok);
     int receiver_offset = scope()->num_parameters() * kPointerSize;
     __ LoadRoot(r2, Heap::kUndefinedValueRootIndex);
     __ str(r2, MemOperand(sp, receiver_offset));
     __ bind(&ok);
-    ASSERT_EQ(kSizeOfOptimizedStrictModePrologue, ok.pos() - begin.pos());
   }
 
+
+  info()->set_prologue_offset(masm_->pc_offset());
   // The following three instructions must remain together and unmodified for
   // code aging to work properly.
   __ stm(db_w, sp, r1.bit() | cp.bit() | fp.bit() | lr.bit());
diff --git a/src/arm/macro-assembler-arm.cc b/src/arm/macro-assembler-arm.cc
index 158476e..7f6c60d 100644
--- a/src/arm/macro-assembler-arm.cc
+++ b/src/arm/macro-assembler-arm.cc
@@ -2222,12 +2222,28 @@
   add(r6, r6, Operand(1));
   str(r6, MemOperand(r7, kLevelOffset));
 
+  if (FLAG_log_timer_events) {
+    FrameScope frame(this, StackFrame::MANUAL);
+    PushSafepointRegisters();
+    PrepareCallCFunction(0, r0);
+    CallCFunction(ExternalReference::log_enter_external_function(isolate()), 0);
+    PopSafepointRegisters();
+  }
+
   // Native call returns to the DirectCEntry stub which redirects to the
   // return address pushed on stack (could have moved after GC).
   // DirectCEntry stub itself is generated early and never moves.
   DirectCEntryStub stub;
   stub.GenerateCall(this, function);
 
+  if (FLAG_log_timer_events) {
+    FrameScope frame(this, StackFrame::MANUAL);
+    PushSafepointRegisters();
+    PrepareCallCFunction(0, r0);
+    CallCFunction(ExternalReference::log_leave_external_function(isolate()), 0);
+    PopSafepointRegisters();
+  }
+
   Label promote_scheduled_exception;
   Label delete_allocated_handles;
   Label leave_exit_frame;
diff --git a/src/arm/stub-cache-arm.cc b/src/arm/stub-cache-arm.cc
index 866ab55..4604c33 100644
--- a/src/arm/stub-cache-arm.cc
+++ b/src/arm/stub-cache-arm.cc
@@ -4690,9 +4690,12 @@
   //  -- r1    : key
   //  -- r2    : receiver
   //  -- lr    : return address
-  //  -- r3    : scratch
+  //  -- r3    : scratch (elements backing store)
   //  -- r4    : scratch
   //  -- r5    : scratch
+  //  -- r6    : scratch
+  //  -- r7    : scratch
+  //  -- r9    : scratch
   // -----------------------------------
   Label miss_force_generic, transition_elements_kind, grow, slow;
   Label finish_store, check_capacity;
@@ -4705,6 +4708,7 @@
   Register scratch2 = r5;
   Register scratch3 = r6;
   Register scratch4 = r7;
+  Register scratch5 = r9;
   Register length_reg = r7;
 
   // This stub is meant to be tail-jumped to, the receiver must already
@@ -4791,6 +4795,17 @@
     __ str(scratch1,
            FieldMemOperand(elements_reg, FixedDoubleArray::kLengthOffset));
 
+    __ mov(scratch1, elements_reg);
+    __ StoreNumberToDoubleElements(value_reg,
+                                   key_reg,
+                                   // All registers after this are overwritten.
+                                   scratch1,
+                                   scratch2,
+                                   scratch3,
+                                   scratch4,
+                                   scratch5,
+                                   &transition_elements_kind);
+
     __ mov(scratch1, Operand(kHoleNanLower32));
     __ mov(scratch2, Operand(kHoleNanUpper32));
     for (int i = 1; i < JSArray::kPreallocatedArrayElements; i++) {
@@ -4799,16 +4814,6 @@
       __ str(scratch2, FieldMemOperand(elements_reg, offset + kPointerSize));
     }
 
-    __ StoreNumberToDoubleElements(value_reg,
-                                   key_reg,
-                                   // All registers after this are overwritten.
-                                   elements_reg,
-                                   scratch1,
-                                   scratch2,
-                                   scratch3,
-                                   scratch4,
-                                   &transition_elements_kind);
-
     // Install the new backing store in the JSArray.
     __ str(elements_reg,
            FieldMemOperand(receiver_reg, JSObject::kElementsOffset));
diff --git a/src/assembler.cc b/src/assembler.cc
index 344e203..25157be 100644
--- a/src/assembler.cc
+++ b/src/assembler.cc
@@ -1056,6 +1056,20 @@
 }
 
 
+ExternalReference ExternalReference::log_enter_external_function(
+    Isolate* isolate) {
+  return ExternalReference(
+      Redirect(isolate, FUNCTION_ADDR(Logger::EnterExternal)));
+}
+
+
+ExternalReference ExternalReference::log_leave_external_function(
+    Isolate* isolate) {
+  return ExternalReference(
+      Redirect(isolate, FUNCTION_ADDR(Logger::LeaveExternal)));
+}
+
+
 ExternalReference ExternalReference::keyed_lookup_cache_keys(Isolate* isolate) {
   return ExternalReference(isolate->keyed_lookup_cache()->keys_address());
 }
diff --git a/src/assembler.h b/src/assembler.h
index 76e0569..4639374 100644
--- a/src/assembler.h
+++ b/src/assembler.h
@@ -661,6 +661,10 @@
   static ExternalReference new_deoptimizer_function(Isolate* isolate);
   static ExternalReference compute_output_frames_function(Isolate* isolate);
 
+  // Log support.
+  static ExternalReference log_enter_external_function(Isolate* isolate);
+  static ExternalReference log_leave_external_function(Isolate* isolate);
+
   // Static data in the keyed lookup cache.
   static ExternalReference keyed_lookup_cache_keys(Isolate* isolate);
   static ExternalReference keyed_lookup_cache_field_offsets(Isolate* isolate);
diff --git a/src/builtins.cc b/src/builtins.cc
index 5c8e32b..d9f8d15 100644
--- a/src/builtins.cc
+++ b/src/builtins.cc
@@ -574,14 +574,12 @@
       MaybeObject* maybe_obj = heap->AllocateUninitializedFixedArray(capacity);
       if (!maybe_obj->To(&new_elms)) return maybe_obj;
 
-      if (len > 0) {
-        ElementsAccessor* accessor = array->GetElementsAccessor();
-        MaybeObject* maybe_failure =
-            accessor->CopyElements(NULL, 0, new_elms, kind, 0, len, elms_obj);
-        ASSERT(!maybe_failure->IsFailure());
-        USE(maybe_failure);
-      }
-      FillWithHoles(heap, new_elms, new_length, capacity);
+      ElementsAccessor* accessor = array->GetElementsAccessor();
+      MaybeObject* maybe_failure = accessor->CopyElements(
+           NULL, 0, new_elms, kind, 0,
+           ElementsAccessor::kCopyToEndAndInitializeToHole, elms_obj);
+      ASSERT(!maybe_failure->IsFailure());
+      USE(maybe_failure);
 
       elms = new_elms;
     }
@@ -623,15 +621,12 @@
           heap->AllocateUninitializedFixedDoubleArray(capacity);
       if (!maybe_obj->To(&new_elms)) return maybe_obj;
 
-      if (len > 0) {
-        ElementsAccessor* accessor = array->GetElementsAccessor();
-        MaybeObject* maybe_failure =
-            accessor->CopyElements(NULL, 0, new_elms, kind, 0, len, elms_obj);
-        ASSERT(!maybe_failure->IsFailure());
-        USE(maybe_failure);
-      }
-
-      FillWithHoles(new_elms, len + to_add, new_elms->length());
+      ElementsAccessor* accessor = array->GetElementsAccessor();
+      MaybeObject* maybe_failure = accessor->CopyElements(
+              NULL, 0, new_elms, kind, 0,
+              ElementsAccessor::kCopyToEndAndInitializeToHole, elms_obj);
+      ASSERT(!maybe_failure->IsFailure());
+      USE(maybe_failure);
     } else {
       // to_add is > 0 and new_length <= elms_len, so elms_obj cannot be the
       // empty_fixed_array.
@@ -787,16 +782,14 @@
     MaybeObject* maybe_elms = heap->AllocateUninitializedFixedArray(capacity);
     if (!maybe_elms->To(&new_elms)) return maybe_elms;
 
-    if (len > 0) {
-      ElementsKind kind = array->GetElementsKind();
-      ElementsAccessor* accessor = array->GetElementsAccessor();
-      MaybeObject* maybe_failure =
-          accessor->CopyElements(NULL, 0, new_elms, kind, to_add, len, elms);
-      ASSERT(!maybe_failure->IsFailure());
-      USE(maybe_failure);
-    }
+    ElementsKind kind = array->GetElementsKind();
+    ElementsAccessor* accessor = array->GetElementsAccessor();
+    MaybeObject* maybe_failure = accessor->CopyElements(
+            NULL, 0, new_elms, kind, to_add,
+            ElementsAccessor::kCopyToEndAndInitializeToHole, elms);
+    ASSERT(!maybe_failure->IsFailure());
+    USE(maybe_failure);
 
-    FillWithHoles(heap, new_elms, new_length, capacity);
     elms = new_elms;
     array->set_elements(elms);
   } else {
@@ -1116,16 +1109,12 @@
         ASSERT(!maybe_failure->IsFailure());
         USE(maybe_failure);
       }
-      const int to_copy = len - actual_delete_count - actual_start;
-      if (to_copy > 0) {
-        MaybeObject* maybe_failure = accessor->CopyElements(
-            NULL, actual_start + actual_delete_count, new_elms, kind,
-            actual_start + item_count, to_copy, elms);
-        ASSERT(!maybe_failure->IsFailure());
-        USE(maybe_failure);
-      }
-
-      FillWithHoles(heap, new_elms, new_length, capacity);
+      MaybeObject* maybe_failure = accessor->CopyElements(
+          NULL, actual_start + actual_delete_count, new_elms, kind,
+          actual_start + item_count,
+          ElementsAccessor::kCopyToEndAndInitializeToHole, elms);
+      ASSERT(!maybe_failure->IsFailure());
+      USE(maybe_failure);
 
       elms_obj = new_elms;
       elms_changed = true;
diff --git a/src/codegen.cc b/src/codegen.cc
index 0163580..83ac854 100644
--- a/src/codegen.cc
+++ b/src/codegen.cc
@@ -107,6 +107,7 @@
   if (!code.is_null()) {
     isolate->counters()->total_compiled_code_size()->Increment(
         code->instruction_size());
+    code->set_prologue_offset(info->prologue_offset());
   }
   return code;
 }
diff --git a/src/compiler.cc b/src/compiler.cc
index 3dfc4e3..ff6e05d 100644
--- a/src/compiler.cc
+++ b/src/compiler.cc
@@ -52,57 +52,53 @@
 
 
 CompilationInfo::CompilationInfo(Handle<Script> script, Zone* zone)
-    : isolate_(script->GetIsolate()),
-      flags_(LanguageModeField::encode(CLASSIC_MODE)),
-      function_(NULL),
-      scope_(NULL),
-      global_scope_(NULL),
+    : flags_(LanguageModeField::encode(CLASSIC_MODE)),
       script_(script),
-      extension_(NULL),
-      pre_parse_data_(NULL),
-      osr_ast_id_(BailoutId::None()),
-      zone_(zone),
-      deferred_handles_(NULL) {
-  Initialize(BASE);
+      osr_ast_id_(BailoutId::None()) {
+  Initialize(zone);
 }
 
 
 CompilationInfo::CompilationInfo(Handle<SharedFunctionInfo> shared_info,
                                  Zone* zone)
-    : isolate_(shared_info->GetIsolate()),
-      flags_(LanguageModeField::encode(CLASSIC_MODE) |
-             IsLazy::encode(true)),
-      function_(NULL),
-      scope_(NULL),
-      global_scope_(NULL),
+    : flags_(LanguageModeField::encode(CLASSIC_MODE) | IsLazy::encode(true)),
       shared_info_(shared_info),
       script_(Handle<Script>(Script::cast(shared_info->script()))),
-      extension_(NULL),
-      pre_parse_data_(NULL),
-      osr_ast_id_(BailoutId::None()),
-      zone_(zone),
-      deferred_handles_(NULL) {
-  Initialize(BASE);
+      osr_ast_id_(BailoutId::None()) {
+  Initialize(zone);
 }
 
 
 CompilationInfo::CompilationInfo(Handle<JSFunction> closure, Zone* zone)
-    : isolate_(closure->GetIsolate()),
-      flags_(LanguageModeField::encode(CLASSIC_MODE) |
-             IsLazy::encode(true)),
-      function_(NULL),
-      scope_(NULL),
-      global_scope_(NULL),
+    : flags_(LanguageModeField::encode(CLASSIC_MODE) | IsLazy::encode(true)),
       closure_(closure),
       shared_info_(Handle<SharedFunctionInfo>(closure->shared())),
       script_(Handle<Script>(Script::cast(shared_info_->script()))),
-      extension_(NULL),
-      pre_parse_data_(NULL),
       context_(closure->context()),
-      osr_ast_id_(BailoutId::None()),
-      zone_(zone),
-      deferred_handles_(NULL) {
-  Initialize(BASE);
+      osr_ast_id_(BailoutId::None()) {
+  Initialize(zone);
+}
+
+
+void CompilationInfo::Initialize(Zone* zone) {
+  isolate_ = script_->GetIsolate();
+  function_ = NULL;
+  scope_ = NULL;
+  global_scope_ = NULL;
+  extension_ = NULL;
+  pre_parse_data_ = NULL;
+  zone_ = zone;
+  deferred_handles_ = NULL;
+  prologue_offset_ = kPrologueOffsetNotSet;
+  mode_ = V8::UseCrankshaft() ? BASE : NONOPT;
+  if (script_->type()->value() == Script::TYPE_NATIVE) {
+    MarkAsNative();
+  }
+  if (!shared_info_.is_null()) {
+    ASSERT(language_mode() == CLASSIC_MODE);
+    SetLanguageMode(shared_info_->language_mode());
+  }
+  set_bailout_reason("unknown");
 }
 
 
diff --git a/src/compiler.h b/src/compiler.h
index 62eedc2..653d5f1 100644
--- a/src/compiler.h
+++ b/src/compiler.h
@@ -35,6 +35,8 @@
 namespace v8 {
 namespace internal {
 
+static const int kPrologueOffsetNotSet = -1;
+
 class ScriptDataImpl;
 
 // CompilationInfo encapsulates some information known at compile time.  It
@@ -186,6 +188,16 @@
   const char* bailout_reason() const { return bailout_reason_; }
   void set_bailout_reason(const char* reason) { bailout_reason_ = reason; }
 
+  int prologue_offset() const {
+    ASSERT_NE(kPrologueOffsetNotSet, prologue_offset_);
+    return prologue_offset_;
+  }
+
+  void set_prologue_offset(int prologue_offset) {
+    ASSERT_EQ(kPrologueOffsetNotSet, prologue_offset_);
+    prologue_offset_ = prologue_offset;
+  }
+
  private:
   Isolate* isolate_;
 
@@ -200,18 +212,7 @@
     NONOPT
   };
 
-  void Initialize(Mode mode) {
-    mode_ = V8::UseCrankshaft() ? mode : NONOPT;
-    ASSERT(!script_.is_null());
-    if (script_->type()->value() == Script::TYPE_NATIVE) {
-      MarkAsNative();
-    }
-    if (!shared_info_.is_null()) {
-      ASSERT(language_mode() == CLASSIC_MODE);
-      SetLanguageMode(shared_info_->language_mode());
-    }
-    set_bailout_reason("unknown");
-  }
+  void Initialize(Zone* zone);
 
   void SetMode(Mode mode) {
     ASSERT(V8::UseCrankshaft());
@@ -285,6 +286,8 @@
 
   const char* bailout_reason_;
 
+  int prologue_offset_;
+
   DISALLOW_COPY_AND_ASSIGN(CompilationInfo);
 };
 
diff --git a/src/d8.cc b/src/d8.cc
index 814a8f4..8233f86 100644
--- a/src/d8.cc
+++ b/src/d8.cc
@@ -1511,9 +1511,9 @@
 class ShellThread : public i::Thread {
  public:
   // Takes ownership of the underlying char array of |files|.
-  ShellThread(Isolate* isolate, int no, char* files)
+  ShellThread(Isolate* isolate, char* files)
       : Thread("d8:ShellThread"),
-        isolate_(isolate), no_(no), files_(files) { }
+        isolate_(isolate), files_(files) { }
 
   ~ShellThread() {
     delete[] files_;
@@ -1522,7 +1522,6 @@
   virtual void Run();
  private:
   Isolate* isolate_;
-  int no_;
   char* files_;
 };
 
@@ -1829,7 +1828,7 @@
         printf("File list '%s' not found\n", options.parallel_files[i]);
         Exit(1);
       }
-      ShellThread* thread = new ShellThread(isolate, threads.length(), files);
+      ShellThread* thread = new ShellThread(isolate, files);
       thread->Start();
       threads.Add(thread);
     }
diff --git a/src/deoptimizer.h b/src/deoptimizer.h
index 4aa38ce..89955b3 100644
--- a/src/deoptimizer.h
+++ b/src/deoptimizer.h
@@ -537,9 +537,6 @@
   intptr_t context_;
   StackFrame::Type type_;
   Smi* state_;
-#ifdef DEBUG
-  Code::Kind kind_;
-#endif
 
   // Continuation is the PC where the execution continues after
   // deoptimizing.
diff --git a/src/elements.cc b/src/elements.cc
index 6103da4..8e1bf3e 100644
--- a/src/elements.cc
+++ b/src/elements.cc
@@ -146,33 +146,36 @@
 }
 
 
-static void CopyObjectToObjectElements(FixedArray* from,
+static void CopyObjectToObjectElements(FixedArrayBase* from_base,
                                        ElementsKind from_kind,
                                        uint32_t from_start,
-                                       FixedArray* to,
+                                       FixedArrayBase* to_base,
                                        ElementsKind to_kind,
                                        uint32_t to_start,
                                        int raw_copy_size) {
-  ASSERT(to->map() != HEAP->fixed_cow_array_map());
+  ASSERT(to_base->map() != HEAP->fixed_cow_array_map());
+  AssertNoAllocation no_allocation;
   int copy_size = raw_copy_size;
   if (raw_copy_size < 0) {
     ASSERT(raw_copy_size == ElementsAccessor::kCopyToEnd ||
            raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole);
-    copy_size = Min(from->length() - from_start,
-                    to->length() - to_start);
-#ifdef DEBUG
-    // FAST_*_ELEMENTS arrays cannot be uninitialized. Ensure they are already
-    // marked with the hole.
+    copy_size = Min(from_base->length() - from_start,
+                    to_base->length() - to_start);
     if (raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole) {
-      for (int i = to_start + copy_size; i < to->length(); ++i) {
-        ASSERT(to->get(i)->IsTheHole());
+      int start = to_start + copy_size;
+      int length = to_base->length() - start;
+      if (length > 0) {
+        Heap* heap = from_base->GetHeap();
+        MemsetPointer(FixedArray::cast(to_base)->data_start() + start,
+                      heap->the_hole_value(), length);
       }
     }
-#endif
   }
-  ASSERT((copy_size + static_cast<int>(to_start)) <= to->length() &&
-         (copy_size + static_cast<int>(from_start)) <= from->length());
+  ASSERT((copy_size + static_cast<int>(to_start)) <= to_base->length() &&
+         (copy_size + static_cast<int>(from_start)) <= from_base->length());
   if (copy_size == 0) return;
+  FixedArray* from = FixedArray::cast(from_base);
+  FixedArray* to = FixedArray::cast(to_base);
   ASSERT(IsFastSmiOrObjectElementsKind(from_kind));
   ASSERT(IsFastSmiOrObjectElementsKind(to_kind));
   Address to_address = to->address() + FixedArray::kHeaderSize;
@@ -193,31 +196,34 @@
 }
 
 
-static void CopyDictionaryToObjectElements(SeededNumberDictionary* from,
+static void CopyDictionaryToObjectElements(FixedArrayBase* from_base,
                                            uint32_t from_start,
-                                           FixedArray* to,
+                                           FixedArrayBase* to_base,
                                            ElementsKind to_kind,
                                            uint32_t to_start,
                                            int raw_copy_size) {
+  SeededNumberDictionary* from = SeededNumberDictionary::cast(from_base);
+  AssertNoAllocation no_allocation;
   int copy_size = raw_copy_size;
   Heap* heap = from->GetHeap();
   if (raw_copy_size < 0) {
     ASSERT(raw_copy_size == ElementsAccessor::kCopyToEnd ||
            raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole);
     copy_size = from->max_number_key() + 1 - from_start;
-#ifdef DEBUG
-    // Fast object arrays cannot be uninitialized. Ensure they are already
-    // marked with the hole.
     if (raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole) {
-      for (int i = to_start + copy_size; i < to->length(); ++i) {
-        ASSERT(to->get(i)->IsTheHole());
+      int start = to_start + copy_size;
+      int length = to_base->length() - start;
+      if (length > 0) {
+        Heap* heap = from->GetHeap();
+        MemsetPointer(FixedArray::cast(to_base)->data_start() + start,
+                      heap->the_hole_value(), length);
       }
     }
-#endif
   }
-  ASSERT(to != from);
+  ASSERT(to_base != from_base);
   ASSERT(IsFastSmiOrObjectElementsKind(to_kind));
   if (copy_size == 0) return;
+  FixedArray* to = FixedArray::cast(to_base);
   uint32_t to_length = to->length();
   if (to_start + copy_size > to_length) {
     copy_size = to_length - to_start;
@@ -244,9 +250,9 @@
 
 
 MUST_USE_RESULT static MaybeObject* CopyDoubleToObjectElements(
-    FixedDoubleArray* from,
+    FixedArrayBase* from_base,
     uint32_t from_start,
-    FixedArray* to,
+    FixedArrayBase* to_base,
     ElementsKind to_kind,
     uint32_t to_start,
     int raw_copy_size) {
@@ -255,21 +261,26 @@
   if (raw_copy_size < 0) {
     ASSERT(raw_copy_size == ElementsAccessor::kCopyToEnd ||
            raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole);
-    copy_size = Min(from->length() - from_start,
-                    to->length() - to_start);
-#ifdef DEBUG
-    // FAST_*_ELEMENTS arrays cannot be uninitialized. Ensure they are already
-    // marked with the hole.
+    copy_size = Min(from_base->length() - from_start,
+                    to_base->length() - to_start);
     if (raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole) {
-      for (int i = to_start + copy_size; i < to->length(); ++i) {
-        ASSERT(to->get(i)->IsTheHole());
+      // Also initialize the area that will be copied over since HeapNumber
+      // allocation below can cause an incremental marking step, requiring all
+      // existing heap objects to be propertly initialized.
+      int start = to_start;
+      int length = to_base->length() - start;
+      if (length > 0) {
+        Heap* heap = from_base->GetHeap();
+        MemsetPointer(FixedArray::cast(to_base)->data_start() + start,
+                      heap->the_hole_value(), length);
       }
     }
-#endif
   }
-  ASSERT((copy_size + static_cast<int>(to_start)) <= to->length() &&
-         (copy_size + static_cast<int>(from_start)) <= from->length());
-  if (copy_size == 0) return from;
+  ASSERT((copy_size + static_cast<int>(to_start)) <= to_base->length() &&
+         (copy_size + static_cast<int>(from_start)) <= from_base->length());
+  if (copy_size == 0) return from_base;
+  FixedDoubleArray* from = FixedDoubleArray::cast(from_base);
+  FixedArray* to = FixedArray::cast(to_base);
   for (int i = 0; i < copy_size; ++i) {
     if (IsFastSmiElementsKind(to_kind)) {
       UNIMPLEMENTED();
@@ -298,26 +309,28 @@
 }
 
 
-static void CopyDoubleToDoubleElements(FixedDoubleArray* from,
+static void CopyDoubleToDoubleElements(FixedArrayBase* from_base,
                                        uint32_t from_start,
-                                       FixedDoubleArray* to,
+                                       FixedArrayBase* to_base,
                                        uint32_t to_start,
                                        int raw_copy_size) {
   int copy_size = raw_copy_size;
   if (raw_copy_size < 0) {
     ASSERT(raw_copy_size == ElementsAccessor::kCopyToEnd ||
            raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole);
-    copy_size = Min(from->length() - from_start,
-                    to->length() - to_start);
+    copy_size = Min(from_base->length() - from_start,
+                    to_base->length() - to_start);
     if (raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole) {
-      for (int i = to_start + copy_size; i < to->length(); ++i) {
-        to->set_the_hole(i);
+      for (int i = to_start + copy_size; i < to_base->length(); ++i) {
+        FixedDoubleArray::cast(to_base)->set_the_hole(i);
       }
     }
   }
-  ASSERT((copy_size + static_cast<int>(to_start)) <= to->length() &&
-         (copy_size + static_cast<int>(from_start)) <= from->length());
+  ASSERT((copy_size + static_cast<int>(to_start)) <= to_base->length() &&
+         (copy_size + static_cast<int>(from_start)) <= from_base->length());
   if (copy_size == 0) return;
+  FixedDoubleArray* from = FixedDoubleArray::cast(from_base);
+  FixedDoubleArray* to = FixedDoubleArray::cast(to_base);
   Address to_address = to->address() + FixedDoubleArray::kHeaderSize;
   Address from_address = from->address() + FixedDoubleArray::kHeaderSize;
   to_address += kDoubleSize * to_start;
@@ -329,25 +342,27 @@
 }
 
 
-static void CopySmiToDoubleElements(FixedArray* from,
+static void CopySmiToDoubleElements(FixedArrayBase* from_base,
                                     uint32_t from_start,
-                                    FixedDoubleArray* to,
+                                    FixedArrayBase* to_base,
                                     uint32_t to_start,
                                     int raw_copy_size) {
   int copy_size = raw_copy_size;
   if (raw_copy_size < 0) {
     ASSERT(raw_copy_size == ElementsAccessor::kCopyToEnd ||
            raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole);
-    copy_size = from->length() - from_start;
+    copy_size = from_base->length() - from_start;
     if (raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole) {
-      for (int i = to_start + copy_size; i < to->length(); ++i) {
-        to->set_the_hole(i);
+      for (int i = to_start + copy_size; i < to_base->length(); ++i) {
+        FixedDoubleArray::cast(to_base)->set_the_hole(i);
       }
     }
   }
-  ASSERT((copy_size + static_cast<int>(to_start)) <= to->length() &&
-         (copy_size + static_cast<int>(from_start)) <= from->length());
+  ASSERT((copy_size + static_cast<int>(to_start)) <= to_base->length() &&
+         (copy_size + static_cast<int>(from_start)) <= from_base->length());
   if (copy_size == 0) return;
+  FixedArray* from = FixedArray::cast(from_base);
+  FixedDoubleArray* to = FixedDoubleArray::cast(to_base);
   Object* the_hole = from->GetHeap()->the_hole_value();
   for (uint32_t from_end = from_start + static_cast<uint32_t>(copy_size);
        from_start < from_end; from_start++, to_start++) {
@@ -361,9 +376,9 @@
 }
 
 
-static void CopyPackedSmiToDoubleElements(FixedArray* from,
+static void CopyPackedSmiToDoubleElements(FixedArrayBase* from_base,
                                           uint32_t from_start,
-                                          FixedDoubleArray* to,
+                                          FixedArrayBase* to_base,
                                           uint32_t to_start,
                                           int packed_size,
                                           int raw_copy_size) {
@@ -372,11 +387,11 @@
   if (raw_copy_size < 0) {
     ASSERT(raw_copy_size == ElementsAccessor::kCopyToEnd ||
            raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole);
-    copy_size = from->length() - from_start;
+    copy_size = packed_size - from_start;
     if (raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole) {
-      to_end = to->length();
+      to_end = to_base->length();
       for (uint32_t i = to_start + copy_size; i < to_end; ++i) {
-        to->set_the_hole(i);
+        FixedDoubleArray::cast(to_base)->set_the_hole(i);
       }
     } else {
       to_end = to_start + static_cast<uint32_t>(copy_size);
@@ -384,11 +399,13 @@
   } else {
     to_end = to_start + static_cast<uint32_t>(copy_size);
   }
-  ASSERT(static_cast<int>(to_end) <= to->length());
+  ASSERT(static_cast<int>(to_end) <= to_base->length());
   ASSERT(packed_size >= 0 && packed_size <= copy_size);
-  ASSERT((copy_size + static_cast<int>(to_start)) <= to->length() &&
-         (copy_size + static_cast<int>(from_start)) <= from->length());
+  ASSERT((copy_size + static_cast<int>(to_start)) <= to_base->length() &&
+         (copy_size + static_cast<int>(from_start)) <= from_base->length());
   if (copy_size == 0) return;
+  FixedArray* from = FixedArray::cast(from_base);
+  FixedDoubleArray* to = FixedDoubleArray::cast(to_base);
   for (uint32_t from_end = from_start + static_cast<uint32_t>(packed_size);
        from_start < from_end; from_start++, to_start++) {
     Object* smi = from->get(from_start);
@@ -398,25 +415,27 @@
 }
 
 
-static void CopyObjectToDoubleElements(FixedArray* from,
+static void CopyObjectToDoubleElements(FixedArrayBase* from_base,
                                        uint32_t from_start,
-                                       FixedDoubleArray* to,
+                                       FixedArrayBase* to_base,
                                        uint32_t to_start,
                                        int raw_copy_size) {
   int copy_size = raw_copy_size;
   if (raw_copy_size < 0) {
     ASSERT(raw_copy_size == ElementsAccessor::kCopyToEnd ||
            raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole);
-    copy_size = from->length() - from_start;
+    copy_size = from_base->length() - from_start;
     if (raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole) {
-      for (int i = to_start + copy_size; i < to->length(); ++i) {
-        to->set_the_hole(i);
+      for (int i = to_start + copy_size; i < to_base->length(); ++i) {
+        FixedDoubleArray::cast(to_base)->set_the_hole(i);
       }
     }
   }
-  ASSERT((copy_size + static_cast<int>(to_start)) <= to->length() &&
-         (copy_size + static_cast<int>(from_start)) <= from->length());
+  ASSERT((copy_size + static_cast<int>(to_start)) <= to_base->length() &&
+         (copy_size + static_cast<int>(from_start)) <= from_base->length());
   if (copy_size == 0) return;
+  FixedArray* from = FixedArray::cast(from_base);
+  FixedDoubleArray* to = FixedDoubleArray::cast(to_base);
   Object* the_hole = from->GetHeap()->the_hole_value();
   for (uint32_t from_end = from_start + copy_size;
        from_start < from_end; from_start++, to_start++) {
@@ -430,23 +449,25 @@
 }
 
 
-static void CopyDictionaryToDoubleElements(SeededNumberDictionary* from,
+static void CopyDictionaryToDoubleElements(FixedArrayBase* from_base,
                                            uint32_t from_start,
-                                           FixedDoubleArray* to,
+                                           FixedArrayBase* to_base,
                                            uint32_t to_start,
                                            int raw_copy_size) {
+  SeededNumberDictionary* from = SeededNumberDictionary::cast(from_base);
   int copy_size = raw_copy_size;
   if (copy_size < 0) {
     ASSERT(copy_size == ElementsAccessor::kCopyToEnd ||
            copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole);
     copy_size = from->max_number_key() + 1 - from_start;
     if (raw_copy_size == ElementsAccessor::kCopyToEndAndInitializeToHole) {
-      for (int i = to_start + copy_size; i < to->length(); ++i) {
-        to->set_the_hole(i);
+      for (int i = to_start + copy_size; i < to_base->length(); ++i) {
+        FixedDoubleArray::cast(to_base)->set_the_hole(i);
       }
     }
   }
   if (copy_size == 0) return;
+  FixedDoubleArray* to = FixedDoubleArray::cast(to_base);
   uint32_t to_length = to->length();
   if (to_start + copy_size > to_length) {
     copy_size = to_length - to_start;
@@ -526,7 +547,7 @@
   static bool HasElementImpl(Object* receiver,
                              JSObject* holder,
                              uint32_t key,
-                             BackingStore* backing_store) {
+                             FixedArrayBase* backing_store) {
     return ElementsAccessorSubclass::GetAttributesImpl(
         receiver, holder, key, backing_store) != ABSENT;
   }
@@ -539,7 +560,7 @@
       backing_store = holder->elements();
     }
     return ElementsAccessorSubclass::HasElementImpl(
-        receiver, holder, key, BackingStore::cast(backing_store));
+        receiver, holder, key, backing_store);
   }
 
   MUST_USE_RESULT virtual MaybeObject* Get(Object* receiver,
@@ -550,15 +571,15 @@
       backing_store = holder->elements();
     }
     return ElementsAccessorSubclass::GetImpl(
-        receiver, holder, key, BackingStore::cast(backing_store));
+        receiver, holder, key, backing_store);
   }
 
   MUST_USE_RESULT static MaybeObject* GetImpl(Object* receiver,
                                               JSObject* obj,
                                               uint32_t key,
-                                              BackingStore* backing_store) {
+                                              FixedArrayBase* backing_store) {
     return (key < ElementsAccessorSubclass::GetCapacityImpl(backing_store))
-           ? backing_store->get(key)
+           ? BackingStore::cast(backing_store)->get(key)
            : backing_store->GetHeap()->the_hole_value();
   }
 
@@ -571,18 +592,18 @@
       backing_store = holder->elements();
     }
     return ElementsAccessorSubclass::GetAttributesImpl(
-        receiver, holder, key, BackingStore::cast(backing_store));
+        receiver, holder, key, backing_store);
   }
 
   MUST_USE_RESULT static PropertyAttributes GetAttributesImpl(
         Object* receiver,
         JSObject* obj,
         uint32_t key,
-        BackingStore* backing_store) {
+        FixedArrayBase* backing_store) {
     if (key >= ElementsAccessorSubclass::GetCapacityImpl(backing_store)) {
       return ABSENT;
     }
-    return backing_store->is_the_hole(key) ? ABSENT : NONE;
+    return BackingStore::cast(backing_store)->is_the_hole(key) ? ABSENT : NONE;
   }
 
   MUST_USE_RESULT virtual PropertyType GetType(
@@ -594,18 +615,19 @@
       backing_store = holder->elements();
     }
     return ElementsAccessorSubclass::GetTypeImpl(
-        receiver, holder, key, BackingStore::cast(backing_store));
+        receiver, holder, key, backing_store);
   }
 
   MUST_USE_RESULT static PropertyType GetTypeImpl(
         Object* receiver,
         JSObject* obj,
         uint32_t key,
-        BackingStore* backing_store) {
+        FixedArrayBase* backing_store) {
     if (key >= ElementsAccessorSubclass::GetCapacityImpl(backing_store)) {
       return NONEXISTENT;
     }
-    return backing_store->is_the_hole(key) ? NONEXISTENT : FIELD;
+    return BackingStore::cast(backing_store)->is_the_hole(key)
+        ? NONEXISTENT : FIELD;
   }
 
   MUST_USE_RESULT virtual AccessorPair* GetAccessorPair(
@@ -617,27 +639,27 @@
       backing_store = holder->elements();
     }
     return ElementsAccessorSubclass::GetAccessorPairImpl(
-        receiver, holder, key, BackingStore::cast(backing_store));
+        receiver, holder, key, backing_store);
   }
 
   MUST_USE_RESULT static AccessorPair* GetAccessorPairImpl(
         Object* receiver,
         JSObject* obj,
         uint32_t key,
-        BackingStore* backing_store) {
+        FixedArrayBase* backing_store) {
     return NULL;
   }
 
   MUST_USE_RESULT virtual MaybeObject* SetLength(JSArray* array,
                                                  Object* length) {
     return ElementsAccessorSubclass::SetLengthImpl(
-        array, length, BackingStore::cast(array->elements()));
+        array, length, array->elements());
   }
 
   MUST_USE_RESULT static MaybeObject* SetLengthImpl(
       JSObject* obj,
       Object* length,
-      BackingStore* backing_store);
+      FixedArrayBase* backing_store);
 
   MUST_USE_RESULT virtual MaybeObject* SetCapacityAndLength(
       JSArray* array,
@@ -715,25 +737,22 @@
     if (from == NULL) {
       from = holder->elements();
     }
-    BackingStore* backing_store = BackingStore::cast(from);
-    uint32_t len1 = ElementsAccessorSubclass::GetCapacityImpl(backing_store);
 
     // Optimize if 'other' is empty.
     // We cannot optimize if 'this' is empty, as other may have holes.
+    uint32_t len1 = ElementsAccessorSubclass::GetCapacityImpl(from);
     if (len1 == 0) return to;
 
     // Compute how many elements are not in other.
     uint32_t extra = 0;
     for (uint32_t y = 0; y < len1; y++) {
-      uint32_t key =
-          ElementsAccessorSubclass::GetKeyForIndexImpl(backing_store, y);
+      uint32_t key = ElementsAccessorSubclass::GetKeyForIndexImpl(from, y);
       if (ElementsAccessorSubclass::HasElementImpl(
-              receiver, holder, key, backing_store)) {
+              receiver, holder, key, from)) {
         MaybeObject* maybe_value =
-            ElementsAccessorSubclass::GetImpl(receiver, holder,
-                                              key, backing_store);
+            ElementsAccessorSubclass::GetImpl(receiver, holder, key, from);
         Object* value;
-        if (!maybe_value->ToObject(&value)) return maybe_value;
+        if (!maybe_value->To(&value)) return maybe_value;
         ASSERT(!value->IsTheHole());
         if (!HasKey(to, value)) {
           extra++;
@@ -745,9 +764,8 @@
 
     // Allocate the result
     FixedArray* result;
-    MaybeObject* maybe_obj =
-        backing_store->GetHeap()->AllocateFixedArray(len0 + extra);
-    if (!maybe_obj->To<FixedArray>(&result)) return maybe_obj;
+    MaybeObject* maybe_obj = from->GetHeap()->AllocateFixedArray(len0 + extra);
+    if (!maybe_obj->To(&result)) return maybe_obj;
 
     // Fill in the content
     {
@@ -763,14 +781,13 @@
     uint32_t index = 0;
     for (uint32_t y = 0; y < len1; y++) {
       uint32_t key =
-          ElementsAccessorSubclass::GetKeyForIndexImpl(backing_store, y);
+          ElementsAccessorSubclass::GetKeyForIndexImpl(from, y);
       if (ElementsAccessorSubclass::HasElementImpl(
-              receiver, holder, key, backing_store)) {
+              receiver, holder, key, from)) {
         MaybeObject* maybe_value =
-            ElementsAccessorSubclass::GetImpl(receiver, holder,
-                                              key, backing_store);
+            ElementsAccessorSubclass::GetImpl(receiver, holder, key, from);
         Object* value;
-        if (!maybe_value->ToObject(&value)) return maybe_value;
+        if (!maybe_value->To(&value)) return maybe_value;
         if (!value->IsTheHole() && !HasKey(to, value)) {
           result->set(len0 + index, value);
           index++;
@@ -782,24 +799,22 @@
   }
 
  protected:
-  static uint32_t GetCapacityImpl(BackingStore* backing_store) {
+  static uint32_t GetCapacityImpl(FixedArrayBase* backing_store) {
     return backing_store->length();
   }
 
   virtual uint32_t GetCapacity(FixedArrayBase* backing_store) {
-    return ElementsAccessorSubclass::GetCapacityImpl(
-        BackingStore::cast(backing_store));
+    return ElementsAccessorSubclass::GetCapacityImpl(backing_store);
   }
 
-  static uint32_t GetKeyForIndexImpl(BackingStore* backing_store,
+  static uint32_t GetKeyForIndexImpl(FixedArrayBase* backing_store,
                                      uint32_t index) {
     return index;
   }
 
   virtual uint32_t GetKeyForIndex(FixedArrayBase* backing_store,
                                   uint32_t index) {
-    return ElementsAccessorSubclass::GetKeyForIndexImpl(
-        BackingStore::cast(backing_store), index);
+    return ElementsAccessorSubclass::GetKeyForIndexImpl(backing_store, index);
   }
 
  private:
@@ -825,7 +840,7 @@
 
   // Adjusts the length of the fast backing store or returns the new length or
   // undefined in case conversion to a slow backing store should be performed.
-  static MaybeObject* SetLengthWithoutNormalize(BackingStore* backing_store,
+  static MaybeObject* SetLengthWithoutNormalize(FixedArrayBase* backing_store,
                                                 JSArray* array,
                                                 Object* length_object,
                                                 uint32_t length) {
@@ -863,7 +878,7 @@
         // Otherwise, fill the unused tail with holes.
         int old_length = FastD2IChecked(array->length()->Number());
         for (int i = length; i < old_length; i++) {
-          backing_store->set_the_hole(i);
+          BackingStore::cast(backing_store)->set_the_hole(i);
         }
       }
       return length_object;
@@ -900,9 +915,8 @@
     bool is_non_strict_arguments_elements_map =
         backing_store->map() == heap->non_strict_arguments_elements_map();
     if (is_non_strict_arguments_elements_map) {
-      backing_store =
-          KindTraits::BackingStore::cast(
-              FixedArray::cast(backing_store)->get(1));
+      backing_store = KindTraits::BackingStore::cast(
+          FixedArray::cast(backing_store)->get(1));
     }
     uint32_t length = static_cast<uint32_t>(
         obj->IsJSArray()
@@ -958,11 +972,11 @@
       Object* receiver,
       JSObject* holder,
       uint32_t key,
-      typename KindTraits::BackingStore* backing_store) {
+      FixedArrayBase* backing_store) {
     if (key >= static_cast<uint32_t>(backing_store->length())) {
       return false;
     }
-    return !backing_store->is_the_hole(key);
+    return !BackingStore::cast(backing_store)->is_the_hole(key);
   }
 
   static void ValidateContents(JSObject* holder, int length) {
@@ -1010,25 +1024,18 @@
                                        int copy_size) {
     if (IsFastSmiOrObjectElementsKind(to_kind)) {
       CopyObjectToObjectElements(
-          FixedArray::cast(from), KindTraits::Kind, from_start,
-          FixedArray::cast(to), to_kind, to_start, copy_size);
+          from, KindTraits::Kind, from_start, to, to_kind, to_start, copy_size);
     } else if (IsFastDoubleElementsKind(to_kind)) {
       if (IsFastSmiElementsKind(KindTraits::Kind)) {
         if (IsFastPackedElementsKind(KindTraits::Kind) &&
             packed_size != kPackedSizeNotKnown) {
           CopyPackedSmiToDoubleElements(
-              FixedArray::cast(from), from_start,
-              FixedDoubleArray::castOrEmptyFixedArray(to), to_start,
-              packed_size, copy_size);
+              from, from_start, to, to_start, packed_size, copy_size);
         } else {
-          CopySmiToDoubleElements(
-              FixedArray::cast(from), from_start,
-              FixedDoubleArray::castOrEmptyFixedArray(to), to_start, copy_size);
+          CopySmiToDoubleElements(from, from_start, to, to_start, copy_size);
         }
       } else {
-        CopyObjectToDoubleElements(
-            FixedArray::cast(from), from_start,
-            FixedDoubleArray::castOrEmptyFixedArray(to), to_start, copy_size);
+        CopyObjectToDoubleElements(from, from_start, to, to_start, copy_size);
       }
     } else {
       UNREACHABLE();
@@ -1132,13 +1139,10 @@
       case FAST_HOLEY_SMI_ELEMENTS:
       case FAST_HOLEY_ELEMENTS:
         return CopyDoubleToObjectElements(
-            FixedDoubleArray::castOrEmptyFixedArray(from), from_start,
-            FixedArray::cast(to), to_kind, to_start, copy_size);
+            from, from_start, to, to_kind, to_start, copy_size);
       case FAST_DOUBLE_ELEMENTS:
       case FAST_HOLEY_DOUBLE_ELEMENTS:
-        CopyDoubleToDoubleElements(
-            FixedDoubleArray::castOrEmptyFixedArray(from), from_start,
-            FixedDoubleArray::castOrEmptyFixedArray(to), to_start, copy_size);
+        CopyDoubleToDoubleElements(from, from_start, to, to_start, copy_size);
         return from;
       default:
         UNREACHABLE();
@@ -1197,10 +1201,10 @@
   MUST_USE_RESULT static MaybeObject* GetImpl(Object* receiver,
                                               JSObject* obj,
                                               uint32_t key,
-                                              BackingStore* backing_store) {
+                                              FixedArrayBase* backing_store) {
     return
         key < ExternalElementsAccessorSubclass::GetCapacityImpl(backing_store)
-        ? backing_store->get(key)
+        ? BackingStore::cast(backing_store)->get(key)
         : backing_store->GetHeap()->undefined_value();
   }
 
@@ -1208,7 +1212,7 @@
       Object* receiver,
       JSObject* obj,
       uint32_t key,
-      BackingStore* backing_store) {
+      FixedArrayBase* backing_store) {
     return
         key < ExternalElementsAccessorSubclass::GetCapacityImpl(backing_store)
           ? NONE : ABSENT;
@@ -1218,7 +1222,7 @@
       Object* receiver,
       JSObject* obj,
       uint32_t key,
-      BackingStore* backing_store) {
+      FixedArrayBase* backing_store) {
     return
         key < ExternalElementsAccessorSubclass::GetCapacityImpl(backing_store)
           ? FIELD : NONEXISTENT;
@@ -1227,7 +1231,7 @@
   MUST_USE_RESULT static MaybeObject* SetLengthImpl(
       JSObject* obj,
       Object* length,
-      BackingStore* backing_store) {
+      FixedArrayBase* backing_store) {
     // External arrays do not support changing their length.
     UNREACHABLE();
     return obj;
@@ -1243,7 +1247,7 @@
   static bool HasElementImpl(Object* receiver,
                              JSObject* holder,
                              uint32_t key,
-                             BackingStore* backing_store) {
+                             FixedArrayBase* backing_store) {
     uint32_t capacity =
         ExternalElementsAccessorSubclass::GetCapacityImpl(backing_store);
     return key < capacity;
@@ -1352,10 +1356,11 @@
   // Adjusts the length of the dictionary backing store and returns the new
   // length according to ES5 section 15.4.5.2 behavior.
   MUST_USE_RESULT static MaybeObject* SetLengthWithoutNormalize(
-      SeededNumberDictionary* dict,
+      FixedArrayBase* store,
       JSArray* array,
       Object* length_object,
       uint32_t length) {
+    SeededNumberDictionary* dict = SeededNumberDictionary::cast(store);
     Heap* heap = array->GetHeap();
     int capacity = dict->Capacity();
     uint32_t new_length = length;
@@ -1465,15 +1470,12 @@
       case FAST_HOLEY_SMI_ELEMENTS:
       case FAST_HOLEY_ELEMENTS:
         CopyDictionaryToObjectElements(
-            SeededNumberDictionary::cast(from), from_start,
-            FixedArray::cast(to), to_kind, to_start, copy_size);
+            from, from_start, to, to_kind, to_start, copy_size);
         return from;
       case FAST_DOUBLE_ELEMENTS:
       case FAST_HOLEY_DOUBLE_ELEMENTS:
         CopyDictionaryToDoubleElements(
-            SeededNumberDictionary::cast(from), from_start,
-            FixedDoubleArray::castOrEmptyFixedArray(to), to_start,
-            copy_size);
+            from, from_start, to, to_start, copy_size);
         return from;
       default:
         UNREACHABLE();
@@ -1496,7 +1498,8 @@
       Object* receiver,
       JSObject* obj,
       uint32_t key,
-      SeededNumberDictionary* backing_store) {
+      FixedArrayBase* store) {
+    SeededNumberDictionary* backing_store = SeededNumberDictionary::cast(store);
     int entry = backing_store->FindEntry(key);
     if (entry != SeededNumberDictionary::kNotFound) {
       Object* element = backing_store->ValueAt(entry);
@@ -1517,10 +1520,12 @@
       Object* receiver,
       JSObject* obj,
       uint32_t key,
-      SeededNumberDictionary* backing_store) {
-    int entry = backing_store->FindEntry(key);
+      FixedArrayBase* backing_store) {
+    SeededNumberDictionary* dictionary =
+        SeededNumberDictionary::cast(backing_store);
+    int entry = dictionary->FindEntry(key);
     if (entry != SeededNumberDictionary::kNotFound) {
-      return backing_store->DetailsAt(entry).attributes();
+      return dictionary->DetailsAt(entry).attributes();
     }
     return ABSENT;
   }
@@ -1529,7 +1534,8 @@
       Object* receiver,
       JSObject* obj,
       uint32_t key,
-      SeededNumberDictionary* backing_store) {
+      FixedArrayBase* store) {
+    SeededNumberDictionary* backing_store = SeededNumberDictionary::cast(store);
     int entry = backing_store->FindEntry(key);
     if (entry != SeededNumberDictionary::kNotFound) {
       return backing_store->DetailsAt(entry).type();
@@ -1541,7 +1547,8 @@
       Object* receiver,
       JSObject* obj,
       uint32_t key,
-      BackingStore* backing_store) {
+      FixedArrayBase* store) {
+    SeededNumberDictionary* backing_store = SeededNumberDictionary::cast(store);
     int entry = backing_store->FindEntry(key);
     if (entry != SeededNumberDictionary::kNotFound &&
         backing_store->DetailsAt(entry).type() == CALLBACKS &&
@@ -1554,13 +1561,14 @@
   static bool HasElementImpl(Object* receiver,
                              JSObject* holder,
                              uint32_t key,
-                             SeededNumberDictionary* backing_store) {
-    return backing_store->FindEntry(key) !=
+                             FixedArrayBase* backing_store) {
+    return SeededNumberDictionary::cast(backing_store)->FindEntry(key) !=
         SeededNumberDictionary::kNotFound;
   }
 
-  static uint32_t GetKeyForIndexImpl(SeededNumberDictionary* dict,
+  static uint32_t GetKeyForIndexImpl(FixedArrayBase* store,
                                      uint32_t index) {
+    SeededNumberDictionary* dict = SeededNumberDictionary::cast(store);
     Object* key = dict->KeyAt(index);
     return Smi::cast(key)->value();
   }
@@ -1583,7 +1591,8 @@
   MUST_USE_RESULT static MaybeObject* GetImpl(Object* receiver,
                                               JSObject* obj,
                                               uint32_t key,
-                                              FixedArray* parameter_map) {
+                                              FixedArrayBase* parameters) {
+    FixedArray* parameter_map = FixedArray::cast(parameters);
     Object* probe = GetParameterMapArg(obj, parameter_map, key);
     if (!probe->IsTheHole()) {
       Context* context = Context::cast(parameter_map->get(0));
@@ -1614,7 +1623,8 @@
       Object* receiver,
       JSObject* obj,
       uint32_t key,
-      FixedArray* parameter_map) {
+      FixedArrayBase* backing_store) {
+    FixedArray* parameter_map = FixedArray::cast(backing_store);
     Object* probe = GetParameterMapArg(obj, parameter_map, key);
     if (!probe->IsTheHole()) {
       return NONE;
@@ -1630,7 +1640,8 @@
       Object* receiver,
       JSObject* obj,
       uint32_t key,
-      FixedArray* parameter_map) {
+      FixedArrayBase* parameters) {
+    FixedArray* parameter_map = FixedArray::cast(parameters);
     Object* probe = GetParameterMapArg(obj, parameter_map, key);
     if (!probe->IsTheHole()) {
       return FIELD;
@@ -1646,7 +1657,8 @@
       Object* receiver,
       JSObject* obj,
       uint32_t key,
-      FixedArray* parameter_map) {
+      FixedArrayBase* parameters) {
+    FixedArray* parameter_map = FixedArray::cast(parameters);
     Object* probe = GetParameterMapArg(obj, parameter_map, key);
     if (!probe->IsTheHole()) {
       return NULL;
@@ -1661,7 +1673,7 @@
   MUST_USE_RESULT static MaybeObject* SetLengthImpl(
       JSObject* obj,
       Object* length,
-      FixedArray* parameter_map) {
+      FixedArrayBase* parameter_map) {
     // TODO(mstarzinger): This was never implemented but will be used once we
     // correctly implement [[DefineOwnProperty]] on arrays.
     UNIMPLEMENTED();
@@ -1700,19 +1712,20 @@
                                                        int packed_size,
                                                        int copy_size) {
     FixedArray* parameter_map = FixedArray::cast(from);
-    FixedArray* arguments = FixedArray::cast(parameter_map->get(1));
+    FixedArrayBase* arguments = FixedArrayBase::cast(parameter_map->get(1));
     ElementsAccessor* accessor = ElementsAccessor::ForArray(arguments);
     return accessor->CopyElements(NULL, from_start, to, to_kind,
                                   to_start, copy_size, arguments);
   }
 
-  static uint32_t GetCapacityImpl(FixedArray* parameter_map) {
+  static uint32_t GetCapacityImpl(FixedArrayBase* backing_store) {
+    FixedArray* parameter_map = FixedArray::cast(backing_store);
     FixedArrayBase* arguments = FixedArrayBase::cast(parameter_map->get(1));
     return Max(static_cast<uint32_t>(parameter_map->length() - 2),
                ForArray(arguments)->GetCapacity(arguments));
   }
 
-  static uint32_t GetKeyForIndexImpl(FixedArray* dict,
+  static uint32_t GetKeyForIndexImpl(FixedArrayBase* dict,
                                      uint32_t index) {
     return index;
   }
@@ -1720,12 +1733,14 @@
   static bool HasElementImpl(Object* receiver,
                              JSObject* holder,
                              uint32_t key,
-                             FixedArray* parameter_map) {
+                             FixedArrayBase* parameters) {
+    FixedArray* parameter_map = FixedArray::cast(parameters);
     Object* probe = GetParameterMapArg(holder, parameter_map, key);
     if (!probe->IsTheHole()) {
       return true;
     } else {
-      FixedArrayBase* arguments = FixedArrayBase::cast(parameter_map->get(1));
+      FixedArrayBase* arguments =
+          FixedArrayBase::cast(FixedArray::cast(parameter_map)->get(1));
       ElementsAccessor* accessor = ElementsAccessor::ForArray(arguments);
       return !accessor->Get(receiver, holder, key, arguments)->IsTheHole();
     }
@@ -1738,7 +1753,7 @@
     uint32_t length = holder->IsJSArray()
         ? Smi::cast(JSArray::cast(holder)->length())->value()
         : parameter_map->length();
-    return key < (length - 2 )
+    return key < (length - 2)
         ? parameter_map->get(key + 2)
         : parameter_map->GetHeap()->the_hole_value();
   }
@@ -1805,7 +1820,7 @@
                                                   ElementsKindTraits>::
     SetLengthImpl(JSObject* obj,
                   Object* length,
-                  typename ElementsKindTraits::BackingStore* backing_store) {
+                  FixedArrayBase* backing_store) {
   JSArray* array = JSArray::cast(obj);
 
   // Fast case: The new length fits into a Smi.
diff --git a/src/extensions/gc-extension.cc b/src/extensions/gc-extension.cc
index 2282075..813b921 100644
--- a/src/extensions/gc-extension.cc
+++ b/src/extensions/gc-extension.cc
@@ -43,7 +43,7 @@
   if (args[0]->BooleanValue()) {
     HEAP->CollectGarbage(NEW_SPACE, "gc extension");
   } else {
-    HEAP->CollectAllGarbage(Heap::kAbortIncrementalMarkingMask, "gc extension");
+    HEAP->CollectAllGarbage(Heap::kNoGCFlags, "gc extension");
   }
   return v8::Undefined();
 }
diff --git a/src/flag-definitions.h b/src/flag-definitions.h
index b25fe5f..61cd864 100644
--- a/src/flag-definitions.h
+++ b/src/flag-definitions.h
@@ -404,7 +404,7 @@
             "flush code that we expect not to use again (during full gc)")
 DEFINE_bool(flush_code_incrementally, false,
             "flush code that we expect not to use again (incrementally)")
-DEFINE_bool(age_code, false,
+DEFINE_bool(age_code, true,
             "track un-executed functions to age code and flush only "
             "old code")
 DEFINE_bool(incremental_marking, true, "use incremental marking")
diff --git a/src/heap.cc b/src/heap.cc
index d7331dd..ff791d8 100644
--- a/src/heap.cc
+++ b/src/heap.cc
@@ -615,7 +615,7 @@
   }
 
   if (collector == MARK_COMPACTOR &&
-      !mark_compact_collector()->abort_incremental_marking_ &&
+      !mark_compact_collector()->abort_incremental_marking() &&
       !incremental_marking()->IsStopped() &&
       !incremental_marking()->should_hurry() &&
       FLAG_incremental_marking_steps) {
@@ -651,16 +651,16 @@
           PerformGarbageCollection(collector, &tracer);
     }
 
-    ASSERT(collector == SCAVENGER || incremental_marking()->IsStopped());
-
-    // This can do debug callbacks and restart incremental marking.
     GarbageCollectionEpilogue();
   }
 
-  if (incremental_marking()->IsStopped()) {
-    if (incremental_marking()->WorthActivating() && NextGCIsLikelyToBeFull()) {
-      incremental_marking()->Start();
-    }
+  // Start incremental marking for the next cycle. The heap snapshot
+  // generator needs incremental marking to stay off after it aborted.
+  if (!mark_compact_collector()->abort_incremental_marking() &&
+      incremental_marking()->IsStopped() &&
+      incremental_marking()->WorthActivating() &&
+      NextGCIsLikelyToBeFull()) {
+    incremental_marking()->Start();
   }
 
   return next_gc_likely_to_collect_more;
@@ -957,6 +957,10 @@
 
   isolate_->counters()->objs_since_last_young()->Set(0);
 
+  // Callbacks that fire after this point might trigger nested GCs and
+  // restart incremental marking, the assertion can't be moved down.
+  ASSERT(collector == SCAVENGER || incremental_marking()->IsStopped());
+
   gc_post_processing_depth_++;
   { DisableAssertNoAllocation allow_allocation;
     GCTracer::Scope scope(tracer, GCTracer::Scope::EXTERNAL);
@@ -3791,6 +3795,7 @@
   code->set_handler_table(empty_fixed_array(), SKIP_WRITE_BARRIER);
   code->set_gc_metadata(Smi::FromInt(0));
   code->set_ic_age(global_ic_age_);
+  code->set_prologue_offset(kPrologueOffsetNotSet);
   // Allow self references to created code object by patching the handle to
   // point to the newly allocated Code object.
   if (!self_reference.is_null()) {
@@ -5318,7 +5323,8 @@
       AgeInlineCaches();
     }
     int mark_sweep_time = Min(TimeMarkSweepWouldTakeInMs(), 1000);
-    if (hint >= mark_sweep_time && incremental_marking()->IsStopped()) {
+    if (hint >= mark_sweep_time && !FLAG_expose_gc &&
+        incremental_marking()->IsStopped()) {
       HistogramTimerScope scope(isolate_->counters()->gc_context());
       CollectAllGarbage(kReduceMemoryFootprintMask,
                         "idle notification: contexts disposed");
@@ -5333,7 +5339,7 @@
     return false;
   }
 
-  if (!FLAG_incremental_marking || Serializer::enabled()) {
+  if (!FLAG_incremental_marking || FLAG_expose_gc || Serializer::enabled()) {
     return IdleGlobalGC();
   }
 
diff --git a/src/ia32/codegen-ia32.cc b/src/ia32/codegen-ia32.cc
index a024339..2f5553c 100644
--- a/src/ia32/codegen-ia32.cc
+++ b/src/ia32/codegen-ia32.cc
@@ -872,42 +872,6 @@
 }
 
 
-byte* Code::FindPlatformCodeAgeSequence() {
-  byte* start = instruction_start();
-  uint32_t young_length;
-  byte* young_sequence = GetNoCodeAgeSequence(&young_length);
-  if (!memcmp(start, young_sequence, young_length) ||
-      *start == kCallOpcode) {
-    return start;
-  } else {
-    if (kind() == FUNCTION) {
-      byte* start_after_strict =
-          start + kSizeOfFullCodegenStrictModePrologue;
-      ASSERT(!memcmp(start_after_strict, young_sequence, young_length) ||
-             start[kSizeOfFullCodegenStrictModePrologue] == kCallOpcode);
-      return start_after_strict;
-    } else {
-      ASSERT(kind() == OPTIMIZED_FUNCTION);
-      start = instruction_start() + kSizeOfOptimizedStrictModePrologue;
-      if (!memcmp(start, young_sequence, young_length) ||
-          *start == kCallOpcode) {
-        return start;
-      }
-      start = instruction_start() + kSizeOfOptimizedAlignStackPrologue;
-      if (!memcmp(start, young_sequence, young_length) ||
-          *start == kCallOpcode) {
-        return start;
-      }
-      start = instruction_start() + kSizeOfOptimizedAlignStackPrologue +
-          kSizeOfOptimizedStrictModePrologue;
-      ASSERT(!memcmp(start, young_sequence, young_length) ||
-             *start == kCallOpcode);
-      return start;
-    }
-  }
-}
-
-
 bool Code::IsYoungSequence(byte* sequence) {
   uint32_t young_length;
   byte* young_sequence = GetNoCodeAgeSequence(&young_length);
diff --git a/src/ia32/codegen-ia32.h b/src/ia32/codegen-ia32.h
index 6de4725..5137274 100644
--- a/src/ia32/codegen-ia32.h
+++ b/src/ia32/codegen-ia32.h
@@ -37,10 +37,6 @@
 // Forward declarations
 class CompilationInfo;
 
-static const int kSizeOfFullCodegenStrictModePrologue = 34;
-static const int kSizeOfOptimizedStrictModePrologue = 12;
-static const int kSizeOfOptimizedAlignStackPrologue = 44;
-
 // -------------------------------------------------------------------------
 // CodeGenerator
 
diff --git a/src/ia32/full-codegen-ia32.cc b/src/ia32/full-codegen-ia32.cc
index 88f204b..6dfec92 100644
--- a/src/ia32/full-codegen-ia32.cc
+++ b/src/ia32/full-codegen-ia32.cc
@@ -138,8 +138,6 @@
   // function calls.
   if (!info->is_classic_mode() || info->is_native()) {
     Label ok;
-    Label start;
-    __ bind(&start);
     __ test(ecx, ecx);
     __ j(zero, &ok, Label::kNear);
     // +1 for return address.
@@ -151,8 +149,6 @@
     __ mov(Operand(esp, receiver_offset),
            Immediate(isolate()->factory()->undefined_value()));
     __ bind(&ok);
-    ASSERT(!FLAG_age_code ||
-           (kSizeOfFullCodegenStrictModePrologue == ok.pos() - start.pos()));
   }
 
   // Open a frame scope to indicate that there is a frame on the stack.  The
@@ -160,6 +156,7 @@
   // the frame (that is done below).
   FrameScope frame_scope(masm_, StackFrame::MANUAL);
 
+  info->set_prologue_offset(masm_->pc_offset());
   __ push(ebp);  // Caller's frame pointer.
   __ mov(ebp, esp);
   __ push(esi);  // Callee's context.
diff --git a/src/ia32/lithium-codegen-ia32.cc b/src/ia32/lithium-codegen-ia32.cc
index 388d496..de60451 100644
--- a/src/ia32/lithium-codegen-ia32.cc
+++ b/src/ia32/lithium-codegen-ia32.cc
@@ -140,8 +140,6 @@
   // receiver object). ecx is zero for method calls and non-zero for
   // function calls.
   if (!info_->is_classic_mode() || info_->is_native()) {
-    Label begin;
-    __ bind(&begin);
     Label ok;
     __ test(ecx, Operand(ecx));
     __ j(zero, &ok, Label::kNear);
@@ -150,14 +148,10 @@
     __ mov(Operand(esp, receiver_offset),
            Immediate(isolate()->factory()->undefined_value()));
     __ bind(&ok);
-    ASSERT(!FLAG_age_code ||
-           (kSizeOfOptimizedStrictModePrologue == ok.pos() - begin.pos()));
   }
 
 
   if (dynamic_frame_alignment_) {
-    Label begin;
-    __ bind(&begin);
     // Move state of dynamic frame alignment into edx.
     __ mov(edx, Immediate(kNoAlignmentPadding));
 
@@ -180,11 +174,9 @@
     __ j(not_zero, &align_loop, Label::kNear);
     __ mov(Operand(ebx, 0), Immediate(kAlignmentZapValue));
     __ bind(&do_not_pad);
-    ASSERT(!FLAG_age_code ||
-           (kSizeOfOptimizedAlignStackPrologue ==
-            do_not_pad.pos() - begin.pos()));
   }
 
+  info()->set_prologue_offset(masm_->pc_offset());
   __ push(ebp);  // Caller's frame pointer.
   __ mov(ebp, esp);
   __ push(esi);  // Callee's context.
diff --git a/src/ia32/macro-assembler-ia32.cc b/src/ia32/macro-assembler-ia32.cc
index 41c8667..14fb8ca 100644
--- a/src/ia32/macro-assembler-ia32.cc
+++ b/src/ia32/macro-assembler-ia32.cc
@@ -1920,9 +1920,25 @@
   mov(edi, Operand::StaticVariable(limit_address));
   add(Operand::StaticVariable(level_address), Immediate(1));
 
+  if (FLAG_log_timer_events) {
+    FrameScope frame(this, StackFrame::MANUAL);
+    PushSafepointRegisters();
+    PrepareCallCFunction(0, eax);
+    CallCFunction(ExternalReference::log_enter_external_function(isolate()), 0);
+    PopSafepointRegisters();
+  }
+
   // Call the api function.
   call(function_address, RelocInfo::RUNTIME_ENTRY);
 
+  if (FLAG_log_timer_events) {
+    FrameScope frame(this, StackFrame::MANUAL);
+    PushSafepointRegisters();
+    PrepareCallCFunction(0, eax);
+    CallCFunction(ExternalReference::log_leave_external_function(isolate()), 0);
+    PopSafepointRegisters();
+  }
+
   if (!kReturnHandlesDirectly) {
     // PrepareCallApiFunction saved pointer to the output slot into
     // callee-save register esi.
diff --git a/src/ia32/stub-cache-ia32.cc b/src/ia32/stub-cache-ia32.cc
index c3a2654..c8695c5 100644
--- a/src/ia32/stub-cache-ia32.cc
+++ b/src/ia32/stub-cache-ia32.cc
@@ -4359,6 +4359,9 @@
     __ mov(FieldOperand(edi, FixedDoubleArray::kLengthOffset),
            Immediate(Smi::FromInt(JSArray::kPreallocatedArrayElements)));
 
+    __ StoreNumberToDoubleElements(eax, edi, ecx, ebx, xmm0,
+                                   &transition_elements_kind, true);
+
     for (int i = 1; i < JSArray::kPreallocatedArrayElements; i++) {
       int offset = FixedDoubleArray::OffsetOfElementAt(i);
       __ mov(FieldOperand(edi, offset), Immediate(kHoleNanLower32));
@@ -4366,9 +4369,6 @@
              Immediate(kHoleNanUpper32));
     }
 
-    __ StoreNumberToDoubleElements(eax, edi, ecx, ebx, xmm0,
-                                   &transition_elements_kind, true);
-
     // Install the new backing store in the JSArray.
     __ mov(FieldOperand(edx, JSObject::kElementsOffset), edi);
     __ RecordWriteField(edx, JSObject::kElementsOffset, edi, ebx,
diff --git a/src/incremental-marking-inl.h b/src/incremental-marking-inl.h
index 8c64978..1c30383 100644
--- a/src/incremental-marking-inl.h
+++ b/src/incremental-marking-inl.h
@@ -44,8 +44,12 @@
     if (Marking::IsBlack(obj_bit)) {
       MemoryChunk* chunk = MemoryChunk::FromAddress(obj->address());
       if (chunk->IsFlagSet(MemoryChunk::HAS_PROGRESS_BAR)) {
-        WhiteToGreyAndPush(value_heap_obj, value_bit);
-        RestartIfNotMarking();
+        if (chunk->IsLeftOfProgressBar(slot)) {
+          WhiteToGreyAndPush(value_heap_obj, value_bit);
+          RestartIfNotMarking();
+        } else {
+          return false;
+        }
       } else {
         BlackToGreyAndUnshift(obj, obj_bit);
         RestartIfNotMarking();
diff --git a/src/incremental-marking.cc b/src/incremental-marking.cc
index 8cdcdb5..1457ee3 100644
--- a/src/incremental-marking.cc
+++ b/src/incremental-marking.cc
@@ -338,10 +338,9 @@
 
 class IncrementalMarkingRootMarkingVisitor : public ObjectVisitor {
  public:
-  IncrementalMarkingRootMarkingVisitor(Heap* heap,
-                                       IncrementalMarking* incremental_marking)
-      : heap_(heap),
-        incremental_marking_(incremental_marking) {
+  explicit IncrementalMarkingRootMarkingVisitor(
+      IncrementalMarking* incremental_marking)
+      : incremental_marking_(incremental_marking) {
   }
 
   void VisitPointer(Object** p) {
@@ -368,7 +367,6 @@
     }
   }
 
-  Heap* heap_;
   IncrementalMarking* incremental_marking_;
 };
 
@@ -493,7 +491,8 @@
   static const intptr_t kActivationThreshold = 0;
 #endif
 
-  return FLAG_incremental_marking &&
+  return !FLAG_expose_gc &&
+      FLAG_incremental_marking &&
       !Serializer::enabled() &&
       heap_->PromotedSpaceSizeOfObjects() > kActivationThreshold;
 }
@@ -628,7 +627,7 @@
   }
 
   // Mark strong roots grey.
-  IncrementalMarkingRootMarkingVisitor visitor(heap_, this);
+  IncrementalMarkingRootMarkingVisitor visitor(this);
   heap_->IterateStrongRoots(&visitor, VISIT_ONLY_STRONG);
 
   // Ready to start incremental marking.
diff --git a/src/log.cc b/src/log.cc
index 463ecc1..76af400 100644
--- a/src/log.cc
+++ b/src/log.cc
@@ -716,6 +716,33 @@
 }
 
 
+void Logger::ExternalSwitch(StateTag old_tag, StateTag new_tag) {
+  if (old_tag != EXTERNAL && new_tag == EXTERNAL) {
+    enter_external_ = OS::Ticks();
+  }
+  if (old_tag == EXTERNAL && new_tag != EXTERNAL && enter_external_ != 0) {
+    TimerEvent("V8.External", enter_external_, OS::Ticks());
+    enter_external_ = 0;
+  }
+}
+
+
+void Logger::EnterExternal() {
+  LOGGER->enter_external_ = OS::Ticks();
+}
+
+
+void Logger::LeaveExternal() {
+  if (enter_external_ == 0) return;
+  Logger* logger = LOGGER;
+  logger->TimerEvent("V8.External", enter_external_, OS::Ticks());
+  logger->enter_external_ = 0;
+}
+
+
+int64_t Logger::enter_external_ = 0;
+
+
 void Logger::TimerEventScope::LogTimerEvent() {
   LOG(isolate_, TimerEvent(name_, start_, OS::Ticks()));
 }
@@ -900,7 +927,7 @@
                                    Address entry_point) {
   if (!log_->IsEnabled() || !FLAG_log_code) return;
   LogMessageBuilder msg(this);
-  msg.Append("%s,%s,",
+  msg.Append("%s,%s,-3,",
              kLogEventsNames[CODE_CREATION_EVENT],
              kLogEventsNames[CALLBACK_TAG]);
   msg.AppendAddress(entry_point);
@@ -956,9 +983,10 @@
   }
   if (!FLAG_log_code) return;
   LogMessageBuilder msg(this);
-  msg.Append("%s,%s,",
+  msg.Append("%s,%s,%d,",
              kLogEventsNames[CODE_CREATION_EVENT],
-             kLogEventsNames[tag]);
+             kLogEventsNames[tag],
+             code->kind());
   msg.AppendAddress(code->address());
   msg.Append(",%d,\"", code->ExecutableSize());
   for (const char* p = comment; *p != '\0'; p++) {
@@ -995,9 +1023,10 @@
   }
   if (!FLAG_log_code) return;
   LogMessageBuilder msg(this);
-  msg.Append("%s,%s,",
+  msg.Append("%s,%s,%d,",
              kLogEventsNames[CODE_CREATION_EVENT],
-             kLogEventsNames[tag]);
+             kLogEventsNames[tag],
+             code->kind());
   msg.AppendAddress(code->address());
   msg.Append(",%d,\"", code->ExecutableSize());
   msg.AppendDetailed(name, false);
@@ -1047,9 +1076,10 @@
   LogMessageBuilder msg(this);
   SmartArrayPointer<char> str =
       name->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
-  msg.Append("%s,%s,",
+  msg.Append("%s,%s,%d,",
              kLogEventsNames[CODE_CREATION_EVENT],
-             kLogEventsNames[tag]);
+             kLogEventsNames[tag],
+             code->kind());
   msg.AppendAddress(code->address());
   msg.Append(",%d,\"%s\",", code->ExecutableSize(), *str);
   msg.AppendAddress(shared->address());
@@ -1094,9 +1124,10 @@
       shared->DebugName()->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
   SmartArrayPointer<char> sourcestr =
       source->ToCString(DISALLOW_NULLS, ROBUST_STRING_TRAVERSAL);
-  msg.Append("%s,%s,",
+  msg.Append("%s,%s,%d,",
              kLogEventsNames[CODE_CREATION_EVENT],
-             kLogEventsNames[tag]);
+             kLogEventsNames[tag],
+             code->kind());
   msg.AppendAddress(code->address());
   msg.Append(",%d,\"%s %s:%d\",",
              code->ExecutableSize(),
@@ -1130,9 +1161,10 @@
   }
   if (!FLAG_log_code) return;
   LogMessageBuilder msg(this);
-  msg.Append("%s,%s,",
+  msg.Append("%s,%s,%d,",
              kLogEventsNames[CODE_CREATION_EVENT],
-             kLogEventsNames[tag]);
+             kLogEventsNames[tag],
+             code->kind());
   msg.AppendAddress(code->address());
   msg.Append(",%d,\"args_count: %d\"", code->ExecutableSize(), args_count);
   msg.Append('\n');
@@ -1167,7 +1199,7 @@
   }
   if (!FLAG_log_code) return;
   LogMessageBuilder msg(this);
-  msg.Append("%s,%s,",
+  msg.Append("%s,%s,-2,",
              kLogEventsNames[CODE_CREATION_EVENT],
              kLogEventsNames[REG_EXP_TAG]);
   msg.AppendAddress(code->address());
@@ -1347,6 +1379,8 @@
   msg.AppendAddress(sample->pc);
   msg.Append(',');
   msg.AppendAddress(sample->sp);
+  msg.Append(",%ld",
+      FLAG_log_timer_events ? static_cast<int>(OS::Ticks() - epoch_) : 0);
   if (sample->has_external_callback) {
     msg.Append(",1,");
     msg.AppendAddress(sample->external_callback);
diff --git a/src/log.h b/src/log.h
index c8f81bc..12dc923 100644
--- a/src/log.h
+++ b/src/log.h
@@ -275,7 +275,13 @@
   void SharedLibraryEvent(const wchar_t* library_path,
                           uintptr_t start,
                           uintptr_t end);
+
+  // ==== Events logged by --log-timer-events. ====
   void TimerEvent(const char* name, int64_t start, int64_t end);
+  void ExternalSwitch(StateTag old_tag, StateTag new_tag);
+
+  static void EnterExternal();
+  static void LeaveExternal();
 
   class TimerEventScope {
    public:
@@ -476,6 +482,7 @@
   Address prev_code_;
 
   int64_t epoch_;
+  static int64_t enter_external_;
 
   friend class CpuProfiler;
 };
diff --git a/src/mark-compact.cc b/src/mark-compact.cc
index 30abe6d..aa1900b 100644
--- a/src/mark-compact.cc
+++ b/src/mark-compact.cc
@@ -3525,7 +3525,6 @@
 
   intptr_t freed_bytes = 0;
   int pages_swept = 0;
-  intptr_t newspace_size = space->heap()->new_space()->Size();
   bool lazy_sweeping_active = false;
   bool unused_page_present = false;
 
@@ -3588,15 +3587,8 @@
         }
         freed_bytes += SweepConservatively(space, p);
         pages_swept++;
-        if (freed_bytes > 2 * newspace_size) {
-          space->SetPagesToSweep(p->next_page());
-          lazy_sweeping_active = true;
-        } else {
-          if (FLAG_gc_verbose) {
-            PrintF("Only %" V8PRIdPTR " bytes freed.  Still sweeping.\n",
-                   freed_bytes);
-          }
-        }
+        space->SetPagesToSweep(p->next_page());
+        lazy_sweeping_active = true;
         break;
       }
       case PRECISE: {
diff --git a/src/mark-compact.h b/src/mark-compact.h
index 0a4c1ea..b652e22 100644
--- a/src/mark-compact.h
+++ b/src/mark-compact.h
@@ -658,6 +658,8 @@
 
   void ClearMarkbits();
 
+  bool abort_incremental_marking() const { return abort_incremental_marking_; }
+
   bool is_compacting() const { return compacting_; }
 
   MarkingParity marking_parity() { return marking_parity_; }
diff --git a/src/mips/code-stubs-mips.cc b/src/mips/code-stubs-mips.cc
index 0e4d37b..a05cee8 100644
--- a/src/mips/code-stubs-mips.cc
+++ b/src/mips/code-stubs-mips.cc
@@ -734,13 +734,13 @@
                                              Register int_scratch,
                                              Destination destination,
                                              FPURegister double_dst,
-                                             Register dst1,
-                                             Register dst2,
+                                             Register dst_mantissa,
+                                             Register dst_exponent,
                                              Register scratch2,
                                              FPURegister single_scratch) {
   ASSERT(!int_scratch.is(scratch2));
-  ASSERT(!int_scratch.is(dst1));
-  ASSERT(!int_scratch.is(dst2));
+  ASSERT(!int_scratch.is(dst_mantissa));
+  ASSERT(!int_scratch.is(dst_exponent));
 
   Label done;
 
@@ -749,64 +749,65 @@
     __ mtc1(int_scratch, single_scratch);
     __ cvt_d_w(double_dst, single_scratch);
     if (destination == kCoreRegisters) {
-      __ Move(dst1, dst2, double_dst);
+      __ Move(dst_mantissa, dst_exponent, double_dst);
     }
   } else {
     Label fewer_than_20_useful_bits;
     // Expected output:
-    // |         dst2            |         dst1            |
+    // |       dst_exponent      |       dst_mantissa      |
     // | s |   exp   |              mantissa               |
 
     // Check for zero.
-    __ mov(dst2, int_scratch);
-    __ mov(dst1, int_scratch);
+    __ mov(dst_exponent, int_scratch);
+    __ mov(dst_mantissa, int_scratch);
     __ Branch(&done, eq, int_scratch, Operand(zero_reg));
 
     // Preload the sign of the value.
-    __ And(dst2, int_scratch, Operand(HeapNumber::kSignMask));
+    __ And(dst_exponent, int_scratch, Operand(HeapNumber::kSignMask));
     // Get the absolute value of the object (as an unsigned integer).
     Label skip_sub;
-    __ Branch(&skip_sub, ge, dst2, Operand(zero_reg));
+    __ Branch(&skip_sub, ge, dst_exponent, Operand(zero_reg));
     __ Subu(int_scratch, zero_reg, int_scratch);
     __ bind(&skip_sub);
 
     // Get mantissa[51:20].
 
     // Get the position of the first set bit.
-    __ Clz(dst1, int_scratch);
+    __ Clz(dst_mantissa, int_scratch);
     __ li(scratch2, 31);
-    __ Subu(dst1, scratch2, dst1);
+    __ Subu(dst_mantissa, scratch2, dst_mantissa);
 
     // Set the exponent.
-    __ Addu(scratch2, dst1, Operand(HeapNumber::kExponentBias));
-    __ Ins(dst2, scratch2,
+    __ Addu(scratch2, dst_mantissa, Operand(HeapNumber::kExponentBias));
+    __ Ins(dst_exponent, scratch2,
         HeapNumber::kExponentShift, HeapNumber::kExponentBits);
 
     // Clear the first non null bit.
     __ li(scratch2, Operand(1));
-    __ sllv(scratch2, scratch2, dst1);
+    __ sllv(scratch2, scratch2, dst_mantissa);
     __ li(at, -1);
     __ Xor(scratch2, scratch2, at);
     __ And(int_scratch, int_scratch, scratch2);
 
     // Get the number of bits to set in the lower part of the mantissa.
-    __ Subu(scratch2, dst1, Operand(HeapNumber::kMantissaBitsInTopWord));
+    __ Subu(scratch2, dst_mantissa,
+        Operand(HeapNumber::kMantissaBitsInTopWord));
     __ Branch(&fewer_than_20_useful_bits, lt, scratch2, Operand(zero_reg));
     // Set the higher 20 bits of the mantissa.
     __ srlv(at, int_scratch, scratch2);
-    __ or_(dst2, dst2, at);
+    __ or_(dst_exponent, dst_exponent, at);
     __ li(at, 32);
     __ subu(scratch2, at, scratch2);
-    __ sllv(dst1, int_scratch, scratch2);
+    __ sllv(dst_mantissa, int_scratch, scratch2);
     __ Branch(&done);
 
     __ bind(&fewer_than_20_useful_bits);
     __ li(at, HeapNumber::kMantissaBitsInTopWord);
-    __ subu(scratch2, at, dst1);
+    __ subu(scratch2, at, dst_mantissa);
     __ sllv(scratch2, int_scratch, scratch2);
-    __ Or(dst2, dst2, scratch2);
-    // Set dst1 to 0.
-    __ mov(dst1, zero_reg);
+    __ Or(dst_exponent, dst_exponent, scratch2);
+    // Set dst_mantissa to 0.
+    __ mov(dst_mantissa, zero_reg);
   }
   __ bind(&done);
 }
@@ -816,8 +817,9 @@
                                                   Register object,
                                                   Destination destination,
                                                   DoubleRegister double_dst,
-                                                  Register dst1,
-                                                  Register dst2,
+                                                  DoubleRegister double_scratch,
+                                                  Register dst_mantissa,
+                                                  Register dst_exponent,
                                                   Register heap_number_map,
                                                   Register scratch1,
                                                   Register scratch2,
@@ -833,8 +835,8 @@
 
   __ JumpIfNotSmi(object, &obj_is_not_smi);
   __ SmiUntag(scratch1, object);
-  ConvertIntToDouble(masm, scratch1, destination, double_dst, dst1, dst2,
-                     scratch2, single_scratch);
+  ConvertIntToDouble(masm, scratch1, destination, double_dst, dst_mantissa,
+                     dst_exponent, scratch2, single_scratch);
   __ Branch(&done);
 
   __ bind(&obj_is_not_smi);
@@ -851,9 +853,10 @@
 
     Register except_flag = scratch2;
     __ EmitFPUTruncate(kRoundToZero,
-                       single_scratch,
-                       double_dst,
                        scratch1,
+                       double_dst,
+                       at,
+                       double_scratch,
                        except_flag,
                        kCheckForInexactConversion);
 
@@ -861,27 +864,51 @@
     __ Branch(not_int32, ne, except_flag, Operand(zero_reg));
 
     if (destination == kCoreRegisters) {
-      __ Move(dst1, dst2, double_dst);
+      __ Move(dst_mantissa, dst_exponent, double_dst);
     }
 
   } else {
     ASSERT(!scratch1.is(object) && !scratch2.is(object));
     // Load the double value in the destination registers.
-    __ lw(dst2, FieldMemOperand(object, HeapNumber::kExponentOffset));
-    __ lw(dst1, FieldMemOperand(object, HeapNumber::kMantissaOffset));
+    bool save_registers = object.is(dst_mantissa) || object.is(dst_exponent);
+    if (save_registers) {
+      // Save both output registers, because the other one probably holds
+      // an important value too.
+      __ Push(dst_exponent, dst_mantissa);
+    }
+    __ lw(dst_exponent, FieldMemOperand(object, HeapNumber::kExponentOffset));
+    __ lw(dst_mantissa, FieldMemOperand(object, HeapNumber::kMantissaOffset));
 
     // Check for 0 and -0.
-    __ And(scratch1, dst1, Operand(~HeapNumber::kSignMask));
-    __ Or(scratch1, scratch1, Operand(dst2));
-    __ Branch(&done, eq, scratch1, Operand(zero_reg));
+    Label zero;
+    __ And(scratch1, dst_exponent, Operand(~HeapNumber::kSignMask));
+    __ Or(scratch1, scratch1, Operand(dst_mantissa));
+    __ Branch(&zero, eq, scratch1, Operand(zero_reg));
 
     // Check that the value can be exactly represented by a 32-bit integer.
     // Jump to not_int32 if that's not the case.
-    DoubleIs32BitInteger(masm, dst1, dst2, scratch1, scratch2, not_int32);
+    Label restore_input_and_miss;
+    DoubleIs32BitInteger(masm, dst_exponent, dst_mantissa, scratch1, scratch2,
+                         &restore_input_and_miss);
 
-    // dst1 and dst2 were trashed. Reload the double value.
-    __ lw(dst2, FieldMemOperand(object, HeapNumber::kExponentOffset));
-    __ lw(dst1, FieldMemOperand(object, HeapNumber::kMantissaOffset));
+    // dst_* were trashed. Reload the double value.
+    if (save_registers) {
+      __ Pop(dst_exponent, dst_mantissa);
+    }
+    __ lw(dst_exponent, FieldMemOperand(object, HeapNumber::kExponentOffset));
+    __ lw(dst_mantissa, FieldMemOperand(object, HeapNumber::kMantissaOffset));
+    __ Branch(&done);
+
+    __ bind(&restore_input_and_miss);
+    if (save_registers) {
+      __ Pop(dst_exponent, dst_mantissa);
+    }
+    __ Branch(not_int32);
+
+    __ bind(&zero);
+    if (save_registers) {
+      __ Drop(2);
+    }
   }
 
   __ bind(&done);
@@ -895,7 +922,8 @@
                                             Register scratch1,
                                             Register scratch2,
                                             Register scratch3,
-                                            DoubleRegister double_scratch,
+                                            DoubleRegister double_scratch0,
+                                            DoubleRegister double_scratch1,
                                             Label* not_int32) {
   ASSERT(!dst.is(object));
   ASSERT(!scratch1.is(object) && !scratch2.is(object) && !scratch3.is(object));
@@ -918,22 +946,19 @@
   if (CpuFeatures::IsSupported(FPU)) {
     CpuFeatures::Scope scope(FPU);
     // Load the double value.
-    __ ldc1(double_scratch, FieldMemOperand(object, HeapNumber::kValueOffset));
+    __ ldc1(double_scratch0, FieldMemOperand(object, HeapNumber::kValueOffset));
 
-    FPURegister single_scratch = double_scratch.low();
     Register except_flag = scratch2;
     __ EmitFPUTruncate(kRoundToZero,
-                       single_scratch,
-                       double_scratch,
+                       dst,
+                       double_scratch0,
                        scratch1,
+                       double_scratch1,
                        except_flag,
                        kCheckForInexactConversion);
 
     // Jump to not_int32 if the operation did not succeed.
     __ Branch(not_int32, ne, except_flag, Operand(zero_reg));
-    // Get the result in the destination register.
-    __ mfc1(dst, single_scratch);
-
   } else {
     // Load the double value in the destination registers.
     __ lw(scratch2, FieldMemOperand(object, HeapNumber::kExponentOffset));
@@ -979,14 +1004,14 @@
 
 
 void FloatingPointHelper::DoubleIs32BitInteger(MacroAssembler* masm,
-                                               Register src1,
-                                               Register src2,
+                                               Register src_exponent,
+                                               Register src_mantissa,
                                                Register dst,
                                                Register scratch,
                                                Label* not_int32) {
   // Get exponent alone in scratch.
   __ Ext(scratch,
-         src1,
+         src_exponent,
          HeapNumber::kExponentShift,
          HeapNumber::kExponentBits);
 
@@ -1006,11 +1031,11 @@
   // Another way to put it is that if (exponent - signbit) > 30 then the
   // number cannot be represented as an int32.
   Register tmp = dst;
-  __ srl(at, src1, 31);
+  __ srl(at, src_exponent, 31);
   __ subu(tmp, scratch, at);
   __ Branch(not_int32, gt, tmp, Operand(30));
   // - Bits [21:0] in the mantissa are not null.
-  __ And(tmp, src2, 0x3fffff);
+  __ And(tmp, src_mantissa, 0x3fffff);
   __ Branch(not_int32, ne, tmp, Operand(zero_reg));
 
   // Otherwise the exponent needs to be big enough to shift left all the
@@ -1021,20 +1046,20 @@
 
   // Get the 32 higher bits of the mantissa in dst.
   __ Ext(dst,
-         src2,
+         src_mantissa,
          HeapNumber::kMantissaBitsInTopWord,
          32 - HeapNumber::kMantissaBitsInTopWord);
-  __ sll(at, src1, HeapNumber::kNonMantissaBitsInTopWord);
+  __ sll(at, src_exponent, HeapNumber::kNonMantissaBitsInTopWord);
   __ or_(dst, dst, at);
 
   // Create the mask and test the lower bits (of the higher bits).
   __ li(at, 32);
   __ subu(scratch, at, scratch);
-  __ li(src2, 1);
-  __ sllv(src1, src2, scratch);
-  __ Subu(src1, src1, Operand(1));
-  __ And(src1, dst, src1);
-  __ Branch(not_int32, ne, src1, Operand(zero_reg));
+  __ li(src_mantissa, 1);
+  __ sllv(src_exponent, src_mantissa, scratch);
+  __ Subu(src_exponent, src_exponent, Operand(1));
+  __ And(src_exponent, dst, src_exponent);
+  __ Branch(not_int32, ne, src_exponent, Operand(zero_reg));
 }
 
 
@@ -2955,6 +2980,7 @@
                                                    right,
                                                    destination,
                                                    f14,
+                                                   f16,
                                                    a2,
                                                    a3,
                                                    heap_number_map,
@@ -2966,6 +2992,7 @@
                                                    left,
                                                    destination,
                                                    f12,
+                                                   f16,
                                                    t0,
                                                    t1,
                                                    heap_number_map,
@@ -3002,9 +3029,10 @@
 
           Register except_flag = scratch2;
           __ EmitFPUTruncate(kRoundToZero,
-                             single_scratch,
-                             f10,
                              scratch1,
+                             f10,
+                             at,
+                             f16,
                              except_flag);
 
           if (result_type_ <= BinaryOpIC::INT32) {
@@ -3013,7 +3041,6 @@
           }
 
           // Check if the result fits in a smi.
-          __ mfc1(scratch1, single_scratch);
           __ Addu(scratch2, scratch1, Operand(0x40000000));
           // If not try to return a heap number.
           __ Branch(&return_heap_number, lt, scratch2, Operand(zero_reg));
@@ -3108,6 +3135,7 @@
                                              scratch2,
                                              scratch3,
                                              f0,
+                                             f2,
                                              &transition);
       FloatingPointHelper::LoadNumberAsInt32(masm,
                                              right,
@@ -3117,6 +3145,7 @@
                                              scratch2,
                                              scratch3,
                                              f0,
+                                             f2,
                                              &transition);
 
       // The ECMA-262 standard specifies that, for shift operations, only the
@@ -3683,9 +3712,10 @@
     Label int_exponent_convert;
     // Detect integer exponents stored as double.
     __ EmitFPUTruncate(kRoundToMinusInf,
-                       single_scratch,
-                       double_exponent,
                        scratch,
+                       double_exponent,
+                       at,
+                       double_scratch,
                        scratch2,
                        kCheckForInexactConversion);
     // scratch2 == 0 means there was no conversion error.
@@ -3743,7 +3773,7 @@
     __ push(ra);
     {
       AllowExternalCallThatCantCauseGC scope(masm);
-      __ PrepareCallCFunction(0, 2, scratch);
+      __ PrepareCallCFunction(0, 2, scratch2);
       __ SetCallCDoubleArguments(double_base, double_exponent);
       __ CallCFunction(
           ExternalReference::power_double_double_function(masm->isolate()),
@@ -3754,7 +3784,6 @@
     __ jmp(&done);
 
     __ bind(&int_exponent_convert);
-    __ mfc1(scratch, single_scratch);
   }
 
   // Calculate power with integer exponent.
diff --git a/src/mips/code-stubs-mips.h b/src/mips/code-stubs-mips.h
index bb36d22..b560c63 100644
--- a/src/mips/code-stubs-mips.h
+++ b/src/mips/code-stubs-mips.h
@@ -657,6 +657,7 @@
                                       Register object,
                                       Destination destination,
                                       FPURegister double_dst,
+                                      FPURegister double_scratch,
                                       Register dst1,
                                       Register dst2,
                                       Register heap_number_map,
@@ -678,7 +679,8 @@
                                 Register scratch1,
                                 Register scratch2,
                                 Register scratch3,
-                                FPURegister double_scratch,
+                                FPURegister double_scratch0,
+                                FPURegister double_scratch1,
                                 Label* not_int32);
 
   // Generate non FPU code to check if a double can be exactly represented by a
diff --git a/src/mips/codegen-mips.cc b/src/mips/codegen-mips.cc
index 51ad474..0119c11 100644
--- a/src/mips/codegen-mips.cc
+++ b/src/mips/codegen-mips.cc
@@ -31,11 +31,11 @@
 
 #include "codegen.h"
 #include "macro-assembler.h"
+#include "simulator-mips.h"
 
 namespace v8 {
 namespace internal {
 
-#define __ ACCESS_MASM(masm)
 
 UnaryMathFunction CreateTranscendentalFunction(TranscendentalCache::Type type) {
   switch (type) {
@@ -49,6 +49,74 @@
 }
 
 
+#define __ masm.
+
+
+#if defined(USE_SIMULATOR)
+byte* fast_exp_mips_machine_code = NULL;
+double fast_exp_simulator(double x) {
+  return Simulator::current(Isolate::Current())->CallFP(
+      fast_exp_mips_machine_code, x, 0);
+}
+#endif
+
+
+UnaryMathFunction CreateExpFunction() {
+  if (!CpuFeatures::IsSupported(FPU)) return &exp;
+  if (!FLAG_fast_math) return &exp;
+  size_t actual_size;
+  byte* buffer = static_cast<byte*>(OS::Allocate(1 * KB, &actual_size, true));
+  if (buffer == NULL) return &exp;
+  ExternalReference::InitializeMathExpData();
+
+  MacroAssembler masm(NULL, buffer, static_cast<int>(actual_size));
+
+  {
+    CpuFeatures::Scope use_fpu(FPU);
+    DoubleRegister input = f12;
+    DoubleRegister result = f0;
+    DoubleRegister double_scratch1 = f4;
+    DoubleRegister double_scratch2 = f6;
+    Register temp1 = t0;
+    Register temp2 = t1;
+    Register temp3 = t2;
+
+    if (!IsMipsSoftFloatABI) {
+      // Input value is in f12 anyway, nothing to do.
+    } else {
+      __ Move(input, a0, a1);
+    }
+    __ Push(temp3, temp2, temp1);
+    MathExpGenerator::EmitMathExp(
+        &masm, input, result, double_scratch1, double_scratch2,
+        temp1, temp2, temp3);
+    __ Pop(temp3, temp2, temp1);
+    if (!IsMipsSoftFloatABI) {
+      // Result is already in f0, nothing to do.
+    } else {
+      __ Move(a0, a1, result);
+    }
+    __ Ret();
+  }
+
+  CodeDesc desc;
+  masm.GetCode(&desc);
+
+  CPU::FlushICache(buffer, actual_size);
+  OS::ProtectCode(buffer, actual_size);
+
+#if !defined(USE_SIMULATOR)
+  return FUNCTION_CAST<UnaryMathFunction>(buffer);
+#else
+  fast_exp_mips_machine_code = buffer;
+  return &fast_exp_simulator;
+#endif
+}
+
+
+#undef __
+
+
 UnaryMathFunction CreateSqrtFunction() {
   return &sqrt;
 }
@@ -72,6 +140,8 @@
 // -------------------------------------------------------------------------
 // Code generators
 
+#define __ ACCESS_MASM(masm)
+
 void ElementsTransitionGenerator::GenerateMapChangeElementsTransition(
     MacroAssembler* masm) {
   // ----------- S t a t e -------------
@@ -446,6 +516,81 @@
   __ bind(&done);
 }
 
+
+static MemOperand ExpConstant(int index, Register base) {
+  return MemOperand(base, index * kDoubleSize);
+}
+
+
+void MathExpGenerator::EmitMathExp(MacroAssembler* masm,
+                                   DoubleRegister input,
+                                   DoubleRegister result,
+                                   DoubleRegister double_scratch1,
+                                   DoubleRegister double_scratch2,
+                                   Register temp1,
+                                   Register temp2,
+                                   Register temp3) {
+  ASSERT(!input.is(result));
+  ASSERT(!input.is(double_scratch1));
+  ASSERT(!input.is(double_scratch2));
+  ASSERT(!result.is(double_scratch1));
+  ASSERT(!result.is(double_scratch2));
+  ASSERT(!double_scratch1.is(double_scratch2));
+  ASSERT(!temp1.is(temp2));
+  ASSERT(!temp1.is(temp3));
+  ASSERT(!temp2.is(temp3));
+  ASSERT(ExternalReference::math_exp_constants(0).address() != NULL);
+
+  Label done;
+
+  __ li(temp3, Operand(ExternalReference::math_exp_constants(0)));
+
+  __ ldc1(double_scratch1, ExpConstant(0, temp3));
+  __ Move(result, kDoubleRegZero);
+  __ BranchF(&done, NULL, ge, double_scratch1, input);
+  __ ldc1(double_scratch2, ExpConstant(1, temp3));
+  __ ldc1(result, ExpConstant(2, temp3));
+  __ BranchF(&done, NULL, ge, input, double_scratch2);
+  __ ldc1(double_scratch1, ExpConstant(3, temp3));
+  __ ldc1(result, ExpConstant(4, temp3));
+  __ mul_d(double_scratch1, double_scratch1, input);
+  __ add_d(double_scratch1, double_scratch1, result);
+  __ Move(temp2, temp1, double_scratch1);
+  __ sub_d(double_scratch1, double_scratch1, result);
+  __ ldc1(result, ExpConstant(6, temp3));
+  __ ldc1(double_scratch2, ExpConstant(5, temp3));
+  __ mul_d(double_scratch1, double_scratch1, double_scratch2);
+  __ sub_d(double_scratch1, double_scratch1, input);
+  __ sub_d(result, result, double_scratch1);
+  __ mul_d(input, double_scratch1, double_scratch1);
+  __ mul_d(result, result, input);
+  __ srl(temp1, temp2, 11);
+  __ ldc1(double_scratch2, ExpConstant(7, temp3));
+  __ mul_d(result, result, double_scratch2);
+  __ sub_d(result, result, double_scratch1);
+  __ ldc1(double_scratch2, ExpConstant(8, temp3));
+  __ add_d(result, result, double_scratch2);
+  __ li(at, 0x7ff);
+  __ And(temp2, temp2, at);
+  __ Addu(temp1, temp1, Operand(0x3ff));
+  __ sll(temp1, temp1, 20);
+
+  // Must not call ExpConstant() after overwriting temp3!
+  __ li(temp3, Operand(ExternalReference::math_exp_log_table()));
+  __ sll(at, temp2, 3);
+  __ addu(at, at, temp3);
+  __ lw(at, MemOperand(at));
+  __ Addu(temp3, temp3, Operand(kPointerSize));
+  __ sll(temp2, temp2, 3);
+  __ addu(temp2, temp2, temp3);
+  __ lw(temp2, MemOperand(temp2));
+  __ Or(temp1, temp1, temp2);
+  __ Move(input, at, temp1);
+  __ mul_d(result, result, input);
+  __ bind(&done);
+}
+
+
 // nop(CODE_AGE_MARKER_NOP)
 static const uint32_t kCodeAgePatchFirstInstruction = 0x00010180;
 
@@ -467,29 +612,6 @@
 }
 
 
-byte* Code::FindPlatformCodeAgeSequence() {
-  byte* start = instruction_start();
-  uint32_t young_length;
-  byte* young_sequence = GetNoCodeAgeSequence(&young_length);
-  if (!memcmp(start, young_sequence, young_length) ||
-      Memory::uint32_at(start) == kCodeAgePatchFirstInstruction) {
-    return start;
-  } else {
-    byte* start_after_strict = NULL;
-    if (kind() == FUNCTION) {
-      start_after_strict = start + kSizeOfFullCodegenStrictModePrologue;
-    } else {
-      ASSERT(kind() == OPTIMIZED_FUNCTION);
-      start_after_strict = start + kSizeOfOptimizedStrictModePrologue;
-    }
-    ASSERT(!memcmp(start_after_strict, young_sequence, young_length) ||
-           Memory::uint32_at(start_after_strict) ==
-           kCodeAgePatchFirstInstruction);
-    return start_after_strict;
-  }
-}
-
-
 bool Code::IsYoungSequence(byte* sequence) {
   uint32_t young_length;
   byte* young_sequence = GetNoCodeAgeSequence(&young_length);
diff --git a/src/mips/codegen-mips.h b/src/mips/codegen-mips.h
index 27c8a8b..0ed2414 100644
--- a/src/mips/codegen-mips.h
+++ b/src/mips/codegen-mips.h
@@ -36,9 +36,6 @@
 namespace v8 {
 namespace internal {
 
-static const int kSizeOfFullCodegenStrictModePrologue = 16;
-static const int kSizeOfOptimizedStrictModePrologue = 16;
-
 // Forward declarations
 class CompilationInfo;
 
@@ -93,6 +90,22 @@
   DISALLOW_COPY_AND_ASSIGN(StringCharLoadGenerator);
 };
 
+
+class MathExpGenerator : public AllStatic {
+ public:
+  static void EmitMathExp(MacroAssembler* masm,
+                          DoubleRegister input,
+                          DoubleRegister result,
+                          DoubleRegister double_scratch1,
+                          DoubleRegister double_scratch2,
+                          Register temp1,
+                          Register temp2,
+                          Register temp3);
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(MathExpGenerator);
+};
+
 } }  // namespace v8::internal
 
 #endif  // V8_MIPS_CODEGEN_MIPS_H_
diff --git a/src/mips/full-codegen-mips.cc b/src/mips/full-codegen-mips.cc
index 5a0bb30..b8b3ea1 100644
--- a/src/mips/full-codegen-mips.cc
+++ b/src/mips/full-codegen-mips.cc
@@ -158,14 +158,11 @@
   // function calls.
   if (!info->is_classic_mode() || info->is_native()) {
     Label ok;
-    Label begin;
-    __ bind(&begin);
     __ Branch(&ok, eq, t1, Operand(zero_reg));
     int receiver_offset = info->scope()->num_parameters() * kPointerSize;
     __ LoadRoot(a2, Heap::kUndefinedValueRootIndex);
     __ sw(a2, MemOperand(sp, receiver_offset));
     __ bind(&ok);
-    ASSERT_EQ(kSizeOfFullCodegenStrictModePrologue, ok.pos() - begin.pos());
   }
 
   // Open a frame scope to indicate that there is a frame on the stack.  The
@@ -175,6 +172,7 @@
 
   int locals_count = info->scope()->num_stack_slots();
 
+  info->set_prologue_offset(masm_->pc_offset());
   // The following three instructions must remain together and unmodified for
   // code aging to work properly.
   __ Push(ra, fp, cp, a1);
diff --git a/src/mips/lithium-codegen-mips.cc b/src/mips/lithium-codegen-mips.cc
index e19caf3..22352e1 100644
--- a/src/mips/lithium-codegen-mips.cc
+++ b/src/mips/lithium-codegen-mips.cc
@@ -136,17 +136,15 @@
   // function calls.
   if (!info_->is_classic_mode() || info_->is_native()) {
     Label ok;
-    Label begin;
-    __ bind(&begin);
     __ Branch(&ok, eq, t1, Operand(zero_reg));
 
     int receiver_offset = scope()->num_parameters() * kPointerSize;
     __ LoadRoot(a2, Heap::kUndefinedValueRootIndex);
     __ sw(a2, MemOperand(sp, receiver_offset));
     __ bind(&ok);
-    ASSERT_EQ(kSizeOfOptimizedStrictModePrologue, ok.pos() - begin.pos());
   }
 
+  info()->set_prologue_offset(masm_->pc_offset());
   // The following three instructions must remain together and unmodified for
   // code aging to work properly.
   __ Push(ra, fp, cp, a1);
@@ -3264,22 +3262,19 @@
 void LCodeGen::DoMathFloor(LUnaryMathOperation* instr) {
   DoubleRegister input = ToDoubleRegister(instr->value());
   Register result = ToRegister(instr->result());
-  FPURegister single_scratch = double_scratch0().low();
   Register scratch1 = scratch0();
   Register except_flag = ToRegister(instr->temp());
 
   __ EmitFPUTruncate(kRoundToMinusInf,
-                     single_scratch,
+                     result,
                      input,
                      scratch1,
+                     double_scratch0(),
                      except_flag);
 
   // Deopt if the operation did not succeed.
   DeoptimizeIf(ne, instr->environment(), except_flag, Operand(zero_reg));
 
-  // Load the result.
-  __ mfc1(result, single_scratch);
-
   if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
     // Test for -0.
     Label done;
@@ -3295,6 +3290,7 @@
 void LCodeGen::DoMathRound(LUnaryMathOperation* instr) {
   DoubleRegister input = ToDoubleRegister(instr->value());
   Register result = ToRegister(instr->result());
+  DoubleRegister double_scratch1 = ToDoubleRegister(instr->temp());
   Register scratch = scratch0();
   Label done, check_sign_on_zero;
 
@@ -3346,17 +3342,15 @@
   }
 
   Register except_flag = scratch;
-
   __ EmitFPUTruncate(kRoundToMinusInf,
-                     double_scratch0().low(),
-                     double_scratch0(),
                      result,
+                     double_scratch0(),
+                     at,
+                     double_scratch1,
                      except_flag);
 
   DeoptimizeIf(ne, instr->environment(), except_flag, Operand(zero_reg));
 
-  __ mfc1(result, double_scratch0().low());
-
   if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
     // Test for -0.
     __ Branch(&done, ne, result, Operand(zero_reg));
@@ -3506,6 +3500,20 @@
 }
 
 
+void LCodeGen::DoMathExp(LMathExp* instr) {
+  DoubleRegister input = ToDoubleRegister(instr->value());
+  DoubleRegister result = ToDoubleRegister(instr->result());
+  DoubleRegister double_scratch1 = ToDoubleRegister(instr->double_temp());
+  DoubleRegister double_scratch2 = double_scratch0();
+  Register temp1 = ToRegister(instr->temp1());
+  Register temp2 = ToRegister(instr->temp2());
+
+  MathExpGenerator::EmitMathExp(
+      masm(), input, result, double_scratch1, double_scratch2,
+      temp1, temp2, scratch0());
+}
+
+
 void LCodeGen::DoMathLog(LUnaryMathOperation* instr) {
   ASSERT(ToDoubleRegister(instr->result()).is(f4));
   TranscendentalCacheStub stub(TranscendentalCache::LOG,
@@ -4251,7 +4259,7 @@
 
   if (FLAG_inline_new) {
     __ LoadRoot(t2, Heap::kHeapNumberMapRootIndex);
-    __ AllocateHeapNumber(t1, a3, t0, t2, &slow);
+    __ AllocateHeapNumber(t1, a3, t0, t2, &slow, DONT_TAG_RESULT);
     __ Move(dst, t1);
     __ Branch(&done);
   }
@@ -4265,11 +4273,13 @@
   __ StoreToSafepointRegisterSlot(zero_reg, dst);
   CallRuntimeFromDeferred(Runtime::kAllocateHeapNumber, 0, instr);
   __ Move(dst, v0);
+  __ Subu(dst, dst, kHeapObjectTag);
 
   // Done. Put the value in dbl_scratch into the value of the allocated heap
   // number.
   __ bind(&done);
-  __ sdc1(dbl_scratch, FieldMemOperand(dst, HeapNumber::kValueOffset));
+  __ sdc1(dbl_scratch, MemOperand(dst, HeapNumber::kValueOffset));
+  __ Addu(dst, dst, kHeapObjectTag);
   __ StoreToSafepointRegisterSlot(dst, dst);
 }
 
@@ -4294,12 +4304,16 @@
   DeferredNumberTagD* deferred = new(zone()) DeferredNumberTagD(this, instr);
   if (FLAG_inline_new) {
     __ LoadRoot(scratch, Heap::kHeapNumberMapRootIndex);
-    __ AllocateHeapNumber(reg, temp1, temp2, scratch, deferred->entry());
+    // We want the untagged address first for performance
+    __ AllocateHeapNumber(reg, temp1, temp2, scratch, deferred->entry(),
+                          DONT_TAG_RESULT);
   } else {
     __ Branch(deferred->entry());
   }
   __ bind(deferred->exit());
-  __ sdc1(input_reg, FieldMemOperand(reg, HeapNumber::kValueOffset));
+  __ sdc1(input_reg, MemOperand(reg, HeapNumber::kValueOffset));
+  // Now that we have finished with the object's real address tag it
+  __ Addu(reg, reg, kHeapObjectTag);
 }
 
 
@@ -4312,6 +4326,7 @@
 
   PushSafepointRegistersScope scope(this, Safepoint::kWithRegisters);
   CallRuntimeFromDeferred(Runtime::kAllocateHeapNumber, 0, instr);
+  __ Subu(v0, v0, kHeapObjectTag);
   __ StoreToSafepointRegisterSlot(v0, reg);
 }
 
@@ -4393,7 +4408,7 @@
   Register scratch1 = scratch0();
   Register scratch2 = ToRegister(instr->temp());
   DoubleRegister double_scratch = double_scratch0();
-  FPURegister single_scratch = double_scratch.low();
+  DoubleRegister double_scratch2 = ToDoubleRegister(instr->temp3());
 
   ASSERT(!scratch1.is(input_reg) && !scratch1.is(scratch2));
   ASSERT(!scratch2.is(input_reg) && !scratch2.is(scratch1));
@@ -4409,7 +4424,7 @@
 
   if (instr->truncating()) {
     Register scratch3 = ToRegister(instr->temp2());
-    DoubleRegister double_scratch2 = ToDoubleRegister(instr->temp3());
+    FPURegister single_scratch = double_scratch.low();
     ASSERT(!scratch3.is(input_reg) &&
            !scratch3.is(scratch1) &&
            !scratch3.is(scratch2));
@@ -4444,18 +4459,16 @@
 
     Register except_flag = scratch2;
     __ EmitFPUTruncate(kRoundToZero,
-                       single_scratch,
+                       input_reg,
                        double_scratch,
                        scratch1,
+                       double_scratch2,
                        except_flag,
                        kCheckForInexactConversion);
 
     // Deopt if the operation did not succeed.
     DeoptimizeIf(ne, instr->environment(), except_flag, Operand(zero_reg));
 
-    // Load the result.
-    __ mfc1(input_reg, single_scratch);
-
     if (instr->hydrogen()->CheckFlag(HValue::kBailoutOnMinusZero)) {
       __ Branch(&done, ne, input_reg, Operand(zero_reg));
 
@@ -4517,10 +4530,10 @@
   Register scratch1 = scratch0();
   Register scratch2 = ToRegister(instr->temp());
   DoubleRegister double_input = ToDoubleRegister(instr->value());
-  FPURegister single_scratch = double_scratch0().low();
 
   if (instr->truncating()) {
     Register scratch3 = ToRegister(instr->temp2());
+    FPURegister single_scratch = double_scratch0().low();
     __ EmitECMATruncate(result_reg,
                         double_input,
                         single_scratch,
@@ -4531,17 +4544,15 @@
     Register except_flag = scratch2;
 
     __ EmitFPUTruncate(kRoundToMinusInf,
-                       single_scratch,
+                       result_reg,
                        double_input,
                        scratch1,
+                       double_scratch0(),
                        except_flag,
                        kCheckForInexactConversion);
 
     // Deopt if the operation did not succeed (except_flag != 0).
     DeoptimizeIf(ne, instr->environment(), except_flag, Operand(zero_reg));
-
-    // Load the result.
-    __ mfc1(result_reg, single_scratch);
   }
 }
 
diff --git a/src/mips/lithium-mips.cc b/src/mips/lithium-mips.cc
index 796d153..56dd33d 100644
--- a/src/mips/lithium-mips.cc
+++ b/src/mips/lithium-mips.cc
@@ -297,6 +297,11 @@
 }
 
 
+void LMathExp::PrintDataTo(StringStream* stream) {
+  value()->PrintTo(stream);
+}
+
+
 void LLoadContextSlot::PrintDataTo(StringStream* stream) {
   context()->PrintTo(stream);
   stream->Add("[%d]", slot_index());
@@ -398,6 +403,15 @@
 }
 
 
+void LStoreKeyedGeneric::PrintDataTo(StringStream* stream) {
+  object()->PrintTo(stream);
+  stream->Add("[");
+  key()->PrintTo(stream);
+  stream->Add("] <- ");
+  value()->PrintTo(stream);
+}
+
+
 void LTransitionElementsKind::PrintDataTo(StringStream* stream) {
   object()->PrintTo(stream);
   stream->Add(" %p -> %p", *original_map(), *transitioned_map());
@@ -1031,6 +1045,15 @@
     LOperand* input = UseFixedDouble(instr->value(), f4);
     LUnaryMathOperation* result = new(zone()) LUnaryMathOperation(input, NULL);
     return MarkAsCall(DefineFixedDouble(result, f4), instr);
+  } else if (op == kMathExp) {
+    ASSERT(instr->representation().IsDouble());
+    ASSERT(instr->value()->representation().IsDouble());
+    LOperand* input = UseTempRegister(instr->value());
+    LOperand* temp1 = TempRegister();
+    LOperand* temp2 = TempRegister();
+    LOperand* double_temp = FixedTemp(f6);  // Chosen by fair dice roll.
+    LMathExp* result = new(zone()) LMathExp(input, double_temp, temp1, temp2);
+    return DefineAsRegister(result);
   } else if (op == kMathPowHalf) {
     // Input cannot be the same as the result.
     // See lithium-codegen-mips.cc::DoMathPowHalf.
@@ -1040,7 +1063,9 @@
     return DefineFixedDouble(result, f4);
   } else {
     LOperand* input = UseRegisterAtStart(instr->value());
-    LOperand* temp = (op == kMathFloor) ? TempRegister() : NULL;
+
+    LOperand* temp = (op == kMathRound) ? FixedTemp(f6) :
+        (op == kMathFloor) ? TempRegister() : NULL;
     LUnaryMathOperation* result = new(zone()) LUnaryMathOperation(input, temp);
     switch (op) {
       case kMathAbs:
@@ -1557,8 +1582,7 @@
         LOperand* temp1 = TempRegister();
         LOperand* temp2 = instr->CanTruncateToInt32() ? TempRegister()
                                                       : NULL;
-        LOperand* temp3 = instr->CanTruncateToInt32() ? FixedTemp(f22)
-                                                      : NULL;
+        LOperand* temp3 = FixedTemp(f22);
         res = DefineSameAsFirst(new(zone()) LTaggedToI(value,
                                                        temp1,
                                                        temp2,
diff --git a/src/mips/lithium-mips.h b/src/mips/lithium-mips.h
index 1baf07d..17ef24c 100644
--- a/src/mips/lithium-mips.h
+++ b/src/mips/lithium-mips.h
@@ -131,6 +131,7 @@
   V(LoadNamedFieldPolymorphic)                  \
   V(LoadNamedGeneric)                           \
   V(MapEnumLength)                              \
+  V(MathExp)                                    \
   V(MathMinMax)                                 \
   V(ModI)                                       \
   V(MulI)                                       \
@@ -641,6 +642,30 @@
 };
 
 
+class LMathExp: public LTemplateInstruction<1, 1, 3> {
+ public:
+  LMathExp(LOperand* value,
+           LOperand* double_temp,
+           LOperand* temp1,
+           LOperand* temp2) {
+    inputs_[0] = value;
+    temps_[0] = temp1;
+    temps_[1] = temp2;
+    temps_[2] = double_temp;
+    ExternalReference::InitializeMathExpData();
+  }
+
+  LOperand* value() { return inputs_[0]; }
+  LOperand* temp1() { return temps_[0]; }
+  LOperand* temp2() { return temps_[1]; }
+  LOperand* double_temp() { return temps_[2]; }
+
+  DECLARE_CONCRETE_INSTRUCTION(MathExp, "math-exp")
+
+  virtual void PrintDataTo(StringStream* stream);
+};
+
+
 class LCmpObjectEqAndBranch: public LControlInstruction<2, 0> {
  public:
   LCmpObjectEqAndBranch(LOperand* left, LOperand* right) {
diff --git a/src/mips/macro-assembler-mips.cc b/src/mips/macro-assembler-mips.cc
index 926b3bf..9249917 100644
--- a/src/mips/macro-assembler-mips.cc
+++ b/src/mips/macro-assembler-mips.cc
@@ -1395,49 +1395,68 @@
 
 
 void MacroAssembler::EmitFPUTruncate(FPURoundingMode rounding_mode,
-                                     FPURegister result,
+                                     Register result,
                                      DoubleRegister double_input,
-                                     Register scratch1,
+                                     Register scratch,
+                                     DoubleRegister double_scratch,
                                      Register except_flag,
                                      CheckForInexactConversion check_inexact) {
+  ASSERT(!result.is(scratch));
+  ASSERT(!double_input.is(double_scratch));
+  ASSERT(!except_flag.is(scratch));
+
   ASSERT(CpuFeatures::IsSupported(FPU));
   CpuFeatures::Scope scope(FPU);
+  Label done;
+
+  // Clear the except flag (0 = no exception)
+  mov(except_flag, zero_reg);
+
+  // Test for values that can be exactly represented as a signed 32-bit integer.
+  cvt_w_d(double_scratch, double_input);
+  mfc1(result, double_scratch);
+  cvt_d_w(double_scratch, double_scratch);
+  BranchF(&done, NULL, eq, double_input, double_scratch);
 
   int32_t except_mask = kFCSRFlagMask;  // Assume interested in all exceptions.
 
   if (check_inexact == kDontCheckForInexactConversion) {
-    // Ingore inexact exceptions.
+    // Ignore inexact exceptions.
     except_mask &= ~kFCSRInexactFlagMask;
   }
 
   // Save FCSR.
-  cfc1(scratch1, FCSR);
+  cfc1(scratch, FCSR);
   // Disable FPU exceptions.
   ctc1(zero_reg, FCSR);
 
   // Do operation based on rounding mode.
   switch (rounding_mode) {
     case kRoundToNearest:
-      Round_w_d(result, double_input);
+      Round_w_d(double_scratch, double_input);
       break;
     case kRoundToZero:
-      Trunc_w_d(result, double_input);
+      Trunc_w_d(double_scratch, double_input);
       break;
     case kRoundToPlusInf:
-      Ceil_w_d(result, double_input);
+      Ceil_w_d(double_scratch, double_input);
       break;
     case kRoundToMinusInf:
-      Floor_w_d(result, double_input);
+      Floor_w_d(double_scratch, double_input);
       break;
   }  // End of switch-statement.
 
   // Retrieve FCSR.
   cfc1(except_flag, FCSR);
   // Restore FCSR.
-  ctc1(scratch1, FCSR);
+  ctc1(scratch, FCSR);
+  // Move the converted value into the result register.
+  mfc1(result, double_scratch);
 
   // Check for fpu exceptions.
   And(except_flag, except_flag, Operand(except_mask));
+
+  bind(&done);
 }
 
 
@@ -3215,7 +3234,8 @@
                                         Register scratch1,
                                         Register scratch2,
                                         Register heap_number_map,
-                                        Label* need_gc) {
+                                        Label* need_gc,
+                                        TaggingMode tagging_mode) {
   // Allocate an object in the heap for the heap number and tag it as a heap
   // object.
   AllocateInNewSpace(HeapNumber::kSize,
@@ -3223,11 +3243,16 @@
                      scratch1,
                      scratch2,
                      need_gc,
-                     TAG_OBJECT);
+                     tagging_mode == TAG_RESULT ? TAG_OBJECT :
+                                                  NO_ALLOCATION_FLAGS);
 
   // Store heap number map in the allocated object.
   AssertRegisterIsRoot(heap_number_map, Heap::kHeapNumberMapRootIndex);
-  sw(heap_number_map, FieldMemOperand(result, HeapObject::kMapOffset));
+  if (tagging_mode == TAG_RESULT) {
+    sw(heap_number_map, FieldMemOperand(result, HeapObject::kMapOffset));
+  } else {
+    sw(heap_number_map, MemOperand(result, HeapObject::kMapOffset));
+  }
 }
 
 
@@ -3951,6 +3976,14 @@
   Addu(s2, s2, Operand(1));
   sw(s2, MemOperand(s3, kLevelOffset));
 
+  if (FLAG_log_timer_events) {
+    FrameScope frame(this, StackFrame::MANUAL);
+    PushSafepointRegisters();
+    PrepareCallCFunction(0, a0);
+    CallCFunction(ExternalReference::log_enter_external_function(isolate()), 0);
+    PopSafepointRegisters();
+  }
+
   // The O32 ABI requires us to pass a pointer in a0 where the returned struct
   // (4 bytes) will be placed. This is also built into the Simulator.
   // Set up the pointer to the returned value (a0). It was allocated in
@@ -3963,6 +3996,14 @@
   DirectCEntryStub stub;
   stub.GenerateCall(this, function);
 
+  if (FLAG_log_timer_events) {
+    FrameScope frame(this, StackFrame::MANUAL);
+    PushSafepointRegisters();
+    PrepareCallCFunction(0, a0);
+    CallCFunction(ExternalReference::log_leave_external_function(isolate()), 0);
+    PopSafepointRegisters();
+  }
+
   // As mentioned above, on MIPS a pointer is returned - we need to dereference
   // it to get the actual return value (which is also a pointer).
   lw(v0, MemOperand(v0));
diff --git a/src/mips/macro-assembler-mips.h b/src/mips/macro-assembler-mips.h
index ada3184..474772e 100644
--- a/src/mips/macro-assembler-mips.h
+++ b/src/mips/macro-assembler-mips.h
@@ -65,6 +65,14 @@
   SIZE_IN_WORDS = 1 << 2
 };
 
+// Flags used for AllocateHeapNumber
+enum TaggingMode {
+  // Tag the result.
+  TAG_RESULT,
+  // Don't tag
+  DONT_TAG_RESULT
+};
+
 // Flags used for the ObjectToDoubleFPURegister function.
 enum ObjectToDoubleFlags {
   // No special flags.
@@ -536,7 +544,8 @@
                           Register scratch1,
                           Register scratch2,
                           Register heap_number_map,
-                          Label* gc_required);
+                          Label* gc_required,
+                          TaggingMode tagging_mode = TAG_RESULT);
   void AllocateHeapNumberWithValue(Register result,
                                    FPURegister value,
                                    Register scratch1,
@@ -753,14 +762,16 @@
                       FPURegister double_scratch,
                       Label *not_int32);
 
-  // Truncates a double using a specific rounding mode.
+  // Truncates a double using a specific rounding mode, and writes the value
+  // to the result register.
   // The except_flag will contain any exceptions caused by the instruction.
-  // If check_inexact is kDontCheckForInexactConversion, then the inexacat
+  // If check_inexact is kDontCheckForInexactConversion, then the inexact
   // exception is masked.
   void EmitFPUTruncate(FPURoundingMode rounding_mode,
-                       FPURegister result,
+                       Register result,
                        DoubleRegister double_input,
-                       Register scratch1,
+                       Register scratch,
+                       DoubleRegister double_scratch,
                        Register except_flag,
                        CheckForInexactConversion check_inexact
                            = kDontCheckForInexactConversion);
diff --git a/src/mips/simulator-mips.cc b/src/mips/simulator-mips.cc
index cb56473..ea359ea 100644
--- a/src/mips/simulator-mips.cc
+++ b/src/mips/simulator-mips.cc
@@ -1016,6 +1016,13 @@
 }
 
 
+void Simulator::set_dw_register(int reg, const int* dbl) {
+  ASSERT((reg >= 0) && (reg < kNumSimuRegisters));
+  registers_[reg] = dbl[0];
+  registers_[reg + 1] = dbl[1];
+}
+
+
 void Simulator::set_fpu_register(int fpureg, int32_t value) {
   ASSERT((fpureg >= 0) && (fpureg < kNumFPURegisters));
   FPUregisters_[fpureg] = value;
@@ -1045,6 +1052,19 @@
 }
 
 
+double Simulator::get_double_from_register_pair(int reg) {
+  ASSERT((reg >= 0) && (reg < kNumSimuRegisters) && ((reg % 2) == 0));
+
+  double dm_val = 0.0;
+  // Read the bits from the unsigned integer register_[] array
+  // into the double precision floating point value and return it.
+  char buffer[2 * sizeof(registers_[0])];
+  memcpy(buffer, &registers_[reg], 2 * sizeof(registers_[0]));
+  memcpy(&dm_val, buffer, 2 * sizeof(registers_[0]));
+  return(dm_val);
+}
+
+
 int32_t Simulator::get_fpu_register(int fpureg) const {
   ASSERT((fpureg >= 0) && (fpureg < kNumFPURegisters));
   return FPUregisters_[fpureg];
@@ -2718,34 +2738,7 @@
 }
 
 
-int32_t Simulator::Call(byte* entry, int argument_count, ...) {
-  va_list parameters;
-  va_start(parameters, argument_count);
-  // Set up arguments.
-
-  // First four arguments passed in registers.
-  ASSERT(argument_count >= 4);
-  set_register(a0, va_arg(parameters, int32_t));
-  set_register(a1, va_arg(parameters, int32_t));
-  set_register(a2, va_arg(parameters, int32_t));
-  set_register(a3, va_arg(parameters, int32_t));
-
-  // Remaining arguments passed on stack.
-  int original_stack = get_register(sp);
-  // Compute position of stack on entry to generated code.
-  int entry_stack = (original_stack - (argument_count - 4) * sizeof(int32_t)
-                                    - kCArgsSlotsSize);
-  if (OS::ActivationFrameAlignment() != 0) {
-    entry_stack &= -OS::ActivationFrameAlignment();
-  }
-  // Store remaining arguments on stack, from low to high memory.
-  intptr_t* stack_argument = reinterpret_cast<intptr_t*>(entry_stack);
-  for (int i = 4; i < argument_count; i++) {
-    stack_argument[i - 4 + kCArgSlotCount] = va_arg(parameters, int32_t);
-  }
-  va_end(parameters);
-  set_register(sp, entry_stack);
-
+void Simulator::CallInternal(byte* entry) {
   // Prepare to execute the code at entry.
   set_register(pc, reinterpret_cast<int32_t>(entry));
   // Put down marker for end of simulation. The simulator will stop simulation
@@ -2809,6 +2802,38 @@
   set_register(gp, gp_val);
   set_register(sp, sp_val);
   set_register(fp, fp_val);
+}
+
+
+int32_t Simulator::Call(byte* entry, int argument_count, ...) {
+  va_list parameters;
+  va_start(parameters, argument_count);
+  // Set up arguments.
+
+  // First four arguments passed in registers.
+  ASSERT(argument_count >= 4);
+  set_register(a0, va_arg(parameters, int32_t));
+  set_register(a1, va_arg(parameters, int32_t));
+  set_register(a2, va_arg(parameters, int32_t));
+  set_register(a3, va_arg(parameters, int32_t));
+
+  // Remaining arguments passed on stack.
+  int original_stack = get_register(sp);
+  // Compute position of stack on entry to generated code.
+  int entry_stack = (original_stack - (argument_count - 4) * sizeof(int32_t)
+                                    - kCArgsSlotsSize);
+  if (OS::ActivationFrameAlignment() != 0) {
+    entry_stack &= -OS::ActivationFrameAlignment();
+  }
+  // Store remaining arguments on stack, from low to high memory.
+  intptr_t* stack_argument = reinterpret_cast<intptr_t*>(entry_stack);
+  for (int i = 4; i < argument_count; i++) {
+    stack_argument[i - 4 + kCArgSlotCount] = va_arg(parameters, int32_t);
+  }
+  va_end(parameters);
+  set_register(sp, entry_stack);
+
+  CallInternal(entry);
 
   // Pop stack passed arguments.
   CHECK_EQ(entry_stack, get_register(sp));
@@ -2819,6 +2844,27 @@
 }
 
 
+double Simulator::CallFP(byte* entry, double d0, double d1) {
+  if (!IsMipsSoftFloatABI) {
+    set_fpu_register_double(f12, d0);
+    set_fpu_register_double(f14, d1);
+  } else {
+    int buffer[2];
+    ASSERT(sizeof(buffer[0]) * 2 == sizeof(d0));
+    memcpy(buffer, &d0, sizeof(d0));
+    set_dw_register(a0, buffer);
+    memcpy(buffer, &d1, sizeof(d1));
+    set_dw_register(a2, buffer);
+  }
+  CallInternal(entry);
+  if (!IsMipsSoftFloatABI) {
+    return get_fpu_register_double(f0);
+  } else {
+    return get_double_from_register_pair(v0);
+  }
+}
+
+
 uintptr_t Simulator::PushAddress(uintptr_t address) {
   int new_sp = get_register(sp) - sizeof(uintptr_t);
   uintptr_t* stack_slot = reinterpret_cast<uintptr_t*>(new_sp);
diff --git a/src/mips/simulator-mips.h b/src/mips/simulator-mips.h
index 776badc..67f5953 100644
--- a/src/mips/simulator-mips.h
+++ b/src/mips/simulator-mips.h
@@ -184,7 +184,9 @@
   // architecture specification and is off by a 8 from the currently executing
   // instruction.
   void set_register(int reg, int32_t value);
+  void set_dw_register(int dreg, const int* dbl);
   int32_t get_register(int reg) const;
+  double get_double_from_register_pair(int reg);
   // Same for FPURegisters.
   void set_fpu_register(int fpureg, int32_t value);
   void set_fpu_register_float(int fpureg, float value);
@@ -214,6 +216,8 @@
   // generated RegExp code with 7 parameters. This is a convenience function,
   // which sets up the simulator state and grabs the result on return.
   int32_t Call(byte* entry, int argument_count, ...);
+  // Alternative: call a 2-argument double function.
+  double CallFP(byte* entry, double d0, double d1);
 
   // Push an address onto the JS stack.
   uintptr_t PushAddress(uintptr_t address);
@@ -353,6 +357,7 @@
   void GetFpArgs(double* x, int32_t* y);
   void SetFpResult(const double& result);
 
+  void CallInternal(byte* entry);
 
   // Architecture state.
   // Registers.
diff --git a/src/mips/stub-cache-mips.cc b/src/mips/stub-cache-mips.cc
index 85497b5..323933b 100644
--- a/src/mips/stub-cache-mips.cc
+++ b/src/mips/stub-cache-mips.cc
@@ -3695,6 +3695,7 @@
                                 Register scratch0,
                                 Register scratch1,
                                 FPURegister double_scratch0,
+                                FPURegister double_scratch1,
                                 Label* fail) {
   if (CpuFeatures::IsSupported(FPU)) {
     CpuFeatures::Scope scope(FPU);
@@ -3710,15 +3711,15 @@
                 DONT_DO_SMI_CHECK);
     __ ldc1(double_scratch0, FieldMemOperand(key, HeapNumber::kValueOffset));
     __ EmitFPUTruncate(kRoundToZero,
-                       double_scratch0,
-                       double_scratch0,
                        scratch0,
+                       double_scratch0,
+                       at,
+                       double_scratch1,
                        scratch1,
                        kCheckForInexactConversion);
 
     __ Branch(fail, ne, scratch1, Operand(zero_reg));
 
-    __ mfc1(scratch0, double_scratch0);
     __ SmiTagCheckOverflow(key, scratch0, scratch1);
     __ BranchOnOverflow(fail, scratch1);
     __ bind(&key_ok);
@@ -3746,7 +3747,7 @@
   // have been verified by the caller to not be a smi.
 
   // Check that the key is a smi or a heap number convertible to a smi.
-  GenerateSmiKeyCheck(masm, key, t0, t1, f2, &miss_force_generic);
+  GenerateSmiKeyCheck(masm, key, t0, t1, f2, f4, &miss_force_generic);
 
   __ lw(a3, FieldMemOperand(receiver, JSObject::kElementsOffset));
   // a3: elements array
@@ -3846,34 +3847,41 @@
     __ Ret();
 
     __ bind(&box_int);
-    // Allocate a HeapNumber for the result and perform int-to-double
-    // conversion.
-    // The arm version uses a temporary here to save r0, but we don't need to
-    // (a0 is not modified).
-    __ LoadRoot(t1, Heap::kHeapNumberMapRootIndex);
-    __ AllocateHeapNumber(v0, a3, t0, t1, &slow);
 
     if (CpuFeatures::IsSupported(FPU)) {
       CpuFeatures::Scope scope(FPU);
+      // Allocate a HeapNumber for the result and perform int-to-double
+      // conversion.
+      // The arm version uses a temporary here to save r0, but we don't need to
+      // (a0 is not modified).
+      __ LoadRoot(t1, Heap::kHeapNumberMapRootIndex);
+      __ AllocateHeapNumber(v0, a3, t0, t1, &slow, DONT_TAG_RESULT);
       __ mtc1(value, f0);
       __ cvt_d_w(f0, f0);
-      __ sdc1(f0, FieldMemOperand(v0, HeapNumber::kValueOffset));
+      __ sdc1(f0, MemOperand(v0, HeapNumber::kValueOffset));
+      __ Addu(v0, v0, kHeapObjectTag);
       __ Ret();
     } else {
-      Register dst1 = t2;
-      Register dst2 = t3;
+      // Allocate a HeapNumber for the result and perform int-to-double
+      // conversion.
+      // The arm version uses a temporary here to save r0, but we don't need to
+      // (a0 is not modified).
+      __ LoadRoot(t1, Heap::kHeapNumberMapRootIndex);
+      __ AllocateHeapNumber(v0, a3, t0, t1, &slow, TAG_RESULT);
+      Register dst_mantissa = t2;
+      Register dst_exponent = t3;
       FloatingPointHelper::Destination dest =
           FloatingPointHelper::kCoreRegisters;
       FloatingPointHelper::ConvertIntToDouble(masm,
                                               value,
                                               dest,
                                               f0,
-                                              dst1,
-                                              dst2,
+                                              dst_mantissa,
+                                              dst_exponent,
                                               t1,
                                               f2);
-      __ sw(dst1, FieldMemOperand(v0, HeapNumber::kMantissaOffset));
-      __ sw(dst2, FieldMemOperand(v0, HeapNumber::kExponentOffset));
+      __ sw(dst_mantissa, FieldMemOperand(v0, HeapNumber::kMantissaOffset));
+      __ sw(dst_exponent, FieldMemOperand(v0, HeapNumber::kExponentOffset));
       __ Ret();
     }
   } else if (elements_kind == EXTERNAL_UNSIGNED_INT_ELEMENTS) {
@@ -3896,7 +3904,7 @@
       // conversion. Don't use a0 and a1 as AllocateHeapNumber clobbers all
       // registers - also when jumping due to exhausted young space.
       __ LoadRoot(t6, Heap::kHeapNumberMapRootIndex);
-      __ AllocateHeapNumber(v0, t2, t3, t6, &slow);
+      __ AllocateHeapNumber(v0, t2, t3, t6, &slow, DONT_TAG_RESULT);
 
       // This is replaced by a macro:
       // __ mtc1(value, f0);     // LS 32-bits.
@@ -3905,8 +3913,9 @@
 
       __ Cvt_d_uw(f0, value, f22);
 
-      __ sdc1(f0, FieldMemOperand(v0, HeapNumber::kValueOffset));
+      __ sdc1(f0, MemOperand(v0, HeapNumber::kValueOffset));
 
+      __ Addu(v0, v0, kHeapObjectTag);
       __ Ret();
     } else {
       // Check whether unsigned integer fits into smi.
@@ -3939,7 +3948,7 @@
       // clobbers all registers - also when jumping due to exhausted young
       // space.
       __ LoadRoot(t6, Heap::kHeapNumberMapRootIndex);
-      __ AllocateHeapNumber(t2, t3, t5, t6, &slow);
+      __ AllocateHeapNumber(t2, t3, t5, t6, &slow, TAG_RESULT);
 
       __ sw(hiword, FieldMemOperand(t2, HeapNumber::kExponentOffset));
       __ sw(loword, FieldMemOperand(t2, HeapNumber::kMantissaOffset));
@@ -3956,17 +3965,19 @@
       // AllocateHeapNumber clobbers all registers - also when jumping due to
       // exhausted young space.
       __ LoadRoot(t6, Heap::kHeapNumberMapRootIndex);
-      __ AllocateHeapNumber(v0, t3, t5, t6, &slow);
+      __ AllocateHeapNumber(v0, t3, t5, t6, &slow, DONT_TAG_RESULT);
       // The float (single) value is already in fpu reg f0 (if we use float).
       __ cvt_d_s(f0, f0);
-      __ sdc1(f0, FieldMemOperand(v0, HeapNumber::kValueOffset));
+      __ sdc1(f0, MemOperand(v0, HeapNumber::kValueOffset));
+
+      __ Addu(v0, v0, kHeapObjectTag);
       __ Ret();
     } else {
       // Allocate a HeapNumber for the result. Don't use a0 and a1 as
       // AllocateHeapNumber clobbers all registers - also when jumping due to
       // exhausted young space.
       __ LoadRoot(t6, Heap::kHeapNumberMapRootIndex);
-      __ AllocateHeapNumber(v0, t3, t5, t6, &slow);
+      __ AllocateHeapNumber(v0, t3, t5, t6, &slow, TAG_RESULT);
       // FPU is not available, do manual single to double conversion.
 
       // a2: floating point value (binary32).
@@ -4021,16 +4032,18 @@
       // AllocateHeapNumber clobbers all registers - also when jumping due to
       // exhausted young space.
       __ LoadRoot(t6, Heap::kHeapNumberMapRootIndex);
-      __ AllocateHeapNumber(v0, t3, t5, t6, &slow);
+      __ AllocateHeapNumber(v0, t3, t5, t6, &slow, DONT_TAG_RESULT);
       // The double value is already in f0
-      __ sdc1(f0, FieldMemOperand(v0, HeapNumber::kValueOffset));
+      __ sdc1(f0, MemOperand(v0, HeapNumber::kValueOffset));
+
+      __ Addu(v0, v0, kHeapObjectTag);
       __ Ret();
     } else {
       // Allocate a HeapNumber for the result. Don't use a0 and a1 as
       // AllocateHeapNumber clobbers all registers - also when jumping due to
       // exhausted young space.
       __ LoadRoot(t6, Heap::kHeapNumberMapRootIndex);
-      __ AllocateHeapNumber(v0, t3, t5, t6, &slow);
+      __ AllocateHeapNumber(v0, t3, t5, t6, &slow, TAG_RESULT);
 
       __ sw(a2, FieldMemOperand(v0, HeapNumber::kMantissaOffset));
       __ sw(a3, FieldMemOperand(v0, HeapNumber::kExponentOffset));
@@ -4088,7 +4101,7 @@
   // have been verified by the caller to not be a smi.
 
   // Check that the key is a smi or a heap number convertible to a smi.
-  GenerateSmiKeyCheck(masm, key, t0, t1, f2, &miss_force_generic);
+  GenerateSmiKeyCheck(masm, key, t0, t1, f2, f4, &miss_force_generic);
 
   __ lw(a3, FieldMemOperand(receiver, JSObject::kElementsOffset));
 
@@ -4167,7 +4180,7 @@
       }
       FloatingPointHelper::ConvertIntToDouble(
           masm, t1, destination,
-          f0, t2, t3,  // These are: double_dst, dst1, dst2.
+          f0, t2, t3,  // These are: double_dst, dst_mantissa, dst_exponent.
           t0, f2);  // These are: scratch2, single_scratch.
       if (destination == FloatingPointHelper::kFPURegisters) {
         CpuFeatures::Scope scope(FPU);
@@ -4477,7 +4490,7 @@
   // have been verified by the caller to not be a smi.
 
   // Check that the key is a smi or a heap number convertible to a smi.
-  GenerateSmiKeyCheck(masm, a0, t0, t1, f2, &miss_force_generic);
+  GenerateSmiKeyCheck(masm, a0, t0, t1, f2, f4, &miss_force_generic);
 
   // Get the elements array.
   __ lw(a2, FieldMemOperand(a1, JSObject::kElementsOffset));
@@ -4528,7 +4541,7 @@
   // have been verified by the caller to not be a smi.
 
   // Check that the key is a smi or a heap number convertible to a smi.
-  GenerateSmiKeyCheck(masm, key_reg, t0, t1, f2, &miss_force_generic);
+  GenerateSmiKeyCheck(masm, key_reg, t0, t1, f2, f4, &miss_force_generic);
 
   // Get the elements array.
   __ lw(elements_reg,
@@ -4548,7 +4561,7 @@
   // Non-NaN. Allocate a new heap number and copy the double value into it.
   __ LoadRoot(heap_number_map, Heap::kHeapNumberMapRootIndex);
   __ AllocateHeapNumber(heap_number_reg, scratch2, scratch3,
-                        heap_number_map, &slow_allocate_heapnumber);
+                        heap_number_map, &slow_allocate_heapnumber, TAG_RESULT);
 
   // Don't need to reload the upper 32 bits of the double, it's already in
   // scratch.
@@ -4602,7 +4615,7 @@
   // have been verified by the caller to not be a smi.
 
   // Check that the key is a smi or a heap number convertible to a smi.
-  GenerateSmiKeyCheck(masm, key_reg, t0, t1, f2, &miss_force_generic);
+  GenerateSmiKeyCheck(masm, key_reg, t0, t1, f2, f4, &miss_force_generic);
 
   if (IsFastSmiElementsKind(elements_kind)) {
     __ JumpIfNotSmi(value_reg, &transition_elements_kind);
@@ -4746,11 +4759,12 @@
   //  -- a1    : key
   //  -- a2    : receiver
   //  -- ra    : return address
-  //  -- a3    : scratch
+  //  -- a3    : scratch (elements backing store)
   //  -- t0    : scratch (elements_reg)
   //  -- t1    : scratch (mantissa_reg)
   //  -- t2    : scratch (exponent_reg)
   //  -- t3    : scratch4
+  //  -- t4    : scratch
   // -----------------------------------
   Label miss_force_generic, transition_elements_kind, grow, slow;
   Label finish_store, check_capacity;
@@ -4763,13 +4777,14 @@
   Register scratch2 = t1;
   Register scratch3 = t2;
   Register scratch4 = t3;
+  Register scratch5 = t4;
   Register length_reg = t3;
 
   // This stub is meant to be tail-jumped to, the receiver must already
   // have been verified by the caller to not be a smi.
 
   // Check that the key is a smi or a heap number convertible to a smi.
-  GenerateSmiKeyCheck(masm, key_reg, t0, t1, f2, &miss_force_generic);
+  GenerateSmiKeyCheck(masm, key_reg, t0, t1, f2, f4, &miss_force_generic);
 
   __ lw(elements_reg,
          FieldMemOperand(receiver_reg, JSObject::kElementsOffset));
@@ -4843,14 +4858,32 @@
     __ AllocateInNewSpace(size, elements_reg, scratch1, scratch2, &slow,
                           TAG_OBJECT);
 
-    // Initialize the new FixedDoubleArray. Leave elements unitialized for
-    // efficiency, they are guaranteed to be initialized before use.
+    // Initialize the new FixedDoubleArray.
     __ LoadRoot(scratch1, Heap::kFixedDoubleArrayMapRootIndex);
     __ sw(scratch1, FieldMemOperand(elements_reg, JSObject::kMapOffset));
     __ li(scratch1, Operand(Smi::FromInt(JSArray::kPreallocatedArrayElements)));
     __ sw(scratch1,
           FieldMemOperand(elements_reg, FixedDoubleArray::kLengthOffset));
 
+    __ mov(scratch1, elements_reg);
+    __ StoreNumberToDoubleElements(value_reg,
+                                   key_reg,
+                                   // All registers after this are overwritten.
+                                   scratch1,
+                                   scratch2,
+                                   scratch3,
+                                   scratch4,
+                                   scratch5,
+                                   &transition_elements_kind);
+
+    __ li(scratch1, Operand(kHoleNanLower32));
+    __ li(scratch2, Operand(kHoleNanUpper32));
+    for (int i = 1; i < JSArray::kPreallocatedArrayElements; i++) {
+      int offset = FixedDoubleArray::OffsetOfElementAt(i);
+      __ sw(scratch1, FieldMemOperand(elements_reg, offset));
+      __ sw(scratch2, FieldMemOperand(elements_reg, offset + kPointerSize));
+    }
+
     // Install the new backing store in the JSArray.
     __ sw(elements_reg,
           FieldMemOperand(receiver_reg, JSObject::kElementsOffset));
@@ -4863,7 +4896,7 @@
     __ sw(length_reg, FieldMemOperand(receiver_reg, JSArray::kLengthOffset));
     __ lw(elements_reg,
           FieldMemOperand(receiver_reg, JSObject::kElementsOffset));
-    __ jmp(&finish_store);
+    __ Ret();
 
     __ bind(&check_capacity);
     // Make sure that the backing store can hold additional elements.
diff --git a/src/objects-inl.h b/src/objects-inl.h
index 6e8d148..b99ba44 100644
--- a/src/objects-inl.h
+++ b/src/objects-inl.h
@@ -2342,13 +2342,6 @@
 // Cast operations
 
 
-FixedDoubleArray* FixedDoubleArray::castOrEmptyFixedArray(Object* object) {
-  ASSERT(object == HeapObject::cast(object)->GetHeap()->empty_fixed_array() ||
-         object->IsFixedDoubleArray());
-  return reinterpret_cast<FixedDoubleArray*>(object);
-}
-
-
 CAST_ACCESSOR(FixedArray)
 CAST_ACCESSOR(FixedDoubleArray)
 CAST_ACCESSOR(DescriptorArray)
@@ -4578,6 +4571,7 @@
 
 
 INT_ACCESSORS(Code, instruction_size, kInstructionSizeOffset)
+INT_ACCESSORS(Code, prologue_offset, kPrologueOffset)
 ACCESSORS(Code, relocation_info, ByteArray, kRelocationInfoOffset)
 ACCESSORS(Code, handler_table, FixedArray, kHandlerTableOffset)
 ACCESSORS(Code, deoptimization_data, FixedArray, kDeoptimizationDataOffset)
diff --git a/src/objects-printer.cc b/src/objects-printer.cc
index b1118de..9a1a58e 100644
--- a/src/objects-printer.cc
+++ b/src/objects-printer.cc
@@ -384,7 +384,7 @@
     case EXTERNAL_DOUBLE_ELEMENTS: {
       ExternalDoubleArray* p = ExternalDoubleArray::cast(elements());
       for (int i = 0; i < p->length(); i++) {
-        PrintF(out, "  %d: %f\n", i, p->get_scalar(i));
+        PrintF(out, "   %d: %f\n", i, p->get_scalar(i));
       }
       break;
     }
@@ -393,11 +393,16 @@
       break;
     case NON_STRICT_ARGUMENTS_ELEMENTS: {
       FixedArray* p = FixedArray::cast(elements());
+      PrintF(out, "   parameter map:");
       for (int i = 2; i < p->length(); i++) {
-        PrintF(out, "   %d: ", i);
+        PrintF(out, " %d:", i - 2);
         p->get(i)->ShortPrint(out);
-        PrintF(out, "\n");
       }
+      PrintF(out, "\n   context: ");
+      p->get(0)->ShortPrint(out);
+      PrintF(out, "\n   arguments: ");
+      p->get(1)->ShortPrint(out);
+      PrintF(out, "\n");
       break;
     }
   }
diff --git a/src/objects.cc b/src/objects.cc
index 944c5a1..324b10c 100644
--- a/src/objects.cc
+++ b/src/objects.cc
@@ -4157,14 +4157,12 @@
   HandleScope scope(isolate);
   Handle<JSObject> self(this);
 
-  Handle<String> name;
   Handle<Object> old_value;
-  bool preexists = false;
-  if (FLAG_harmony_observation && map()->is_observed()) {
-    name = isolate->factory()->Uint32ToString(index);
-    preexists = self->HasLocalElement(index);
-    if (preexists) {
-      old_value = GetLocalElementAccessorPair(index) != NULL
+  bool should_enqueue_change_record = false;
+  if (FLAG_harmony_observation && self->map()->is_observed()) {
+    should_enqueue_change_record = self->HasLocalElement(index);
+    if (should_enqueue_change_record) {
+      old_value = self->GetLocalElementAccessorPair(index) != NULL
           ? Handle<Object>::cast(isolate->factory()->the_hole_value())
           : Object::GetElement(self, index);
     }
@@ -4181,9 +4179,9 @@
   Handle<Object> hresult;
   if (!result->ToHandle(&hresult, isolate)) return result;
 
-  if (FLAG_harmony_observation && map()->is_observed()) {
-    if (preexists && !self->HasLocalElement(index))
-      EnqueueChangeRecord(self, "deleted", name, old_value);
+  if (should_enqueue_change_record && !self->HasLocalElement(index)) {
+    Handle<String> name = isolate->factory()->Uint32ToString(index);
+    EnqueueChangeRecord(self, "deleted", name, old_value);
   }
 
   return *hresult;
@@ -4243,7 +4241,8 @@
   Handle<String> hname(name);
 
   Handle<Object> old_value(isolate->heap()->the_hole_value());
-  if (FLAG_harmony_observation && map()->is_observed()) {
+  bool is_observed = FLAG_harmony_observation && self->map()->is_observed();
+  if (is_observed) {
     old_value = handle(lookup.GetLazyValue(), isolate);
   }
   MaybeObject* result;
@@ -4268,9 +4267,8 @@
   Handle<Object> hresult;
   if (!result->ToHandle(&hresult, isolate)) return result;
 
-  if (FLAG_harmony_observation && map()->is_observed()) {
-    if (!self->HasLocalProperty(*hname))
-      EnqueueChangeRecord(self, "deleted", hname, old_value);
+  if (is_observed && !self->HasLocalProperty(*hname)) {
+    EnqueueChangeRecord(self, "deleted", hname, old_value);
   }
 
   return *hresult;
@@ -4924,11 +4922,12 @@
   bool is_element = name->AsArrayIndex(&index);
 
   Handle<Object> old_value = isolate->factory()->the_hole_value();
+  bool is_observed = FLAG_harmony_observation && self->map()->is_observed();
   bool preexists = false;
-  if (FLAG_harmony_observation && map()->is_observed()) {
+  if (is_observed) {
     if (is_element) {
       preexists = HasLocalElement(index);
-      if (preexists && GetLocalElementAccessorPair(index) == NULL) {
+      if (preexists && self->GetLocalElementAccessorPair(index) == NULL) {
         old_value = Object::GetElement(self, index);
       }
     } else {
@@ -4946,7 +4945,7 @@
   Handle<Object> hresult;
   if (!result->ToHandle(&hresult, isolate)) return result;
 
-  if (FLAG_harmony_observation && map()->is_observed()) {
+  if (is_observed) {
     const char* type = preexists ? "reconfigured" : "new";
     EnqueueChangeRecord(self, type, name, old_value);
   }
@@ -8876,11 +8875,10 @@
 
 byte* Code::FindCodeAgeSequence() {
   return FLAG_age_code &&
-      strlen(FLAG_stop_at) == 0 &&
-      !ProfileEntryHookStub::HasEntryHook() &&
+      prologue_offset() != kPrologueOffsetNotSet &&
       (kind() == OPTIMIZED_FUNCTION ||
        (kind() == FUNCTION && !has_debug_break_slots()))
-      ? FindPlatformCodeAgeSequence()
+      ? instruction_start() + prologue_offset()
       : NULL;
 }
 
@@ -9283,9 +9281,8 @@
 
   // Allocate a new fast elements backing store.
   FixedArray* new_elements;
-  { MaybeObject* maybe = heap->AllocateFixedArrayWithHoles(capacity);
-    if (!maybe->To(&new_elements)) return maybe;
-  }
+  MaybeObject* maybe = heap->AllocateUninitializedFixedArray(capacity);
+  if (!maybe->To(&new_elements)) return maybe;
 
   ElementsKind elements_kind = GetElementsKind();
   ElementsKind new_elements_kind;
@@ -9309,10 +9306,10 @@
   }
   FixedArrayBase* old_elements = elements();
   ElementsAccessor* accessor = ElementsAccessor::ForKind(elements_kind);
-  { MaybeObject* maybe_obj =
-        accessor->CopyElements(this, new_elements, new_elements_kind);
-    if (maybe_obj->IsFailure()) return maybe_obj;
-  }
+  MaybeObject* maybe_obj =
+      accessor->CopyElements(this, new_elements, new_elements_kind);
+  if (maybe_obj->IsFailure()) return maybe_obj;
+
   if (elements_kind != NON_STRICT_ARGUMENTS_ELEMENTS) {
     Map* new_map = map();
     if (new_elements_kind != elements_kind) {
@@ -10345,7 +10342,7 @@
   Handle<Object> old_length;
 
   if (old_attributes != ABSENT) {
-    if (GetLocalElementAccessorPair(index) == NULL)
+    if (self->GetLocalElementAccessorPair(index) == NULL)
       old_value = Object::GetElement(self, index);
   } else if (self->IsJSArray()) {
     // Store old array length in case adding an element grows the array.
@@ -11598,9 +11595,8 @@
  public:
   explicit SubStringAsciiSymbolKey(Handle<SeqOneByteString> string,
                                    int from,
-                                   int length,
-                                   uint32_t seed)
-      : string_(string), from_(from), length_(length), seed_(seed) { }
+                                   int length)
+      : string_(string), from_(from), length_(length) { }
 
   uint32_t Hash() {
     ASSERT(length_ >= 0);
@@ -11657,7 +11653,6 @@
   int from_;
   int length_;
   uint32_t hash_field_;
-  uint32_t seed_;
 };
 
 
@@ -12583,7 +12578,7 @@
     int from,
     int length,
     Object** s) {
-  SubStringAsciiSymbolKey key(str, from, length, GetHeap()->HashSeed());
+  SubStringAsciiSymbolKey key(str, from, length);
   return LookupKey(&key, s);
 }
 
@@ -13271,8 +13266,7 @@
       PropertyType type = DetailsAt(i).type();
       ASSERT(type != FIELD);
       instance_descriptor_length++;
-      if (type == NORMAL &&
-          (!value->IsJSFunction() || heap->InNewSpace(value))) {
+      if (type == NORMAL && !value->IsJSFunction()) {
         number_of_fields += 1;
       }
     }
@@ -13337,7 +13331,7 @@
       int enumeration_index = details.descriptor_index();
       PropertyType type = details.type();
 
-      if (value->IsJSFunction() && !heap->InNewSpace(value)) {
+      if (value->IsJSFunction()) {
         ConstantFunctionDescriptor d(key,
                                      JSFunction::cast(value),
                                      details.attributes(),
diff --git a/src/objects.h b/src/objects.h
index 7d46c06..c476692 100644
--- a/src/objects.h
+++ b/src/objects.h
@@ -2489,7 +2489,6 @@
 
   // Casting.
   static inline FixedDoubleArray* cast(Object* obj);
-  static inline FixedDoubleArray* castOrEmptyFixedArray(Object* obj);
 
   // Maximal allowed size, in bytes, of a single FixedDoubleArray.
   // Prevents overflowing size computations, as well as extreme memory
@@ -4325,6 +4324,11 @@
   inline void set_ic_age(int count);
   inline int ic_age();
 
+  // [prologue_offset]: Offset of the function prologue, used for aging
+  // FUNCTIONs and OPTIMIZED_FUNCTIONs.
+  inline int prologue_offset();
+  inline void set_prologue_offset(int offset);
+
   // Unchecked accessors to be used during GC.
   inline ByteArray* unchecked_relocation_info();
   inline FixedArray* unchecked_deoptimization_data();
@@ -4593,8 +4597,10 @@
   static const int kKindSpecificFlags1Offset = kFlagsOffset + kIntSize;
   static const int kKindSpecificFlags2Offset =
       kKindSpecificFlags1Offset + kIntSize;
+  // Note: We might be able to squeeze this into the flags above.
+  static const int kPrologueOffset = kKindSpecificFlags2Offset + kIntSize;
 
-  static const int kHeaderPaddingStart = kKindSpecificFlags2Offset + kIntSize;
+  static const int kHeaderPaddingStart = kPrologueOffset + kIntSize;
 
   // Add padding to align the instruction start following right after
   // the Code object header.
@@ -4688,7 +4694,6 @@
   static Code* GetCodeAgeStub(Age age, MarkingParity parity);
 
   // Code aging -- platform-specific
-  byte* FindPlatformCodeAgeSequence();
   static void PatchPlatformCodeAge(byte* sequence, Age age,
                                    MarkingParity parity);
 
diff --git a/src/parser.cc b/src/parser.cc
index a7bb4e7..6e18381 100644
--- a/src/parser.cc
+++ b/src/parser.cc
@@ -3714,16 +3714,16 @@
   int literal_index = current_function_state_->NextMaterializedLiteralIndex();
 
   // Allocate a fixed array to hold all the object literals.
-  Handle<FixedArray> object_literals =
-      isolate()->factory()->NewFixedArray(values->length(), TENURED);
-  Handle<FixedDoubleArray> double_literals;
-  ElementsKind elements_kind = FAST_SMI_ELEMENTS;
-  bool has_hole_values = false;
+  Handle<JSArray> array =
+      isolate()->factory()->NewJSArray(0, FAST_HOLEY_SMI_ELEMENTS);
+  isolate()->factory()->SetElementsCapacityAndLength(
+      array, values->length(), values->length());
 
   // Fill in the literals.
   Heap* heap = isolate()->heap();
   bool is_simple = true;
   int depth = 1;
+  bool is_holey = false;
   for (int i = 0, n = values->length(); i < n; i++) {
     MaterializedLiteral* m_literal = values->at(i)->AsMaterializedLiteral();
     if (m_literal != NULL && m_literal->depth() + 1 > depth) {
@@ -3731,83 +3731,33 @@
     }
     Handle<Object> boilerplate_value = GetBoilerplateValue(values->at(i));
     if (boilerplate_value->IsTheHole()) {
-      has_hole_values = true;
-      object_literals->set_the_hole(i);
-      if (elements_kind == FAST_DOUBLE_ELEMENTS) {
-        double_literals->set_the_hole(i);
-      }
+      is_holey = true;
     } else if (boilerplate_value->IsUndefined()) {
       is_simple = false;
-      object_literals->set(i, Smi::FromInt(0));
-      if (elements_kind == FAST_DOUBLE_ELEMENTS) {
-        double_literals->set(i, 0);
-      }
+      JSObject::SetOwnElement(
+          array, i, handle(Smi::FromInt(0), isolate()), kNonStrictMode);
     } else {
-      // Examine each literal element, and adjust the ElementsKind if the
-      // literal element is not of a type that can be stored in the current
-      // ElementsKind.  Start with FAST_SMI_ONLY_ELEMENTS, and transition to
-      // FAST_DOUBLE_ELEMENTS and FAST_ELEMENTS as necessary.  Always remember
-      // the tagged value, no matter what the ElementsKind is in case we
-      // ultimately end up in FAST_ELEMENTS.
-      object_literals->set(i, *boilerplate_value);
-      if (elements_kind == FAST_SMI_ELEMENTS) {
-        // Smi only elements. Notice if a transition to FAST_DOUBLE_ELEMENTS or
-        // FAST_ELEMENTS is required.
-        if (!boilerplate_value->IsSmi()) {
-          if (boilerplate_value->IsNumber() && FLAG_smi_only_arrays) {
-            // Allocate a double array on the FAST_DOUBLE_ELEMENTS transition to
-            // avoid over-allocating in TENURED space.
-            double_literals = isolate()->factory()->NewFixedDoubleArray(
-                values->length(), TENURED);
-            // Copy the contents of the FAST_SMI_ONLY_ELEMENT array to the
-            // FAST_DOUBLE_ELEMENTS array so that they are in sync.
-            for (int j = 0; j < i; ++j) {
-              Object* smi_value = object_literals->get(j);
-              if (smi_value->IsTheHole()) {
-                double_literals->set_the_hole(j);
-              } else {
-                double_literals->set(j, Smi::cast(smi_value)->value());
-              }
-            }
-            double_literals->set(i, boilerplate_value->Number());
-            elements_kind = FAST_DOUBLE_ELEMENTS;
-          } else {
-            elements_kind = FAST_ELEMENTS;
-          }
-        }
-      } else if (elements_kind == FAST_DOUBLE_ELEMENTS) {
-        // Continue to store double values in to FAST_DOUBLE_ELEMENTS arrays
-        // until the first value is seen that can't be stored as a double.
-        if (boilerplate_value->IsNumber()) {
-          double_literals->set(i, boilerplate_value->Number());
-        } else {
-          elements_kind = FAST_ELEMENTS;
-        }
-      }
+      JSObject::SetOwnElement(array, i, boilerplate_value, kNonStrictMode);
     }
   }
 
+  Handle<FixedArrayBase> element_values(array->elements());
+
   // Simple and shallow arrays can be lazily copied, we transform the
   // elements array to a copy-on-write array.
   if (is_simple && depth == 1 && values->length() > 0 &&
-      elements_kind != FAST_DOUBLE_ELEMENTS) {
-    object_literals->set_map(heap->fixed_cow_array_map());
+      array->HasFastSmiOrObjectElements()) {
+    element_values->set_map(heap->fixed_cow_array_map());
   }
 
-  Handle<FixedArrayBase> element_values = elements_kind == FAST_DOUBLE_ELEMENTS
-      ? Handle<FixedArrayBase>(double_literals)
-      : Handle<FixedArrayBase>(object_literals);
-
   // Remember both the literal's constant values as well as the ElementsKind
   // in a 2-element FixedArray.
-  Handle<FixedArray> literals =
-      isolate()->factory()->NewFixedArray(2, TENURED);
+  Handle<FixedArray> literals = isolate()->factory()->NewFixedArray(2, TENURED);
 
-  if (has_hole_values || !FLAG_packed_arrays) {
-    elements_kind = GetHoleyElementsKind(elements_kind);
-  }
+  ElementsKind kind = array->GetElementsKind();
+  kind = is_holey ? GetHoleyElementsKind(kind) : GetPackedElementsKind(kind);
 
-  literals->set(0, Smi::FromInt(elements_kind));
+  literals->set(0, Smi::FromInt(kind));
   literals->set(1, *element_values);
 
   return factory()->NewArrayLiteral(
diff --git a/src/parser.h b/src/parser.h
index 93fd1b8..0f85f91 100644
--- a/src/parser.h
+++ b/src/parser.h
@@ -96,7 +96,6 @@
 
  private:
   Vector<unsigned> backing_;
-  bool owns_data_;
 };
 
 
diff --git a/src/spaces.cc b/src/spaces.cc
index 0ac23d2..cacd969 100644
--- a/src/spaces.cc
+++ b/src/spaces.cc
@@ -2391,10 +2391,13 @@
 HeapObject* PagedSpace::SlowAllocateRaw(int size_in_bytes) {
   // Allocation in this space has failed.
 
-  // If there are unswept pages advance lazy sweeper then sweep one page before
-  // allocating a new page.
-  if (first_unswept_page_->is_valid()) {
-    AdvanceSweeper(size_in_bytes);
+  // If there are unswept pages advance lazy sweeper a bounded number of times
+  // until we find a size_in_bytes contiguous piece of memory
+  const int kMaxSweepingTries = 5;
+  bool sweeping_complete = false;
+
+  for (int i = 0; i < kMaxSweepingTries && !sweeping_complete; i++) {
+    sweeping_complete = AdvanceSweeper(size_in_bytes);
 
     // Retry the free list allocation.
     HeapObject* object = free_list_.Allocate(size_in_bytes);
diff --git a/src/spaces.h b/src/spaces.h
index 4fbabd6..56f629e 100644
--- a/src/spaces.h
+++ b/src/spaces.h
@@ -503,6 +503,12 @@
     }
   }
 
+  bool IsLeftOfProgressBar(Object** slot) {
+    Address slot_address = reinterpret_cast<Address>(slot);
+    ASSERT(slot_address > this->address());
+    return (slot_address - (this->address() + kObjectStartOffset)) <
+           progress_bar();
+  }
 
   static void IncrementLiveBytesFromGC(Address address, int by) {
     MemoryChunk::FromAddress(address)->IncrementLiveBytes(by);
@@ -2434,11 +2440,9 @@
   FixedSpace(Heap* heap,
              intptr_t max_capacity,
              AllocationSpace id,
-             int object_size_in_bytes,
-             const char* name)
+             int object_size_in_bytes)
       : PagedSpace(heap, max_capacity, id, NOT_EXECUTABLE),
-        object_size_in_bytes_(object_size_in_bytes),
-        name_(name) {
+        object_size_in_bytes_(object_size_in_bytes) {
     page_extra_ = Page::kNonCodeObjectAreaSize % object_size_in_bytes;
   }
 
@@ -2455,9 +2459,6 @@
  private:
   // The size of objects in this space.
   int object_size_in_bytes_;
-
-  // The name of this space.
-  const char* name_;
 };
 
 
@@ -2468,7 +2469,7 @@
  public:
   // Creates a map space object with a maximum capacity.
   MapSpace(Heap* heap, intptr_t max_capacity, AllocationSpace id)
-      : FixedSpace(heap, max_capacity, id, Map::kSize, "map"),
+      : FixedSpace(heap, max_capacity, id, Map::kSize),
         max_map_space_pages_(kMaxMapPageIndex - 1) {
   }
 
@@ -2509,7 +2510,7 @@
  public:
   // Creates a property cell space object with a maximum capacity.
   CellSpace(Heap* heap, intptr_t max_capacity, AllocationSpace id)
-      : FixedSpace(heap, max_capacity, id, JSGlobalPropertyCell::kSize, "cell")
+      : FixedSpace(heap, max_capacity, id, JSGlobalPropertyCell::kSize)
   {}
 
   virtual int RoundSizeDownToObjectAlignment(int size) {
diff --git a/src/store-buffer.h b/src/store-buffer.h
index 0ade8ce..79046d1 100644
--- a/src/store-buffer.h
+++ b/src/store-buffer.h
@@ -210,8 +210,7 @@
   explicit StoreBufferRebuildScope(Heap* heap,
                                    StoreBuffer* store_buffer,
                                    StoreBufferCallback callback)
-      : heap_(heap),
-        store_buffer_(store_buffer),
+      : store_buffer_(store_buffer),
         stored_state_(store_buffer->store_buffer_rebuilding_enabled_),
         stored_callback_(store_buffer->callback_) {
     store_buffer_->store_buffer_rebuilding_enabled_ = true;
@@ -226,7 +225,6 @@
   }
 
  private:
-  Heap* heap_;
   StoreBuffer* store_buffer_;
   bool stored_state_;
   StoreBufferCallback stored_callback_;
diff --git a/src/version.cc b/src/version.cc
index 1b7f5c8..bd75eeb 100644
--- a/src/version.cc
+++ b/src/version.cc
@@ -34,8 +34,8 @@
 // cannot be changed without changing the SCons build script.
 #define MAJOR_VERSION     3
 #define MINOR_VERSION     15
-#define BUILD_NUMBER      6
-#define PATCH_LEVEL       2
+#define BUILD_NUMBER      7
+#define PATCH_LEVEL       0
 // Use 1 for candidates and 0 otherwise.
 // (Boolean macro values are not supported by all preprocessors.)
 #define IS_CANDIDATE_VERSION 0
diff --git a/src/vm-state-inl.h b/src/vm-state-inl.h
index 97febd0..bc48160 100644
--- a/src/vm-state-inl.h
+++ b/src/vm-state-inl.h
@@ -67,6 +67,10 @@
     LOG(isolate, UncheckedStringEvent("From", StateToString(previous_tag_)));
   }
 
+  if (FLAG_log_timer_events) {
+    LOG(isolate, ExternalSwitch(previous_tag_, tag));
+  }
+
   isolate_->SetCurrentVMState(tag);
 }
 
@@ -80,6 +84,10 @@
         UncheckedStringEvent("To", StateToString(previous_tag_)));
   }
 
+  if (FLAG_log_timer_events) {
+    LOG(isolate_, ExternalSwitch(isolate_->current_vm_state(), previous_tag_));
+  }
+
   isolate_->SetCurrentVMState(previous_tag_);
 }
 
diff --git a/src/x64/codegen-x64.cc b/src/x64/codegen-x64.cc
index e2471e6..67d1d90 100644
--- a/src/x64/codegen-x64.cc
+++ b/src/x64/codegen-x64.cc
@@ -681,28 +681,6 @@
 }
 
 
-byte* Code::FindPlatformCodeAgeSequence() {
-  byte* start = instruction_start();
-  uint32_t young_length;
-  byte* young_sequence = GetNoCodeAgeSequence(&young_length);
-  if (!memcmp(start, young_sequence, young_length) ||
-      *start == kCallOpcode) {
-    return start;
-  } else {
-    byte* start_after_strict = NULL;
-    if (kind() == FUNCTION) {
-      start_after_strict = start + kSizeOfFullCodegenStrictModePrologue;
-    } else {
-      ASSERT(kind() == OPTIMIZED_FUNCTION);
-      start_after_strict = start + kSizeOfOptimizedStrictModePrologue;
-    }
-    ASSERT(!memcmp(start_after_strict, young_sequence, young_length) ||
-           *start_after_strict == kCallOpcode);
-    return start_after_strict;
-  }
-}
-
-
 bool Code::IsYoungSequence(byte* sequence) {
   uint32_t young_length;
   byte* young_sequence = GetNoCodeAgeSequence(&young_length);
diff --git a/src/x64/codegen-x64.h b/src/x64/codegen-x64.h
index 73438d7..d444095 100644
--- a/src/x64/codegen-x64.h
+++ b/src/x64/codegen-x64.h
@@ -39,9 +39,6 @@
 
 enum TypeofState { INSIDE_TYPEOF, NOT_INSIDE_TYPEOF };
 
-static const int kSizeOfFullCodegenStrictModePrologue = 14;
-static const int kSizeOfOptimizedStrictModePrologue = 14;
-
 // -------------------------------------------------------------------------
 // CodeGenerator
 
diff --git a/src/x64/full-codegen-x64.cc b/src/x64/full-codegen-x64.cc
index 1e16c66..650337a 100644
--- a/src/x64/full-codegen-x64.cc
+++ b/src/x64/full-codegen-x64.cc
@@ -138,8 +138,6 @@
   // function calls.
   if (!info->is_classic_mode() || info->is_native()) {
     Label ok;
-    Label begin;
-    __ bind(&begin);
     __ testq(rcx, rcx);
     __ j(zero, &ok, Label::kNear);
     // +1 for return address.
@@ -147,8 +145,6 @@
     __ LoadRoot(kScratchRegister, Heap::kUndefinedValueRootIndex);
     __ movq(Operand(rsp, receiver_offset), kScratchRegister);
     __ bind(&ok);
-    ASSERT(!FLAG_age_code ||
-           (kSizeOfFullCodegenStrictModePrologue == ok.pos() - begin.pos()));
   }
 
   // Open a frame scope to indicate that there is a frame on the stack.  The
@@ -156,6 +152,7 @@
   // the frame (that is done below).
   FrameScope frame_scope(masm_, StackFrame::MANUAL);
 
+  info->set_prologue_offset(masm_->pc_offset());
   __ push(rbp);  // Caller's frame pointer.
   __ movq(rbp, rsp);
   __ push(rsi);  // Callee's context.
diff --git a/src/x64/lithium-codegen-x64.cc b/src/x64/lithium-codegen-x64.cc
index c430465..9217a94 100644
--- a/src/x64/lithium-codegen-x64.cc
+++ b/src/x64/lithium-codegen-x64.cc
@@ -133,8 +133,6 @@
   // object). rcx is zero for method calls and non-zero for function
   // calls.
   if (!info_->is_classic_mode() || info_->is_native()) {
-    Label begin;
-    __ bind(&begin);
     Label ok;
     __ testq(rcx, rcx);
     __ j(zero, &ok, Label::kNear);
@@ -143,10 +141,9 @@
     __ LoadRoot(kScratchRegister, Heap::kUndefinedValueRootIndex);
     __ movq(Operand(rsp, receiver_offset), kScratchRegister);
     __ bind(&ok);
-    ASSERT(!FLAG_age_code ||
-           (kSizeOfOptimizedStrictModePrologue == ok.pos() - begin.pos()));
   }
 
+  info()->set_prologue_offset(masm_->pc_offset());
   __ push(rbp);  // Caller's frame pointer.
   __ movq(rbp, rsp);
   __ push(rsi);  // Callee's context.
diff --git a/src/x64/macro-assembler-x64.cc b/src/x64/macro-assembler-x64.cc
index 5b85a24..4e4f2c5 100644
--- a/src/x64/macro-assembler-x64.cc
+++ b/src/x64/macro-assembler-x64.cc
@@ -720,11 +720,28 @@
   movq(prev_next_address_reg, Operand(base_reg, kNextOffset));
   movq(prev_limit_reg, Operand(base_reg, kLimitOffset));
   addl(Operand(base_reg, kLevelOffset), Immediate(1));
+
+  if (FLAG_log_timer_events) {
+    FrameScope frame(this, StackFrame::MANUAL);
+    PushSafepointRegisters();
+    PrepareCallCFunction(0);
+    CallCFunction(ExternalReference::log_enter_external_function(isolate()), 0);
+    PopSafepointRegisters();
+  }
+
   // Call the api function!
   movq(rax, reinterpret_cast<int64_t>(function_address),
        RelocInfo::RUNTIME_ENTRY);
   call(rax);
 
+  if (FLAG_log_timer_events) {
+    FrameScope frame(this, StackFrame::MANUAL);
+    PushSafepointRegisters();
+    PrepareCallCFunction(0);
+    CallCFunction(ExternalReference::log_leave_external_function(isolate()), 0);
+    PopSafepointRegisters();
+  }
+
 #if defined(_WIN64) && !defined(__MINGW64__)
   // rax keeps a pointer to v8::Handle, unpack it.
   movq(rax, Operand(rax, 0));
diff --git a/src/x64/stub-cache-x64.cc b/src/x64/stub-cache-x64.cc
index cd0124b..683aa9d 100644
--- a/src/x64/stub-cache-x64.cc
+++ b/src/x64/stub-cache-x64.cc
@@ -4108,16 +4108,16 @@
     __ Move(FieldOperand(rdi, FixedDoubleArray::kLengthOffset),
             Smi::FromInt(JSArray::kPreallocatedArrayElements));
 
-    __ movq(r8, BitCast<int64_t, uint64_t>(kHoleNanInt64), RelocInfo::NONE);
-    for (int i = 1; i < JSArray::kPreallocatedArrayElements; i++) {
-      __ movq(FieldOperand(rdi, FixedDoubleArray::OffsetOfElementAt(i)), r8);
-    }
-
     // Increment the length of the array.
     __ SmiToInteger32(rcx, rcx);
     __ StoreNumberToDoubleElements(rax, rdi, rcx, xmm0,
                                    &restore_key_transition_elements_kind);
 
+    __ movq(r8, BitCast<int64_t, uint64_t>(kHoleNanInt64), RelocInfo::NONE);
+    for (int i = 1; i < JSArray::kPreallocatedArrayElements; i++) {
+      __ movq(FieldOperand(rdi, FixedDoubleArray::OffsetOfElementAt(i)), r8);
+    }
+
     // Install the new backing store in the JSArray.
     __ movq(FieldOperand(rdx, JSObject::kElementsOffset), rdi);
     __ RecordWriteField(rdx, JSObject::kElementsOffset, rdi, rbx,
diff --git a/test/cctest/test-api.cc b/test/cctest/test-api.cc
index a51d301..aa85e2a 100644
--- a/test/cctest/test-api.cc
+++ b/test/cctest/test-api.cc
@@ -626,6 +626,8 @@
 
 
 THREADED_TEST(ScavengeExternalString) {
+  i::FLAG_stress_compaction = false;
+  i::FLAG_gc_global = false;
   int dispose_count = 0;
   bool in_new_space = false;
   {
@@ -646,6 +648,8 @@
 
 
 THREADED_TEST(ScavengeExternalAsciiString) {
+  i::FLAG_stress_compaction = false;
+  i::FLAG_gc_global = false;
   int dispose_count = 0;
   bool in_new_space = false;
   {
@@ -2546,6 +2550,8 @@
 // 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) {
+  i::FLAG_stress_compaction = false;
+  i::FLAG_gc_global = false;
   HandleScope scope;
   LocalContext env;
 
@@ -17987,7 +17993,6 @@
 
    private:
      ThreadInterruptTest* test_;
-     struct sigaction sa_;
   };
 
   i::Semaphore* sem_;
diff --git a/test/cctest/test-heap-profiler.cc b/test/cctest/test-heap-profiler.cc
index 5235971..eeb5a9d 100644
--- a/test/cctest/test-heap-profiler.cc
+++ b/test/cctest/test-heap-profiler.cc
@@ -1015,7 +1015,6 @@
 
  private:
   bool disposed_;
-  int category_;
   int hash_;
   const char* group_label_;
   const char* label_;
diff --git a/test/cctest/test-heap.cc b/test/cctest/test-heap.cc
index a51b37e..f5bac2c 100644
--- a/test/cctest/test-heap.cc
+++ b/test/cctest/test-heap.cc
@@ -1944,7 +1944,7 @@
   if (!i::V8::UseCrankshaft() || i::FLAG_always_opt) return;
   v8::HandleScope scope;
 
-  FillUpNewSpace(HEAP->new_space());
+  SimulateFullSpace(HEAP->new_space());
   AlwaysAllocateScope always_allocate;
   v8::Local<v8::Value> res = CompileRun(
       "function c(x) {"
@@ -2153,14 +2153,9 @@
 
     // Generate a sliced string that is based on the above parent and
     // lives in old-space.
-    FillUpNewSpace(HEAP->new_space());
+    SimulateFullSpace(HEAP->new_space());
     AlwaysAllocateScope always_allocate;
-    Handle<String> t;
-    // TODO(mstarzinger): Unfortunately FillUpNewSpace() still leaves
-    // some slack, so we need to allocate a few sliced strings.
-    for (int i = 0; i < 16; i++) {
-      t = FACTORY->NewProperSubString(s, 5, 35);
-    }
+    Handle<String> t = FACTORY->NewProperSubString(s, 5, 35);
     CHECK(t->IsSlicedString());
     CHECK(!HEAP->InNewSpace(*t));
     *slice.location() = *t.location();
diff --git a/test/cctest/test-lockers.cc b/test/cctest/test-lockers.cc
index 5035f87..57f7178 100644
--- a/test/cctest/test-lockers.cc
+++ b/test/cctest/test-lockers.cc
@@ -59,9 +59,9 @@
 class KangarooThread : public v8::internal::Thread {
  public:
   KangarooThread(v8::Isolate* isolate,
-                 v8::Handle<v8::Context> context, int value)
+                 v8::Handle<v8::Context> context)
       : Thread("KangarooThread"),
-        isolate_(isolate), context_(context), value_(value) {
+        isolate_(isolate), context_(context) {
   }
 
   void Run() {
@@ -90,7 +90,6 @@
  private:
   v8::Isolate* isolate_;
   Persistent<v8::Context> context_;
-  int value_;
 };
 
 // Migrates an isolate from one thread to another
@@ -106,7 +105,7 @@
     CHECK_EQ(isolate, v8::internal::Isolate::Current());
     CompileRun("function getValue() { return 30; }");
   }
-  KangarooThread thread1(isolate, context, 1);
+  KangarooThread thread1(isolate, context);
   thread1.Start();
   thread1.Join();
 }
diff --git a/test/cctest/test-log.cc b/test/cctest/test-log.cc
index 6f2324d..892a542 100644
--- a/test/cctest/test-log.cc
+++ b/test/cctest/test-log.cc
@@ -392,7 +392,7 @@
 
   i::EmbeddedVector<char, 100> ref_data;
   i::OS::SNPrintF(ref_data,
-                  "code-creation,Callback,0x%" V8PRIxPTR ",1,\"method1\"\0",
+                  "code-creation,Callback,-3,0x%" V8PRIxPTR ",1,\"method1\"\0",
                   ObjMethod1);
 
   CHECK_NE(NULL, StrNStr(log.start(), ref_data.start(), log.length()));
@@ -435,21 +435,21 @@
 
   EmbeddedVector<char, 100> prop1_getter_record;
   i::OS::SNPrintF(prop1_getter_record,
-                  "code-creation,Callback,0x%" V8PRIxPTR ",1,\"get prop1\"",
+                  "code-creation,Callback,-3,0x%" V8PRIxPTR ",1,\"get prop1\"",
                   Prop1Getter);
   CHECK_NE(NULL,
            StrNStr(log.start(), prop1_getter_record.start(), log.length()));
 
   EmbeddedVector<char, 100> prop1_setter_record;
   i::OS::SNPrintF(prop1_setter_record,
-                  "code-creation,Callback,0x%" V8PRIxPTR ",1,\"set prop1\"",
+                  "code-creation,Callback,-3,0x%" V8PRIxPTR ",1,\"set prop1\"",
                   Prop1Setter);
   CHECK_NE(NULL,
            StrNStr(log.start(), prop1_setter_record.start(), log.length()));
 
   EmbeddedVector<char, 100> prop2_getter_record;
   i::OS::SNPrintF(prop2_getter_record,
-                  "code-creation,Callback,0x%" V8PRIxPTR ",1,\"get prop2\"",
+                  "code-creation,Callback,-3,0x%" V8PRIxPTR ",1,\"get prop2\"",
                   Prop2Getter);
   CHECK_NE(NULL,
            StrNStr(log.start(), prop2_getter_record.start(), log.length()));
diff --git a/test/cctest/test-mark-compact.cc b/test/cctest/test-mark-compact.cc
index c0ab763..69abd8d 100644
--- a/test/cctest/test-mark-compact.cc
+++ b/test/cctest/test-mark-compact.cc
@@ -311,6 +311,7 @@
 }
 
 TEST(ObjectGroups) {
+  FLAG_incremental_marking = false;
   InitializeVM();
   GlobalHandles* global_handles = Isolate::Current()->global_handles();
 
diff --git a/test/mjsunit/regress/regress-121407.js b/test/mjsunit/regress/regress-121407.js
index 25033fb..4403708 100644
--- a/test/mjsunit/regress/regress-121407.js
+++ b/test/mjsunit/regress/regress-121407.js
@@ -37,4 +37,4 @@
 a.length=2000;
 for (var i = 0; i <= 256; i++) {
     a[i] = new Object();
-}
\ No newline at end of file
+}
diff --git a/test/mjsunit/regress/regress-2433.js b/test/mjsunit/regress/regress-2433.js
new file mode 100644
index 0000000..dfe7131
--- /dev/null
+++ b/test/mjsunit/regress/regress-2433.js
@@ -0,0 +1,36 @@
+// Copyright 2012 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.
+
+// Transitioning from a PackedSmi to PackedDouble should fill the destination
+// with holes.
+//
+// See http://code.google.com/p/v8/issues/detail?id=2433 for details.
+
+arr = [];
+arr[0] = 0;
+arr[0] = 1.1;
+assertEquals(undefined, arr[1]);
diff --git a/test/mjsunit/regress/regress-crbug-162085.js b/test/mjsunit/regress/regress-crbug-162085.js
index f26c711..a53b2c9 100644
--- a/test/mjsunit/regress/regress-crbug-162085.js
+++ b/test/mjsunit/regress/regress-crbug-162085.js
@@ -30,6 +30,7 @@
 var a = [1,2,3];
 a.length = 0;
 a[0] = 1.4;
+assertEquals(1.4, a[0]);
 assertEquals(undefined, a[1]);
 assertEquals(undefined, a[2]);
 assertEquals(undefined, a[3]);
@@ -43,6 +44,7 @@
 grow_store(a2,1,1.4);
 a2.length = 0;
 grow_store(a2,0,1.5);
+assertEquals(1.5, a2[0]);
 assertEquals(undefined, a2[1]);
 assertEquals(undefined, a2[2]);
 assertEquals(undefined, a2[3]);
@@ -53,3 +55,17 @@
 grow_store(a3, 1, o);
 assertEquals(1.3, a3[0]);
 assertEquals(o, a3[1]);
+
+// Ensure the double array growstub initializes the array with holes.
+function grow_store2(a,i,v) {
+  a[i] = v;
+}
+
+var a4 = [1.3];
+grow_store2(a4,1,1.4);
+a4.length = 0;
+grow_store2(a4,0,1);
+assertEquals(1, a4[0]);
+assertEquals(undefined, a4[1]);
+assertEquals(undefined, a4[2]);
+assertEquals(undefined, a4[3]);
diff --git a/test/mjsunit/regress/regress-observe-empty-double-array.js b/test/mjsunit/regress/regress-observe-empty-double-array.js
new file mode 100644
index 0000000..aea9c73
--- /dev/null
+++ b/test/mjsunit/regress/regress-observe-empty-double-array.js
@@ -0,0 +1,37 @@
+// Copyright 2012 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.
+
+// Flags: --harmony-observation --allow-natives-syntax
+//
+// Test passes if it does not crash.
+
+arr = [1.1];
+Object.observe(arr, function(){});
+arr.length = 0;
+assertTrue(%HasFastDoubleElements(arr));
+// Should not crash
+arr.push(1.1);
diff --git a/test/mjsunit/tools/tickprocessor-test-func-info.log b/test/mjsunit/tools/tickprocessor-test-func-info.log
index e4015d4..5e64dc0 100644
--- a/test/mjsunit/tools/tickprocessor-test-func-info.log
+++ b/test/mjsunit/tools/tickprocessor-test-func-info.log
@@ -2,10 +2,10 @@
 shared-library,"/lib32/libm-2.7.so",0xf7db6000,0xf7dd9000
 shared-library,"ffffe000-fffff000",0xffffe000,0xfffff000
 profiler,"begin",1
-code-creation,Stub,0x424260,348,"CompareStub_GE"
-code-creation,LazyCompile,0x2a8100,18535,"DrawQube 3d-cube.js:188",0xf43abcac,
-code-creation,LazyCompile,0x480100,3908,"DrawLine 3d-cube.js:17",0xf43abc50,
-tick,0x424284,0xbfffeea0,0,0x480600,0,0x2aaaa5
-tick,0x42429f,0xbfffed88,0,0x480600,0,0x2aacb4
-tick,0x48063d,0xbfffec7c,0,0x2d0f7c,0,0x2aaec6
+code-creation,Stub,0,0x424260,348,"CompareStub_GE"
+code-creation,LazyCompile,0,0x2a8100,18535,"DrawQube 3d-cube.js:188",0xf43abcac,
+code-creation,LazyCompile,0,0x480100,3908,"DrawLine 3d-cube.js:17",0xf43abc50,
+tick,0x424284,0xbfffeea0,0,0,0x480600,0,0x2aaaa5
+tick,0x42429f,0xbfffed88,0,0,0x480600,0,0x2aacb4
+tick,0x48063d,0xbfffec7c,0,0,0x2d0f7c,0,0x2aaec6
 profiler,"end"
diff --git a/test/mjsunit/tools/tickprocessor-test.log b/test/mjsunit/tools/tickprocessor-test.log
index db8be79..5ddad89 100644
--- a/test/mjsunit/tools/tickprocessor-test.log
+++ b/test/mjsunit/tools/tickprocessor-test.log
@@ -2,24 +2,24 @@
 shared-library,"/lib32/libm-2.7.so",0xf7db6000,0xf7dd9000
 shared-library,"ffffe000-fffff000",0xffffe000,0xfffff000
 profiler,"begin",1
-code-creation,Stub,0xf540a100,474,"CEntryStub"
-code-creation,Script,0xf541cd80,736,"exp.js"
-code-creation,Stub,0xf541d0e0,47,"RuntimeStub_Math_exp"
-code-creation,LazyCompile,0xf541d120,145,"exp native math.js:41"
+code-creation,Stub,0,0xf540a100,474,"CEntryStub"
+code-creation,Script,0,0xf541cd80,736,"exp.js"
+code-creation,Stub,0,0xf541d0e0,47,"RuntimeStub_Math_exp"
+code-creation,LazyCompile,0,0xf541d120,145,"exp native math.js:41"
 function-creation,0xf441d280,0xf541d120
-code-creation,LoadIC,0xf541d280,117,"j"
-code-creation,LoadIC,0xf541d360,63,"i"
-tick,0x80f82d1,0xffdfe880,0,0,0,0xf541ce5c
-tick,0x80f89a1,0xffdfecf0,0,0,0,0xf541ce5c
-tick,0x8123b5c,0xffdff1a0,0,0,0,0xf541d1a1,0xf541ceea
-tick,0x8123b65,0xffdff1a0,0,0,0,0xf541d1a1,0xf541ceea
-tick,0xf541d2be,0xffdff1e4,0,0,0
-tick,0xf541d320,0xffdff1dc,0,0,0
-tick,0xf541d384,0xffdff1d8,0,0,0
-tick,0xf7db94da,0xffdff0ec,0,0,0,0xf541d1a1,0xf541ceea
-tick,0xf7db951c,0xffdff0f0,0,0,0,0xf541d1a1,0xf541ceea
-tick,0xf7dbc508,0xffdff14c,0,0,0,0xf541d1a1,0xf541ceea
-tick,0xf7dbff21,0xffdff198,0,0,0,0xf541d1a1,0xf541ceea
-tick,0xf7edec90,0xffdff0ec,0,0,0,0xf541d1a1,0xf541ceea
-tick,0xffffe402,0xffdff488,0,0,0
+code-creation,LoadIC,0,0xf541d280,117,"j"
+code-creation,LoadIC,0,0xf541d360,63,"i"
+tick,0x80f82d1,0xffdfe880,0,0,0,0,0xf541ce5c
+tick,0x80f89a1,0xffdfecf0,0,0,0,0,0xf541ce5c
+tick,0x8123b5c,0xffdff1a0,0,0,0,0,0xf541d1a1,0xf541ceea
+tick,0x8123b65,0xffdff1a0,0,0,0,0,0xf541d1a1,0xf541ceea
+tick,0xf541d2be,0xffdff1e4,0,0,0,0
+tick,0xf541d320,0xffdff1dc,0,0,0,0
+tick,0xf541d384,0xffdff1d8,0,0,0,0
+tick,0xf7db94da,0xffdff0ec,0,0,0,0,0xf541d1a1,0xf541ceea
+tick,0xf7db951c,0xffdff0f0,0,0,0,0,0xf541d1a1,0xf541ceea
+tick,0xf7dbc508,0xffdff14c,0,0,0,0,0xf541d1a1,0xf541ceea
+tick,0xf7dbff21,0xffdff198,0,0,0,0,0xf541d1a1,0xf541ceea
+tick,0xf7edec90,0xffdff0ec,0,0,0,0,0xf541d1a1,0xf541ceea
+tick,0xffffe402,0xffdff488,0,0,0,0
 profiler,"end"
diff --git a/tools/plot-timer-events b/tools/plot-timer-events
index 1db2c31..efa82bc 100755
--- a/tools/plot-timer-events
+++ b/tools/plot-timer-events
@@ -34,6 +34,7 @@
 
 # nm spits out 'no symbols found' messages to stderr.
 cat $log_file | $d8_exec $tools_path/csvparser.js \
+    $tools_path/splaytree.js $tools_path/codemap.js \
     $tools_path/logreader.js $tools_path/plot-timer-events.js \
     2>/dev/null | gnuplot > timer-events.png
 
diff --git a/tools/plot-timer-events.js b/tools/plot-timer-events.js
index 8ef0b8e..a41f080 100644
--- a/tools/plot-timer-events.js
+++ b/tools/plot-timer-events.js
@@ -25,50 +25,83 @@
 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 
-var kExecutionName = 'V8.Execute';
+var kV8BinarySuffixes = ["/d8", "/libv8.so"];
+var kStackFrames = 8;
 
-var TimerEvents = {
-  'V8.Execute':
-       { ranges: [], color: "#444444", pause: false, index:  1 },
-  'V8.CompileFullCode':
-       { ranges: [], color: "#CC0000", pause:  true, index:  2 },
-  'V8.RecompileSynchronous':
-       { ranges: [], color: "#CC0044", pause:  true, index:  3 },
-  'V8.RecompileParallel':
-       { ranges: [], color: "#CC4499", pause: false, index:  4 },
-  'V8.CompileEval':
-       { ranges: [], color: "#CC4400", pause:  true, index:  5 },
-  'V8.Parse':
-       { ranges: [], color: "#00CC00", pause:  true, index:  6 },
-  'V8.PreParse':
-       { ranges: [], color: "#44CC00", pause:  true, index:  7 },
-  'V8.ParseLazy':
-       { ranges: [], color: "#00CC44", pause:  true, index:  8 },
-  'V8.GCScavenger':
-       { ranges: [], color: "#0044CC", pause:  true, index:  9 },
-  'V8.GCCompactor':
-       { ranges: [], color: "#4444CC", pause:  true, index: 10 },
-  'V8.GCContext':
-       { ranges: [], color: "#4400CC", pause:  true, index: 11 },
-}
+var kTimerEventWidth = 0.33;
+var kExecutionFrameWidth = 0.2;
+var kStackFrameWidth = 0.1;
+var kGapWidth = 0.05;
 
-var kNumRows = 11;
-var kBarWidth = 0.33;
-var kPauseTolerance = 0.05;  // Milliseconds.
-var kY1Offset = 3;
-var kY2Factor = 5;
+var kPauseTolerance = 0.1;  // Milliseconds.
+var kY1Offset = 10;
+
 var kResX = 1600;
-var kResY = 400;
-var kLabelPadding = 5;
+var kResY = 600;
+var kPauseLabelPadding = 5;
 var kNumPauseLabels = 7;
+var kTickHalfDuration = 0.5;  // Milliseconds
+var kCodeKindLabelPadding = 100;
 
 var kOverrideRangeStart = undefined;
 var kOverrideRangeEnd = undefined;
 
+var num_timer_event = kY1Offset + 0.5;
+
+
+function TimerEvent(color, pause, no_execution) {
+  this.color = color;
+  this.pause = pause;
+  this.ranges = [];
+  this.no_execution = no_execution;
+  this.index = ++num_timer_event;
+}
+
+
+var TimerEvents = {
+  'V8.Execute':              new TimerEvent("#000000", false, false),
+  'V8.External':             new TimerEvent("#3399FF", false,  true),
+  'V8.CompileFullCode':      new TimerEvent("#CC0000",  true,  true),
+  'V8.RecompileSynchronous': new TimerEvent("#CC0044",  true,  true),
+  'V8.RecompileParallel':    new TimerEvent("#CC4499", false, false),
+  'V8.CompileEval':          new TimerEvent("#CC4400",  true,  true),
+  'V8.Parse':                new TimerEvent("#00CC00",  true,  true),
+  'V8.PreParse':             new TimerEvent("#44CC00",  true,  true),
+  'V8.ParseLazy':            new TimerEvent("#00CC44",  true,  true),
+  'V8.GCScavenger':          new TimerEvent("#0044CC",  true,  true),
+  'V8.GCCompactor':          new TimerEvent("#4444CC",  true,  true),
+  'V8.GCContext':            new TimerEvent("#4400CC",  true,  true),
+}
+
+var kExecutionEvent = TimerEvents['V8.Execute'];
+
+
+function CodeKind(color, kinds) {
+  this.color = color;
+  this.in_execution = [];
+  this.stack_frames = [];
+  for (var i = 0; i < kStackFrames; i++) this.stack_frames.push([]);
+  this.kinds = kinds;
+}
+
+
+var CodeKinds = {
+  'external ': new CodeKind("#3399FF", [-3]),
+  'reg.exp. ': new CodeKind("#0000FF", [-2]),
+  'runtime  ': new CodeKind("#000000", [-1]),
+  'full code': new CodeKind("#DD0000", [0]),
+  'opt code ': new CodeKind("#00EE00", [1]),
+  'code stub': new CodeKind("#FF00FF", [2]),
+  'built-in ': new CodeKind("#AA00AA", [3]),
+  'inl.cache': new CodeKind("#4444AA", [4, 5, 6, 7, 8, 9, 10, 11, 12, 13]),
+}
+
+
 var xrange_start = Infinity;
 var xrange_end = 0;
 var obj_index = 0;
 var execution_pauses = [];
+var code_map = new CodeMap();
 
 
 function Range(start, end) {
@@ -88,19 +121,89 @@
   length /= 1000;
   var end = start + length;
   event.ranges.push(new Range(start, end));
-  if (name == kExecutionName) {
+  if (event == kExecutionEvent) {
     if (start < xrange_start) xrange_start = start;
     if (end > xrange_end) xrange_end = end;
   }
 }
 
 
+function ProcessCodeCreateEvent(type, kind, address, size, name) {
+  var code_entry = new CodeMap.CodeEntry(size, name);
+  code_entry.kind = kind;
+  code_map.addCode(address, code_entry);
+}
+
+
+function ProcessCodeMoveEvent(from, to) {
+  code_map.moveCode(from, to);
+}
+
+
+function ProcessCodeDeleteEvent(address) {
+  code_map.deleteCode(address);
+}
+
+
+function ProcessSharedLibrary(name, start, end) {
+  var code_entry = new CodeMap.CodeEntry(end - start, name);
+  code_entry.kind = -3;  // External code kind.
+  for (var i = 0; i < kV8BinarySuffixes.length; i++) {
+    var suffix = kV8BinarySuffixes[i];
+    if (name.indexOf(suffix, name.length - suffix.length) >= 0) {
+      code_entry.kind = -1;  // V8 runtime code kind.
+      break;
+    }
+  }
+  code_map.addLibrary(start, code_entry);
+}
+
+
+function FindCodeKind(kind) {
+  for (name in CodeKinds) {
+    if (CodeKinds[name].kinds.indexOf(kind) >= 0) {
+      return CodeKinds[name];
+    }
+  }
+}
+
+
+function ProcessTickEvent(pc, sp, timer, unused_x, unused_y, vmstate, stack) {
+  timer /= 1000;
+  var tick = new Range(timer - kTickHalfDuration, timer + kTickHalfDuration);
+
+  var entry = code_map.findEntry(pc);
+  if (entry) {
+    FindCodeKind(entry.kind).in_execution.push(tick);
+  }
+
+  for (var i = 0; i < kStackFrames; i++) {
+    if (!stack[i]) break;
+    var entry = code_map.findEntry(stack[i]);
+    if (entry) {
+      FindCodeKind(entry.kind).stack_frames[i].push(tick);
+    }
+  }
+}
+
+
 function CollectData() {
   // Collect data from log.
   var logreader = new LogReader(
-    { 'timer-event' : { parsers: [null, parseInt, parseInt],
-                        processor: ProcessTimerEvent
-                      } });
+    { 'timer-event' :   { parsers: [null, parseInt, parseInt],
+                          processor: ProcessTimerEvent },
+      'shared-library': { parsers: [null, parseInt, parseInt],
+                          processor: ProcessSharedLibrary },
+      'code-creation':  { parsers: [null, parseInt, parseInt, parseInt, null],
+                          processor: ProcessCodeCreateEvent },
+      'code-move':      { parsers: [parseInt, parseInt],
+                          processor: ProcessCodeMoveEvent },
+      'code-delete':    { parsers: [parseInt],
+                          processor: ProcessCodeDeleteEvent },
+      'tick':           { parsers: [parseInt, parseInt, parseInt,
+                                    null, null, parseInt, 'var-args'],
+                          processor: ProcessTickEvent },
+    });
 
   var line;
   while (line = readline()) {
@@ -112,25 +215,42 @@
     var event = TimerEvents[name];
     if (!event.pause) continue;
     var ranges = event.ranges;
+    for (var j = 0; j < ranges.length; j++) execution_pauses.push(ranges[j]);
+  }
+  execution_pauses = MergeRanges(execution_pauses);
+
+  // Knock out time not spent in javascript execution.  Note that this also
+  // includes time spent external code, which do not contribute to execution
+  // pauses.
+  var exclude_ranges = [];
+  for (name in TimerEvents) {
+    var event = TimerEvents[name];
+    if (!event.no_execution) continue;
+    var ranges = event.ranges;
     // Add ranges of this event to the pause list.
     for (var j = 0; j < ranges.length; j++) {
-      execution_pauses.push(ranges[j]);
+      exclude_ranges.push(ranges[j]);
     }
   }
+
+  kExecutionEvent.ranges = MergeRanges(kExecutionEvent.ranges);
+  exclude_ranges = MergeRanges(exclude_ranges);
+  kExecutionEvent.ranges = ExcludeRanges(kExecutionEvent.ranges,
+                                         exclude_ranges);
 }
 
 
-function drawBar(row, color, start, end) {
+function DrawBar(row, color, start, end, width) {
   obj_index++;
   command = "set object " + obj_index + " rect";
-  command += " from " + start + ", " + (row - kBarWidth + kY1Offset);
-  command += " to " + end + ", " + (row + kBarWidth + kY1Offset);
+  command += " from " + start + ", " + (row - width);
+  command += " to " + end + ", " + (row + width);
   command += " fc rgb \"" + color + "\"";
   print(command);
 }
 
 
-function MergeRanges(ranges, merge_tolerance) {
+function MergeRanges(ranges) {
   ranges.sort(function(a, b) { return a.start - b.start; });
   var result = [];
   var j = 0;
@@ -141,7 +261,7 @@
     for (j = i + 1; j < ranges.length; j++) {
       var next_range = ranges[j];
       // Don't merge ranges if there is no overlap (including merge tolerance).
-      if (next_range.start >= merge_end + kPauseTolerance) break;
+      if (next_range.start > merge_end + kPauseTolerance) break;
       // Merge ranges.
       if (next_range.end > merge_end) {  // Extend range end.
         merge_end = next_range.end;
@@ -239,10 +359,9 @@
 function GnuplotOutput() {
   xrange_start = kOverrideRangeStart ? kOverrideRangeStart : xrange_start;
   xrange_end = kOverrideRangeEnd ? kOverrideRangeEnd : xrange_end;
-
   print("set terminal pngcairo size " + kResX + "," + kResY +
         " enhanced font 'Helvetica,10'");
-  print("set yrange [0:" + (kNumRows + kY1Offset + 1) + "]");
+  print("set yrange [0:" + (num_timer_event + 1) + "]");
   print("set xlabel \"execution time in ms\"");
   print("set xrange [" + xrange_start + ":" + xrange_end + "]");
   print("set style fill pattern 2 bo 1");
@@ -255,57 +374,71 @@
   var ytics = [];
   for (name in TimerEvents) {
     var index = TimerEvents[name].index;
-    ytics.push('"' + name + '"' + ' ' + (index + kY1Offset));
+    ytics.push('"' + name + '"' + ' ' + index);
   }
+  ytics.push('"code kind being executed"' + ' ' + (kY1Offset - 1));
+  ytics.push('"top ' + kStackFrames + ' js stack frames"' + ' ' +
+             (kY1Offset - 2));
+  ytics.push('"pause times" 0');
   print("set ytics out nomirror (" + ytics.join(', ') + ")");
 
-  // Smallest visible gap given our resolution.
-  // We remove superfluous objects to go easy on Gnuplot.
-  var tolerance = (xrange_end - xrange_start) / kResX / 2;
-
-  // Sort, merge and remove invisible gaps for each time row.
-  for (var name in TimerEvents) {
-    var event = TimerEvents[name];
-    event.ranges = MergeRanges(event.ranges, tolerance);
-  }
-
-  // Knock out execution pauses.
-  var execution_event = TimerEvents[kExecutionName];
-  var exclude_ranges = MergeRanges(execution_pauses, tolerance);
-  execution_event.ranges = ExcludeRanges(execution_event.ranges,
-                                         exclude_ranges);
-  execution_event.ranges = MergeRanges(execution_event.ranges, tolerance);
-
   // Plot timeline.
   for (var name in TimerEvents) {
     var event = TimerEvents[name];
-    var ranges = event.ranges;
+    var ranges = MergeRanges(event.ranges);
     for (var i = 0; i < ranges.length; i++) {
-      drawBar(event.index, event.color, ranges[i].start, ranges[i].end);
+      DrawBar(event.index, event.color,
+              ranges[i].start, ranges[i].end,
+              kTimerEventWidth);
     }
   }
 
+  // Plot code kind gathered from ticks.
+  for (var name in CodeKinds) {
+    var code_kind = CodeKinds[name];
+    var offset = kY1Offset - 1;
+    // Top most frame.
+    var row = MergeRanges(code_kind.in_execution);
+    for (var j = 0; j < row.length; j++) {
+      DrawBar(offset, code_kind.color,
+              row[j].start, row[j].end, kExecutionFrameWidth);
+    }
+    offset = offset - 2 * kExecutionFrameWidth - kGapWidth;
+    // Javascript frames.
+    for (var i = 0; i < kStackFrames; i++) {
+      offset = offset - 2 * kStackFrameWidth - kGapWidth;
+      row = MergeRanges(code_kind.stack_frames[i]);
+      for (var j = 0; j < row.length; j++) {
+        DrawBar(offset, code_kind.color,
+                row[j].start, row[j].end, kStackFrameWidth);
+      }
+    }
+  }
+
+  // Add labels as legend for code kind colors.
+  var padding = kCodeKindLabelPadding * (xrange_end - xrange_start) / kResX;
+  var label_x = xrange_start;
+  var label_y = kY1Offset;
+  for (var name in CodeKinds) {
+    label_x += padding;
+    print("set label \"" + name + "\" at " + label_x + "," + label_y +
+          " textcolor rgb \"" + CodeKinds[name].color + "\"" +
+          " font \"Helvetica,9'\"");
+  }
+
   if (execution_pauses.length == 0) {
     // Force plot and return without plotting execution pause impulses.
     print("plot 1/0");
     return;
   }
 
-  // Plot execution pauses as impulses.  This may be better resolved
-  // due to possibly smaller merge tolerance.
-  if (tolerance > kPauseTolerance) {
-    execution_pauses = MergeRanges(execution_pauses, kPauseTolerance);
-  } else {
-    execution_pauses = exclude_ranges;
-  }
-
   // Label the longest pauses.
   execution_pauses.sort(
       function(a, b) { return b.duration() - a.duration(); });
 
   var max_pause_time = execution_pauses[0].duration();
-  var padding = kLabelPadding * (xrange_end - xrange_start) / kResX;
-  var y_scale = kY1Offset / max_pause_time;
+  padding = kPauseLabelPadding * (xrange_end - xrange_start) / kResX;
+  var y_scale = kY1Offset / max_pause_time / 2;
   for (var i = 0; i < execution_pauses.length && i < kNumPauseLabels; i++) {
     var pause = execution_pauses[i];
     var label_content = (pause.duration() | 0) + " ms";
@@ -316,8 +449,8 @@
   }
 
   // Scale second Y-axis appropriately.
-  print("set y2range [0:" + (max_pause_time * kY2Factor) + "]");
-
+  var y2range = max_pause_time * num_timer_event / kY1Offset * 2;
+  print("set y2range [0:" + y2range + "]");
   // Plot graph with impulses as data set.
   print("plot '-' using 1:2 axes x1y2 with impulses ls 1");
   for (var i = 0; i < execution_pauses.length; i++) {
diff --git a/tools/tickprocessor.js b/tools/tickprocessor.js
index 78f4cee..7530c6b 100644
--- a/tools/tickprocessor.js
+++ b/tools/tickprocessor.js
@@ -73,7 +73,7 @@
 function SnapshotLogProcessor() {
   LogReader.call(this, {
       'code-creation': {
-          parsers: [null, parseInt, parseInt, null, 'var-args'],
+          parsers: [null, parseInt, parseInt, parseInt, null, 'var-args'],
           processor: this.processCodeCreation },
       'code-move': { parsers: [parseInt, parseInt],
           processor: this.processCodeMove },
@@ -107,7 +107,7 @@
 
 
 SnapshotLogProcessor.prototype.processCodeCreation = function(
-    type, start, size, name, maybe_func) {
+    type, kind, start, size, name, maybe_func) {
   if (maybe_func.length) {
     var funcAddr = parseInt(maybe_func[0]);
     var state = parseState(maybe_func[1]);
@@ -156,7 +156,7 @@
       'shared-library': { parsers: [null, parseInt, parseInt],
           processor: this.processSharedLibrary },
       'code-creation': {
-          parsers: [null, parseInt, parseInt, null, 'var-args'],
+          parsers: [null, parseInt, parseInt, parseInt, null, 'var-args'],
           processor: this.processCodeCreation },
       'code-move': { parsers: [parseInt, parseInt],
           processor: this.processCodeMove },
@@ -167,7 +167,7 @@
       'snapshot-pos': { parsers: [parseInt, parseInt],
           processor: this.processSnapshotPosition },
       'tick': {
-          parsers: [parseInt, parseInt, parseInt,
+          parsers: [parseInt, parseInt, parseInt, parseInt,
                     parseInt, parseInt, 'var-args'],
           processor: this.processTick },
       'heap-sample-begin': { parsers: [null, null, parseInt],
@@ -309,7 +309,7 @@
 
 
 TickProcessor.prototype.processCodeCreation = function(
-    type, start, size, name, maybe_func) {
+    type, kind, start, size, name, maybe_func) {
   name = this.deserializedEntriesNames_[start] || name;
   if (maybe_func.length) {
     var funcAddr = parseInt(maybe_func[0]);
@@ -350,6 +350,7 @@
 
 TickProcessor.prototype.processTick = function(pc,
                                                sp,
+                                               ns_since_start,
                                                is_external_callback,
                                                tos_or_external_callback,
                                                vmState,