Merge WebKit at r59636: Update v8 to r4660.

Will build and run with current webkit.

Change-Id: I57bae621fd894da363ba84e1757ad09eb7c502b9
diff --git a/src/arm/assembler-arm.cc b/src/arm/assembler-arm.cc
index 7990368..f1f59ce 100644
--- a/src/arm/assembler-arm.cc
+++ b/src/arm/assembler-arm.cc
@@ -1157,6 +1157,35 @@
 }
 
 
+void Assembler::ldrd(Register dst, const MemOperand& src, Condition cond) {
+  ASSERT(src.rm().is(no_reg));
+#ifdef CAN_USE_ARMV7_INSTRUCTIONS
+  addrmod3(cond | B7 | B6 | B4, dst, src);
+#else
+  ldr(dst, src, cond);
+  MemOperand src1(src);
+  src1.set_offset(src1.offset() + 4);
+  Register dst1(dst);
+  dst1.code_ = dst1.code_ + 1;
+  ldr(dst1, src1, cond);
+#endif
+}
+
+
+void Assembler::strd(Register src, const MemOperand& dst, Condition cond) {
+  ASSERT(dst.rm().is(no_reg));
+#ifdef CAN_USE_ARMV7_INSTRUCTIONS
+  addrmod3(cond | B7 | B6 | B5 | B4, src, dst);
+#else
+  str(src, dst, cond);
+  MemOperand dst1(dst);
+  dst1.set_offset(dst1.offset() + 4);
+  Register src1(src);
+  src1.code_ = src1.code_ + 1;
+  str(src1, dst1, cond);
+#endif
+}
+
 // Load/Store multiple instructions.
 void Assembler::ldm(BlockAddrMode am,
                     Register base,
diff --git a/src/arm/assembler-arm.h b/src/arm/assembler-arm.h
index 839ed67..61b84d4 100644
--- a/src/arm/assembler-arm.h
+++ b/src/arm/assembler-arm.h
@@ -448,6 +448,18 @@
   explicit MemOperand(Register rn, Register rm,
                       ShiftOp shift_op, int shift_imm, AddrMode am = Offset);
 
+  void set_offset(int32_t offset) {
+      ASSERT(rm_.is(no_reg));
+      offset_ = offset;
+  }
+
+  uint32_t offset() {
+      ASSERT(rm_.is(no_reg));
+      return offset_;
+  }
+
+  Register rm() const {return rm_;}
+
  private:
   Register rn_;  // base
   Register rm_;  // register offset
@@ -755,6 +767,8 @@
   void strh(Register src, const MemOperand& dst, Condition cond = al);
   void ldrsb(Register dst, const MemOperand& src, Condition cond = al);
   void ldrsh(Register dst, const MemOperand& src, Condition cond = al);
+  void ldrd(Register dst, const MemOperand& src, Condition cond = al);
+  void strd(Register src, const MemOperand& dst, Condition cond = al);
 
   // Load/Store multiple instructions
   void ldm(BlockAddrMode am, Register base, RegList dst, Condition cond = al);
diff --git a/src/arm/builtins-arm.cc b/src/arm/builtins-arm.cc
index 7bb8c46..5718cb3 100644
--- a/src/arm/builtins-arm.cc
+++ b/src/arm/builtins-arm.cc
@@ -107,7 +107,7 @@
   // Allocate the JSArray object together with space for a fixed array with the
   // requested elements.
   int size = JSArray::kSize + FixedArray::SizeFor(initial_capacity);
-  __ AllocateInNewSpace(size / kPointerSize,
+  __ AllocateInNewSpace(size,
                         result,
                         scratch2,
                         scratch3,
@@ -191,7 +191,7 @@
   // keeps the code below free of special casing for the empty array.
   int size = JSArray::kSize +
              FixedArray::SizeFor(JSArray::kPreallocatedArrayElements);
-  __ AllocateInNewSpace(size / kPointerSize,
+  __ AllocateInNewSpace(size,
                         result,
                         elements_array_end,
                         scratch1,
@@ -208,12 +208,13 @@
   __ add(elements_array_end,
          elements_array_end,
          Operand(array_size, ASR, kSmiTagSize));
-  __ AllocateInNewSpace(elements_array_end,
-                        result,
-                        scratch1,
-                        scratch2,
-                        gc_required,
-                        TAG_OBJECT);
+  __ AllocateInNewSpace(
+      elements_array_end,
+      result,
+      scratch1,
+      scratch2,
+      gc_required,
+      static_cast<AllocationFlags>(TAG_OBJECT | SIZE_IN_WORDS));
 
   // Allocated the JSArray. Now initialize the fields except for the elements
   // array.
@@ -561,7 +562,7 @@
     // r2: initial map
     // r7: undefined
     __ ldrb(r3, FieldMemOperand(r2, Map::kInstanceSizeOffset));
-    __ AllocateInNewSpace(r3, r4, r5, r6, &rt_call, NO_ALLOCATION_FLAGS);
+    __ AllocateInNewSpace(r3, r4, r5, r6, &rt_call, SIZE_IN_WORDS);
 
     // Allocated the JSObject, now initialize the fields. Map is set to initial
     // map and properties and elements are set to empty fixed array.
@@ -632,12 +633,13 @@
     // r5: start of next object
     // r7: undefined
     __ add(r0, r3, Operand(FixedArray::kHeaderSize / kPointerSize));
-    __ AllocateInNewSpace(r0,
-                          r5,
-                          r6,
-                          r2,
-                          &undo_allocation,
-                          RESULT_CONTAINS_TOP);
+    __ AllocateInNewSpace(
+        r0,
+        r5,
+        r6,
+        r2,
+        &undo_allocation,
+        static_cast<AllocationFlags>(RESULT_CONTAINS_TOP | SIZE_IN_WORDS));
 
     // Initialize the FixedArray.
     // r1: constructor
diff --git a/src/arm/codegen-arm.cc b/src/arm/codegen-arm.cc
index dea0b63..68ae026 100644
--- a/src/arm/codegen-arm.cc
+++ b/src/arm/codegen-arm.cc
@@ -33,6 +33,7 @@
 #include "debug.h"
 #include "ic-inl.h"
 #include "jsregexp.h"
+#include "jump-target-light-inl.h"
 #include "parser.h"
 #include "regexp-macro-assembler.h"
 #include "regexp-stack.h"
@@ -40,10 +41,12 @@
 #include "runtime.h"
 #include "scopes.h"
 #include "virtual-frame-inl.h"
+#include "virtual-frame-arm-inl.h"
 
 namespace v8 {
 namespace internal {
 
+
 #define __ ACCESS_MASM(masm_)
 
 static void EmitIdenticalObjectComparison(MacroAssembler* masm,
@@ -191,7 +194,7 @@
       frame_->AllocateStackSlots();
 
       VirtualFrame::SpilledScope spilled_scope(frame_);
-      int heap_slots = scope()->num_heap_slots();
+      int heap_slots = scope()->num_heap_slots() - Context::MIN_CONTEXT_SLOTS;
       if (heap_slots > 0) {
         // Allocate local context.
         // Get outer context and create a new context based on it.
@@ -274,7 +277,7 @@
 
     // Initialize the function return target after the locals are set
     // up, because it needs the expected frame height from the frame.
-    function_return_.set_direction(JumpTarget::BIDIRECTIONAL);
+    function_return_.SetExpectedHeight();
     function_return_is_shadowed_ = false;
 
     // Generate code to 'execute' declarations and initialize functions
@@ -1143,44 +1146,66 @@
       int shift_value = int_value & 0x1f;  // least significant 5 bits
       DeferredCode* deferred =
         new DeferredInlineSmiOperation(op, shift_value, false, mode, tos);
-      __ tst(tos, Operand(kSmiTagMask));
-      deferred->Branch(ne);
-      __ mov(scratch, Operand(tos, ASR, kSmiTagSize));  // remove tags
+      uint32_t problematic_mask = kSmiTagMask;
+      // For unsigned shift by zero all negative smis are problematic.
+      if (shift_value == 0 && op == Token::SHR) problematic_mask |= 0x80000000;
+      __ tst(tos, Operand(problematic_mask));
+      deferred->Branch(ne);  // Go slow for problematic input.
       switch (op) {
         case Token::SHL: {
           if (shift_value != 0) {
-            __ mov(scratch, Operand(scratch, LSL, shift_value));
+            int adjusted_shift = shift_value - kSmiTagSize;
+            ASSERT(adjusted_shift >= 0);
+            if (adjusted_shift != 0) {
+              __ mov(scratch, Operand(tos, LSL, adjusted_shift));
+              // Check that the *signed* result fits in a smi.
+              __ add(scratch2, scratch, Operand(0x40000000), SetCC);
+              deferred->Branch(mi);
+              __ mov(tos, Operand(scratch, LSL, kSmiTagSize));
+            } else {
+              // Check that the *signed* result fits in a smi.
+              __ add(scratch2, tos, Operand(0x40000000), SetCC);
+              deferred->Branch(mi);
+              __ mov(tos, Operand(tos, LSL, kSmiTagSize));
+            }
           }
-          // check that the *signed* result fits in a smi
-          __ add(scratch2, scratch, Operand(0x40000000), SetCC);
-          deferred->Branch(mi);
           break;
         }
         case Token::SHR: {
-          // LSR by immediate 0 means shifting 32 bits.
           if (shift_value != 0) {
+            __ mov(scratch, Operand(tos, ASR, kSmiTagSize));  // Remove tag.
+            // LSR by immediate 0 means shifting 32 bits.
             __ mov(scratch, Operand(scratch, LSR, shift_value));
+            if (shift_value == 1) {
+              // check that the *unsigned* result fits in a smi
+              // neither of the two high-order bits can be set:
+              // - 0x80000000: high bit would be lost when smi tagging
+              // - 0x40000000: this number would convert to negative when
+              // smi tagging these two cases can only happen with shifts
+              // by 0 or 1 when handed a valid smi
+              __ tst(scratch, Operand(0xc0000000));
+              deferred->Branch(ne);
+            }
+            __ mov(tos, Operand(scratch, LSL, kSmiTagSize));
           }
-          // check that the *unsigned* result fits in a smi
-          // neither of the two high-order bits can be set:
-          // - 0x80000000: high bit would be lost when smi tagging
-          // - 0x40000000: this number would convert to negative when
-          // smi tagging these two cases can only happen with shifts
-          // by 0 or 1 when handed a valid smi
-          __ tst(scratch, Operand(0xc0000000));
-          deferred->Branch(ne);
           break;
         }
         case Token::SAR: {
+          // In the ARM instructions set, ASR by immediate 0 means shifting 32
+          // bits.
           if (shift_value != 0) {
-            // ASR by immediate 0 means shifting 32 bits.
-            __ mov(scratch, Operand(scratch, ASR, shift_value));
+            // Do the shift and the tag removal in one operation.  If the shift
+            // is 31 bits (the highest possible value) then we emit the
+            // instruction as a shift by 0 which means shift arithmetically by
+            // 32.
+            __ mov(tos, Operand(tos, ASR, (kSmiTagSize + shift_value) & 0x1f));
+            // Put tag back.
+            __ mov(tos, Operand(tos, LSL, kSmiTagSize));
           }
           break;
         }
         default: UNREACHABLE();
       }
-      __ mov(tos, Operand(scratch, LSL, kSmiTagSize));
       deferred->BindExit();
       frame_->EmitPush(tos);
       break;
@@ -1486,8 +1511,7 @@
   // Then process it as a normal function call.
   __ ldr(r0, MemOperand(sp, 3 * kPointerSize));
   __ ldr(r1, MemOperand(sp, 2 * kPointerSize));
-  __ str(r0, MemOperand(sp, 2 * kPointerSize));
-  __ str(r1, MemOperand(sp, 3 * kPointerSize));
+  __ strd(r0, MemOperand(sp, 2 * kPointerSize));
 
   CallFunctionStub call_function(2, NOT_IN_LOOP, NO_CALL_FUNCTION_FLAGS);
   frame_->CallStub(&call_function, 3);
@@ -1550,7 +1574,7 @@
   VirtualFrame::SpilledScope spilled_scope(frame_);
   Comment cmnt(masm_, "[ Block");
   CodeForStatementPosition(node);
-  node->break_target()->set_direction(JumpTarget::FORWARD_ONLY);
+  node->break_target()->SetExpectedHeight();
   VisitStatementsAndSpill(node->statements());
   if (node->break_target()->is_linked()) {
     node->break_target()->Bind();
@@ -1837,7 +1861,7 @@
   VirtualFrame::SpilledScope spilled_scope(frame_);
   Comment cmnt(masm_, "[ SwitchStatement");
   CodeForStatementPosition(node);
-  node->break_target()->set_direction(JumpTarget::FORWARD_ONLY);
+  node->break_target()->SetExpectedHeight();
 
   LoadAndSpill(node->tag());
 
@@ -1926,7 +1950,7 @@
   VirtualFrame::SpilledScope spilled_scope(frame_);
   Comment cmnt(masm_, "[ DoWhileStatement");
   CodeForStatementPosition(node);
-  node->break_target()->set_direction(JumpTarget::FORWARD_ONLY);
+  node->break_target()->SetExpectedHeight();
   JumpTarget body(JumpTarget::BIDIRECTIONAL);
   IncrementLoopNesting();
 
@@ -1936,14 +1960,14 @@
   ConditionAnalysis info = AnalyzeCondition(node->cond());
   switch (info) {
     case ALWAYS_TRUE:
-      node->continue_target()->set_direction(JumpTarget::BIDIRECTIONAL);
+      node->continue_target()->SetExpectedHeight();
       node->continue_target()->Bind();
       break;
     case ALWAYS_FALSE:
-      node->continue_target()->set_direction(JumpTarget::FORWARD_ONLY);
+      node->continue_target()->SetExpectedHeight();
       break;
     case DONT_KNOW:
-      node->continue_target()->set_direction(JumpTarget::FORWARD_ONLY);
+      node->continue_target()->SetExpectedHeight();
       body.Bind();
       break;
   }
@@ -2007,12 +2031,12 @@
   ConditionAnalysis info = AnalyzeCondition(node->cond());
   if (info == ALWAYS_FALSE) return;
 
-  node->break_target()->set_direction(JumpTarget::FORWARD_ONLY);
+  node->break_target()->SetExpectedHeight();
   IncrementLoopNesting();
 
   // Label the top of the loop with the continue target for the backward
   // CFG edge.
-  node->continue_target()->set_direction(JumpTarget::BIDIRECTIONAL);
+  node->continue_target()->SetExpectedHeight();
   node->continue_target()->Bind();
 
   if (info == DONT_KNOW) {
@@ -2061,17 +2085,17 @@
   ConditionAnalysis info = AnalyzeCondition(node->cond());
   if (info == ALWAYS_FALSE) return;
 
-  node->break_target()->set_direction(JumpTarget::FORWARD_ONLY);
+  node->break_target()->SetExpectedHeight();
   IncrementLoopNesting();
 
   // If there is no update statement, label the top of the loop with the
   // continue target, otherwise with the loop target.
   JumpTarget loop(JumpTarget::BIDIRECTIONAL);
   if (node->next() == NULL) {
-    node->continue_target()->set_direction(JumpTarget::BIDIRECTIONAL);
+    node->continue_target()->SetExpectedHeight();
     node->continue_target()->Bind();
   } else {
-    node->continue_target()->set_direction(JumpTarget::FORWARD_ONLY);
+    node->continue_target()->SetExpectedHeight();
     loop.Bind();
   }
 
@@ -2276,11 +2300,11 @@
   // sp[4] : enumerable
   // Grab the current frame's height for the break and continue
   // targets only after all the state is pushed on the frame.
-  node->break_target()->set_direction(JumpTarget::FORWARD_ONLY);
-  node->continue_target()->set_direction(JumpTarget::FORWARD_ONLY);
+  node->break_target()->SetExpectedHeight();
+  node->continue_target()->SetExpectedHeight();
 
-  __ ldr(r0, frame_->ElementAt(0));  // load the current count
-  __ ldr(r1, frame_->ElementAt(1));  // load the length
+  // Load the current count to r0, load the length to r1.
+  __ ldrd(r0, frame_->ElementAt(0));
   __ cmp(r0, r1);  // compare to the array length
   node->break_target()->Branch(hs);
 
@@ -2767,44 +2791,13 @@
     JumpTarget slow;
     JumpTarget done;
 
-    // Generate fast-case code for variables that might be shadowed by
-    // eval-introduced variables.  Eval is used a lot without
-    // introducing variables.  In those cases, we do not want to
-    // perform a runtime call for all variables in the scope
-    // containing the eval.
-    if (slot->var()->mode() == Variable::DYNAMIC_GLOBAL) {
-      LoadFromGlobalSlotCheckExtensions(slot, typeof_state, &slow);
-      // If there was no control flow to slow, we can exit early.
-      if (!slow.is_linked()) {
-        frame_->EmitPush(r0);
-        return;
-      }
-      frame_->SpillAll();
-
-      done.Jump();
-
-    } else if (slot->var()->mode() == Variable::DYNAMIC_LOCAL) {
-      frame_->SpillAll();
-      Slot* potential_slot = slot->var()->local_if_not_shadowed()->slot();
-      // Only generate the fast case for locals that rewrite to slots.
-      // This rules out argument loads.
-      if (potential_slot != NULL) {
-        __ ldr(r0,
-               ContextSlotOperandCheckExtensions(potential_slot,
-                                                 r1,
-                                                 r2,
-                                                 &slow));
-        if (potential_slot->var()->mode() == Variable::CONST) {
-          __ LoadRoot(ip, Heap::kTheHoleValueRootIndex);
-          __ cmp(r0, ip);
-          __ LoadRoot(r0, Heap::kUndefinedValueRootIndex, eq);
-        }
-        // There is always control flow to slow from
-        // ContextSlotOperandCheckExtensions so we have to jump around
-        // it.
-        done.Jump();
-      }
-    }
+    // Generate fast case for loading from slots that correspond to
+    // local/global variables or arguments unless they are shadowed by
+    // eval-introduced bindings.
+    EmitDynamicLoadFromSlotFastCase(slot,
+                                    typeof_state,
+                                    &slow,
+                                    &done);
 
     slow.Bind();
     VirtualFrame::SpilledScope spilled_scope(frame_);
@@ -3019,6 +3012,67 @@
 }
 
 
+void CodeGenerator::EmitDynamicLoadFromSlotFastCase(Slot* slot,
+                                                    TypeofState typeof_state,
+                                                    JumpTarget* slow,
+                                                    JumpTarget* done) {
+  // Generate fast-case code for variables that might be shadowed by
+  // eval-introduced variables.  Eval is used a lot without
+  // introducing variables.  In those cases, we do not want to
+  // perform a runtime call for all variables in the scope
+  // containing the eval.
+  if (slot->var()->mode() == Variable::DYNAMIC_GLOBAL) {
+    LoadFromGlobalSlotCheckExtensions(slot, typeof_state, slow);
+    frame_->SpillAll();
+    done->Jump();
+
+  } else if (slot->var()->mode() == Variable::DYNAMIC_LOCAL) {
+    frame_->SpillAll();
+    Slot* potential_slot = slot->var()->local_if_not_shadowed()->slot();
+    Expression* rewrite = slot->var()->local_if_not_shadowed()->rewrite();
+    if (potential_slot != NULL) {
+      // Generate fast case for locals that rewrite to slots.
+      __ ldr(r0,
+             ContextSlotOperandCheckExtensions(potential_slot,
+                                               r1,
+                                               r2,
+                                               slow));
+      if (potential_slot->var()->mode() == Variable::CONST) {
+        __ LoadRoot(ip, Heap::kTheHoleValueRootIndex);
+        __ cmp(r0, ip);
+        __ LoadRoot(r0, Heap::kUndefinedValueRootIndex, eq);
+      }
+      done->Jump();
+    } else if (rewrite != NULL) {
+      // Generate fast case for argument loads.
+      Property* property = rewrite->AsProperty();
+      if (property != NULL) {
+        VariableProxy* obj_proxy = property->obj()->AsVariableProxy();
+        Literal* key_literal = property->key()->AsLiteral();
+        if (obj_proxy != NULL &&
+            key_literal != NULL &&
+            obj_proxy->IsArguments() &&
+            key_literal->handle()->IsSmi()) {
+          // Load arguments object if there are no eval-introduced
+          // variables. Then load the argument from the arguments
+          // object using keyed load.
+          __ ldr(r0,
+                 ContextSlotOperandCheckExtensions(obj_proxy->var()->slot(),
+                                                   r1,
+                                                   r2,
+                                                   slow));
+          frame_->EmitPush(r0);
+          __ mov(r1, Operand(key_literal->handle()));
+          frame_->EmitPush(r1);
+          EmitKeyedLoad();
+          done->Jump();
+        }
+      }
+    }
+  }
+}
+
+
 void CodeGenerator::VisitSlot(Slot* node) {
 #ifdef DEBUG
   int original_height = frame_->height();
@@ -3473,7 +3527,8 @@
   if (node->is_compound()) {
     // For a compound assignment the right-hand side is a binary operation
     // between the current property value and the actual right-hand side.
-    // Load of the current value leaves receiver and key on the stack.
+    // Duplicate receiver and key for loading the current property value.
+    frame_->Dup2();
     EmitKeyedLoad();
     frame_->EmitPush(r0);
 
@@ -3702,9 +3757,30 @@
   } else if (var != NULL && var->slot() != NULL &&
              var->slot()->type() == Slot::LOOKUP) {
     // ----------------------------------
-    // JavaScript example: 'with (obj) foo(1, 2, 3)'  // foo is in obj
+    // JavaScript examples:
+    //
+    //  with (obj) foo(1, 2, 3)  // foo may be in obj.
+    //
+    //  function f() {};
+    //  function g() {
+    //    eval(...);
+    //    f();  // f could be in extension object.
+    //  }
     // ----------------------------------
 
+    // JumpTargets do not yet support merging frames so the frame must be
+    // spilled when jumping to these targets.
+    JumpTarget slow, done;
+
+    // Generate fast case for loading functions from slots that
+    // correspond to local/global variables or arguments unless they
+    // are shadowed by eval-introduced bindings.
+    EmitDynamicLoadFromSlotFastCase(var->slot(),
+                                    NOT_INSIDE_TYPEOF,
+                                    &slow,
+                                    &done);
+
+    slow.Bind();
     // Load the function
     frame_->EmitPush(cp);
     __ mov(r0, Operand(var->name()));
@@ -3716,7 +3792,20 @@
     frame_->EmitPush(r0);  // function
     frame_->EmitPush(r1);  // receiver
 
-    // Call the function.
+    // If fast case code has been generated, emit code to push the
+    // function and receiver and have the slow path jump around this
+    // code.
+    if (done.is_linked()) {
+      JumpTarget call;
+      call.Jump();
+      done.Bind();
+      frame_->EmitPush(r0);  // function
+      LoadGlobalReceiver(r1);  // receiver
+      call.Bind();
+    }
+
+    // Call the function. At this point, everything is spilled but the
+    // function and receiver are in r0 and r1.
     CallWithArguments(args, NO_CALL_FUNCTION_FLAGS, node->position());
     frame_->EmitPush(r0);
 
@@ -3767,19 +3856,23 @@
       // -------------------------------------------
 
       LoadAndSpill(property->obj());
+      if (!property->is_synthetic()) {
+        // Duplicate receiver for later use.
+        __ ldr(r0, MemOperand(sp, 0));
+        frame_->EmitPush(r0);
+      }
       LoadAndSpill(property->key());
       EmitKeyedLoad();
-      frame_->Drop();  // key
       // Put the function below the receiver.
       if (property->is_synthetic()) {
         // Use the global receiver.
-        frame_->Drop();
-        frame_->EmitPush(r0);
+        frame_->EmitPush(r0);  // Function.
         LoadGlobalReceiver(r0);
       } else {
-        frame_->EmitPop(r1);  // receiver
-        frame_->EmitPush(r0);  // function
-        frame_->EmitPush(r1);  // receiver
+        // Switch receiver and function.
+        frame_->EmitPop(r1);  // Receiver.
+        frame_->EmitPush(r0);  // Function.
+        frame_->EmitPush(r1);  // Receiver.
       }
 
       // Call the function.
@@ -4359,12 +4452,13 @@
         (JSRegExpResult::kSize + FixedArray::kHeaderSize) / kPointerSize;
     __ mov(r5, Operand(r1, LSR, kSmiTagSize + kSmiShiftSize));
     __ add(r2, r5, Operand(objects_size));
-    __ AllocateInNewSpace(r2,  // In: Size, in words.
-                          r0,  // Out: Start of allocation (tagged).
-                          r3,  // Scratch register.
-                          r4,  // Scratch register.
-                          &slowcase,
-                          TAG_OBJECT);
+    __ AllocateInNewSpace(
+        r2,  // In: Size, in words.
+        r0,  // Out: Start of allocation (tagged).
+        r3,  // Scratch register.
+        r4,  // Scratch register.
+        &slowcase,
+        static_cast<AllocationFlags>(TAG_OBJECT | SIZE_IN_WORDS));
     // r0: Start of allocated area, object-tagged.
     // r1: Number of elements in array, as smi.
     // r5: Number of elements, untagged.
@@ -4837,7 +4931,6 @@
 #ifdef DEBUG
   int original_height = frame_->height();
 #endif
-  VirtualFrame::SpilledScope spilled_scope(frame_);
   Comment cmnt(masm_, "[ CountOperation");
 
   bool is_postfix = node->is_postfix();
@@ -4846,10 +4939,8 @@
   Variable* var = node->expression()->AsVariableProxy()->AsVariable();
   bool is_const = (var != NULL && var->mode() == Variable::CONST);
 
-  // Postfix: Make room for the result.
   if (is_postfix) {
-     __ mov(r0, Operand(0));
-     frame_->EmitPush(r0);
+    frame_->EmitPush(Operand(Smi::FromInt(0)));
   }
 
   // A constant reference is not saved to, so a constant reference is not a
@@ -4859,35 +4950,33 @@
       // Spoof the virtual frame to have the expected height (one higher
       // than on entry).
       if (!is_postfix) {
-        __ mov(r0, Operand(Smi::FromInt(0)));
-        frame_->EmitPush(r0);
+        frame_->EmitPush(Operand(Smi::FromInt(0)));
       }
       ASSERT_EQ(original_height + 1, frame_->height());
       return;
     }
+    // This pushes 0, 1 or 2 words on the object to be used later when updating
+    // the target.  It also pushes the current value of the target.
     target.GetValue();
-    frame_->EmitPop(r0);
 
     JumpTarget slow;
     JumpTarget exit;
 
-    // Load the value (1) into register r1.
-    __ mov(r1, Operand(Smi::FromInt(1)));
-
     // Check for smi operand.
-    __ tst(r0, Operand(kSmiTagMask));
+    Register value = frame_->PopToRegister();
+    __ tst(value, Operand(kSmiTagMask));
     slow.Branch(ne);
 
     // Postfix: Store the old value as the result.
     if (is_postfix) {
-      __ str(r0, frame_->ElementAt(target.size()));
+      frame_->SetElementAt(value, target.size());
     }
 
     // Perform optimistic increment/decrement.
     if (is_increment) {
-      __ add(r0, r0, Operand(r1), SetCC);
+      __ add(value, value, Operand(Smi::FromInt(1)), SetCC);
     } else {
-      __ sub(r0, r0, Operand(r1), SetCC);
+      __ sub(value, value, Operand(Smi::FromInt(1)), SetCC);
     }
 
     // If the increment/decrement didn't overflow, we're done.
@@ -4895,41 +4984,50 @@
 
     // Revert optimistic increment/decrement.
     if (is_increment) {
-      __ sub(r0, r0, Operand(r1));
+      __ sub(value, value, Operand(Smi::FromInt(1)));
     } else {
-      __ add(r0, r0, Operand(r1));
+      __ add(value, value, Operand(Smi::FromInt(1)));
     }
 
-    // Slow case: Convert to number.
+    // Slow case: Convert to number.  At this point the
+    // value to be incremented is in the value register..
     slow.Bind();
+
+    // Convert the operand to a number.
+    frame_->EmitPush(value);
+
     {
-      // Convert the operand to a number.
-      frame_->EmitPush(r0);
+      VirtualFrame::SpilledScope spilled(frame_);
       frame_->InvokeBuiltin(Builtins::TO_NUMBER, CALL_JS, 1);
-    }
-    if (is_postfix) {
-      // Postfix: store to result (on the stack).
-      __ str(r0, frame_->ElementAt(target.size()));
+
+      if (is_postfix) {
+        // Postfix: store to result (on the stack).
+        __ str(r0, frame_->ElementAt(target.size()));
+      }
+
+      // Compute the new value.
+      frame_->EmitPush(r0);
+      frame_->EmitPush(Operand(Smi::FromInt(1)));
+      if (is_increment) {
+        frame_->CallRuntime(Runtime::kNumberAdd, 2);
+      } else {
+        frame_->CallRuntime(Runtime::kNumberSub, 2);
+      }
     }
 
-    // Compute the new value.
-    __ mov(r1, Operand(Smi::FromInt(1)));
-    frame_->EmitPush(r0);
-    frame_->EmitPush(r1);
-    if (is_increment) {
-      frame_->CallRuntime(Runtime::kNumberAdd, 2);
-    } else {
-      frame_->CallRuntime(Runtime::kNumberSub, 2);
-    }
-
+    __ Move(value, r0);
     // Store the new value in the target if not const.
+    // At this point the answer is in the value register.
     exit.Bind();
-    frame_->EmitPush(r0);
+    frame_->EmitPush(value);
+    // Set the target with the result, leaving the result on
+    // top of the stack.  Removes the target from the stack if
+    // it has a non-zero size.
     if (!is_const) target.SetValue(NOT_CONST_INIT);
   }
 
   // Postfix: Discard the new value and use the old.
-  if (is_postfix) frame_->EmitPop(r0);
+  if (is_postfix) frame_->Pop();
   ASSERT_EQ(original_height + 1, frame_->height());
 }
 
@@ -5372,24 +5470,37 @@
 
 class DeferredReferenceGetKeyedValue: public DeferredCode {
  public:
-  DeferredReferenceGetKeyedValue() {
+  DeferredReferenceGetKeyedValue(Register key, Register receiver)
+      : key_(key), receiver_(receiver) {
     set_comment("[ DeferredReferenceGetKeyedValue");
   }
 
   virtual void Generate();
+
+ private:
+  Register key_;
+  Register receiver_;
 };
 
 
 void DeferredReferenceGetKeyedValue::Generate() {
+  ASSERT((key_.is(r0) && receiver_.is(r1)) ||
+         (key_.is(r1) && receiver_.is(r0)));
+
   Register scratch1 = VirtualFrame::scratch0();
   Register scratch2 = VirtualFrame::scratch1();
   __ DecrementCounter(&Counters::keyed_load_inline, 1, scratch1, scratch2);
   __ IncrementCounter(&Counters::keyed_load_inline_miss, 1, scratch1, scratch2);
 
+  // Ensure key in r0 and receiver in r1 to match keyed load ic calling
+  // convention.
+  if (key_.is(r1)) {
+    __ Swap(r0, r1, ip);
+  }
+
   // The rest of the instructions in the deferred code must be together.
   { Assembler::BlockConstPoolScope block_const_pool(masm_);
-    // Call keyed load IC. It has all arguments on the stack and the key in r0.
-    __ ldr(r0, MemOperand(sp, 0));
+    // Call keyed load IC. It has the arguments key and receiver in r0 and r1.
     Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize));
     __ Call(ic, RelocInfo::CODE_TARGET);
     // The call must be followed by a nop instruction to indicate that the
@@ -5522,14 +5633,14 @@
     __ IncrementCounter(&Counters::keyed_load_inline, 1,
                         frame_->scratch0(), frame_->scratch1());
 
-    // Load the receiver and key from the stack.
-    frame_->SpillAllButCopyTOSToR1R0();
-    Register receiver = r0;
-    Register key = r1;
+    // Load the key and receiver from the stack.
+    Register key = frame_->PopToRegister();
+    Register receiver = frame_->PopToRegister(key);
     VirtualFrame::SpilledScope spilled(frame_);
 
+    // The deferred code expects key and receiver in registers.
     DeferredReferenceGetKeyedValue* deferred =
-        new DeferredReferenceGetKeyedValue();
+        new DeferredReferenceGetKeyedValue(key, receiver);
 
     // Check that the receiver is a heap object.
     __ tst(receiver, Operand(kSmiTagMask));
@@ -5539,17 +5650,16 @@
     // property code which can be patched. Therefore the exact number of
     // instructions generated need to be fixed, so the constant pool is blocked
     // while generating this code.
-#ifdef DEBUG
-    int kInlinedKeyedLoadInstructions = 19;
-    Label check_inlined_codesize;
-    masm_->bind(&check_inlined_codesize);
-#endif
     { Assembler::BlockConstPoolScope block_const_pool(masm_);
       Register scratch1 = VirtualFrame::scratch0();
       Register scratch2 = VirtualFrame::scratch1();
       // Check the map. The null map used below is patched by the inline cache
       // code.
       __ ldr(scratch1, FieldMemOperand(receiver, HeapObject::kMapOffset));
+#ifdef DEBUG
+    Label check_inlined_codesize;
+    masm_->bind(&check_inlined_codesize);
+#endif
       __ mov(scratch2, Operand(Factory::null_value()));
       __ cmp(scratch1, scratch2);
       deferred->Branch(ne);
@@ -5577,17 +5687,15 @@
       __ add(scratch1,
              scratch1,
              Operand(FixedArray::kHeaderSize - kHeapObjectTag));
-      __ ldr(r0,
+      __ ldr(scratch1,
              MemOperand(scratch1, key, LSL,
                         kPointerSizeLog2 - (kSmiTagSize + kSmiShiftSize)));
-      __ cmp(r0, scratch2);
-      // This is the only branch to deferred where r0 and r1 do not contain the
-      // receiver and key.  We can't just load undefined here because we have to
-      // check the prototype.
+      __ cmp(scratch1, scratch2);
       deferred->Branch(eq);
 
+      __ mov(r0, scratch1);
       // Make sure that the expected number of instructions are generated.
-      ASSERT_EQ(kInlinedKeyedLoadInstructions,
+      ASSERT_EQ(kInlinedKeyedLoadInstructionsAfterPatchSize,
                 masm_->InstructionsGeneratedSince(&check_inlined_codesize));
     }
 
@@ -5721,6 +5829,9 @@
       Slot* slot = expression_->AsVariableProxy()->AsVariable()->slot();
       ASSERT(slot != NULL);
       cgen_->LoadFromSlotCheckForArguments(slot, NOT_INSIDE_TYPEOF);
+      if (!persist_after_get_) {
+        cgen_->UnloadReference(this);
+      }
       break;
     }
 
@@ -5730,23 +5841,26 @@
       ASSERT(!is_global || var->is_global());
       cgen_->EmitNamedLoad(GetName(), is_global);
       cgen_->frame()->EmitPush(r0);
+      if (!persist_after_get_) {
+        cgen_->UnloadReference(this);
+      }
       break;
     }
 
     case KEYED: {
+      if (persist_after_get_) {
+        cgen_->frame()->Dup2();
+      }
       ASSERT(property != NULL);
       cgen_->EmitKeyedLoad();
       cgen_->frame()->EmitPush(r0);
+      if (!persist_after_get_) set_unloaded();
       break;
     }
 
     default:
       UNREACHABLE();
   }
-
-  if (!persist_after_get_) {
-    cgen_->UnloadReference(this);
-  }
 }
 
 
@@ -5806,7 +5920,7 @@
   __ pop(r3);
 
   // Attempt to allocate new JSFunction in new space.
-  __ AllocateInNewSpace(JSFunction::kSize / kPointerSize,
+  __ AllocateInNewSpace(JSFunction::kSize,
                         r0,
                         r1,
                         r2,
@@ -5847,7 +5961,7 @@
   int length = slots_ + Context::MIN_CONTEXT_SLOTS;
 
   // Attempt to allocate the context in new space.
-  __ AllocateInNewSpace(length + (FixedArray::kHeaderSize / kPointerSize),
+  __ AllocateInNewSpace(FixedArray::SizeFor(length),
                         r0,
                         r1,
                         r2,
@@ -5915,7 +6029,7 @@
 
   // Allocate both the JS array and the elements array in one big
   // allocation. This avoids multiple limit checks.
-  __ AllocateInNewSpace(size / kPointerSize,
+  __ AllocateInNewSpace(size,
                         r0,
                         r1,
                         r2,
@@ -6248,8 +6362,7 @@
     ConvertToDoubleStub stub1(r3, r2, r7, r6);
     __ Call(stub1.GetCode(), RelocInfo::CODE_TARGET);
     // Load rhs to a double in r0, r1.
-    __ ldr(r1, FieldMemOperand(r0, HeapNumber::kValueOffset + kPointerSize));
-    __ ldr(r0, FieldMemOperand(r0, HeapNumber::kValueOffset));
+    __ ldrd(r0, FieldMemOperand(r0, HeapNumber::kValueOffset));
     __ pop(lr);
   }
 
@@ -6284,8 +6397,7 @@
   } else {
     __ push(lr);
     // Load lhs to a double in r2, r3.
-    __ ldr(r3, FieldMemOperand(r1, HeapNumber::kValueOffset + kPointerSize));
-    __ ldr(r2, FieldMemOperand(r1, HeapNumber::kValueOffset));
+    __ ldrd(r2, FieldMemOperand(r1, HeapNumber::kValueOffset));
     // Convert rhs to a double in r0, r1.
     __ mov(r7, Operand(r0));
     ConvertToDoubleStub stub2(r1, r0, r7, r6);
@@ -6449,10 +6561,8 @@
     __ sub(r7, r1, Operand(kHeapObjectTag));
     __ vldr(d7, r7, HeapNumber::kValueOffset);
   } else {
-    __ ldr(r2, FieldMemOperand(r1, HeapNumber::kValueOffset));
-    __ ldr(r3, FieldMemOperand(r1, HeapNumber::kValueOffset + kPointerSize));
-    __ ldr(r1, FieldMemOperand(r0, HeapNumber::kValueOffset + kPointerSize));
-    __ ldr(r0, FieldMemOperand(r0, HeapNumber::kValueOffset));
+    __ ldrd(r2, FieldMemOperand(r1, HeapNumber::kValueOffset));
+    __ ldrd(r0, FieldMemOperand(r0, HeapNumber::kValueOffset));
   }
   __ jmp(both_loaded_as_doubles);
 }
@@ -6829,8 +6939,7 @@
       __ vldr(d7, r7, HeapNumber::kValueOffset);
     } else {
       // Calling convention says that second double is in r2 and r3.
-      __ ldr(r2, FieldMemOperand(r0, HeapNumber::kValueOffset));
-      __ ldr(r3, FieldMemOperand(r0, HeapNumber::kValueOffset + 4));
+      __ ldrd(r2, FieldMemOperand(r0, HeapNumber::kValueOffset));
     }
     __ jmp(&finished_loading_r0);
     __ bind(&r0_is_smi);
@@ -6882,8 +6991,7 @@
       __ vldr(d6, r7, HeapNumber::kValueOffset);
     } else {
       // Calling convention says that first double is in r0 and r1.
-      __ ldr(r0, FieldMemOperand(r1, HeapNumber::kValueOffset));
-      __ ldr(r1, FieldMemOperand(r1, HeapNumber::kValueOffset + 4));
+      __ ldrd(r0, FieldMemOperand(r1, HeapNumber::kValueOffset));
     }
     __ jmp(&finished_loading_r1);
     __ bind(&r1_is_smi);
@@ -6954,8 +7062,7 @@
       __ stc(p1, cr8, MemOperand(r4, HeapNumber::kValueOffset));
   #else
       // Double returned in registers 0 and 1.
-      __ str(r0, FieldMemOperand(r5, HeapNumber::kValueOffset));
-      __ str(r1, FieldMemOperand(r5, HeapNumber::kValueOffset + 4));
+      __ strd(r0, FieldMemOperand(r5, HeapNumber::kValueOffset));
   #endif
       __ mov(r0, Operand(r5));
       // And we are done.
@@ -8206,6 +8313,22 @@
 
   // Get the prototype of the function (r4 is result, r2 is scratch).
   __ ldr(r1, MemOperand(sp, 0));
+  // r1 is function, r3 is map.
+
+  // Look up the function and the map in the instanceof cache.
+  Label miss;
+  __ LoadRoot(ip, Heap::kInstanceofCacheFunctionRootIndex);
+  __ cmp(r1, ip);
+  __ b(ne, &miss);
+  __ LoadRoot(ip, Heap::kInstanceofCacheMapRootIndex);
+  __ cmp(r3, ip);
+  __ b(ne, &miss);
+  __ LoadRoot(r0, Heap::kInstanceofCacheAnswerRootIndex);
+  __ pop();
+  __ pop();
+  __ mov(pc, Operand(lr));
+
+  __ bind(&miss);
   __ TryGetFunctionPrototype(r1, r4, r2, &slow);
 
   // Check that the function prototype is a JS object.
@@ -8215,6 +8338,9 @@
   __ cmp(r5, Operand(LAST_JS_OBJECT_TYPE));
   __ b(gt, &slow);
 
+  __ StoreRoot(r1, Heap::kInstanceofCacheFunctionRootIndex);
+  __ StoreRoot(r3, Heap::kInstanceofCacheMapRootIndex);
+
   // Register mapping: r3 is object map and r4 is function prototype.
   // Get prototype of object into r2.
   __ ldr(r2, FieldMemOperand(r3, Map::kPrototypeOffset));
@@ -8232,12 +8358,14 @@
 
   __ bind(&is_instance);
   __ mov(r0, Operand(Smi::FromInt(0)));
+  __ StoreRoot(r0, Heap::kInstanceofCacheAnswerRootIndex);
   __ pop();
   __ pop();
   __ mov(pc, Operand(lr));  // Return.
 
   __ bind(&is_not_instance);
   __ mov(r0, Operand(Smi::FromInt(1)));
+  __ StoreRoot(r0, Heap::kInstanceofCacheAnswerRootIndex);
   __ pop();
   __ pop();
   __ mov(pc, Operand(lr));  // Return.
@@ -8324,8 +8452,7 @@
   __ str(r3, MemOperand(sp, 1 * kPointerSize));
 
   // Try the new space allocation. Start out with computing the size
-  // of the arguments object and the elements array (in words, not
-  // bytes because AllocateInNewSpace expects words).
+  // of the arguments object and the elements array in words.
   Label add_arguments_object;
   __ bind(&try_allocate);
   __ cmp(r1, Operand(0));
@@ -8336,7 +8463,13 @@
   __ add(r1, r1, Operand(Heap::kArgumentsObjectSize / kPointerSize));
 
   // Do the allocation of both objects in one go.
-  __ AllocateInNewSpace(r1, r0, r2, r3, &runtime, TAG_OBJECT);
+  __ AllocateInNewSpace(
+      r1,
+      r0,
+      r2,
+      r3,
+      &runtime,
+      static_cast<AllocationFlags>(TAG_OBJECT | SIZE_IN_WORDS));
 
   // Get the arguments boilerplate from the current (global) context.
   int offset = Context::SlotOffset(Context::ARGUMENTS_BOILERPLATE_INDEX);
@@ -8406,9 +8539,9 @@
   // Just jump directly to runtime if native RegExp is not selected at compile
   // time or if regexp entry in generated code is turned off runtime switch or
   // at compilation.
-#ifndef V8_NATIVE_REGEXP
+#ifdef V8_INTERPRETED_REGEXP
   __ TailCallRuntime(Runtime::kRegExpExec, 4, 1);
-#else  // V8_NATIVE_REGEXP
+#else  // V8_INTERPRETED_REGEXP
   if (!FLAG_regexp_entry_native) {
     __ TailCallRuntime(Runtime::kRegExpExec, 4, 1);
     return;
@@ -8501,9 +8634,9 @@
   // string length. A negative value will be greater (unsigned comparison).
   __ ldr(r0, MemOperand(sp, kPreviousIndexOffset));
   __ tst(r0, Operand(kSmiTagMask));
-  __ b(eq, &runtime);
+  __ b(ne, &runtime);
   __ cmp(r3, Operand(r0));
-  __ b(le, &runtime);
+  __ b(ls, &runtime);
 
   // r2: Number of capture registers
   // subject: Subject string
@@ -8518,11 +8651,7 @@
   __ ldr(last_match_info_elements,
          FieldMemOperand(r0, JSArray::kElementsOffset));
   __ ldr(r0, FieldMemOperand(last_match_info_elements, HeapObject::kMapOffset));
-#if ANDROID
   __ LoadRoot(ip, Heap::kFixedArrayMapRootIndex);
-#else
-  __ LoadRoot(ip, kFixedArrayMapRootIndex);
-#endif
   __ cmp(r0, ip);
   __ b(ne, &runtime);
   // Check that the last match info has space for the capture registers and the
@@ -8745,7 +8874,7 @@
   // Do the runtime call to execute the regexp.
   __ bind(&runtime);
   __ TailCallRuntime(Runtime::kRegExpExec, 4, 1);
-#endif  // V8_NATIVE_REGEXP
+#endif  // V8_INTERPRETED_REGEXP
 }
 
 
diff --git a/src/arm/codegen-arm.h b/src/arm/codegen-arm.h
index bb76b63..33a85c4 100644
--- a/src/arm/codegen-arm.h
+++ b/src/arm/codegen-arm.h
@@ -29,6 +29,7 @@
 #define V8_ARM_CODEGEN_ARM_H_
 
 #include "ic-inl.h"
+#include "ast.h"
 
 namespace v8 {
 namespace internal {
@@ -36,6 +37,7 @@
 // Forward declarations
 class CompilationInfo;
 class DeferredCode;
+class JumpTarget;
 class RegisterAllocator;
 class RegisterFile;
 
@@ -217,6 +219,9 @@
   // expected arguments. Otherwise return -1.
   static int InlineRuntimeCallArgumentsCount(Handle<String> name);
 
+  // Constants related to patching of inlined load/store.
+  static const int kInlinedKeyedLoadInstructionsAfterPatchSize = 19;
+
  private:
   // Construction/Destruction
   explicit CodeGenerator(MacroAssembler* masm);
@@ -309,6 +314,7 @@
   // Read a value from a slot and leave it on top of the expression stack.
   void LoadFromSlot(Slot* slot, TypeofState typeof_state);
   void LoadFromSlotCheckForArguments(Slot* slot, TypeofState state);
+
   // Store the value on top of the stack to a slot.
   void StoreToSlot(Slot* slot, InitState init_state);
 
@@ -338,6 +344,15 @@
                                          TypeofState typeof_state,
                                          JumpTarget* slow);
 
+  // Support for loading from local/global variables and arguments
+  // whose location is known unless they are shadowed by
+  // eval-introduced bindings. Generates no code for unsupported slot
+  // types and therefore expects to fall through to the slow jump target.
+  void EmitDynamicLoadFromSlotFastCase(Slot* slot,
+                                       TypeofState typeof_state,
+                                       JumpTarget* slow,
+                                       JumpTarget* done);
+
   // Special code for typeof expressions: Unfortunately, we must
   // be careful when loading the expression in 'typeof'
   // expressions. We are not allowed to throw reference errors for
diff --git a/src/arm/constants-arm.h b/src/arm/constants-arm.h
index 5eed13f..57c5c1c 100644
--- a/src/arm/constants-arm.h
+++ b/src/arm/constants-arm.h
@@ -72,6 +72,10 @@
 # define CAN_USE_THUMB_INSTRUCTIONS 1
 #endif
 
+#if CAN_USE_UNALIGNED_ACCESSES
+#define V8_TARGET_CAN_READ_UNALIGNED 1
+#endif
+
 // Using blx may yield better code, so use it when required or when available
 #if defined(USE_THUMB_INTERWORK) || defined(CAN_USE_ARMV5_INSTRUCTIONS)
 #define USE_BLX 1
diff --git a/src/arm/disasm-arm.cc b/src/arm/disasm-arm.cc
index 4ba3094..4051096 100644
--- a/src/arm/disasm-arm.cc
+++ b/src/arm/disasm-arm.cc
@@ -418,6 +418,12 @@
         ASSERT(STRING_STARTS_WITH(format, "memop"));
         if (instr->HasL()) {
           Print("ldr");
+        } else if ((instr->Bits(27, 25) == 0) && (instr->Bit(20) == 0)) {
+          if (instr->Bits(7, 4) == 0xf) {
+            Print("strd");
+          } else {
+            Print("ldrd");
+          }
         } else {
           Print("str");
         }
@@ -614,6 +620,47 @@
       } else {
         Unknown(instr);  // not used by V8
       }
+    } else if ((instr->Bit(20) == 0) && ((instr->Bits(7, 4) & 0xd) == 0xd)) {
+      // ldrd, strd
+      switch (instr->PUField()) {
+        case 0: {
+          if (instr->Bit(22) == 0) {
+            Format(instr, "'memop'cond's 'rd, ['rn], -'rm");
+          } else {
+            Format(instr, "'memop'cond's 'rd, ['rn], #-'off8");
+          }
+          break;
+        }
+        case 1: {
+          if (instr->Bit(22) == 0) {
+            Format(instr, "'memop'cond's 'rd, ['rn], +'rm");
+          } else {
+            Format(instr, "'memop'cond's 'rd, ['rn], #+'off8");
+          }
+          break;
+        }
+        case 2: {
+          if (instr->Bit(22) == 0) {
+            Format(instr, "'memop'cond's 'rd, ['rn, -'rm]'w");
+          } else {
+            Format(instr, "'memop'cond's 'rd, ['rn, #-'off8]'w");
+          }
+          break;
+        }
+        case 3: {
+          if (instr->Bit(22) == 0) {
+            Format(instr, "'memop'cond's 'rd, ['rn, +'rm]'w");
+          } else {
+            Format(instr, "'memop'cond's 'rd, ['rn, #+'off8]'w");
+          }
+          break;
+        }
+        default: {
+          // The PU field is a 2-bit field.
+          UNREACHABLE();
+          break;
+        }
+      }
     } else {
       // extra load/store instructions
       switch (instr->PUField()) {
diff --git a/src/arm/full-codegen-arm.cc b/src/arm/full-codegen-arm.cc
index e9bdfe5..6680af9 100644
--- a/src/arm/full-codegen-arm.cc
+++ b/src/arm/full-codegen-arm.cc
@@ -738,15 +738,10 @@
     // Load the key.
     __ mov(r0, Operand(key_literal->handle()));
 
-    // Push both as arguments to ic.
-    __ Push(r1, r0);
-
-    // Call keyed load IC. It has all arguments on the stack and the key in r0.
+    // Call keyed load IC. It has arguments key and receiver in r0 and r1.
     Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize));
     __ Call(ic, RelocInfo::CODE_TARGET);
-
-    // Drop key and object left on the stack by IC, and push the result.
-    DropAndApply(2, context, r0);
+    Apply(context, r0);
   }
 }
 
@@ -935,8 +930,16 @@
       }
       break;
     case KEYED_PROPERTY:
-      VisitForValue(prop->obj(), kStack);
-      VisitForValue(prop->key(), kStack);
+      // We need the key and receiver on both the stack and in r0 and r1.
+      if (expr->is_compound()) {
+        VisitForValue(prop->obj(), kStack);
+        VisitForValue(prop->key(), kAccumulator);
+        __ ldr(r1, MemOperand(sp, 0));
+        __ push(r0);
+      } else {
+        VisitForValue(prop->obj(), kStack);
+        VisitForValue(prop->key(), kStack);
+      }
       break;
   }
 
@@ -1005,8 +1008,7 @@
 
 void FullCodeGenerator::EmitKeyedPropertyLoad(Property* prop) {
   SetSourcePosition(prop->position());
-  // Call keyed load IC. It has all arguments on the stack and the key in r0.
-  __ ldr(r0, MemOperand(sp, 0));
+  // Call keyed load IC. It has arguments key and receiver in r0 and r1.
   Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize));
   __ Call(ic, RelocInfo::CODE_TARGET);
 }
@@ -1171,10 +1173,10 @@
     // Drop receiver left on the stack by IC.
     DropAndApply(1, context_, r0);
   } else {
-    VisitForValue(expr->key(), kStack);
+    VisitForValue(expr->key(), kAccumulator);
+    __ pop(r1);
     EmitKeyedPropertyLoad(expr);
-    // Drop key and receiver left on the stack by IC.
-    DropAndApply(2, context_, r0);
+    Apply(context_, r0);
   }
 }
 
@@ -1246,24 +1248,31 @@
       // Call to a keyed property, use keyed load IC followed by function
       // call.
       VisitForValue(prop->obj(), kStack);
-      VisitForValue(prop->key(), kStack);
+      VisitForValue(prop->key(), kAccumulator);
       // Record source code position for IC call.
       SetSourcePosition(prop->position());
-      // Call keyed load IC. It has all arguments on the stack and the key in
-      // r0.
-      __ ldr(r0, MemOperand(sp, 0));
+      if (prop->is_synthetic()) {
+        __ pop(r1);  // We do not need to keep the receiver.
+      } else {
+        __ ldr(r1, MemOperand(sp, 0));  // Keep receiver, to call function on.
+      }
+
       Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize));
       __ Call(ic, RelocInfo::CODE_TARGET);
-      // Load receiver object into r1.
       if (prop->is_synthetic()) {
+        // Push result (function).
+        __ push(r0);
+        // Push Global receiver.
         __ ldr(r1, CodeGenerator::GlobalObject());
         __ ldr(r1, FieldMemOperand(r1, GlobalObject::kGlobalReceiverOffset));
+        __ push(r1);
       } else {
-        __ ldr(r1, MemOperand(sp, kPointerSize));
+        // Pop receiver.
+        __ pop(r1);
+        // Push result (function).
+        __ push(r0);
+        __ push(r1);
       }
-      // Overwrite (object, key) with (function, receiver).
-      __ str(r0, MemOperand(sp, kPointerSize));
-      __ str(r1, MemOperand(sp));
       EmitCallWithStub(expr);
     }
   } else {
@@ -1552,7 +1561,9 @@
     if (assign_type == NAMED_PROPERTY) {
       EmitNamedPropertyLoad(prop);
     } else {
-      VisitForValue(prop->key(), kStack);
+      VisitForValue(prop->key(), kAccumulator);
+      __ ldr(r1, MemOperand(sp, 0));
+      __ push(r0);
       EmitKeyedPropertyLoad(prop);
     }
   }
diff --git a/src/arm/ic-arm.cc b/src/arm/ic-arm.cc
index 5b1915f..c308d69 100644
--- a/src/arm/ic-arm.cc
+++ b/src/arm/ic-arm.cc
@@ -28,6 +28,7 @@
 #include "v8.h"
 
 #include "assembler-arm.h"
+#include "codegen.h"
 #include "codegen-inl.h"
 #include "disasm.h"
 #include "ic-inl.h"
@@ -639,7 +640,9 @@
 
   // Patch the map check.
   Address ldr_map_instr_address =
-      inline_end_address - 18 * Assembler::kInstrSize;
+      inline_end_address -
+      CodeGenerator::kInlinedKeyedLoadInstructionsAfterPatchSize *
+      Assembler::kInstrSize;
   Assembler::set_target_address_at(ldr_map_instr_address,
                                    reinterpret_cast<Address>(map));
   return true;
@@ -683,11 +686,9 @@
   // ---------- S t a t e --------------
   //  -- lr     : return address
   //  -- r0     : key
-  //  -- sp[0]  : key
-  //  -- sp[4]  : receiver
+  //  -- r1     : receiver
   // -----------------------------------
 
-  __ ldr(r1, MemOperand(sp, kPointerSize));
   __ Push(r1, r0);
 
   ExternalReference ref = ExternalReference(IC_Utility(kKeyedLoadIC_Miss));
@@ -699,11 +700,9 @@
   // ---------- S t a t e --------------
   //  -- lr     : return address
   //  -- r0     : key
-  //  -- sp[0]  : key
-  //  -- sp[4]  : receiver
+  //  -- r1     : receiver
   // -----------------------------------
 
-  __ ldr(r1, MemOperand(sp, kPointerSize));
   __ Push(r1, r0);
 
   __ TailCallRuntime(Runtime::kGetProperty, 2, 1);
@@ -714,18 +713,17 @@
   // ---------- S t a t e --------------
   //  -- lr     : return address
   //  -- r0     : key
-  //  -- sp[0]  : key
-  //  -- sp[4]  : receiver
+  //  -- r1     : receiver
   // -----------------------------------
   Label slow, fast, check_pixel_array, check_number_dictionary;
 
-  // Get the object from the stack.
-  __ ldr(r1, MemOperand(sp, kPointerSize));
+  Register key = r0;
+  Register receiver = r1;
 
   // Check that the object isn't a smi.
-  __ BranchOnSmi(r1, &slow);
+  __ BranchOnSmi(receiver, &slow);
   // Get the map of the receiver.
-  __ ldr(r2, FieldMemOperand(r1, HeapObject::kMapOffset));
+  __ ldr(r2, FieldMemOperand(receiver, HeapObject::kMapOffset));
   // Check bit field.
   __ ldrb(r3, FieldMemOperand(r2, Map::kBitFieldOffset));
   __ tst(r3, Operand(kSlowCaseBitFieldMask));
@@ -740,60 +738,65 @@
   __ b(lt, &slow);
 
   // Check that the key is a smi.
-  __ BranchOnNotSmi(r0, &slow);
-  // Save key in r2 in case we want it for the number dictionary case.
-  __ mov(r2, r0);
-  __ mov(r0, Operand(r0, ASR, kSmiTagSize));
+  __ BranchOnNotSmi(key, &slow);
+  // Untag key into r2..
+  __ mov(r2, Operand(key, ASR, kSmiTagSize));
 
   // Get the elements array of the object.
-  __ ldr(r1, FieldMemOperand(r1, JSObject::kElementsOffset));
+  __ ldr(r4, FieldMemOperand(receiver, JSObject::kElementsOffset));
   // Check that the object is in fast mode (not dictionary).
-  __ ldr(r3, FieldMemOperand(r1, HeapObject::kMapOffset));
+  __ ldr(r3, FieldMemOperand(r4, HeapObject::kMapOffset));
   __ LoadRoot(ip, Heap::kFixedArrayMapRootIndex);
   __ cmp(r3, ip);
   __ b(ne, &check_pixel_array);
   // Check that the key (index) is within bounds.
-  __ ldr(r3, FieldMemOperand(r1, Array::kLengthOffset));
-  __ cmp(r0, r3);
+  __ ldr(r3, FieldMemOperand(r4, Array::kLengthOffset));
+  __ cmp(r2, r3);
   __ b(hs, &slow);
   // Fast case: Do the load.
-  __ add(r3, r1, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
-  __ ldr(r0, MemOperand(r3, r0, LSL, kPointerSizeLog2));
+  __ add(r3, r4, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
+  __ ldr(r2, MemOperand(r3, r2, LSL, kPointerSizeLog2));
   __ LoadRoot(ip, Heap::kTheHoleValueRootIndex);
-  __ cmp(r0, ip);
+  __ cmp(r2, ip);
   // In case the loaded value is the_hole we have to consult GetProperty
   // to ensure the prototype chain is searched.
   __ b(eq, &slow);
+  __ mov(r0, r2);
   __ Ret();
 
   // Check whether the elements is a pixel array.
+  // r0: key
+  // r2: untagged index
+  // r3: elements map
+  // r4: elements
   __ bind(&check_pixel_array);
   __ LoadRoot(ip, Heap::kPixelArrayMapRootIndex);
   __ cmp(r3, ip);
   __ b(ne, &check_number_dictionary);
-  __ ldr(ip, FieldMemOperand(r1, PixelArray::kLengthOffset));
-  __ cmp(r0, ip);
+  __ ldr(ip, FieldMemOperand(r4, PixelArray::kLengthOffset));
+  __ cmp(r2, ip);
   __ b(hs, &slow);
-  __ ldr(ip, FieldMemOperand(r1, PixelArray::kExternalPointerOffset));
-  __ ldrb(r0, MemOperand(ip, r0));
-  __ mov(r0, Operand(r0, LSL, kSmiTagSize));  // Tag result as smi.
+  __ ldr(ip, FieldMemOperand(r4, PixelArray::kExternalPointerOffset));
+  __ ldrb(r2, MemOperand(ip, r2));
+  __ mov(r0, Operand(r2, LSL, kSmiTagSize));  // Tag result as smi.
   __ Ret();
 
   __ bind(&check_number_dictionary);
   // Check whether the elements is a number dictionary.
-  // r0: untagged index
-  // r1: elements
-  // r2: key
+  // r0: key
+  // r2: untagged index
+  // r3: elements map
+  // r4: elements
   __ LoadRoot(ip, Heap::kHashTableMapRootIndex);
   __ cmp(r3, ip);
   __ b(ne, &slow);
-  GenerateNumberDictionaryLoad(masm, &slow, r1, r2, r0, r3, r4);
+  GenerateNumberDictionaryLoad(masm, &slow, r4, r0, r2, r3, r5);
+  __ mov(r0, r2);
   __ Ret();
 
-  // Slow case: Push extra copies of the arguments (2).
+  // Slow case, key and receiver still in r0 and r1.
   __ bind(&slow);
-  __ IncrementCounter(&Counters::keyed_load_generic_slow, 1, r0, r1);
-  __ ldr(r0, MemOperand(sp, 0));
+  __ IncrementCounter(&Counters::keyed_load_generic_slow, 1, r2, r3);
   GenerateRuntimeGetProperty(masm);
 }
 
@@ -802,8 +805,7 @@
   // ---------- S t a t e --------------
   //  -- lr     : return address
   //  -- r0     : key
-  //  -- sp[0]  : key
-  //  -- sp[4]  : receiver
+  //  -- r1     : receiver
   // -----------------------------------
   Label miss;
   Label index_not_smi;
@@ -811,9 +813,6 @@
   Label slow_char_code;
   Label got_char_code;
 
-  // Get the object from the stack.
-  __ ldr(r1, MemOperand(sp, kPointerSize));
-
   Register object = r1;
   Register index = r0;
   Register code = r2;
@@ -913,25 +912,21 @@
   // ---------- S t a t e --------------
   //  -- lr     : return address
   //  -- r0     : key
-  //  -- sp[0]  : key
-  //  -- sp[4]  : receiver
+  //  -- r1     : receiver
   // -----------------------------------
   Label slow, failed_allocation;
 
-  // Get the object from the stack.
-  __ ldr(r1, MemOperand(sp, kPointerSize));
-
-  // r0: key
-  // r1: receiver object
+  Register key = r0;
+  Register receiver = r1;
 
   // Check that the object isn't a smi
-  __ BranchOnSmi(r1, &slow);
+  __ BranchOnSmi(receiver, &slow);
 
   // Check that the key is a smi.
-  __ BranchOnNotSmi(r0, &slow);
+  __ BranchOnNotSmi(key, &slow);
 
   // Check that the object is a JS object. Load map into r2.
-  __ CompareObjectType(r1, r2, r3, FIRST_JS_OBJECT_TYPE);
+  __ CompareObjectType(receiver, r2, r3, FIRST_JS_OBJECT_TYPE);
   __ b(lt, &slow);
 
   // Check that the receiver does not require access checks.  We need
@@ -943,53 +938,51 @@
 
   // Check that the elements array is the appropriate type of
   // ExternalArray.
-  // r0: index (as a smi)
-  // r1: JSObject
-  __ ldr(r1, FieldMemOperand(r1, JSObject::kElementsOffset));
-  __ ldr(r2, FieldMemOperand(r1, HeapObject::kMapOffset));
+  __ ldr(r3, FieldMemOperand(receiver, JSObject::kElementsOffset));
+  __ ldr(r2, FieldMemOperand(r3, HeapObject::kMapOffset));
   __ LoadRoot(ip, Heap::RootIndexForExternalArrayType(array_type));
   __ cmp(r2, ip);
   __ b(ne, &slow);
 
   // Check that the index is in range.
-  __ ldr(ip, FieldMemOperand(r1, ExternalArray::kLengthOffset));
-  __ cmp(r1, Operand(r0, ASR, kSmiTagSize));
+  __ ldr(ip, FieldMemOperand(r3, ExternalArray::kLengthOffset));
+  __ cmp(ip, Operand(key, ASR, kSmiTagSize));
   // Unsigned comparison catches both negative and too-large values.
   __ b(lo, &slow);
 
-  // r0: index (smi)
-  // r1: elements array
-  __ ldr(r1, FieldMemOperand(r1, ExternalArray::kExternalPointerOffset));
-  // r1: base pointer of external storage
+  // r3: elements array
+  __ ldr(r3, FieldMemOperand(r3, ExternalArray::kExternalPointerOffset));
+  // r3: base pointer of external storage
 
   // We are not untagging smi key and instead work with it
   // as if it was premultiplied by 2.
   ASSERT((kSmiTag == 0) && (kSmiTagSize == 1));
 
+  Register value = r2;
   switch (array_type) {
     case kExternalByteArray:
-      __ ldrsb(r0, MemOperand(r1, r0, LSR, 1));
+      __ ldrsb(value, MemOperand(r3, key, LSR, 1));
       break;
     case kExternalUnsignedByteArray:
-      __ ldrb(r0, MemOperand(r1, r0, LSR, 1));
+      __ ldrb(value, MemOperand(r3, key, LSR, 1));
       break;
     case kExternalShortArray:
-      __ ldrsh(r0, MemOperand(r1, r0, LSL, 0));
+      __ ldrsh(value, MemOperand(r3, key, LSL, 0));
       break;
     case kExternalUnsignedShortArray:
-      __ ldrh(r0, MemOperand(r1, r0, LSL, 0));
+      __ ldrh(value, MemOperand(r3, key, LSL, 0));
       break;
     case kExternalIntArray:
     case kExternalUnsignedIntArray:
-      __ ldr(r0, MemOperand(r1, r0, LSL, 1));
+      __ ldr(value, MemOperand(r3, key, LSL, 1));
       break;
     case kExternalFloatArray:
       if (CpuFeatures::IsSupported(VFP3)) {
         CpuFeatures::Scope scope(VFP3);
-        __ add(r0, r1, Operand(r0, LSL, 1));
-        __ vldr(s0, r0, 0);
+        __ add(r2, r3, Operand(key, LSL, 1));
+        __ vldr(s0, r2, 0);
       } else {
-        __ ldr(r0, MemOperand(r1, r0, LSL, 1));
+        __ ldr(value, MemOperand(r3, key, LSL, 1));
       }
       break;
     default:
@@ -998,37 +991,36 @@
   }
 
   // For integer array types:
-  // r0: value
+  // r2: value
   // For floating-point array type
   // s0: value (if VFP3 is supported)
-  // r0: value (if VFP3 is not supported)
+  // r2: value (if VFP3 is not supported)
 
   if (array_type == kExternalIntArray) {
     // For the Int and UnsignedInt array types, we need to see whether
     // the value can be represented in a Smi. If not, we need to convert
     // it to a HeapNumber.
     Label box_int;
-    __ cmp(r0, Operand(0xC0000000));
+    __ cmp(value, Operand(0xC0000000));
     __ b(mi, &box_int);
-    __ mov(r0, Operand(r0, LSL, kSmiTagSize));
+    // Tag integer as smi and return it.
+    __ mov(r0, Operand(value, LSL, kSmiTagSize));
     __ Ret();
 
     __ bind(&box_int);
-
-    __ mov(r1, r0);
-    // Allocate a HeapNumber for the int and perform int-to-double
-    // conversion.
+    // Allocate a HeapNumber for the result and perform int-to-double
+    // conversion. Use r0 for result as key is not needed any more.
     __ AllocateHeapNumber(r0, r3, r4, &slow);
 
     if (CpuFeatures::IsSupported(VFP3)) {
       CpuFeatures::Scope scope(VFP3);
-      __ vmov(s0, r1);
+      __ vmov(s0, value);
       __ vcvt_f64_s32(d0, s0);
-      __ sub(r1, r0, Operand(kHeapObjectTag));
-      __ vstr(d0, r1, HeapNumber::kValueOffset);
+      __ sub(r3, r0, Operand(kHeapObjectTag));
+      __ vstr(d0, r3, HeapNumber::kValueOffset);
       __ Ret();
     } else {
-      WriteInt32ToHeapNumberStub stub(r1, r0, r3);
+      WriteInt32ToHeapNumberStub stub(value, r0, r3);
       __ TailCallStub(&stub);
     }
   } else if (array_type == kExternalUnsignedIntArray) {
@@ -1038,51 +1030,60 @@
     if (CpuFeatures::IsSupported(VFP3)) {
       CpuFeatures::Scope scope(VFP3);
       Label box_int, done;
-      __ tst(r0, Operand(0xC0000000));
+      __ tst(value, Operand(0xC0000000));
       __ b(ne, &box_int);
-
-      __ mov(r0, Operand(r0, LSL, kSmiTagSize));
+      // Tag integer as smi and return it.
+      __ mov(r0, Operand(value, LSL, kSmiTagSize));
       __ Ret();
 
       __ bind(&box_int);
-      __ vmov(s0, r0);
-      __ AllocateHeapNumber(r0, r1, r2, &slow);
+      __ vmov(s0, value);
+      // Allocate a HeapNumber for the result and perform int-to-double
+      // conversion. Don't use r0 and r1 as AllocateHeapNumber clobbers all
+      // registers - also when jumping due to exhausted young space.
+      __ AllocateHeapNumber(r2, r3, r4, &slow);
 
       __ vcvt_f64_u32(d0, s0);
-      __ sub(r1, r0, Operand(kHeapObjectTag));
+      __ sub(r1, r2, Operand(kHeapObjectTag));
       __ vstr(d0, r1, HeapNumber::kValueOffset);
+
+      __ mov(r0, r2);
       __ Ret();
     } else {
       // Check whether unsigned integer fits into smi.
       Label box_int_0, box_int_1, done;
-      __ tst(r0, Operand(0x80000000));
+      __ tst(value, Operand(0x80000000));
       __ b(ne, &box_int_0);
-      __ tst(r0, Operand(0x40000000));
+      __ tst(value, Operand(0x40000000));
       __ b(ne, &box_int_1);
-
       // Tag integer as smi and return it.
-      __ mov(r0, Operand(r0, LSL, kSmiTagSize));
+      __ mov(r0, Operand(value, LSL, kSmiTagSize));
       __ Ret();
 
+      Register hiword = value;  // r2.
+      Register loword = r3;
+
       __ bind(&box_int_0);
       // Integer does not have leading zeros.
-      GenerateUInt2Double(masm, r0, r1, r2, 0);
+      GenerateUInt2Double(masm, hiword, loword, r4, 0);
       __ b(&done);
 
       __ bind(&box_int_1);
       // Integer has one leading zero.
-      GenerateUInt2Double(masm, r0, r1, r2, 1);
+      GenerateUInt2Double(masm, hiword, loword, r4, 1);
+
 
       __ bind(&done);
-      // Integer was converted to double in registers r0:r1.
-      // Wrap it into a HeapNumber.
-      __ AllocateHeapNumber(r2, r3, r5, &slow);
+      // Integer was converted to double in registers hiword:loword.
+      // Wrap it into a HeapNumber. Don't use r0 and r1 as AllocateHeapNumber
+      // clobbers all registers - also when jumping due to exhausted young
+      // space.
+      __ AllocateHeapNumber(r4, r5, r6, &slow);
 
-      __ str(r0, FieldMemOperand(r2, HeapNumber::kExponentOffset));
-      __ str(r1, FieldMemOperand(r2, HeapNumber::kMantissaOffset));
+      __ str(hiword, FieldMemOperand(r4, HeapNumber::kExponentOffset));
+      __ str(loword, FieldMemOperand(r4, HeapNumber::kMantissaOffset));
 
-      __ mov(r0, r2);
-
+      __ mov(r0, r4);
       __ Ret();
     }
   } else if (array_type == kExternalFloatArray) {
@@ -1090,40 +1091,52 @@
     // HeapNumber.
     if (CpuFeatures::IsSupported(VFP3)) {
       CpuFeatures::Scope scope(VFP3);
-      __ AllocateHeapNumber(r0, r1, r2, &slow);
+      // Allocate a HeapNumber for the result. Don't use r0 and r1 as
+      // AllocateHeapNumber clobbers all registers - also when jumping due to
+      // exhausted young space.
+      __ AllocateHeapNumber(r2, r3, r4, &slow);
       __ vcvt_f64_f32(d0, s0);
-      __ sub(r1, r0, Operand(kHeapObjectTag));
+      __ sub(r1, r2, Operand(kHeapObjectTag));
       __ vstr(d0, r1, HeapNumber::kValueOffset);
+
+      __ mov(r0, r2);
       __ Ret();
     } else {
-      __ AllocateHeapNumber(r3, r1, r2, &slow);
+      // Allocate a HeapNumber for the result. Don't use r0 and r1 as
+      // AllocateHeapNumber clobbers all registers - also when jumping due to
+      // exhausted young space.
+      __ AllocateHeapNumber(r3, r4, r5, &slow);
       // VFP is not available, do manual single to double conversion.
 
-      // r0: floating point value (binary32)
+      // r2: floating point value (binary32)
+      // r3: heap number for result
 
-      // Extract mantissa to r1.
-      __ and_(r1, r0, Operand(kBinary32MantissaMask));
+      // Extract mantissa to r0. OK to clobber r0 now as there are no jumps to
+      // the slow case from here.
+      __ and_(r0, value, Operand(kBinary32MantissaMask));
 
-      // Extract exponent to r2.
-      __ mov(r2, Operand(r0, LSR, kBinary32MantissaBits));
-      __ and_(r2, r2, Operand(kBinary32ExponentMask >> kBinary32MantissaBits));
+      // Extract exponent to r1. OK to clobber r1 now as there are no jumps to
+      // the slow case from here.
+      __ mov(r1, Operand(value, LSR, kBinary32MantissaBits));
+      __ and_(r1, r1, Operand(kBinary32ExponentMask >> kBinary32MantissaBits));
 
       Label exponent_rebiased;
-      __ teq(r2, Operand(0x00));
+      __ teq(r1, Operand(0x00));
       __ b(eq, &exponent_rebiased);
 
-      __ teq(r2, Operand(0xff));
-      __ mov(r2, Operand(0x7ff), LeaveCC, eq);
+      __ teq(r1, Operand(0xff));
+      __ mov(r1, Operand(0x7ff), LeaveCC, eq);
       __ b(eq, &exponent_rebiased);
 
       // Rebias exponent.
-      __ add(r2,
-             r2,
+      __ add(r1,
+             r1,
              Operand(-kBinary32ExponentBias + HeapNumber::kExponentBias));
 
       __ bind(&exponent_rebiased);
-      __ and_(r0, r0, Operand(kBinary32SignMask));
-      __ orr(r0, r0, Operand(r2, LSL, HeapNumber::kMantissaBitsInTopWord));
+      __ and_(r2, value, Operand(kBinary32SignMask));
+      value = no_reg;
+      __ orr(r2, r2, Operand(r1, LSL, HeapNumber::kMantissaBitsInTopWord));
 
       // Shift mantissa.
       static const int kMantissaShiftForHiWord =
@@ -1132,24 +1145,25 @@
       static const int kMantissaShiftForLoWord =
           kBitsPerInt - kMantissaShiftForHiWord;
 
-      __ orr(r0, r0, Operand(r1, LSR, kMantissaShiftForHiWord));
-      __ mov(r1, Operand(r1, LSL, kMantissaShiftForLoWord));
+      __ orr(r2, r2, Operand(r0, LSR, kMantissaShiftForHiWord));
+      __ mov(r0, Operand(r0, LSL, kMantissaShiftForLoWord));
 
-      __ str(r0, FieldMemOperand(r3, HeapNumber::kExponentOffset));
-      __ str(r1, FieldMemOperand(r3, HeapNumber::kMantissaOffset));
+      __ str(r2, FieldMemOperand(r3, HeapNumber::kExponentOffset));
+      __ str(r0, FieldMemOperand(r3, HeapNumber::kMantissaOffset));
+
       __ mov(r0, r3);
       __ Ret();
     }
 
   } else {
-    __ mov(r0, Operand(r0, LSL, kSmiTagSize));
+    // Tag integer as smi and return it.
+    __ mov(r0, Operand(value, LSL, kSmiTagSize));
     __ Ret();
   }
 
-  // Slow case: Load name and receiver from stack and jump to runtime.
+  // Slow case, key and receiver still in r0 and r1.
   __ bind(&slow);
-  __ IncrementCounter(&Counters::keyed_load_external_array_slow, 1, r0, r1);
-  __ ldr(r0, MemOperand(sp, 0));
+  __ IncrementCounter(&Counters::keyed_load_external_array_slow, 1, r2, r3);
   GenerateRuntimeGetProperty(masm);
 }
 
@@ -1158,14 +1172,10 @@
   // ---------- S t a t e --------------
   //  -- lr     : return address
   //  -- r0     : key
-  //  -- sp[0]  : key
-  //  -- sp[4]  : receiver
+  //  -- r1     : receiver
   // -----------------------------------
   Label slow;
 
-  // Get the object from the stack.
-  __ ldr(r1, MemOperand(sp, kPointerSize));
-
   // Check that the receiver isn't a smi.
   __ BranchOnSmi(r1, &slow);
 
diff --git a/src/arm/jump-target-arm.cc b/src/arm/jump-target-arm.cc
index a13de0e..8d182be 100644
--- a/src/arm/jump-target-arm.cc
+++ b/src/arm/jump-target-arm.cc
@@ -47,28 +47,15 @@
   // which are still live in the C++ code.
   ASSERT(cgen()->HasValidEntryRegisters());
 
-  if (is_bound()) {
-    // Backward jump.  There already a frame expectation at the target.
-    ASSERT(direction_ == BIDIRECTIONAL);
-    cgen()->frame()->MergeTo(entry_frame_);
+  if (entry_frame_set_) {
+    // There already a frame expectation at the target.
+    cgen()->frame()->MergeTo(&entry_frame_);
     cgen()->DeleteFrame();
   } else {
-    // Use the current frame as the expected one at the target if necessary.
-    if (entry_frame_ == NULL) {
-      entry_frame_ = cgen()->frame();
-      RegisterFile empty;
-      cgen()->SetFrame(NULL, &empty);
-    } else {
-      cgen()->frame()->MergeTo(entry_frame_);
-      cgen()->DeleteFrame();
-    }
-
-    // The predicate is_linked() should be made true.  Its implementation
-    // detects the presence of a frame pointer in the reaching_frames_ list.
-    if (!is_linked()) {
-      reaching_frames_.Add(NULL);
-      ASSERT(is_linked());
-    }
+    // Clone the current frame to use as the expected one at the target.
+    set_entry_frame(cgen()->frame());
+    RegisterFile empty;
+    cgen()->SetFrame(NULL, &empty);
   }
   __ jmp(&entry_label_);
 }
@@ -77,23 +64,19 @@
 void JumpTarget::DoBranch(Condition cc, Hint ignored) {
   ASSERT(cgen()->has_valid_frame());
 
-  if (is_bound()) {
-    ASSERT(direction_ == BIDIRECTIONAL);
+  if (entry_frame_set_) {
     // Backward branch.  We have an expected frame to merge to on the
     // backward edge.
-    cgen()->frame()->MergeTo(entry_frame_);
+    if (cc == al) {
+      cgen()->frame()->MergeTo(&entry_frame_);
+    } else {
+      // We can't do conditional merges yet so you have to ensure that all
+      // conditional branches to the JumpTarget have the same virtual frame.
+      ASSERT(cgen()->frame()->Equals(&entry_frame_));
+    }
   } else {
-    // Clone the current frame to use as the expected one at the target if
-    // necessary.
-    if (entry_frame_ == NULL) {
-      entry_frame_ = new VirtualFrame(cgen()->frame());
-    }
-    // The predicate is_linked() should be made true.  Its implementation
-    // detects the presence of a frame pointer in the reaching_frames_ list.
-    if (!is_linked()) {
-      reaching_frames_.Add(NULL);
-      ASSERT(is_linked());
-    }
+    // Clone the current frame to use as the expected one at the target.
+    set_entry_frame(cgen()->frame());
   }
   __ b(cc, &entry_label_);
 }
@@ -113,15 +96,10 @@
 
   // Calls are always 'forward' so we use a copy of the current frame (plus
   // one for a return address) as the expected frame.
-  ASSERT(entry_frame_ == NULL);
-  VirtualFrame* target_frame = new VirtualFrame(cgen()->frame());
-  target_frame->Adjust(1);
-  entry_frame_ = target_frame;
-
-  // The predicate is_linked() should now be made true.  Its implementation
-  // detects the presence of a frame pointer in the reaching_frames_ list.
-  reaching_frames_.Add(NULL);
-  ASSERT(is_linked());
+  ASSERT(!entry_frame_set_);
+  VirtualFrame target_frame = *cgen()->frame();
+  target_frame.Adjust(1);
+  set_entry_frame(&target_frame);
 
   __ bl(&entry_label_);
 }
@@ -136,76 +114,24 @@
 
   if (cgen()->has_valid_frame()) {
     // If there is a current frame we can use it on the fall through.
-    if (entry_frame_ == NULL) {
-      entry_frame_ = new VirtualFrame(cgen()->frame());
+    if (!entry_frame_set_) {
+      entry_frame_ = *cgen()->frame();
+      entry_frame_set_ = true;
     } else {
-      ASSERT(cgen()->frame()->Equals(entry_frame_));
+      cgen()->frame()->MergeTo(&entry_frame_);
     }
   } else {
     // If there is no current frame we must have an entry frame which we can
     // copy.
-    ASSERT(entry_frame_ != NULL);
+    ASSERT(entry_frame_set_);
     RegisterFile empty;
-    cgen()->SetFrame(new VirtualFrame(entry_frame_), &empty);
-  }
-
-  // The predicate is_linked() should be made false.  Its implementation
-  // detects the presence (or absence) of frame pointers in the
-  // reaching_frames_ list.  If we inserted a bogus frame to make
-  // is_linked() true, remove it now.
-  if (is_linked()) {
-    reaching_frames_.Clear();
+    cgen()->SetFrame(new VirtualFrame(&entry_frame_), &empty);
   }
 
   __ bind(&entry_label_);
 }
 
 
-void BreakTarget::Jump() {
-  // On ARM we do not currently emit merge code for jumps, so we need to do
-  // it explicitly here.  The only merging necessary is to drop extra
-  // statement state from the stack.
-  ASSERT(cgen()->has_valid_frame());
-  int count = cgen()->frame()->height() - expected_height_;
-  cgen()->frame()->Drop(count);
-  DoJump();
-}
-
-
-void BreakTarget::Jump(Result* arg) {
-  UNIMPLEMENTED();
-}
-
-
-void BreakTarget::Bind() {
-#ifdef DEBUG
-  // All the forward-reaching frames should have been adjusted at the
-  // jumps to this target.
-  for (int i = 0; i < reaching_frames_.length(); i++) {
-    ASSERT(reaching_frames_[i] == NULL ||
-           reaching_frames_[i]->height() == expected_height_);
-  }
-#endif
-  // Drop leftover statement state from the frame before merging, even
-  // on the fall through.  This is so we can bind the return target
-  // with state on the frame.
-  if (cgen()->has_valid_frame()) {
-    int count = cgen()->frame()->height() - expected_height_;
-    // On ARM we do not currently emit merge code at binding sites, so we need
-    // to do it explicitly here.  The only merging necessary is to drop extra
-    // statement state from the stack.
-    cgen()->frame()->Drop(count);
-  }
-
-  DoBind();
-}
-
-
-void BreakTarget::Bind(Result* arg) {
-  UNIMPLEMENTED();
-}
-
-
 #undef __
 
 
diff --git a/src/arm/macro-assembler-arm.cc b/src/arm/macro-assembler-arm.cc
index d97f04b..c4b153f 100644
--- a/src/arm/macro-assembler-arm.cc
+++ b/src/arm/macro-assembler-arm.cc
@@ -232,6 +232,13 @@
 }
 
 
+void MacroAssembler::StoreRoot(Register source,
+                               Heap::RootListIndex index,
+                               Condition cond) {
+  str(source, MemOperand(roots, index << kPointerSizeLog2), cond);
+}
+
+
 void MacroAssembler::RecordWriteHelper(Register object,
                                        Register offset,
                                        Register scratch) {
@@ -926,6 +933,12 @@
   ASSERT(!result.is(scratch1));
   ASSERT(!scratch1.is(scratch2));
 
+  // Make object size into bytes.
+  if ((flags & SIZE_IN_WORDS) != 0) {
+    object_size *= kPointerSize;
+  }
+  ASSERT_EQ(0, object_size & kObjectAlignmentMask);
+
   // Load address of new object into result and allocation top address into
   // scratch1.
   ExternalReference new_space_allocation_top =
@@ -948,23 +961,16 @@
       ExternalReference::new_space_allocation_limit_address();
   mov(scratch2, Operand(new_space_allocation_limit));
   ldr(scratch2, MemOperand(scratch2));
-  add(result, result, Operand(object_size * kPointerSize));
+  add(result, result, Operand(object_size));
   cmp(result, Operand(scratch2));
   b(hi, gc_required);
-
-  // Update allocation top. result temporarily holds the new top.
-  if (FLAG_debug_code) {
-    tst(result, Operand(kObjectAlignmentMask));
-    Check(eq, "Unaligned allocation in new space");
-  }
   str(result, MemOperand(scratch1));
 
   // Tag and adjust back to start of new object.
   if ((flags & TAG_OBJECT) != 0) {
-    sub(result, result, Operand((object_size * kPointerSize) -
-                                kHeapObjectTag));
+    sub(result, result, Operand(object_size - kHeapObjectTag));
   } else {
-    sub(result, result, Operand(object_size * kPointerSize));
+    sub(result, result, Operand(object_size));
   }
 }
 
@@ -1001,7 +1007,11 @@
       ExternalReference::new_space_allocation_limit_address();
   mov(scratch2, Operand(new_space_allocation_limit));
   ldr(scratch2, MemOperand(scratch2));
-  add(result, result, Operand(object_size, LSL, kPointerSizeLog2));
+  if ((flags & SIZE_IN_WORDS) != 0) {
+    add(result, result, Operand(object_size, LSL, kPointerSizeLog2));
+  } else {
+    add(result, result, Operand(object_size));
+  }
   cmp(result, Operand(scratch2));
   b(hi, gc_required);
 
@@ -1013,7 +1023,11 @@
   str(result, MemOperand(scratch1));
 
   // Adjust back to start of new object.
-  sub(result, result, Operand(object_size, LSL, kPointerSizeLog2));
+  if ((flags & SIZE_IN_WORDS) != 0) {
+    sub(result, result, Operand(object_size, LSL, kPointerSizeLog2));
+  } else {
+    sub(result, result, Operand(object_size));
+  }
 
   // Tag object if requested.
   if ((flags & TAG_OBJECT) != 0) {
@@ -1054,10 +1068,7 @@
   mov(scratch1, Operand(length, LSL, 1));  // Length in bytes, not chars.
   add(scratch1, scratch1,
       Operand(kObjectAlignmentMask + SeqTwoByteString::kHeaderSize));
-  // AllocateInNewSpace expects the size in words, so we can round down
-  // to kObjectAlignment and divide by kPointerSize in the same shift.
-  ASSERT_EQ(kPointerSize, kObjectAlignmentMask + 1);
-  mov(scratch1, Operand(scratch1, ASR, kPointerSizeLog2));
+  and_(scratch1, scratch1, Operand(~kObjectAlignmentMask));
 
   // Allocate two-byte string in new space.
   AllocateInNewSpace(scratch1,
@@ -1088,10 +1099,7 @@
   ASSERT(kCharSize == 1);
   add(scratch1, length,
       Operand(kObjectAlignmentMask + SeqAsciiString::kHeaderSize));
-  // AllocateInNewSpace expects the size in words, so we can round down
-  // to kObjectAlignment and divide by kPointerSize in the same shift.
-  ASSERT_EQ(kPointerSize, kObjectAlignmentMask + 1);
-  mov(scratch1, Operand(scratch1, ASR, kPointerSizeLog2));
+  and_(scratch1, scratch1, Operand(~kObjectAlignmentMask));
 
   // Allocate ASCII string in new space.
   AllocateInNewSpace(scratch1,
@@ -1115,7 +1123,7 @@
                                                Register scratch1,
                                                Register scratch2,
                                                Label* gc_required) {
-  AllocateInNewSpace(ConsString::kSize / kPointerSize,
+  AllocateInNewSpace(ConsString::kSize,
                      result,
                      scratch1,
                      scratch2,
@@ -1135,7 +1143,7 @@
                                              Register scratch1,
                                              Register scratch2,
                                              Label* gc_required) {
-  AllocateInNewSpace(ConsString::kSize / kPointerSize,
+  AllocateInNewSpace(ConsString::kSize,
                      result,
                      scratch1,
                      scratch2,
@@ -1549,7 +1557,7 @@
                                         Label* gc_required) {
   // Allocate an object in the heap for the heap number and tag it as a heap
   // object.
-  AllocateInNewSpace(HeapNumber::kSize / kPointerSize,
+  AllocateInNewSpace(HeapNumber::kSize,
                      result,
                      scratch1,
                      scratch2,
diff --git a/src/arm/macro-assembler-arm.h b/src/arm/macro-assembler-arm.h
index 2ec7a39..9cf93da 100644
--- a/src/arm/macro-assembler-arm.h
+++ b/src/arm/macro-assembler-arm.h
@@ -52,6 +52,21 @@
 };
 
 
+// Flags used for the AllocateInNewSpace functions.
+enum AllocationFlags {
+  // No special flags.
+  NO_ALLOCATION_FLAGS = 0,
+  // Return the pointer to the allocated already tagged as a heap object.
+  TAG_OBJECT = 1 << 0,
+  // The content of the result register already contains the allocation top in
+  // new space.
+  RESULT_CONTAINS_TOP = 1 << 1,
+  // Specify that the requested size of the space to allocate is specified in
+  // words instead of bytes.
+  SIZE_IN_WORDS = 1 << 2
+};
+
+
 // MacroAssembler implements a collection of frequently used macros.
 class MacroAssembler: public Assembler {
  public:
@@ -85,6 +100,10 @@
   void LoadRoot(Register destination,
                 Heap::RootListIndex index,
                 Condition cond = al);
+  // Store an object to the root table.
+  void StoreRoot(Register source,
+                 Heap::RootListIndex index,
+                 Condition cond = al);
 
 
   // Check if object is in new space.
@@ -280,7 +299,9 @@
   // Allocate an object in new space. The object_size is specified in words (not
   // bytes). If the new space is exhausted control continues at the gc_required
   // label. The allocated object is returned in result. If the flag
-  // tag_allocated_object is true the result is tagged as as a heap object.
+  // tag_allocated_object is true the result is tagged as as a heap object. All
+  // registers are clobbered also when control continues at the gc_required
+  // label.
   void AllocateInNewSpace(int object_size,
                           Register result,
                           Register scratch1,
@@ -324,8 +345,9 @@
                                Register scratch2,
                                Label* gc_required);
 
-  // Allocates a heap number or jumps to the need_gc label if the young space
-  // is full and a scavenge is needed.
+  // Allocates a heap number or jumps to the gc_required label if the young
+  // space is full and a scavenge is needed. All registers are clobbered also
+  // when control continues at the gc_required label.
   void AllocateHeapNumber(Register result,
                           Register scratch1,
                           Register scratch2,
diff --git a/src/arm/regexp-macro-assembler-arm.cc b/src/arm/regexp-macro-assembler-arm.cc
index 2fdba14..64fe5d6 100644
--- a/src/arm/regexp-macro-assembler-arm.cc
+++ b/src/arm/regexp-macro-assembler-arm.cc
@@ -1210,14 +1210,31 @@
     __ add(r0, current_input_offset(), Operand(cp_offset * char_size()));
     offset = r0;
   }
-  // We assume that we cannot do unaligned loads on ARM, so this function
-  // must only be used to load a single character at a time.
+  // The ldr, str, ldrh, strh instructions can do unaligned accesses, if the CPU
+  // and the operating system running on the target allow it.
+  // If unaligned load/stores are not supported then this function must only
+  // be used to load a single character at a time.
+#if !V8_TARGET_CAN_READ_UNALIGNED
   ASSERT(characters == 1);
+#endif
+
   if (mode_ == ASCII) {
-    __ ldrb(current_character(), MemOperand(end_of_input_address(), offset));
+    if (characters == 4) {
+      __ ldr(current_character(), MemOperand(end_of_input_address(), offset));
+    } else if (characters == 2) {
+      __ ldrh(current_character(), MemOperand(end_of_input_address(), offset));
+    } else {
+      ASSERT(characters == 1);
+      __ ldrb(current_character(), MemOperand(end_of_input_address(), offset));
+    }
   } else {
     ASSERT(mode_ == UC16);
-    __ ldrh(current_character(), MemOperand(end_of_input_address(), offset));
+    if (characters == 2) {
+      __ ldr(current_character(), MemOperand(end_of_input_address(), offset));
+    } else {
+      ASSERT(characters == 1);
+      __ ldrh(current_character(), MemOperand(end_of_input_address(), offset));
+    }
   }
 }
 
diff --git a/src/arm/simulator-arm.cc b/src/arm/simulator-arm.cc
index 5fe7d5f..e4601f3 100644
--- a/src/arm/simulator-arm.cc
+++ b/src/arm/simulator-arm.cc
@@ -728,6 +728,13 @@
 }
 
 
+void Simulator::set_dw_register(int dreg, const int* dbl) {
+  ASSERT((dreg >= 0) && (dreg < num_d_registers));
+  registers_[dreg] = dbl[0];
+  registers_[dreg + 1] = dbl[1];
+}
+
+
 // Raw access to the PC register.
 void Simulator::set_pc(int32_t value) {
   pc_modified_ = true;
@@ -864,27 +871,42 @@
   registers_[12] = 0x50Bad4U;
 }
 
-
-// The ARM cannot do unaligned reads and writes.  On some ARM platforms an
-// interrupt is caused.  On others it does a funky rotation thing.  For now we
-// simply disallow unaligned reads, but at some point we may want to move to
-// emulating the rotate behaviour.  Note that simulator runs have the runtime
+// Some Operating Systems allow unaligned access on ARMv7 targets. We
+// assume that unaligned accesses are not allowed unless the v8 build system
+// defines the CAN_USE_UNALIGNED_ACCESSES macro to be non-zero.
+// The following statements below describes the behavior of the ARM CPUs
+// that don't support unaligned access.
+// Some ARM platforms raise an interrupt on detecting unaligned access.
+// On others it does a funky rotation thing.  For now we
+// simply disallow unaligned reads.  Note that simulator runs have the runtime
 // system running directly on the host system and only generated code is
 // executed in the simulator.  Since the host is typically IA32 we will not
-// get the correct ARM-like behaviour on unaligned accesses.
+// get the correct ARM-like behaviour on unaligned accesses for those ARM
+// targets that don't support unaligned loads and stores.
+
 
 int Simulator::ReadW(int32_t addr, Instr* instr) {
+#if V8_TARGET_CAN_READ_UNALIGNED
+  intptr_t* ptr = reinterpret_cast<intptr_t*>(addr);
+  return *ptr;
+#else
   if ((addr & 3) == 0) {
     intptr_t* ptr = reinterpret_cast<intptr_t*>(addr);
     return *ptr;
   }
-  PrintF("Unaligned read at 0x%08x\n", addr);
+  PrintF("Unaligned read at 0x%08x, pc=%p\n", addr, instr);
   UNIMPLEMENTED();
   return 0;
+#endif
 }
 
 
 void Simulator::WriteW(int32_t addr, int value, Instr* instr) {
+#if V8_TARGET_CAN_READ_UNALIGNED
+  intptr_t* ptr = reinterpret_cast<intptr_t*>(addr);
+  *ptr = value;
+  return;
+#else
   if ((addr & 3) == 0) {
     intptr_t* ptr = reinterpret_cast<intptr_t*>(addr);
     *ptr = value;
@@ -892,10 +914,15 @@
   }
   PrintF("Unaligned write at 0x%08x, pc=%p\n", addr, instr);
   UNIMPLEMENTED();
+#endif
 }
 
 
 uint16_t Simulator::ReadHU(int32_t addr, Instr* instr) {
+#if V8_TARGET_CAN_READ_UNALIGNED
+  uint16_t* ptr = reinterpret_cast<uint16_t*>(addr);
+  return *ptr;
+#else
   if ((addr & 1) == 0) {
     uint16_t* ptr = reinterpret_cast<uint16_t*>(addr);
     return *ptr;
@@ -903,10 +930,15 @@
   PrintF("Unaligned unsigned halfword read at 0x%08x, pc=%p\n", addr, instr);
   UNIMPLEMENTED();
   return 0;
+#endif
 }
 
 
 int16_t Simulator::ReadH(int32_t addr, Instr* instr) {
+#if V8_TARGET_CAN_READ_UNALIGNED
+  int16_t* ptr = reinterpret_cast<int16_t*>(addr);
+  return *ptr;
+#else
   if ((addr & 1) == 0) {
     int16_t* ptr = reinterpret_cast<int16_t*>(addr);
     return *ptr;
@@ -914,10 +946,16 @@
   PrintF("Unaligned signed halfword read at 0x%08x\n", addr);
   UNIMPLEMENTED();
   return 0;
+#endif
 }
 
 
 void Simulator::WriteH(int32_t addr, uint16_t value, Instr* instr) {
+#if V8_TARGET_CAN_READ_UNALIGNED
+  uint16_t* ptr = reinterpret_cast<uint16_t*>(addr);
+  *ptr = value;
+  return;
+#else
   if ((addr & 1) == 0) {
     uint16_t* ptr = reinterpret_cast<uint16_t*>(addr);
     *ptr = value;
@@ -925,10 +963,16 @@
   }
   PrintF("Unaligned unsigned halfword write at 0x%08x, pc=%p\n", addr, instr);
   UNIMPLEMENTED();
+#endif
 }
 
 
 void Simulator::WriteH(int32_t addr, int16_t value, Instr* instr) {
+#if V8_TARGET_CAN_READ_UNALIGNED
+  int16_t* ptr = reinterpret_cast<int16_t*>(addr);
+  *ptr = value;
+  return;
+#else
   if ((addr & 1) == 0) {
     int16_t* ptr = reinterpret_cast<int16_t*>(addr);
     *ptr = value;
@@ -936,6 +980,7 @@
   }
   PrintF("Unaligned halfword write at 0x%08x, pc=%p\n", addr, instr);
   UNIMPLEMENTED();
+#endif
 }
 
 
@@ -963,6 +1008,41 @@
 }
 
 
+int32_t* Simulator::ReadDW(int32_t addr) {
+#if V8_TARGET_CAN_READ_UNALIGNED
+  int32_t* ptr = reinterpret_cast<int32_t*>(addr);
+  return ptr;
+#else
+  if ((addr & 3) == 0) {
+    int32_t* ptr = reinterpret_cast<int32_t*>(addr);
+    return ptr;
+  }
+  PrintF("Unaligned read at 0x%08x\n", addr);
+  UNIMPLEMENTED();
+  return 0;
+#endif
+}
+
+
+void Simulator::WriteDW(int32_t addr, int32_t value1, int32_t value2) {
+#if V8_TARGET_CAN_READ_UNALIGNED
+  int32_t* ptr = reinterpret_cast<int32_t*>(addr);
+  *ptr++ = value1;
+  *ptr = value2;
+  return;
+#else
+  if ((addr & 3) == 0) {
+    int32_t* ptr = reinterpret_cast<int32_t*>(addr);
+    *ptr++ = value1;
+    *ptr = value2;
+    return;
+  }
+  PrintF("Unaligned write at 0x%08x\n", addr);
+  UNIMPLEMENTED();
+#endif
+}
+
+
 // Returns the limit of the stack area to enable checking for stack overflows.
 uintptr_t Simulator::StackLimit() const {
   // Leave a safety margin of 256 bytes to prevent overrunning the stack when
@@ -1590,7 +1670,19 @@
           }
         }
       }
-      if (instr->HasH()) {
+      if (((instr->Bits(7, 4) & 0xd) == 0xd) && (instr->Bit(20) == 0)) {
+        ASSERT((rd % 2) == 0);
+        if (instr->HasH()) {
+          // The strd instruction.
+          int32_t value1 = get_register(rd);
+          int32_t value2 = get_register(rd+1);
+          WriteDW(addr, value1, value2);
+        } else {
+          // The ldrd instruction.
+          int* rn_data = ReadDW(addr);
+          set_dw_register(rd, rn_data);
+        }
+      } else if (instr->HasH()) {
         if (instr->HasSign()) {
           if (instr->HasL()) {
             int16_t val = ReadH(addr, instr);
diff --git a/src/arm/simulator-arm.h b/src/arm/simulator-arm.h
index 91614ea..61af3aa 100644
--- a/src/arm/simulator-arm.h
+++ b/src/arm/simulator-arm.h
@@ -159,6 +159,7 @@
   // instruction.
   void set_register(int reg, int32_t value);
   int32_t get_register(int reg) const;
+  void set_dw_register(int dreg, const int* dbl);
 
   // Support for VFP.
   void set_s_register(int reg, unsigned int value);
@@ -252,6 +253,9 @@
   inline int ReadW(int32_t addr, Instr* instr);
   inline void WriteW(int32_t addr, int value, Instr* instr);
 
+  int32_t* ReadDW(int32_t addr);
+  void WriteDW(int32_t addr, int32_t value1, int32_t value2);
+
   // Executing is handled based on the instruction type.
   void DecodeType01(Instr* instr);  // both type 0 and type 1 rolled into one
   void DecodeType2(Instr* instr);
diff --git a/src/arm/stub-cache-arm.cc b/src/arm/stub-cache-arm.cc
index 095631d..877354c 100644
--- a/src/arm/stub-cache-arm.cc
+++ b/src/arm/stub-cache-arm.cc
@@ -1121,11 +1121,7 @@
   __ Jump(ic, RelocInfo::CODE_TARGET);
 
   // Return the generated code.
-  String* function_name = NULL;
-  if (function->shared()->name()->IsString()) {
-    function_name = String::cast(function->shared()->name());
-  }
-  return GetCode(CONSTANT_FUNCTION, function_name);
+  return GetCode(function);
 }
 
 
@@ -1175,11 +1171,7 @@
   __ Jump(ic, RelocInfo::CODE_TARGET);
 
   // Return the generated code.
-  String* function_name = NULL;
-  if (function->shared()->name()->IsString()) {
-    function_name = String::cast(function->shared()->name());
-  }
-  return GetCode(CONSTANT_FUNCTION, function_name);
+  return GetCode(function);
 }
 
 
@@ -1194,9 +1186,9 @@
   // -----------------------------------
   SharedFunctionInfo* function_info = function->shared();
   if (function_info->HasCustomCallGenerator()) {
-    CustomCallGenerator generator =
-        ToCData<CustomCallGenerator>(function_info->function_data());
-    Object* result = generator(this, object, holder, function, name, check);
+    const int id = function_info->custom_call_generator_id();
+    Object* result =
+        CompileCustomCall(id, object, holder, function, name, check);
     // undefined means bail out to regular compiler.
     if (!result->IsUndefined()) {
       return result;
@@ -1334,11 +1326,7 @@
   __ Jump(ic, RelocInfo::CODE_TARGET);
 
   // Return the generated code.
-  String* function_name = NULL;
-  if (function->shared()->name()->IsString()) {
-    function_name = String::cast(function->shared()->name());
-  }
-  return GetCode(CONSTANT_FUNCTION, function_name);
+  return GetCode(function);
 }
 
 
@@ -1825,8 +1813,7 @@
   // ----------- S t a t e -------------
   //  -- lr    : return address
   //  -- r0    : key
-  //  -- sp[0] : key
-  //  -- sp[4] : receiver
+  //  -- r1    : receiver
   // -----------------------------------
   Label miss;
 
@@ -1834,7 +1821,6 @@
   __ cmp(r0, Operand(Handle<String>(name)));
   __ b(ne, &miss);
 
-  __ ldr(r1, MemOperand(sp, kPointerSize));  // Receiver.
   GenerateLoadField(receiver, holder, r1, r2, r3, index, name, &miss);
   __ bind(&miss);
   GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
@@ -1850,8 +1836,7 @@
   // ----------- S t a t e -------------
   //  -- lr    : return address
   //  -- r0    : key
-  //  -- sp[0] : key
-  //  -- sp[4] : receiver
+  //  -- r1    : receiver
   // -----------------------------------
   Label miss;
 
@@ -1860,7 +1845,6 @@
   __ b(ne, &miss);
 
   Failure* failure = Failure::InternalError();
-  __ ldr(r1, MemOperand(sp, kPointerSize));  // Receiver.
   bool success = GenerateLoadCallback(receiver, holder, r1, r0, r2, r3,
                                       callback, name, &miss, &failure);
   if (!success) return failure;
@@ -1879,8 +1863,7 @@
   // ----------- S t a t e -------------
   //  -- lr    : return address
   //  -- r0    : key
-  //  -- sp[0] : key
-  //  -- sp[4] : receiver
+  //  -- r1    : receiver
   // -----------------------------------
   Label miss;
 
@@ -1888,7 +1871,6 @@
   __ cmp(r0, Operand(Handle<String>(name)));
   __ b(ne, &miss);
 
-  __ ldr(r1, MemOperand(sp, kPointerSize));  // Receiver.
   GenerateLoadConstant(receiver, holder, r1, r2, r3, value, name, &miss);
   __ bind(&miss);
   GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
@@ -1904,8 +1886,7 @@
   // ----------- S t a t e -------------
   //  -- lr    : return address
   //  -- r0    : key
-  //  -- sp[0] : key
-  //  -- sp[4] : receiver
+  //  -- r1    : receiver
   // -----------------------------------
   Label miss;
 
@@ -1915,7 +1896,6 @@
 
   LookupResult lookup;
   LookupPostInterceptor(holder, name, &lookup);
-  __ ldr(r1, MemOperand(sp, kPointerSize));  // Receiver.
   GenerateLoadInterceptor(receiver,
                           holder,
                           &lookup,
@@ -1936,8 +1916,7 @@
   // ----------- S t a t e -------------
   //  -- lr    : return address
   //  -- r0    : key
-  //  -- sp[0] : key
-  //  -- sp[4] : receiver
+  //  -- r1    : receiver
   // -----------------------------------
   Label miss;
 
@@ -1945,7 +1924,6 @@
   __ cmp(r0, Operand(Handle<String>(name)));
   __ b(ne, &miss);
 
-  __ ldr(r1, MemOperand(sp, kPointerSize));  // Receiver.
   GenerateLoadArrayLength(masm(), r1, r2, &miss);
   __ bind(&miss);
   GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
@@ -1958,8 +1936,7 @@
   // ----------- S t a t e -------------
   //  -- lr    : return address
   //  -- r0    : key
-  //  -- sp[0] : key
-  //  -- sp[4] : receiver
+  //  -- r1    : receiver
   // -----------------------------------
   Label miss;
   __ IncrementCounter(&Counters::keyed_load_string_length, 1, r1, r3);
@@ -1968,7 +1945,6 @@
   __ cmp(r0, Operand(Handle<String>(name)));
   __ b(ne, &miss);
 
-  __ ldr(r1, MemOperand(sp, kPointerSize));  // Receiver.
   GenerateLoadStringLength(masm(), r1, r2, r3, &miss);
   __ bind(&miss);
   __ DecrementCounter(&Counters::keyed_load_string_length, 1, r1, r3);
@@ -1984,8 +1960,7 @@
   // ----------- S t a t e -------------
   //  -- lr    : return address
   //  -- r0    : key
-  //  -- sp[0] : key
-  //  -- sp[4] : receiver
+  //  -- r1    : receiver
   // -----------------------------------
   GenerateLoadMiss(masm(), Code::KEYED_LOAD_IC);
 
@@ -2085,7 +2060,7 @@
                         r5,
                         r6,
                         &generic_stub_call,
-                        NO_ALLOCATION_FLAGS);
+                        SIZE_IN_WORDS);
 
   // Allocated the JSObject, now initialize the fields. Map is set to initial
   // map and properties and elements are set to empty fixed array.
diff --git a/src/arm/virtual-frame-arm-inl.h b/src/arm/virtual-frame-arm-inl.h
new file mode 100644
index 0000000..a97cde4
--- /dev/null
+++ b/src/arm/virtual-frame-arm-inl.h
@@ -0,0 +1,53 @@
+// Copyright 2010 the V8 project authors. All rights reserved.
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+//     * Redistributions of source code must retain the above copyright
+//       notice, this list of conditions and the following disclaimer.
+//     * Redistributions in binary form must reproduce the above
+//       copyright notice, this list of conditions and the following
+//       disclaimer in the documentation and/or other materials provided
+//       with the distribution.
+//     * Neither the name of Google Inc. nor the names of its
+//       contributors may be used to endorse or promote products derived
+//       from this software without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+#ifndef V8_VIRTUAL_FRAME_ARM_INL_H_
+#define V8_VIRTUAL_FRAME_ARM_INL_H_
+
+#include "assembler-arm.h"
+#include "virtual-frame-arm.h"
+
+namespace v8 {
+namespace internal {
+
+// These VirtualFrame methods should actually be in a virtual-frame-arm-inl.h
+// file if such a thing existed.
+MemOperand VirtualFrame::ParameterAt(int index) {
+  // Index -1 corresponds to the receiver.
+  ASSERT(-1 <= index);  // -1 is the receiver.
+  ASSERT(index <= parameter_count());
+  return MemOperand(fp, (1 + parameter_count() - index) * kPointerSize);
+}
+
+  // The receiver frame slot.
+MemOperand VirtualFrame::Receiver() {
+  return ParameterAt(-1);
+}
+
+} }  // namespace v8::internal
+
+#endif  // V8_VIRTUAL_FRAME_ARM_INL_H_
diff --git a/src/arm/virtual-frame-arm.cc b/src/arm/virtual-frame-arm.cc
index bf5cff2..f7b337d 100644
--- a/src/arm/virtual-frame-arm.cc
+++ b/src/arm/virtual-frame-arm.cc
@@ -72,8 +72,15 @@
 
 void VirtualFrame::MergeTo(VirtualFrame* expected) {
   if (Equals(expected)) return;
+  MergeTOSTo(expected->top_of_stack_state_);
+  ASSERT(register_allocation_map_ == expected->register_allocation_map_);
+}
+
+
+void VirtualFrame::MergeTOSTo(
+    VirtualFrame::TopOfStack expected_top_of_stack_state) {
 #define CASE_NUMBER(a, b) ((a) * TOS_STATES + (b))
-  switch (CASE_NUMBER(top_of_stack_state_, expected->top_of_stack_state_)) {
+  switch (CASE_NUMBER(top_of_stack_state_, expected_top_of_stack_state)) {
     case CASE_NUMBER(NO_TOS_REGISTERS, NO_TOS_REGISTERS):
       break;
     case CASE_NUMBER(NO_TOS_REGISTERS, R0_TOS):
@@ -154,7 +161,7 @@
       UNREACHABLE();
 #undef CASE_NUMBER
   }
-  ASSERT(register_allocation_map_ == expected->register_allocation_map_);
+  top_of_stack_state_ = expected_top_of_stack_state;
 }
 
 
@@ -323,7 +330,8 @@
 
 void VirtualFrame::CallKeyedLoadIC() {
   Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize));
-  SpillAllButCopyTOSToR0();
+  PopToR1R0();
+  SpillAll();
   CallCodeObject(ic, RelocInfo::CODE_TARGET, 0);
 }
 
@@ -417,7 +425,7 @@
 
 
 void VirtualFrame::EmitPop(Register reg) {
-  ASSERT(!is_used(reg));
+  ASSERT(!is_used(RegisterAllocator::ToNumber(reg)));
   if (top_of_stack_state_ == NO_TOS_REGISTERS) {
     __ pop(reg);
   } else {
@@ -505,21 +513,25 @@
       break;
     case R0_TOS:
       __ mov(r1, r0);
+      // r0 and r1 contains the same value. Prefer a state with r0 holding TOS.
       top_of_stack_state_ = R0_R1_TOS;
       break;
     case R1_TOS:
       __ mov(r0, r1);
+      // r0 and r1 contains the same value. Prefer a state with r0 holding TOS.
       top_of_stack_state_ = R0_R1_TOS;
       break;
     case R0_R1_TOS:
       __ push(r1);
       __ mov(r1, r0);
-      // No need to change state as r0 and r1 now contains the same value.
+      // r0 and r1 contains the same value. Prefer a state with r0 holding TOS.
+      top_of_stack_state_ = R0_R1_TOS;
       break;
     case R1_R0_TOS:
       __ push(r0);
       __ mov(r0, r1);
-      // No need to change state as r0 and r1 now contains the same value.
+      // r0 and r1 contains the same value. Prefer a state with r0 holding TOS.
+      top_of_stack_state_ = R0_R1_TOS;
       break;
     default:
       UNREACHABLE();
@@ -528,11 +540,49 @@
 }
 
 
+void VirtualFrame::Dup2() {
+  if (SpilledScope::is_spilled()) {
+    __ ldr(ip, MemOperand(sp, kPointerSize));
+    __ push(ip);
+    __ ldr(ip, MemOperand(sp, kPointerSize));
+    __ push(ip);
+  } else {
+    switch (top_of_stack_state_) {
+      case NO_TOS_REGISTERS:
+        __ ldr(r0, MemOperand(sp, 0));
+        __ ldr(r1, MemOperand(sp, kPointerSize));
+        top_of_stack_state_ = R0_R1_TOS;
+        break;
+      case R0_TOS:
+        __ push(r0);
+        __ ldr(r1, MemOperand(sp, kPointerSize));
+        top_of_stack_state_ = R0_R1_TOS;
+        break;
+      case R1_TOS:
+        __ push(r1);
+        __ ldr(r0, MemOperand(sp, kPointerSize));
+        top_of_stack_state_ = R1_R0_TOS;
+        break;
+      case R0_R1_TOS:
+        __ Push(r1, r0);
+        top_of_stack_state_ = R0_R1_TOS;
+        break;
+      case R1_R0_TOS:
+        __ Push(r0, r1);
+        top_of_stack_state_ = R1_R0_TOS;
+        break;
+      default:
+        UNREACHABLE();
+    }
+  }
+  element_count_ += 2;
+}
+
+
 Register VirtualFrame::PopToRegister(Register but_not_to_this_one) {
   ASSERT(but_not_to_this_one.is(r0) ||
          but_not_to_this_one.is(r1) ||
          but_not_to_this_one.is(no_reg));
-  AssertIsNotSpilled();
   element_count_--;
   if (top_of_stack_state_ == NO_TOS_REGISTERS) {
     if (but_not_to_this_one.is(r0)) {
@@ -584,6 +634,39 @@
 }
 
 
+void VirtualFrame::SetElementAt(Register reg, int this_far_down) {
+  if (this_far_down == 0) {
+    Pop();
+    Register dest = GetTOSRegister();
+    if (dest.is(reg)) {
+      // We already popped one item off the top of the stack.  If the only
+      // free register is the one we were asked to push then we have been
+      // asked to push a register that was already in use, which cannot
+      // happen.  It therefore folows that there are two free TOS registers:
+      ASSERT(top_of_stack_state_ == NO_TOS_REGISTERS);
+      dest = dest.is(r0) ? r1 : r0;
+    }
+    __ mov(dest, reg);
+    EmitPush(dest);
+  } else if (this_far_down == 1) {
+    int virtual_elements = kVirtualElements[top_of_stack_state_];
+    if (virtual_elements < 2) {
+      __ str(reg, ElementAt(this_far_down));
+    } else {
+      ASSERT(virtual_elements == 2);
+      ASSERT(!reg.is(r0));
+      ASSERT(!reg.is(r1));
+      Register dest = kBottomRegister[top_of_stack_state_];
+      __ mov(dest, reg);
+    }
+  } else {
+    ASSERT(this_far_down >= 2);
+    ASSERT(kVirtualElements[top_of_stack_state_] <= 2);
+    __ str(reg, ElementAt(this_far_down));
+  }
+}
+
+
 Register VirtualFrame::GetTOSRegister() {
   if (SpilledScope::is_spilled()) return r0;
 
diff --git a/src/arm/virtual-frame-arm.h b/src/arm/virtual-frame-arm.h
index 77bc70e..655194d 100644
--- a/src/arm/virtual-frame-arm.h
+++ b/src/arm/virtual-frame-arm.h
@@ -29,11 +29,14 @@
 #define V8_ARM_VIRTUAL_FRAME_ARM_H_
 
 #include "register-allocator.h"
-#include "scopes.h"
 
 namespace v8 {
 namespace internal {
 
+// This dummy class is only used to create invalid virtual frames.
+extern class InvalidVirtualFrameInitializer {}* kInvalidVirtualFrameInitializer;
+
+
 // -------------------------------------------------------------------------
 // Virtual frames
 //
@@ -82,26 +85,8 @@
     // is not spilled, ie. where register allocation occurs.  Eventually
     // when RegisterAllocationScope is ubiquitous it can be removed
     // along with the (by then unused) SpilledScope class.
-    explicit RegisterAllocationScope(CodeGenerator* cgen)
-      : cgen_(cgen),
-        old_is_spilled_(SpilledScope::is_spilled_) {
-      SpilledScope::is_spilled_ = false;
-      if (old_is_spilled_) {
-        VirtualFrame* frame = cgen->frame();
-        if (frame != NULL) {
-          frame->AssertIsSpilled();
-        }
-      }
-    }
-    ~RegisterAllocationScope() {
-      SpilledScope::is_spilled_ = old_is_spilled_;
-      if (old_is_spilled_) {
-        VirtualFrame* frame = cgen_->frame();
-        if (frame != NULL) {
-          frame->SpillAll();
-        }
-      }
-    }
+    inline explicit RegisterAllocationScope(CodeGenerator* cgen);
+    inline ~RegisterAllocationScope();
 
    private:
     CodeGenerator* cgen_;
@@ -116,19 +101,20 @@
   // Construct an initial virtual frame on entry to a JS function.
   inline VirtualFrame();
 
+  // Construct an invalid virtual frame, used by JumpTargets.
+  inline VirtualFrame(InvalidVirtualFrameInitializer* dummy);
+
   // Construct a virtual frame as a clone of an existing one.
   explicit inline VirtualFrame(VirtualFrame* original);
 
-  CodeGenerator* cgen() { return CodeGeneratorScope::Current(); }
-  MacroAssembler* masm() { return cgen()->masm(); }
+  inline CodeGenerator* cgen();
+  inline MacroAssembler* masm();
 
   // The number of elements on the virtual frame.
   int element_count() { return element_count_; }
 
   // The height of the virtual expression stack.
-  int height() {
-    return element_count() - expression_base_index();
-  }
+  inline int height();
 
   bool is_used(int num) {
     switch (num) {
@@ -160,10 +146,6 @@
     }
   }
 
-  bool is_used(Register reg) {
-    return is_used(RegisterAllocator::ToNumber(reg));
-  }
-
   // Add extra in-memory elements to the top of the frame to match an actual
   // frame (eg, the frame after an exception handler is pushed).  No code is
   // emitted.
@@ -247,16 +229,13 @@
 
   // An element of the expression stack as an assembly operand.
   MemOperand ElementAt(int index) {
-    AssertIsSpilled();
-    return MemOperand(sp, index * kPointerSize);
+    int adjusted_index = index - kVirtualElements[top_of_stack_state_];
+    ASSERT(adjusted_index >= 0);
+    return MemOperand(sp, adjusted_index * kPointerSize);
   }
 
   // A frame-allocated local as an assembly operand.
-  MemOperand LocalAt(int index) {
-    ASSERT(0 <= index);
-    ASSERT(index < local_count());
-    return MemOperand(fp, kLocal0Offset - index * kPointerSize);
-  }
+  inline MemOperand LocalAt(int index);
 
   // Push the address of the receiver slot on the frame.
   void PushReceiverSlotAddress();
@@ -268,26 +247,17 @@
   MemOperand Context() { return MemOperand(fp, kContextOffset); }
 
   // A parameter as an assembly operand.
-  MemOperand ParameterAt(int index) {
-    // Index -1 corresponds to the receiver.
-    ASSERT(-1 <= index);  // -1 is the receiver.
-    ASSERT(index <= parameter_count());
-    return MemOperand(fp, (1 + parameter_count() - index) * kPointerSize);
-  }
+  inline MemOperand ParameterAt(int index);
 
   // The receiver frame slot.
-  MemOperand Receiver() { return ParameterAt(-1); }
+  inline MemOperand Receiver();
 
   // Push a try-catch or try-finally handler on top of the virtual frame.
   void PushTryHandler(HandlerType type);
 
   // Call stub given the number of arguments it expects on (and
   // removes from) the stack.
-  void CallStub(CodeStub* stub, int arg_count) {
-    if (arg_count != 0) Forget(arg_count);
-    ASSERT(cgen()->HasValidEntryRegisters());
-    masm()->CallStub(stub);
-  }
+  inline void CallStub(CodeStub* stub, int arg_count);
 
   // Call JS function from top of the stack with arguments
   // taken from the stack.
@@ -316,8 +286,8 @@
   // Result is returned in r0.
   void CallStoreIC(Handle<String> name, bool is_contextual);
 
-  // Call keyed load IC. Key and receiver are on the stack. Result is returned
-  // in r0.
+  // Call keyed load IC. Key and receiver are on the stack. Both are consumed.
+  // Result is returned in r0.
   void CallKeyedLoadIC();
 
   // Call keyed store IC. Key and receiver are on the stack and the value is in
@@ -355,6 +325,9 @@
   // Duplicate the top of stack.
   void Dup();
 
+  // Duplicate the two elements on top of stack.
+  void Dup2();
+
   // Flushes all registers, but it puts a copy of the top-of-stack in r0.
   void SpillAllButCopyTOSToR0();
 
@@ -383,6 +356,12 @@
   void EmitPush(MemOperand operand);
   void EmitPushRoot(Heap::RootListIndex index);
 
+  // Overwrite the nth thing on the stack.  If the nth position is in a
+  // register then this turns into a mov, otherwise an str.  Afterwards
+  // you can still use the register even if it is a register that can be
+  // used for TOS (r0 or r1).
+  void SetElementAt(Register reg, int this_far_down);
+
   // Get a register which is free and which must be immediately used to
   // push on the top of the stack.
   Register GetTOSRegister();
@@ -446,13 +425,13 @@
   int stack_pointer() { return element_count_ - 1; }
 
   // The number of frame-allocated locals and parameters respectively.
-  int parameter_count() { return cgen()->scope()->num_parameters(); }
-  int local_count() { return cgen()->scope()->num_stack_slots(); }
+  inline int parameter_count();
+  inline int local_count();
 
   // The index of the element that is at the processor's frame pointer
   // (the fp register).  The parameters, receiver, function, and context
   // are below the frame pointer.
-  int frame_pointer() { return parameter_count() + 3; }
+  inline int frame_pointer();
 
   // The index of the first parameter.  The receiver lies below the first
   // parameter.
@@ -460,26 +439,22 @@
 
   // The index of the context slot in the frame.  It is immediately
   // below the frame pointer.
-  int context_index() { return frame_pointer() - 1; }
+  inline int context_index();
 
   // The index of the function slot in the frame.  It is below the frame
   // pointer and context slot.
-  int function_index() { return frame_pointer() - 2; }
+  inline int function_index();
 
   // The index of the first local.  Between the frame pointer and the
   // locals lies the return address.
-  int local0_index() { return frame_pointer() + 2; }
+  inline int local0_index();
 
   // The index of the base of the expression stack.
-  int expression_base_index() { return local0_index() + local_count(); }
+  inline int expression_base_index();
 
   // Convert a frame index into a frame pointer relative offset into the
   // actual stack.
-  int fp_relative(int index) {
-    ASSERT(index < element_count());
-    ASSERT(frame_pointer() < element_count());  // FP is on the frame.
-    return (frame_pointer() - index) * kPointerSize;
-  }
+  inline int fp_relative(int index);
 
   // Spill all elements in registers. Spill the top spilled_args elements
   // on the frame.  Sync all other frame elements.
@@ -491,10 +466,13 @@
   // onto the physical stack and made free.
   void EnsureOneFreeTOSRegister();
 
+  // Emit instructions to get the top of stack state from where we are to where
+  // we want to be.
+  void MergeTOSTo(TopOfStack expected_state);
+
   inline bool Equals(VirtualFrame* other);
 
   friend class JumpTarget;
-  friend class DeferredCode;
 };