Reduced code size by using shorter instruction encoding when possible.

Added a --help option to the shell sample and to the d8 shell.

Added visual studio project files for building the ARM simulator.

Fixed a number of ARM simulator issues.

Fixed bug in out-of-memory handling on ARM.

Implemented shell support for passing arguments to a script from the command line.

Fixed bug in date code that made certain date functions return -0 instead of 0 for dates before the epoch.

Restricted applications of eval so it can only be used in the context of the associated global object.

Treat byte-order marks as whitespace characters.


git-svn-id: http://v8.googlecode.com/svn/trunk@768 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
diff --git a/src/codegen-arm.cc b/src/codegen-arm.cc
index 4c2f465..e5120ae 100644
--- a/src/codegen-arm.cc
+++ b/src/codegen-arm.cc
@@ -35,6 +35,84 @@
 
 namespace v8 { namespace internal {
 
+#define __ masm_->
+
+// -------------------------------------------------------------------------
+// VirtualFrame implementation.
+
+VirtualFrame::VirtualFrame(CodeGenerator* cgen) {
+  ASSERT(cgen->scope() != NULL);
+
+  masm_ = cgen->masm();
+  frame_local_count_ = cgen->scope()->num_stack_slots();
+  parameter_count_ = cgen->scope()->num_parameters();
+}
+
+
+void VirtualFrame::Enter() {
+  Comment cmnt(masm_, "[ Enter JS frame");
+#ifdef DEBUG
+  { Label done, fail;
+    __ tst(r1, Operand(kSmiTagMask));
+    __ b(eq, &fail);
+    __ ldr(r2, FieldMemOperand(r1, HeapObject::kMapOffset));
+    __ ldrb(r2, FieldMemOperand(r2, Map::kInstanceTypeOffset));
+    __ cmp(r2, Operand(JS_FUNCTION_TYPE));
+    __ b(eq, &done);
+    __ bind(&fail);
+    __ stop("CodeGenerator::EnterJSFrame - r1 not a function");
+    __ bind(&done);
+  }
+#endif  // DEBUG
+
+  __ stm(db_w, sp, r1.bit() | cp.bit() | fp.bit() | lr.bit());
+  // Adjust FP to point to saved FP.
+  __ add(fp, sp, Operand(2 * kPointerSize));
+}
+
+
+void VirtualFrame::Exit() {
+  Comment cmnt(masm_, "[ Exit JS frame");
+  // Drop the execution stack down to the frame pointer and restore the caller
+  // frame pointer and return address.
+  __ mov(sp, fp);
+  __ ldm(ia_w, sp, fp.bit() | lr.bit());
+}
+
+
+void VirtualFrame::AllocateLocals() {
+  if (frame_local_count_ > 0) {
+    Comment cmnt(masm_, "[ Allocate space for locals");
+      // Initialize stack slots with 'undefined' value.
+    __ mov(ip, Operand(Factory::undefined_value()));
+    for (int i = 0; i < frame_local_count_; i++) {
+      __ push(ip);
+    }
+  }
+}
+
+
+void VirtualFrame::Drop(int count) {
+  ASSERT(count >= 0);
+  if (count > 0) {
+    __ add(sp, sp, Operand(count * kPointerSize));
+  }
+}
+
+
+void VirtualFrame::Pop() { Drop(1); }
+
+
+void VirtualFrame::Pop(Register reg) {
+  __ pop(reg);
+}
+
+
+void VirtualFrame::Push(Register reg) {
+  __ push(reg);
+}
+
+
 // -------------------------------------------------------------------------
 // CodeGenState implementation.
 
@@ -67,11 +145,9 @@
 }
 
 
-// -----------------------------------------------------------------------------
+// -------------------------------------------------------------------------
 // CodeGenerator implementation
 
-#define __ masm_->
-
 CodeGenerator::CodeGenerator(int buffer_size, Handle<Script> script,
                              bool is_eval)
     : is_eval_(is_eval),
@@ -79,6 +155,7 @@
       deferred_(8),
       masm_(new MacroAssembler(NULL, buffer_size)),
       scope_(NULL),
+      frame_(NULL),
       cc_reg_(al),
       state_(NULL),
       break_stack_height_(0) {
@@ -86,7 +163,6 @@
 
 
 // Calling conventions:
-
 // r0: the number of arguments
 // fp: frame pointer
 // sp: stack pointer
@@ -94,13 +170,17 @@
 // cp: callee's context
 
 void CodeGenerator::GenCode(FunctionLiteral* fun) {
-  Scope* scope = fun->scope();
   ZoneList<Statement*>* body = fun->body();
 
   // Initialize state.
-  { CodeGenState state(this);
-    scope_ = scope;
-    cc_reg_ = al;
+  ASSERT(scope_ == NULL);
+  scope_ = fun->scope();
+  ASSERT(frame_ == NULL);
+  VirtualFrame virtual_frame(this);
+  frame_ = &virtual_frame;
+  cc_reg_ = al;
+  {
+    CodeGenState state(this);
 
     // Entry
     // stack: function, receiver, arguments, return address
@@ -110,9 +190,7 @@
     // pp: caller's parameter pointer
     // cp: callee's context
 
-    { Comment cmnt(masm_, "[ enter JS frame");
-      EnterJSFrame();
-    }
+    frame_->Enter();
     // tos: code slot
 #ifdef DEBUG
     if (strlen(FLAG_stop_at) > 0 &&
@@ -122,20 +200,13 @@
 #endif
 
     // Allocate space for locals and initialize them.
-    if (scope->num_stack_slots() > 0) {
-      Comment cmnt(masm_, "[ allocate space for locals");
-      // Initialize stack slots with 'undefined' value.
-      __ mov(ip, Operand(Factory::undefined_value()));
-      for (int i = 0; i < scope->num_stack_slots(); i++) {
-        __ push(ip);
-      }
-    }
+    frame_->AllocateLocals();
 
-    if (scope->num_heap_slots() > 0) {
+    if (scope_->num_heap_slots() > 0) {
       // Allocate local context.
       // Get outer context and create a new context based on it.
-      __ ldr(r0, FunctionOperand());
-      __ push(r0);
+      __ ldr(r0, frame_->Function());
+      frame_->Push(r0);
       __ CallRuntime(Runtime::kNewContext, 1);  // r0 holds the result
 
       if (kDebug) {
@@ -146,10 +217,10 @@
         __ bind(&verified_true);
       }
       // Update context local.
-      __ str(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
+      __ str(cp, frame_->Context());
     }
 
-    // TODO(1241774): Improve this code!!!
+    // TODO(1241774): Improve this code:
     // 1) only needed if we have a context
     // 2) no need to recompute context ptr every single time
     // 3) don't copy parameter operand code from SlotOperand!
@@ -164,12 +235,12 @@
       // order: such a parameter is copied repeatedly into the same
       // context location and thus the last value is what is seen inside
       // the function.
-      for (int i = 0; i < scope->num_parameters(); i++) {
-        Variable* par = scope->parameter(i);
+      for (int i = 0; i < scope_->num_parameters(); i++) {
+        Variable* par = scope_->parameter(i);
         Slot* slot = par->slot();
         if (slot != NULL && slot->type() == Slot::CONTEXT) {
-          ASSERT(!scope->is_global_scope());  // no parameters in global scope
-          __ ldr(r1, ParameterOperand(i));
+          ASSERT(!scope_->is_global_scope());  // no parameters in global scope
+          __ ldr(r1, frame_->Parameter(i));
           // Loads r2 with context; used below in RecordWrite.
           __ str(r1, SlotOperand(slot, r2));
           // Load the offset into r3.
@@ -181,59 +252,55 @@
       }
     }
 
-    // Store the arguments object.
-    // This must happen after context initialization because
-    // the arguments array may be stored in the context!
-    if (scope->arguments() != NULL) {
-      ASSERT(scope->arguments_shadow() != NULL);
+    // Store the arguments object.  This must happen after context
+    // initialization because the arguments object may be stored in the
+    // context.
+    if (scope_->arguments() != NULL) {
+      ASSERT(scope_->arguments_shadow() != NULL);
       Comment cmnt(masm_, "[ allocate arguments object");
-      { Reference shadow_ref(this, scope->arguments_shadow());
-        { Reference arguments_ref(this, scope->arguments());
+      { Reference shadow_ref(this, scope_->arguments_shadow());
+        { Reference arguments_ref(this, scope_->arguments());
           ArgumentsAccessStub stub(ArgumentsAccessStub::NEW_OBJECT);
-          __ ldr(r2, FunctionOperand());
+          __ ldr(r2, frame_->Function());
           // The receiver is below the arguments, the return address,
           // and the frame pointer on the stack.
-          const int kReceiverDisplacement = 2 + scope->num_parameters();
+          const int kReceiverDisplacement = 2 + scope_->num_parameters();
           __ add(r1, fp, Operand(kReceiverDisplacement * kPointerSize));
-          __ mov(r0, Operand(Smi::FromInt(scope->num_parameters())));
+          __ mov(r0, Operand(Smi::FromInt(scope_->num_parameters())));
           __ stm(db_w, sp, r0.bit() | r1.bit() | r2.bit());
           __ CallStub(&stub);
-          __ push(r0);
+          frame_->Push(r0);
           arguments_ref.SetValue(NOT_CONST_INIT);
         }
         shadow_ref.SetValue(NOT_CONST_INIT);
       }
-      __ pop(r0);  // Value is no longer needed.
+      frame_->Pop();  // Value is no longer needed.
     }
 
-    // Generate code to 'execute' declarations and initialize
-    // functions (source elements). In case of an illegal
-    // redeclaration we need to handle that instead of processing the
-    // declarations.
-    if (scope->HasIllegalRedeclaration()) {
+    // Generate code to 'execute' declarations and initialize functions
+    // (source elements). In case of an illegal redeclaration we need to
+    // handle that instead of processing the declarations.
+    if (scope_->HasIllegalRedeclaration()) {
       Comment cmnt(masm_, "[ illegal redeclarations");
-      scope->VisitIllegalRedeclaration(this);
+      scope_->VisitIllegalRedeclaration(this);
     } else {
       Comment cmnt(masm_, "[ declarations");
-      // ProcessDeclarations calls DeclareGlobals indirectly
-      ProcessDeclarations(scope->declarations());
-
-      // Bail out if a stack-overflow exception occurred when
-      // processing declarations.
+      ProcessDeclarations(scope_->declarations());
+      // Bail out if a stack-overflow exception occurred when processing
+      // declarations.
       if (HasStackOverflow()) return;
     }
 
     if (FLAG_trace) {
-      // Push a valid value as the parameter. The runtime call only uses
-      // it as the return value to indicate non-failure.
       __ CallRuntime(Runtime::kTraceEnter, 0);
+      // Ignore the return value.
     }
     CheckStack();
 
     // Compile the body of the function in a vanilla state. Don't
     // bother compiling all the code if the scope has an illegal
     // redeclaration.
-    if (!scope->HasIllegalRedeclaration()) {
+    if (!scope_->HasIllegalRedeclaration()) {
       Comment cmnt(masm_, "[ function body");
 #ifdef DEBUG
       bool is_builtin = Bootstrapper::IsActive();
@@ -241,6 +308,7 @@
           is_builtin ? FLAG_trace_builtin_calls : FLAG_trace_calls;
       if (should_trace) {
         __ CallRuntime(Runtime::kDebugTrace, 0);
+        // Ignore the return value.
       }
 #endif
       VisitStatements(body);
@@ -259,19 +327,20 @@
   if (FLAG_trace) {
     // Push the return value on the stack as the parameter.
     // Runtime::TraceExit returns the parameter as it is.
-    __ push(r0);
+    frame_->Push(r0);
     __ CallRuntime(Runtime::kTraceExit, 1);
   }
 
   // Tear down the frame which will restore the caller's frame pointer and the
   // link register.
-  ExitJSFrame();
+  frame_->Exit();
 
   __ add(sp, sp, Operand((scope_->num_parameters() + 1) * kPointerSize));
   __ mov(pc, lr);
 
   // Code generation state must be reset.
   scope_ = NULL;
+  frame_ = NULL;
   ASSERT(!has_cc());
   ASSERT(state_ == NULL);
 }
@@ -290,13 +359,10 @@
   int index = slot->index();
   switch (slot->type()) {
     case Slot::PARAMETER:
-      return ParameterOperand(index);
+      return frame_->Parameter(index);
 
-    case Slot::LOCAL: {
-      ASSERT(0 <= index && index < scope()->num_stack_slots());
-      const int kLocalOffset = JavaScriptFrameConstants::kLocal0Offset;
-      return MemOperand(fp, kLocalOffset - index * kPointerSize);
-    }
+    case Slot::LOCAL:
+      return frame_->Local(index);
 
     case Slot::CONTEXT: {
       // Follow the context chain if necessary.
@@ -331,16 +397,17 @@
 }
 
 
-// Loads a value on the stack. If it is a boolean value, the result may have
-// been (partially) translated into branches, or it may have set the condition
-// code register. If force_cc is set, the value is forced to set the condition
-// code register and no value is pushed. If the condition code register was set,
-// has_cc() is true and cc_reg_ contains the condition to test for 'true'.
+// Loads a value on TOS. If it is a boolean value, the result may have been
+// (partially) translated into branches, or it may have set the condition
+// code register. If force_cc is set, the value is forced to set the
+// condition code register and no value is pushed. If the condition code
+// register was set, has_cc() is true and cc_reg_ contains the condition to
+// test for 'true'.
 void CodeGenerator::LoadCondition(Expression* x,
-                                     TypeofState typeof_state,
-                                     Label* true_target,
-                                     Label* false_target,
-                                     bool force_cc) {
+                                  TypeofState typeof_state,
+                                  Label* true_target,
+                                  Label* false_target,
+                                  bool force_cc) {
   ASSERT(!has_cc());
 
   { CodeGenState new_state(this, typeof_state, true_target, false_target);
@@ -348,6 +415,13 @@
   }
   if (force_cc && !has_cc()) {
     // Convert the TOS value to a boolean in the condition code register.
+    // Visiting an expression may possibly choose neither (a) to leave a
+    // value in the condition code register nor (b) to leave a value in TOS
+    // (eg, by compiling to only jumps to the targets).  In that case the
+    // code generated by ToBoolean is wrong because it assumes the value of
+    // the expression in TOS.  So long as there is always a value in TOS or
+    // the condition code register when control falls through to here (there
+    // is), the code generated by ToBoolean is dead and therefore safe.
     ToBoolean(true_target, false_target);
   }
   ASSERT(has_cc() || !force_cc);
@@ -364,11 +438,11 @@
     Label loaded, materialize_true;
     __ b(cc_reg_, &materialize_true);
     __ mov(r0, Operand(Factory::false_value()));
-    __ push(r0);
+    frame_->Push(r0);
     __ b(&loaded);
     __ bind(&materialize_true);
     __ mov(r0, Operand(Factory::true_value()));
-    __ push(r0);
+    frame_->Push(r0);
     __ bind(&loaded);
     cc_reg_ = al;
   }
@@ -384,7 +458,7 @@
     if (true_target.is_linked()) {
       __ bind(&true_target);
       __ mov(r0, Operand(Factory::true_value()));
-      __ push(r0);
+      frame_->Push(r0);
     }
     // if both "true" and "false" need to be reincarnated,
     // jump across code for "false"
@@ -394,7 +468,7 @@
     if (false_target.is_linked()) {
       __ bind(&false_target);
       __ mov(r0, Operand(Factory::false_value()));
-      __ push(r0);
+      frame_->Push(r0);
     }
     // everything is loaded at this point
     __ bind(&loaded);
@@ -405,14 +479,15 @@
 
 void CodeGenerator::LoadGlobal() {
   __ ldr(r0, GlobalObject());
-  __ push(r0);
+  frame_->Push(r0);
 }
 
 
-void CodeGenerator::LoadGlobalReceiver(Register s) {
-  __ ldr(s, ContextOperand(cp, Context::GLOBAL_INDEX));
-  __ ldr(s, FieldMemOperand(s, GlobalObject::kGlobalReceiverOffset));
-  __ push(s);
+void CodeGenerator::LoadGlobalReceiver(Register scratch) {
+  __ ldr(scratch, ContextOperand(cp, Context::GLOBAL_INDEX));
+  __ ldr(scratch,
+         FieldMemOperand(scratch, GlobalObject::kGlobalReceiverOffset));
+  frame_->Push(scratch);
 }
 
 
@@ -450,7 +525,6 @@
 
 void CodeGenerator::LoadReference(Reference* ref) {
   Comment cmnt(masm_, "[ LoadReference");
-
   Expression* e = ref->expression();
   Property* property = e->AsProperty();
   Variable* var = e->AsVariableProxy()->AsVariable();
@@ -492,15 +566,13 @@
 
 
 void CodeGenerator::UnloadReference(Reference* ref) {
+  // Pop a reference from the stack while preserving TOS.
   Comment cmnt(masm_, "[ UnloadReference");
-
   int size = ref->size();
-  if (size <= 0) {
-    // Do nothing. No popping is necessary.
-  } else {
-    __ pop(r0);
-    __ add(sp, sp, Operand(size * kPointerSize));
-    __ push(r0);
+  if (size > 0) {
+    frame_->Pop(r0);
+    frame_->Drop(size);
+    frame_->Push(r0);
   }
 }
 
@@ -509,10 +581,10 @@
 // register to a boolean in the condition code register. The code
 // may jump to 'false_target' in case the register converts to 'false'.
 void CodeGenerator::ToBoolean(Label* true_target,
-                                 Label* false_target) {
+                              Label* false_target) {
   // Note: The generated code snippet does not change stack variables.
   //       Only the condition code should be set.
-  __ pop(r0);
+  frame_->Pop(r0);
 
   // Fast case checks
 
@@ -535,10 +607,9 @@
   __ b(eq, true_target);
 
   // Slow case: call the runtime.
-  __ push(r0);
+  frame_->Push(r0);
   __ CallRuntime(Runtime::kToBool, 1);
-
-  // Convert result (r0) to condition code
+  // Convert the result (r0) to a condition code.
   __ cmp(r0, Operand(Factory::false_value()));
 
   cc_reg_ = ne;
@@ -639,8 +710,8 @@
     case Token::SHL:
     case Token::SHR:
     case Token::SAR: {
-      __ pop(r0);  // r0 : y
-      __ pop(r1);  // r1 : x
+      frame_->Pop(r0);  // r0 : y
+      frame_->Pop(r1);  // r1 : x
       GenericBinaryOpStub stub(op);
       __ CallStub(&stub);
       break;
@@ -659,9 +730,9 @@
     }
 
     case Token::COMMA:
-      __ pop(r0);
+      frame_->Pop(r0);
       // simply discard left value
-      __ pop();
+      frame_->Pop();
       break;
 
     default:
@@ -749,8 +820,8 @@
 
 
 void CodeGenerator::SmiOperation(Token::Value op,
-                                    Handle<Object> value,
-                                    bool reversed) {
+                                 Handle<Object> value,
+                                 bool reversed) {
   // NOTE: This is an attempt to inline (a bit) more of the code for
   // some possible smi operations (like + and -) when (at least) one
   // of the operands is a literal smi. With this optimization, the
@@ -763,7 +834,7 @@
   int int_value = Smi::cast(*value)->value();
 
   Label exit;
-  __ pop(r0);
+  frame_->Pop(r0);
 
   switch (op) {
     case Token::ADD: {
@@ -816,8 +887,8 @@
     case Token::SAR: {
       if (reversed) {
         __ mov(ip, Operand(value));
-        __ push(ip);
-        __ push(r0);
+        frame_->Push(ip);
+        frame_->Push(r0);
         GenericBinaryOperation(op);
 
       } else {
@@ -867,13 +938,13 @@
 
     default:
       if (!reversed) {
-        __ push(r0);
+        frame_->Push(r0);
         __ mov(r0, Operand(value));
-        __ push(r0);
+        frame_->Push(r0);
       } else {
         __ mov(ip, Operand(value));
-        __ push(ip);
-        __ push(r0);
+        frame_->Push(ip);
+        frame_->Push(r0);
       }
       GenericBinaryOperation(op);
       break;
@@ -895,18 +966,18 @@
   // Implement '>' and '<=' by reversal to obtain ECMA-262 conversion order.
   if (cc == gt || cc == le) {
     cc = ReverseCondition(cc);
-    __ pop(r1);
-    __ pop(r0);
+    frame_->Pop(r1);
+    frame_->Pop(r0);
   } else {
-    __ pop(r0);
-    __ pop(r1);
+    frame_->Pop(r0);
+    frame_->Pop(r1);
   }
   __ orr(r2, r0, Operand(r1));
   __ tst(r2, Operand(kSmiTagMask));
   __ b(eq, &smi);
 
   // Perform non-smi comparison by runtime call.
-  __ push(r1);
+  frame_->Push(r1);
 
   // Figure out which native to call and setup the arguments.
   Builtins::JavaScript native;
@@ -923,14 +994,14 @@
       ASSERT(cc == gt || cc == ge);  // remaining cases
       ncr = LESS;
     }
-    __ push(r0);
+    frame_->Push(r0);
     __ mov(r0, Operand(Smi::FromInt(ncr)));
     argc = 2;
   }
 
   // Call the native; it returns -1 (less), 0 (equal), or 1 (greater)
   // tagged as a small integer.
-  __ push(r0);
+  frame_->Push(r0);
   __ mov(r0, Operand(argc));
   __ InvokeBuiltin(native, CALL_JS);
   __ cmp(r0, Operand(0));
@@ -979,8 +1050,8 @@
   __ CallStub(&call_function);
 
   // Restore context and pop function from the stack.
-  __ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
-  __ pop();  // discard the TOS
+  __ ldr(cp, frame_->Context());
+  frame_->Pop();  // discard the TOS
 }
 
 
@@ -1012,10 +1083,10 @@
 
 void CodeGenerator::DeclareGlobals(Handle<FixedArray> pairs) {
   __ mov(r0, Operand(pairs));
-  __ push(r0);
-  __ push(cp);
+  frame_->Push(r0);
+  frame_->Push(cp);
   __ mov(r0, Operand(Smi::FromInt(is_eval() ? 1 : 0)));
-  __ push(r0);
+  frame_->Push(r0);
   __ CallRuntime(Runtime::kDeclareGlobals, 3);
   // The result is discarded.
 }
@@ -1035,26 +1106,26 @@
     // during variable resolution and must have mode DYNAMIC.
     ASSERT(var->mode() == Variable::DYNAMIC);
     // For now, just do a runtime call.
-    __ push(cp);
+    frame_->Push(cp);
     __ mov(r0, Operand(var->name()));
-    __ push(r0);
+    frame_->Push(r0);
     // Declaration nodes are always declared in only two modes.
     ASSERT(node->mode() == Variable::VAR || node->mode() == Variable::CONST);
     PropertyAttributes attr = node->mode() == Variable::VAR ? NONE : READ_ONLY;
     __ mov(r0, Operand(Smi::FromInt(attr)));
-    __ push(r0);
+    frame_->Push(r0);
     // Push initial value, if any.
     // Note: For variables we must not push an initial value (such as
     // 'undefined') because we may have a (legal) redeclaration and we
     // must not destroy the current value.
     if (node->mode() == Variable::CONST) {
       __ mov(r0, Operand(Factory::the_hole_value()));
-      __ push(r0);
+      frame_->Push(r0);
     } else if (node->fun() != NULL) {
       Load(node->fun());
     } else {
       __ mov(r0, Operand(0));  // no initial value!
-      __ push(r0);
+      frame_->Push(r0);
     }
     __ CallRuntime(Runtime::kDeclareContextSlot, 4);
     // Ignore the return value (declarations are statements).
@@ -1081,7 +1152,7 @@
     // safe to pop the value lying on top of the reference before unloading
     // the reference itself (which preserves the top of stack) because we
     // know it is a zero-sized reference.
-    __ pop();
+    frame_->Pop();
   }
 }
 
@@ -1092,7 +1163,7 @@
   Expression* expression = node->expression();
   expression->MarkAsStatement();
   Load(expression);
-  __ pop();
+  frame_->Pop();
 }
 
 
@@ -1157,7 +1228,7 @@
     if (has_cc()) {
       cc_reg_ = al;
     } else {
-      __ pop(r0);  // __ Pop(no_reg)
+      frame_->Pop();
     }
   }
 
@@ -1167,10 +1238,8 @@
 
 
 void CodeGenerator::CleanStack(int num_bytes) {
-  ASSERT(num_bytes >= 0);
-  if (num_bytes > 0) {
-    __ add(sp, sp, Operand(num_bytes));
-  }
+  ASSERT(num_bytes % kPointerSize == 0);
+  frame_->Drop(num_bytes / kPointerSize);
 }
 
 
@@ -1195,7 +1264,7 @@
   if (FLAG_debug_info) RecordStatementPosition(node);
   Load(node->expression());
   // Move the function result into r0.
-  __ pop(r0);
+  frame_->Pop(r0);
 
   __ b(&function_return_);
 }
@@ -1214,7 +1283,7 @@
     __ bind(&verified_true);
   }
   // Update context local.
-  __ str(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
+  __ str(cp, frame_->Context());
 }
 
 
@@ -1223,7 +1292,7 @@
   // Pop context.
   __ ldr(cp, ContextOperand(cp, Context::PREVIOUS_INDEX));
   // Update context local.
-  __ str(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
+  __ str(cp, frame_->Context());
 }
 
 
@@ -1246,7 +1315,7 @@
 
   ASSERT(kSmiTag == 0 && kSmiTagSize <= 2);
 
-  __ pop(r0);
+  frame_->Pop(r0);
 
   // Test for a Smi value in a HeapNumber.
   Label is_smi;
@@ -1256,7 +1325,7 @@
   __ ldrb(r1, MemOperand(r1, Map::kInstanceTypeOffset - kHeapObjectTag));
   __ cmp(r1, Operand(HEAP_NUMBER_TYPE));
   __ b(ne, fail_label);
-  __ push(r0);
+  frame_->Push(r0);
   __ CallRuntime(Runtime::kNumberToSmi, 1);
   __ bind(&is_smi);
 
@@ -1324,8 +1393,8 @@
     } else {
       __ bind(&next);
       next.Unuse();
-      __ ldr(r0, MemOperand(sp, 0));
-      __ push(r0);  // duplicate TOS
+      __ ldr(r0, frame_->Top());
+      frame_->Push(r0);  // duplicate TOS
       Load(clause->label());
       Comparison(eq, true);
       Branch(false, &next);
@@ -1333,7 +1402,7 @@
 
     // Entering the case statement for the first time. Remove the switch value
     // from the stack.
-    __ pop(r0);
+    frame_->Pop();
 
     // Generate code for the body.
     // This is also the target for the fall through from the previous case's
@@ -1352,7 +1421,7 @@
     __ b(&default_case);
   } else {
     // Remove the switch value from the stack.
-    __ pop(r0);
+    frame_->Pop();
   }
 
   __ bind(&fall_through);
@@ -1448,7 +1517,7 @@
 
   // Get the object to enumerate over (converted to JSObject).
   Load(node->enumerable());
-  __ pop(r0);
+  frame_->Pop(r0);
 
   // Both SpiderMonkey and kjs ignore null and undefined in contrast
   // to the specification.  12.6.4 mandates a call to ToObject.
@@ -1473,7 +1542,7 @@
   __ b(hs, &jsobject);
 
   __ bind(&primitive);
-  __ push(r0);
+  frame_->Push(r0);
   __ mov(r0, Operand(0));
   __ InvokeBuiltin(Builtins::TO_OBJECT, CALL_JS);
 
@@ -1481,8 +1550,8 @@
   __ bind(&jsobject);
 
   // Get the set of properties (as a FixedArray or Map).
-  __ push(r0);  // duplicate the object being enumerated
-  __ push(r0);
+  frame_->Push(r0);  // duplicate the object being enumerated
+  frame_->Push(r0);
   __ CallRuntime(Runtime::kGetPropertyNamesFast, 1);
 
   // If we got a Map, we can do a fast modification check.
@@ -1499,28 +1568,28 @@
   __ ldr(r2,
          FieldMemOperand(r1, DescriptorArray::kEnumCacheBridgeCacheOffset));
 
-  __ push(r0);  // map
-  __ push(r2);  // enum cache bridge cache
+  frame_->Push(r0);  // map
+  frame_->Push(r2);  // enum cache bridge cache
   __ ldr(r0, FieldMemOperand(r2, FixedArray::kLengthOffset));
   __ mov(r0, Operand(r0, LSL, kSmiTagSize));
-  __ push(r0);
+  frame_->Push(r0);
   __ mov(r0, Operand(Smi::FromInt(0)));
-  __ push(r0);
+  frame_->Push(r0);
   __ b(&entry);
 
 
   __ bind(&fixed_array);
 
   __ mov(r1, Operand(Smi::FromInt(0)));
-  __ push(r1);  // insert 0 in place of Map
-  __ push(r0);
+  frame_->Push(r1);  // insert 0 in place of Map
+  frame_->Push(r0);
 
   // Push the length of the array and the initial index onto the stack.
   __ ldr(r0, FieldMemOperand(r0, FixedArray::kLengthOffset));
   __ mov(r0, Operand(r0, LSL, kSmiTagSize));
-  __ push(r0);
+  frame_->Push(r0);
   __ mov(r0, Operand(Smi::FromInt(0)));  // init index
-  __ push(r0);
+  frame_->Push(r0);
 
   __ b(&entry);
 
@@ -1531,9 +1600,9 @@
   // Next.
   __ bind(node->continue_target());
   __ bind(&next);
-  __ pop(r0);
+  frame_->Pop(r0);
   __ add(r0, r0, Operand(Smi::FromInt(1)));
-  __ push(r0);
+  frame_->Push(r0);
 
   // Condition.
   __ bind(&entry);
@@ -1543,31 +1612,31 @@
   // sp[2] : array or enum cache
   // sp[3] : 0 or map
   // sp[4] : enumerable
-  __ ldr(r0, MemOperand(sp, 0 * kPointerSize));  // load the current count
-  __ ldr(r1, MemOperand(sp, 1 * kPointerSize));  // load the length
+  __ ldr(r0, frame_->Element(0));  // load the current count
+  __ ldr(r1, frame_->Element(1));  // load the length
   __ cmp(r0, Operand(r1));  // compare to the array length
   __ b(hs, &cleanup);
 
-  __ ldr(r0, MemOperand(sp, 0 * kPointerSize));
+  __ ldr(r0, frame_->Element(0));
 
   // Get the i'th entry of the array.
-  __ ldr(r2, MemOperand(sp, 2 * kPointerSize));
+  __ ldr(r2, frame_->Element(2));
   __ add(r2, r2, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
   __ ldr(r3, MemOperand(r2, r0, LSL, kPointerSizeLog2 - kSmiTagSize));
 
   // Get Map or 0.
-  __ ldr(r2, MemOperand(sp, 3 * kPointerSize));
+  __ ldr(r2, frame_->Element(3));
   // Check if this (still) matches the map of the enumerable.
   // If not, we have to filter the key.
-  __ ldr(r1, MemOperand(sp, 4 * kPointerSize));
+  __ ldr(r1, frame_->Element(4));
   __ ldr(r1, FieldMemOperand(r1, HeapObject::kMapOffset));
   __ cmp(r1, Operand(r2));
   __ b(eq, &end_del_check);
 
   // Convert the entry to a string (or null if it isn't a property anymore).
-  __ ldr(r0, MemOperand(sp, 4 * kPointerSize));  // push enumerable
-  __ push(r0);
-  __ push(r3);  // push entry
+  __ ldr(r0, frame_->Element(4));  // push enumerable
+  frame_->Push(r0);
+  frame_->Push(r3);  // push entry
   __ mov(r0, Operand(1));
   __ InvokeBuiltin(Builtins::FILTER_KEY, CALL_JS);
   __ mov(r3, Operand(r0));
@@ -1581,12 +1650,12 @@
 
   // Store the entry in the 'each' expression and take another spin in the loop.
   // r3: i'th entry of the enum cache (or string there of)
-  __ push(r3);  // push entry
+  frame_->Push(r3);  // push entry
   { Reference each(this, node->each());
     if (!each.is_illegal()) {
       if (each.size() > 0) {
-        __ ldr(r0, MemOperand(sp, kPointerSize * each.size()));
-        __ push(r0);
+        __ ldr(r0, frame_->Element(each.size()));
+        frame_->Push(r0);
       }
       // If the reference was to a slot we rely on the convenient property
       // that it doesn't matter whether a value (eg, r3 pushed above) is
@@ -1598,20 +1667,20 @@
         // ie, now the topmost value of the non-zero sized reference), since
         // we will discard the top of stack after unloading the reference
         // anyway.
-        __ pop(r0);
+        frame_->Pop(r0);
       }
     }
   }
   // Discard the i'th entry pushed above or else the remainder of the
   // reference, whichever is currently on top of the stack.
-  __ pop();
+  frame_->Pop();
   CheckStack();  // TODO(1222600): ignore if body contains calls.
   __ jmp(&loop);
 
   // Cleanup.
   __ bind(&cleanup);
   __ bind(node->break_target());
-  __ add(sp, sp, Operand(5 * kPointerSize));
+  frame_->Drop(5);
 
   // Exit.
   __ bind(&exit);
@@ -1626,11 +1695,10 @@
   Label try_block, exit;
 
   __ bl(&try_block);
-
   // --- Catch block ---
+  frame_->Push(r0);
 
   // Store the caught exception in the catch variable.
-  __ push(r0);
   { Reference ref(this, node->catch_var());
     ASSERT(ref.is_slot());
     // Here we make use of the convenient property that it doesn't matter
@@ -1640,7 +1708,7 @@
   }
 
   // Remove the exception from the stack.
-  __ pop();
+  frame_->Pop();
 
   VisitStatements(node->catch_block()->statements());
   __ b(&exit);
@@ -1667,7 +1735,7 @@
 
   // Generate code for the statements in the try block.
   VisitStatements(node->try_block()->statements());
-  __ pop(r0);  // Discard the result.
+  frame_->Pop();  // Discard the result.
 
   // Stop the introduced shadowing and count the number of required unlinks.
   // After shadowing stops, the original labels are unshadowed and the
@@ -1680,13 +1748,14 @@
 
   // Unlink from try chain.
   // TOS contains code slot
-  const int kNextOffset = StackHandlerConstants::kNextOffset +
-      StackHandlerConstants::kAddressDisplacement;
-  __ ldr(r1, MemOperand(sp, kNextOffset));  // read next_sp
+  const int kNextIndex = (StackHandlerConstants::kNextOffset
+                          + StackHandlerConstants::kAddressDisplacement)
+                       / kPointerSize;
+  __ ldr(r1, frame_->Element(kNextIndex));  // read next_sp
   __ mov(r3, Operand(ExternalReference(Top::k_handler_address)));
   __ str(r1, MemOperand(r3));
   ASSERT(StackHandlerConstants::kCodeOffset == 0);  // first field is code
-  __ add(sp, sp, Operand(StackHandlerConstants::kSize - kPointerSize));
+  frame_->Drop(StackHandlerConstants::kSize / kPointerSize - 1);
   // Code slot popped.
   if (nof_unlinks > 0) __ b(&exit);
 
@@ -1702,10 +1771,10 @@
       __ mov(r3, Operand(ExternalReference(Top::k_handler_address)));
       __ ldr(sp, MemOperand(r3));
 
-      __ ldr(r1, MemOperand(sp, kNextOffset));
+      __ ldr(r1, frame_->Element(kNextIndex));
       __ str(r1, MemOperand(r3));
       ASSERT(StackHandlerConstants::kCodeOffset == 0);  // first field is code
-      __ add(sp, sp, Operand(StackHandlerConstants::kSize - kPointerSize));
+      frame_->Drop(StackHandlerConstants::kSize / kPointerSize - 1);
       // Code slot popped.
 
       __ b(shadows[i]->original_label());
@@ -1728,7 +1797,7 @@
 
   __ bl(&try_block);
 
-  __ push(r0);  // save exception object on the stack
+  frame_->Push(r0);  // save exception object on the stack
   // In case of thrown exceptions, this is where we continue.
   __ mov(r2, Operand(Smi::FromInt(THROWING)));
   __ b(&finally_block);
@@ -1766,7 +1835,7 @@
 
   // Set the state on the stack to FALLING.
   __ mov(r0, Operand(Factory::undefined_value()));  // fake TOS
-  __ push(r0);
+  frame_->Push(r0);
   __ mov(r2, Operand(Smi::FromInt(FALLING)));
   if (nof_unlinks > 0) __ b(&unlink);
 
@@ -1778,11 +1847,11 @@
       if (shadows[i]->original_label() == &function_return_) {
         // If this label shadowed the function return, materialize the
         // return value on the stack.
-        __ push(r0);
+        frame_->Push(r0);
       } else {
         // Fake TOS for labels that shadowed breaks and continues.
         __ mov(r0, Operand(Factory::undefined_value()));
-        __ push(r0);
+        frame_->Push(r0);
       }
       __ mov(r2, Operand(Smi::FromInt(JUMPING + i)));
       __ b(&unlink);
@@ -1792,25 +1861,26 @@
   // Unlink from try chain;
   __ bind(&unlink);
 
-  __ pop(r0);  // Store TOS in r0 across stack manipulation
+  frame_->Pop(r0);  // Store TOS in r0 across stack manipulation
   // Reload sp from the top handler, because some statements that we
   // break from (eg, for...in) may have left stuff on the stack.
   __ mov(r3, Operand(ExternalReference(Top::k_handler_address)));
   __ ldr(sp, MemOperand(r3));
-  const int kNextOffset = StackHandlerConstants::kNextOffset +
-      StackHandlerConstants::kAddressDisplacement;
-  __ ldr(r1, MemOperand(sp, kNextOffset));
+  const int kNextIndex = (StackHandlerConstants::kNextOffset
+                          + StackHandlerConstants::kAddressDisplacement)
+                       / kPointerSize;
+  __ ldr(r1, frame_->Element(kNextIndex));
   __ str(r1, MemOperand(r3));
   ASSERT(StackHandlerConstants::kCodeOffset == 0);  // first field is code
-  __ add(sp, sp, Operand(StackHandlerConstants::kSize - kPointerSize));
+  frame_->Drop(StackHandlerConstants::kSize / kPointerSize - 1);
   // Code slot popped.
-  __ push(r0);
+  frame_->Push(r0);
 
   // --- Finally block ---
   __ bind(&finally_block);
 
   // Push the state on the stack.
-  __ push(r2);
+  frame_->Push(r2);
 
   // We keep two elements on the stack - the (possibly faked) result
   // and the state - while evaluating the finally block. Record it, so
@@ -1823,8 +1893,8 @@
   VisitStatements(node->finally_block()->statements());
 
   // Restore state and return value or faked TOS.
-  __ pop(r2);
-  __ pop(r0);
+  frame_->Pop(r2);
+  frame_->Pop(r0);
   break_stack_height_ -= kFinallyStackSize;
 
   // Generate code to jump to the right destination for all used (formerly)
@@ -1848,7 +1918,7 @@
   __ b(ne, &exit);
 
   // Rethrow exception.
-  __ push(r0);
+  frame_->Push(r0);
   __ CallRuntime(Runtime::kReThrow, 1);
 
   // Done.
@@ -1869,12 +1939,12 @@
 
   // Push the boilerplate on the stack.
   __ mov(r0, Operand(boilerplate));
-  __ push(r0);
+  frame_->Push(r0);
 
   // Create a new closure.
-  __ push(cp);
+  frame_->Push(cp);
   __ CallRuntime(Runtime::kNewClosure, 2);
-  __ push(r0);
+  frame_->Push(r0);
 }
 
 
@@ -1915,16 +1985,16 @@
     ASSERT(slot->var()->mode() == Variable::DYNAMIC);
 
     // For now, just do a runtime call.
-    __ push(cp);
+    frame_->Push(cp);
     __ mov(r0, Operand(slot->var()->name()));
-    __ push(r0);
+    frame_->Push(r0);
 
     if (typeof_state == INSIDE_TYPEOF) {
       __ CallRuntime(Runtime::kLoadContextSlotNoReferenceError, 2);
     } else {
       __ CallRuntime(Runtime::kLoadContextSlot, 2);
     }
-    __ push(r0);
+    frame_->Push(r0);
 
   } else {
     // Note: We would like to keep the assert below, but it fires because of
@@ -1933,16 +2003,16 @@
 
     // Special handling for locals allocated in registers.
     __ ldr(r0, SlotOperand(slot, r2));
-    __ push(r0);
+    frame_->Push(r0);
     if (slot->var()->mode() == Variable::CONST) {
       // Const slots may contain 'the hole' value (the constant hasn't been
       // initialized yet) which needs to be converted into the 'undefined'
       // value.
       Comment cmnt(masm_, "[ Unhole const");
-      __ pop(r0);
+      frame_->Pop(r0);
       __ cmp(r0, Operand(Factory::the_hole_value()));
       __ mov(r0, Operand(Factory::undefined_value()), LeaveCC, eq);
-      __ push(r0);
+      frame_->Push(r0);
     }
   }
 }
@@ -1972,7 +2042,7 @@
 void CodeGenerator::VisitLiteral(Literal* node) {
   Comment cmnt(masm_, "[ Literal");
   __ mov(r0, Operand(node->handle()));
-  __ push(r0);
+  frame_->Push(r0);
 }
 
 
@@ -1982,7 +2052,7 @@
   // Retrieve the literal array and check the allocated entry.
 
   // Load the function of this activation.
-  __ ldr(r1, FunctionOperand());
+  __ ldr(r1, frame_->Function());
 
   // Load the literals array of the function.
   __ ldr(r1, FieldMemOperand(r1, JSFunction::kLiteralsOffset));
@@ -1998,19 +2068,19 @@
 
   // If the entry is undefined we call the runtime system to computed
   // the literal.
-  __ push(r1);  // literal array  (0)
+  frame_->Push(r1);  // literal array  (0)
   __ mov(r0, Operand(Smi::FromInt(node->literal_index())));
-  __ push(r0);  // literal index  (1)
+  frame_->Push(r0);  // literal index  (1)
   __ mov(r0, Operand(node->pattern()));  // RegExp pattern (2)
-  __ push(r0);
+  frame_->Push(r0);
   __ mov(r0, Operand(node->flags()));  // RegExp flags   (3)
-  __ push(r0);
+  frame_->Push(r0);
   __ CallRuntime(Runtime::kMaterializeRegExpLiteral, 4);
   __ mov(r2, Operand(r0));
 
   __ bind(&done);
   // Push the literal.
-  __ push(r2);
+  frame_->Push(r2);
 }
 
 
@@ -2055,7 +2125,7 @@
   // Retrieve the literal array and check the allocated entry.
 
   // Load the function of this activation.
-  __ ldr(r1, FunctionOperand());
+  __ ldr(r1, frame_->Function());
 
   // Load the literals array of the function.
   __ ldr(r1, FieldMemOperand(r1, JSFunction::kLiteralsOffset));
@@ -2072,11 +2142,11 @@
   __ bind(deferred->exit());
 
   // Push the object literal boilerplate.
-  __ push(r2);
+  frame_->Push(r2);
 
   // Clone the boilerplate object.
   __ CallRuntime(Runtime::kCloneObjectLiteralBoilerplate, 1);
-  __ push(r0);  // save the result
+  frame_->Push(r0);  // save the result
   // r0: cloned object literal
 
   for (int i = 0; i < node->properties()->length(); i++) {
@@ -2087,32 +2157,32 @@
       case ObjectLiteral::Property::CONSTANT: break;
       case ObjectLiteral::Property::COMPUTED:  // fall through
       case ObjectLiteral::Property::PROTOTYPE: {
-        __ push(r0);  // dup the result
+        frame_->Push(r0);  // dup the result
         Load(key);
         Load(value);
         __ CallRuntime(Runtime::kSetProperty, 3);
         // restore r0
-        __ ldr(r0, MemOperand(sp, 0));
+        __ ldr(r0, frame_->Top());
         break;
       }
       case ObjectLiteral::Property::SETTER: {
-        __ push(r0);
+        frame_->Push(r0);
         Load(key);
         __ mov(r0, Operand(Smi::FromInt(1)));
-        __ push(r0);
+        frame_->Push(r0);
         Load(value);
         __ CallRuntime(Runtime::kDefineAccessor, 4);
-        __ ldr(r0, MemOperand(sp, 0));
+        __ ldr(r0, frame_->Top());
         break;
       }
       case ObjectLiteral::Property::GETTER: {
-        __ push(r0);
+        frame_->Push(r0);
         Load(key);
         __ mov(r0, Operand(Smi::FromInt(0)));
-        __ push(r0);
+        frame_->Push(r0);
         Load(value);
         __ CallRuntime(Runtime::kDefineAccessor, 4);
-        __ ldr(r0, MemOperand(sp, 0));
+        __ ldr(r0, frame_->Top());
         break;
       }
     }
@@ -2125,15 +2195,15 @@
 
   // Call runtime to create the array literal.
   __ mov(r0, Operand(node->literals()));
-  __ push(r0);
+  frame_->Push(r0);
   // Load the function of this frame.
-  __ ldr(r0, FunctionOperand());
+  __ ldr(r0, frame_->Function());
   __ ldr(r0, FieldMemOperand(r0, JSFunction::kLiteralsOffset));
-  __ push(r0);
+  frame_->Push(r0);
   __ CallRuntime(Runtime::kCreateArrayLiteral, 2);
 
   // Push the resulting array literal on the stack.
-  __ push(r0);
+  frame_->Push(r0);
 
   // Generate code to set the elements in the array that are not
   // literals.
@@ -2145,10 +2215,10 @@
     if (value->AsLiteral() == NULL) {
       // The property must be set by generated code.
       Load(value);
-      __ pop(r0);
+      frame_->Pop(r0);
 
       // Fetch the object literal
-      __ ldr(r1, MemOperand(sp, 0));
+      __ ldr(r1, frame_->Top());
         // Get the elements array.
       __ ldr(r1, FieldMemOperand(r1, JSObject::kElementsOffset));
 
@@ -2181,12 +2251,12 @@
     Literal* literal = node->value()->AsLiteral();
     if (literal != NULL && literal->handle()->IsSmi()) {
       SmiOperation(node->binary_op(), literal->handle(), false);
-      __ push(r0);
+      frame_->Push(r0);
 
     } else {
       Load(node->value());
       GenericBinaryOperation(node->binary_op());
-      __ push(r0);
+      frame_->Push(r0);
     }
   }
 
@@ -2216,7 +2286,7 @@
   Load(node->exception());
   __ RecordPosition(node->position());
   __ CallRuntime(Runtime::kThrow, 1);
-  __ push(r0);
+  frame_->Push(r0);
 }
 
 
@@ -2257,7 +2327,7 @@
 
     // Push the name of the function and the receiver onto the stack.
     __ mov(r0, Operand(var->name()));
-    __ push(r0);
+    frame_->Push(r0);
 
     // Pass the global object as the receiver and let the IC stub
     // patch the stack to use the global proxy as 'this' in the
@@ -2271,10 +2341,10 @@
     Handle<Code> stub = ComputeCallInitialize(args->length());
     __ RecordPosition(node->position());
     __ Call(stub, RelocInfo::CODE_TARGET_CONTEXT);
-    __ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
+    __ ldr(cp, frame_->Context());
     // Remove the function from the stack.
-    __ pop();
-    __ push(r0);
+    frame_->Pop();
+    frame_->Push(r0);
 
   } else if (var != NULL && var->slot() != NULL &&
              var->slot()->type() == Slot::LOOKUP) {
@@ -2283,19 +2353,19 @@
     // ----------------------------------
 
     // Load the function
-    __ push(cp);
+    frame_->Push(cp);
     __ mov(r0, Operand(var->name()));
-    __ push(r0);
+    frame_->Push(r0);
     __ CallRuntime(Runtime::kLoadContextSlot, 2);
     // r0: slot value; r1: receiver
 
     // Load the receiver.
-    __ push(r0);  // function
-    __ push(r1);  // receiver
+    frame_->Push(r0);  // function
+    frame_->Push(r1);  // receiver
 
     // Call the function.
     CallWithArguments(args, node->position());
-    __ push(r0);
+    frame_->Push(r0);
 
   } else if (property != NULL) {
     // Check if the key is a literal string.
@@ -2308,7 +2378,7 @@
 
       // Push the name of the function and the receiver onto the stack.
       __ mov(r0, Operand(literal->handle()));
-      __ push(r0);
+      frame_->Push(r0);
       Load(property->obj());
 
       // Load the arguments.
@@ -2318,12 +2388,12 @@
       Handle<Code> stub = ComputeCallInitialize(args->length());
       __ RecordPosition(node->position());
       __ Call(stub, RelocInfo::CODE_TARGET);
-      __ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
+      __ ldr(cp, frame_->Context());
 
       // Remove the function from the stack.
-      __ pop();
+      frame_->Pop();
 
-      __ push(r0);  // push after get rid of function from the stack
+      frame_->Push(r0);  // push after get rid of function from the stack
 
     } else {
       // -------------------------------------------
@@ -2335,11 +2405,11 @@
       ref.GetValue(NOT_INSIDE_TYPEOF);  // receiver
 
       // Pass receiver to called function.
-      __ ldr(r0, MemOperand(sp, ref.size() * kPointerSize));
-      __ push(r0);
+      __ ldr(r0, frame_->Element(ref.size()));
+      frame_->Push(r0);
       // Call the function.
       CallWithArguments(args, node->position());
-      __ push(r0);
+      frame_->Push(r0);
     }
 
   } else {
@@ -2355,7 +2425,7 @@
 
     // Call the function.
     CallWithArguments(args, node->position());
-    __ push(r0);
+    frame_->Push(r0);
   }
 }
 
@@ -2383,7 +2453,7 @@
   __ mov(r0, Operand(args->length()));
 
   // Load the function into r1 as per calling convention.
-  __ ldr(r1, MemOperand(sp, (args->length() + 1) * kPointerSize));
+  __ ldr(r1, frame_->Element(args->length() + 1));
 
   // Call the construct call builtin that handles allocation and
   // constructor invocation.
@@ -2392,7 +2462,7 @@
           RelocInfo::CONSTRUCT_CALL);
 
   // Discard old TOS value and push r0 on the stack (same as Pop(), push(r0)).
-  __ str(r0, MemOperand(sp, 0 * kPointerSize));
+  __ str(r0, frame_->Top());
 }
 
 
@@ -2400,7 +2470,7 @@
   ASSERT(args->length() == 1);
   Label leave;
   Load(args->at(0));
-  __ pop(r0);  // r0 contains object.
+  frame_->Pop(r0);  // r0 contains object.
   // if (object->IsSmi()) return the object.
   __ tst(r0, Operand(kSmiTagMask));
   __ b(eq, &leave);
@@ -2413,7 +2483,7 @@
   // Load the value.
   __ ldr(r0, FieldMemOperand(r0, JSValue::kValueOffset));
   __ bind(&leave);
-  __ push(r0);
+  frame_->Push(r0);
 }
 
 
@@ -2422,8 +2492,8 @@
   Label leave;
   Load(args->at(0));  // Load the object.
   Load(args->at(1));  // Load the value.
-  __ pop(r0);  // r0 contains value
-  __ pop(r1);  // r1 contains object
+  frame_->Pop(r0);  // r0 contains value
+  frame_->Pop(r1);  // r1 contains object
   // if (object->IsSmi()) return object.
   __ tst(r1, Operand(kSmiTagMask));
   __ b(eq, &leave);
@@ -2440,14 +2510,14 @@
   __ RecordWrite(r1, r2, r3);
   // Leave.
   __ bind(&leave);
-  __ push(r0);
+  frame_->Push(r0);
 }
 
 
 void CodeGenerator::GenerateIsSmi(ZoneList<Expression*>* args) {
   ASSERT(args->length() == 1);
   Load(args->at(0));
-  __ pop(r0);
+  frame_->Pop(r0);
   __ tst(r0, Operand(kSmiTagMask));
   cc_reg_ = eq;
 }
@@ -2456,7 +2526,7 @@
 void CodeGenerator::GenerateIsNonNegativeSmi(ZoneList<Expression*>* args) {
   ASSERT(args->length() == 1);
   Load(args->at(0));
-  __ pop(r0);
+  frame_->Pop(r0);
   __ tst(r0, Operand(kSmiTagMask | 0x80000000));
   cc_reg_ = eq;
 }
@@ -2468,7 +2538,7 @@
 void CodeGenerator::GenerateFastCharCodeAt(ZoneList<Expression*>* args) {
   ASSERT(args->length() == 2);
   __ mov(r0, Operand(Factory::undefined_value()));
-  __ push(r0);
+  frame_->Push(r0);
 }
 
 
@@ -2479,7 +2549,7 @@
   // We need the CC bits to come out as not_equal in the case where the
   // object is a smi.  This can't be done with the usual test opcode so
   // we use XOR to get the right CC bits.
-  __ pop(r0);
+  frame_->Pop(r0);
   __ and_(r1, r0, Operand(kSmiTagMask));
   __ eor(r1, r1, Operand(kSmiTagMask), SetCC);
   __ b(ne, &answer);
@@ -2503,7 +2573,7 @@
   // Call the shared stub to get to the arguments.length.
   ArgumentsAccessStub stub(ArgumentsAccessStub::READ_LENGTH);
   __ CallStub(&stub);
-  __ push(r0);
+  frame_->Push(r0);
 }
 
 
@@ -2513,13 +2583,13 @@
   // Satisfy contract with ArgumentsAccessStub:
   // Load the key into r1 and the formal parameters count into r0.
   Load(args->at(0));
-  __ pop(r1);
+  frame_->Pop(r1);
   __ mov(r0, Operand(Smi::FromInt(scope_->num_parameters())));
 
   // Call the shared stub to get to arguments[key].
   ArgumentsAccessStub stub(ArgumentsAccessStub::READ_ELEMENT);
   __ CallStub(&stub);
-  __ push(r0);
+  frame_->Push(r0);
 }
 
 
@@ -2529,8 +2599,8 @@
   // Load the two objects into registers and perform the comparison.
   Load(args->at(0));
   Load(args->at(1));
-  __ pop(r0);
-  __ pop(r1);
+  frame_->Pop(r0);
+  frame_->Pop(r1);
   __ cmp(r0, Operand(r1));
   cc_reg_ = eq;
 }
@@ -2549,25 +2619,25 @@
 
     // Call the C runtime function.
     __ CallRuntime(function, args->length());
-    __ push(r0);
+    frame_->Push(r0);
 
   } else {
     // Prepare stack for calling JS runtime function.
     __ mov(r0, Operand(node->name()));
-    __ push(r0);
+    frame_->Push(r0);
     // Push the builtins object found in the current global object.
     __ ldr(r1, GlobalObject());
     __ ldr(r0, FieldMemOperand(r1, GlobalObject::kBuiltinsOffset));
-    __ push(r0);
+    frame_->Push(r0);
 
     for (int i = 0; i < args->length(); i++) Load(args->at(i));
 
     // Call the JS runtime function.
     Handle<Code> stub = ComputeCallInitialize(args->length());
     __ Call(stub, RelocInfo::CODE_TARGET);
-    __ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
-    __ pop();
-    __ push(r0);
+    __ ldr(cp, frame_->Context());
+    frame_->Pop();
+    frame_->Push(r0);
   }
 }
 
@@ -2599,20 +2669,20 @@
       if (variable->is_global()) {
         LoadGlobal();
         __ mov(r0, Operand(variable->name()));
-        __ push(r0);
+        frame_->Push(r0);
         __ mov(r0, Operand(1));  // not counting receiver
         __ InvokeBuiltin(Builtins::DELETE, CALL_JS);
 
       } else if (slot != NULL && slot->type() == Slot::LOOKUP) {
         // lookup the context holding the named variable
-        __ push(cp);
+        frame_->Push(cp);
         __ mov(r0, Operand(variable->name()));
-        __ push(r0);
+        frame_->Push(r0);
         __ CallRuntime(Runtime::kLookupContext, 2);
         // r0: context
-        __ push(r0);
+        frame_->Push(r0);
         __ mov(r0, Operand(variable->name()));
-        __ push(r0);
+        frame_->Push(r0);
         __ mov(r0, Operand(1));  // not counting receiver
         __ InvokeBuiltin(Builtins::DELETE, CALL_JS);
 
@@ -2625,21 +2695,21 @@
     } else {
       // Default: Result of deleting expressions is true.
       Load(node->expression());  // may have side-effects
-      __ pop();
+      frame_->Pop();
       __ mov(r0, Operand(Factory::true_value()));
     }
-    __ push(r0);
+    frame_->Push(r0);
 
   } else if (op == Token::TYPEOF) {
     // Special case for loading the typeof expression; see comment on
     // LoadTypeofExpression().
     LoadTypeofExpression(node->expression());
     __ CallRuntime(Runtime::kTypeof, 1);
-    __ push(r0);  // r0 has result
+    frame_->Push(r0);  // r0 has result
 
   } else {
     Load(node->expression());
-    __ pop(r0);
+    frame_->Pop(r0);
     switch (op) {
       case Token::NOT:
       case Token::DELETE:
@@ -2660,7 +2730,7 @@
         __ tst(r0, Operand(kSmiTagMask));
         __ b(eq, &smi_label);
 
-        __ push(r0);
+        frame_->Push(r0);
         __ mov(r0, Operand(0));  // not counting receiver
         __ InvokeBuiltin(Builtins::BIT_NOT, CALL_JS);
 
@@ -2683,7 +2753,7 @@
         Label continue_label;
         __ tst(r0, Operand(kSmiTagMask));
         __ b(eq, &continue_label);
-        __ push(r0);
+        frame_->Push(r0);
         __ mov(r0, Operand(0));  // not counting receiver
         __ InvokeBuiltin(Builtins::TO_NUMBER, CALL_JS);
         __ bind(&continue_label);
@@ -2692,7 +2762,7 @@
       default:
         UNREACHABLE();
     }
-    __ push(r0);  // r0 has result
+    frame_->Push(r0);  // r0 has result
   }
 }
 
@@ -2709,13 +2779,13 @@
   // Postfix: Make room for the result.
   if (is_postfix) {
      __ mov(r0, Operand(0));
-     __ push(r0);
+     frame_->Push(r0);
   }
 
   { Reference target(this, node->expression());
     if (target.is_illegal()) return;
     target.GetValue(NOT_INSIDE_TYPEOF);
-    __ pop(r0);
+    frame_->Pop(r0);
 
     Label slow, exit;
 
@@ -2727,7 +2797,9 @@
     __ b(ne, &slow);
 
     // Postfix: Store the old value as the result.
-    if (is_postfix) __ str(r0, MemOperand(sp, target.size() * kPointerSize));
+    if (is_postfix) {
+      __ str(r0, frame_->Element(target.size()));
+    }
 
     // Perform optimistic increment/decrement.
     if (is_increment) {
@@ -2754,7 +2826,7 @@
       InvokeBuiltinStub stub(InvokeBuiltinStub::ToNumber, 2);
       __ CallStub(&stub);
       // Store to result (on the stack).
-      __ str(r0, MemOperand(sp, target.size() * kPointerSize));
+      __ str(r0, frame_->Element(target.size()));
     }
 
     // Compute the new value by calling the right JavaScript native.
@@ -2768,12 +2840,12 @@
 
     // Store the new value in the target if not const.
     __ bind(&exit);
-    __ push(r0);
+    frame_->Push(r0);
     if (!is_const) target.SetValue(NOT_CONST_INIT);
   }
 
   // Postfix: Discard the new value and use the old.
-  if (is_postfix) __ pop(r0);
+  if (is_postfix) frame_->Pop(r0);
 }
 
 
@@ -2814,8 +2886,8 @@
     } else {
       Label pop_and_continue, exit;
 
-      __ ldr(r0, MemOperand(sp, 0));  // dup the stack top
-      __ push(r0);
+      __ ldr(r0, frame_->Top());  // dup the stack top
+      frame_->Push(r0);
       // Avoid popping the result if it converts to 'false' using the
       // standard ToBoolean() conversion as described in ECMA-262,
       // section 9.2, page 30.
@@ -2824,7 +2896,7 @@
 
       // Pop the result of evaluating the first part.
       __ bind(&pop_and_continue);
-      __ pop(r0);
+      frame_->Pop(r0);
 
       // Evaluate right side expression.
       __ bind(&is_true);
@@ -2855,8 +2927,8 @@
     } else {
       Label pop_and_continue, exit;
 
-      __ ldr(r0, MemOperand(sp, 0));
-      __ push(r0);
+      __ ldr(r0, frame_->Top());
+      frame_->Push(r0);
       // Avoid popping the result if it converts to 'true' using the
       // standard ToBoolean() conversion as described in ECMA-262,
       // section 9.2, page 30.
@@ -2865,7 +2937,7 @@
 
       // Pop the result of evaluating the first part.
       __ bind(&pop_and_continue);
-      __ pop(r0);
+      frame_->Pop(r0);
 
       // Evaluate right side expression.
       __ bind(&is_false);
@@ -2894,14 +2966,14 @@
       Load(node->right());
       GenericBinaryOperation(node->op());
     }
-    __ push(r0);
+    frame_->Push(r0);
   }
 }
 
 
 void CodeGenerator::VisitThisFunction(ThisFunction* node) {
-  __ ldr(r0, FunctionOperand());
-  __ push(r0);
+  __ ldr(r0, frame_->Function());
+  frame_->Push(r0);
 }
 
 
@@ -2913,55 +2985,47 @@
   Expression* right = node->right();
   Token::Value op = node->op();
 
-  // NOTE: To make null checks efficient, we check if either left or
-  // right is the literal 'null'. If so, we optimize the code by
-  // inlining a null check instead of calling the (very) general
-  // runtime routine for checking equality.
-
+  // To make null checks efficient, we check if either left or right is the
+  // literal 'null'. If so, we optimize the code by inlining a null check
+  // instead of calling the (very) general runtime routine for checking
+  // equality.
   if (op == Token::EQ || op == Token::EQ_STRICT) {
     bool left_is_null =
-      left->AsLiteral() != NULL && left->AsLiteral()->IsNull();
+        left->AsLiteral() != NULL && left->AsLiteral()->IsNull();
     bool right_is_null =
-      right->AsLiteral() != NULL && right->AsLiteral()->IsNull();
-    // The 'null' value is only equal to 'null' or 'undefined'.
+        right->AsLiteral() != NULL && right->AsLiteral()->IsNull();
+    // The 'null' value can only be equal to 'null' or 'undefined'.
     if (left_is_null || right_is_null) {
       Load(left_is_null ? right : left);
-      Label exit, undetectable;
-      __ pop(r0);
+      frame_->Pop(r0);
       __ cmp(r0, Operand(Factory::null_value()));
 
-      // The 'null' value is only equal to 'undefined' if using
-      // non-strict comparisons.
+      // The 'null' value is only equal to 'undefined' if using non-strict
+      // comparisons.
       if (op != Token::EQ_STRICT) {
-        __ b(eq, &exit);
+        __ b(eq, true_target());
+
         __ cmp(r0, Operand(Factory::undefined_value()));
+        __ b(eq, true_target());
 
-        // NOTE: it can be undetectable object.
-        __ b(eq, &exit);
         __ tst(r0, Operand(kSmiTagMask));
+        __ b(eq, false_target());
 
-        __ b(ne, &undetectable);
-        __ b(false_target());
-
-        __ bind(&undetectable);
-        __ ldr(r1, FieldMemOperand(r0, HeapObject::kMapOffset));
-        __ ldrb(r2, FieldMemOperand(r1, Map::kBitFieldOffset));
-        __ and_(r2, r2, Operand(1 << Map::kIsUndetectable));
-        __ cmp(r2, Operand(1 << Map::kIsUndetectable));
+        // It can be an undetectable object.
+        __ ldr(r0, FieldMemOperand(r0, HeapObject::kMapOffset));
+        __ ldrb(r0, FieldMemOperand(r0, Map::kBitFieldOffset));
+        __ and_(r0, r0, Operand(1 << Map::kIsUndetectable));
+        __ cmp(r0, Operand(1 << Map::kIsUndetectable));
       }
 
-      __ bind(&exit);
-
       cc_reg_ = eq;
       return;
     }
   }
 
-
-  // NOTE: To make typeof testing for natives implemented in
-  // JavaScript really efficient, we generate special code for
-  // expressions of the form: 'typeof <expression> == <string>'.
-
+  // To make typeof testing for natives implemented in JavaScript really
+  // efficient, we generate special code for expressions of the form:
+  // 'typeof <expression> == <string>'.
   UnaryOperation* operation = left->AsUnaryOperation();
   if ((op == Token::EQ || op == Token::EQ_STRICT) &&
       (operation != NULL && operation->op() == Token::TYPEOF) &&
@@ -2971,7 +3035,7 @@
 
     // Load the operand, move it to register r1.
     LoadTypeofExpression(operation->expression());
-    __ pop(r1);
+    frame_->Pop(r1);
 
     if (check->Equals(Heap::number_symbol())) {
       __ tst(r1, Operand(kSmiTagMask));
@@ -2986,7 +3050,7 @@
 
       __ ldr(r1, FieldMemOperand(r1, HeapObject::kMapOffset));
 
-      // NOTE: it might be an undetectable string object
+      // It can be an undetectable string object.
       __ ldrb(r2, FieldMemOperand(r1, Map::kBitFieldOffset));
       __ and_(r2, r2, Operand(1 << Map::kIsUndetectable));
       __ cmp(r2, Operand(1 << Map::kIsUndetectable));
@@ -3009,7 +3073,7 @@
       __ tst(r1, Operand(kSmiTagMask));
       __ b(eq, false_target());
 
-      // NOTE: it can be undetectable object.
+      // It can be an undetectable object.
       __ ldr(r1, FieldMemOperand(r1, HeapObject::kMapOffset));
       __ ldrb(r2, FieldMemOperand(r1, Map::kBitFieldOffset));
       __ and_(r2, r2, Operand(1 << Map::kIsUndetectable));
@@ -3033,7 +3097,7 @@
       __ cmp(r1, Operand(Factory::null_value()));
       __ b(eq, true_target());
 
-      // NOTE: it might be an undetectable object.
+      // It can be an undetectable object.
       __ ldrb(r1, FieldMemOperand(r2, Map::kBitFieldOffset));
       __ and_(r1, r1, Operand(1 << Map::kIsUndetectable));
       __ cmp(r1, Operand(1 << Map::kIsUndetectable));
@@ -3046,8 +3110,8 @@
       cc_reg_ = le;
 
     } else {
-      // Uncommon case: Typeof testing against a string literal that
-      // is never returned from the typeof operator.
+      // Uncommon case: typeof testing against a string literal that is
+      // never returned from the typeof operator.
       __ b(false_target());
     }
     return;
@@ -3083,7 +3147,7 @@
     case Token::IN:
       __ mov(r0, Operand(1));  // not counting receiver
       __ InvokeBuiltin(Builtins::IN, CALL_JS);
-      __ push(r0);
+      frame_->Push(r0);
       break;
 
     case Token::INSTANCEOF:
@@ -3108,34 +3172,6 @@
 }
 
 
-void CodeGenerator::EnterJSFrame() {
-#if defined(DEBUG)
-  { Label done, fail;
-    __ tst(r1, Operand(kSmiTagMask));
-    __ b(eq, &fail);
-    __ ldr(r2, FieldMemOperand(r1, HeapObject::kMapOffset));
-    __ ldrb(r2, FieldMemOperand(r2, Map::kInstanceTypeOffset));
-    __ cmp(r2, Operand(JS_FUNCTION_TYPE));
-    __ b(eq, &done);
-    __ bind(&fail);
-    __ stop("CodeGenerator::EnterJSFrame - r1 not a function");
-    __ bind(&done);
-  }
-#endif  // DEBUG
-
-  __ stm(db_w, sp, r1.bit() | cp.bit() | fp.bit() | lr.bit());
-  __ add(fp, sp, Operand(2 * kPointerSize));  // Adjust FP to point to saved FP.
-}
-
-
-void CodeGenerator::ExitJSFrame() {
-  // Drop the execution stack down to the frame pointer and restore the caller
-  // frame pointer and return address.
-  __ mov(sp, fp);
-  __ ldm(ia_w, sp, fp.bit() | lr.bit());
-}
-
-
 #undef __
 #define __ masm->
 
@@ -3160,6 +3196,7 @@
   ASSERT(!is_illegal());
   ASSERT(!cgen_->has_cc());
   MacroAssembler* masm = cgen_->masm();
+  VirtualFrame* frame = cgen_->frame();
   Property* property = expression_->AsProperty();
   if (property != NULL) {
     __ RecordPosition(property->position());
@@ -3193,7 +3230,7 @@
       } else {
         __ Call(ic, RelocInfo::CODE_TARGET);
       }
-      __ push(r0);
+      frame->Push(r0);
       break;
     }
 
@@ -3202,10 +3239,16 @@
       // distinction between expressions in a typeof and not in a typeof.
       Comment cmnt(masm, "[ Load from keyed Property");
       ASSERT(property != NULL);
-      // TODO(1224671): Implement inline caching for keyed loads as on ia32.
-      GetPropertyStub stub;
-      __ CallStub(&stub);
-      __ push(r0);
+      Handle<Code> ic(Builtins::builtin(Builtins::KeyedLoadIC_Initialize));
+
+      Variable* var = expression_->AsVariableProxy()->AsVariable();
+      if (var != NULL) {
+        ASSERT(var->is_global());
+        __ Call(ic, RelocInfo::CODE_TARGET_CONTEXT);
+      } else {
+        __ Call(ic, RelocInfo::CODE_TARGET);
+      }
+      frame->Push(r0);
       break;
     }
 
@@ -3219,6 +3262,7 @@
   ASSERT(!is_illegal());
   ASSERT(!cgen_->has_cc());
   MacroAssembler* masm = cgen_->masm();
+  VirtualFrame* frame = cgen_->frame();
   Property* property = expression_->AsProperty();
   if (property != NULL) {
     __ RecordPosition(property->position());
@@ -3233,9 +3277,9 @@
         ASSERT(slot->var()->mode() == Variable::DYNAMIC);
 
         // For now, just do a runtime call.
-        __ push(cp);
+        frame->Push(cp);
         __ mov(r0, Operand(slot->var()->name()));
-        __ push(r0);
+        frame->Push(r0);
 
         if (init_state == CONST_INIT) {
           // Same as the case for a normal store, but ignores attribute
@@ -3259,7 +3303,7 @@
         }
         // Storing a variable must keep the (new) value on the expression
         // stack. This is necessary for compiling assignment expressions.
-        __ push(r0);
+        frame->Push(r0);
 
       } else {
         ASSERT(slot->var()->mode() != Variable::DYNAMIC);
@@ -3285,9 +3329,9 @@
         // initialize consts to 'the hole' value and by doing so, end up
         // calling this code.  r2 may be loaded with context; used below in
         // RecordWrite.
-        __ pop(r0);
+        frame->Pop(r0);
         __ str(r0, cgen_->SlotOperand(slot, r2));
-        __ push(r0);
+        frame->Push(r0);
         if (slot->type() == Slot::CONTEXT) {
           // Skip write barrier if the written value is a smi.
           __ tst(r0, Operand(kSmiTagMask));
@@ -3310,13 +3354,13 @@
     case NAMED: {
       Comment cmnt(masm, "[ Store to named Property");
       // Call the appropriate IC code.
-      __ pop(r0);  // value
+      frame->Pop(r0);  // value
       // Setup the name register.
       Handle<String> name(GetName());
       __ mov(r2, Operand(name));
       Handle<Code> ic(Builtins::builtin(Builtins::StoreIC_Initialize));
       __ Call(ic, RelocInfo::CODE_TARGET);
-      __ push(r0);
+      frame->Push(r0);
       break;
     }
 
@@ -3325,10 +3369,13 @@
       Property* property = expression_->AsProperty();
       ASSERT(property != NULL);
       __ RecordPosition(property->position());
-      __ pop(r0);  // value
-      SetPropertyStub stub;
-      __ CallStub(&stub);
-      __ push(r0);
+
+      // Call IC code.
+      Handle<Code> ic(Builtins::builtin(Builtins::KeyedStoreIC_Initialize));
+      // TODO(1222589): Make the IC grab the values from the stack.
+      frame->Pop(r0);  // value
+      __ Call(ic, RelocInfo::CODE_TARGET);
+      frame->Push(r0);
       break;
     }
 
@@ -3813,8 +3860,16 @@
   // Restore the stack to the address of the ENTRY handler
   __ mov(sp, Operand(r3));
 
-  // restore parameter- and frame-pointer and pop state.
-  __ ldm(ia_w, sp, r3.bit() | pp.bit() | fp.bit());
+  // Stack layout at this point. See also PushTryHandler
+  // r3, sp ->   next handler
+  //             state (ENTRY)
+  //             pp
+  //             fp
+  //             lr
+
+  // Discard ENTRY state (r2 is not used), and restore parameter-
+  // and frame-pointer and pop state.
+  __ ldm(ia_w, sp, r2.bit() | r3.bit() | pp.bit() | fp.bit());
   // Before returning we restore the context from the frame pointer if not NULL.
   // The frame pointer is NULL in the exception handler of a JS entry frame.
   __ cmp(fp, Operand(0));
@@ -4044,7 +4099,7 @@
   // sets it to 0 to signal the existence of the JSEntry frame.
   __ mov(ip, Operand(Top::pending_exception_address()));
   __ str(r0, MemOperand(ip));
-  __ mov(r0, Operand(Handle<Failure>(Failure::Exception())));
+  __ mov(r0, Operand(reinterpret_cast<int32_t>(Failure::Exception())));
   __ b(&exit);
 
   // Invoke: Link this frame into the handler chain.
@@ -4229,7 +4284,10 @@
   // Slow-case: Non-function called.
   __ bind(&slow);
   __ mov(r0, Operand(argc_));  // Setup the number of arguments.
-  __ InvokeBuiltin(Builtins::CALL_NON_FUNCTION, JUMP_JS);
+  __ mov(r2, Operand(0));
+  __ GetBuiltinEntry(r3, Builtins::CALL_NON_FUNCTION);
+  __ Jump(Handle<Code>(Builtins::builtin(Builtins::ArgumentsAdaptorTrampoline)),
+          RelocInfo::CODE_TARGET);
 }