Update V8 to r4588

We're using WebKit r58033, as used by
http://src.chromium.org/svn/releases/5.0.387.0/DEPS
This requires http://v8.googlecode.com/svn/trunk@4465 but this version has a
crashing bug for ARM. Instead we use http://v8.googlecode.com/svn/trunk@4588,
which is used by http://src.chromium.org/svn/releases/6.0.399.0/DEPS

Note that a trivial bug fix was required in arm/codegen-arm.cc. This is guarded
with ANDROID. See http://code.google.com/p/v8/issues/detail?id=703

Change-Id: I459647a8286c4f8c7405f0c5581ecbf051a6f1e8
diff --git a/src/mips/macro-assembler-mips.cc b/src/mips/macro-assembler-mips.cc
index b733bdd..c276af5 100644
--- a/src/mips/macro-assembler-mips.cc
+++ b/src/mips/macro-assembler-mips.cc
@@ -55,7 +55,7 @@
 
 void MacroAssembler::Jump(intptr_t target, RelocInfo::Mode rmode,
                           Condition cond, Register r1, const Operand& r2) {
-  Jump(Operand(target), cond, r1, r2);
+  Jump(Operand(target, rmode), cond, r1, r2);
 }
 
 
@@ -81,7 +81,7 @@
 
 void MacroAssembler::Call(intptr_t target, RelocInfo::Mode rmode,
                           Condition cond, Register r1, const Operand& r2) {
-  Call(Operand(target), cond, r1, r2);
+  Call(Operand(target, rmode), cond, r1, r2);
 }
 
 
@@ -106,7 +106,7 @@
 
 void MacroAssembler::LoadRoot(Register destination,
                               Heap::RootListIndex index) {
-  lw(destination, MemOperand(s4, index << kPointerSizeLog2));
+  lw(destination, MemOperand(s6, index << kPointerSizeLog2));
 }
 
 void MacroAssembler::LoadRoot(Register destination,
@@ -114,8 +114,7 @@
                               Condition cond,
                               Register src1, const Operand& src2) {
   Branch(NegateCondition(cond), 2, src1, src2);
-  nop();
-  lw(destination, MemOperand(s4, index << kPointerSizeLog2));
+  lw(destination, MemOperand(s6, index << kPointerSizeLog2));
 }
 
 
@@ -320,7 +319,6 @@
 }
 
 
-// load wartd in a register
 void MacroAssembler::li(Register rd, Operand j, bool gen2instr) {
   ASSERT(!j.is_reg());
 
@@ -372,7 +370,7 @@
   int16_t NumToPush = NumberOfBitsSet(regs);
 
   addiu(sp, sp, -4 * NumToPush);
-  for (int16_t i = 0; i < kNumRegisters; i++) {
+  for (int16_t i = kNumRegisters; i > 0; i--) {
     if ((regs & (1 << i)) != 0) {
       sw(ToRegister(i), MemOperand(sp, 4 * (NumToPush - ++NumSaved)));
     }
@@ -385,7 +383,7 @@
   int16_t NumToPush = NumberOfBitsSet(regs);
 
   addiu(sp, sp, -4 * NumToPush);
-  for (int16_t i = kNumRegisters; i > 0; i--) {
+  for (int16_t i = 0; i < kNumRegisters; i++) {
     if ((regs & (1 << i)) != 0) {
       sw(ToRegister(i), MemOperand(sp, 4 * (NumToPush - ++NumSaved)));
     }
@@ -396,7 +394,7 @@
 void MacroAssembler::MultiPop(RegList regs) {
   int16_t NumSaved = 0;
 
-  for (int16_t i = kNumRegisters; i > 0; i--) {
+  for (int16_t i = 0; i < kNumRegisters; i++) {
     if ((regs & (1 << i)) != 0) {
       lw(ToRegister(i), MemOperand(sp, 4 * (NumSaved++)));
     }
@@ -408,7 +406,7 @@
 void MacroAssembler::MultiPopReversed(RegList regs) {
   int16_t NumSaved = 0;
 
-  for (int16_t i = 0; i < kNumRegisters; i++) {
+  for (int16_t i = kNumRegisters; i > 0; i--) {
     if ((regs & (1 << i)) != 0) {
       lw(ToRegister(i), MemOperand(sp, 4 * (NumSaved++)));
     }
@@ -422,7 +420,7 @@
 // Trashes the at register if no scratch register is provided.
 void MacroAssembler::Branch(Condition cond, int16_t offset, Register rs,
                             const Operand& rt, Register scratch) {
-  Register r2;
+  Register r2 = no_reg;
   if (rt.is_reg()) {
     // We don't want any other register but scratch clobbered.
     ASSERT(!scratch.is(rs) && !scratch.is(rt.rm_));
@@ -484,12 +482,14 @@
     default:
       UNREACHABLE();
   }
+  // Emit a nop in the branch delay slot.
+  nop();
 }
 
 
 void MacroAssembler::Branch(Condition cond,  Label* L, Register rs,
                             const Operand& rt, Register scratch) {
-  Register r2;
+  Register r2 = no_reg;
   if (rt.is_reg()) {
     r2 = rt.rm_;
   } else if (cond != cc_always) {
@@ -550,6 +550,8 @@
     default:
       UNREACHABLE();
   }
+  // Emit a nop in the branch delay slot.
+  nop();
 }
 
 
@@ -559,7 +561,7 @@
 // cases, so we keep slt and add an intermediate third instruction.
 void MacroAssembler::BranchAndLink(Condition cond, int16_t offset, Register rs,
                                    const Operand& rt, Register scratch) {
-  Register r2;
+  Register r2 = no_reg;
   if (rt.is_reg()) {
     r2 = rt.rm_;
   } else if (cond != cc_always) {
@@ -629,12 +631,14 @@
     default:
       UNREACHABLE();
   }
+  // Emit a nop in the branch delay slot.
+  nop();
 }
 
 
 void MacroAssembler::BranchAndLink(Condition cond, Label* L, Register rs,
                                    const Operand& rt, Register scratch) {
-  Register r2;
+  Register r2 = no_reg;
   if (rt.is_reg()) {
     r2 = rt.rm_;
   } else if (cond != cc_always) {
@@ -704,6 +708,8 @@
     default:
       UNREACHABLE();
   }
+  // Emit a nop in the branch delay slot.
+  nop();
 }
 
 
@@ -714,7 +720,6 @@
       jr(target.rm());
     } else {
       Branch(NegateCondition(cond), 2, rs, rt);
-      nop();
       jr(target.rm());
     }
   } else {    // !target.is_reg()
@@ -723,20 +728,20 @@
         j(target.imm32_);
       } else {
         Branch(NegateCondition(cond), 2, rs, rt);
-        nop();
-        j(target.imm32_);  // will generate only one instruction.
+        j(target.imm32_);  // Will generate only one instruction.
       }
     } else {  // MustUseAt(target)
-      li(at, rt);
+      li(at, target);
       if (cond == cc_always) {
         jr(at);
       } else {
         Branch(NegateCondition(cond), 2, rs, rt);
-        nop();
-        jr(at);  // will generate only one instruction.
+        jr(at);  // Will generate only one instruction.
       }
     }
   }
+  // Emit a nop in the branch delay slot.
+  nop();
 }
 
 
@@ -747,7 +752,6 @@
       jalr(target.rm());
     } else {
       Branch(NegateCondition(cond), 2, rs, rt);
-      nop();
       jalr(target.rm());
     }
   } else {    // !target.is_reg()
@@ -756,20 +760,20 @@
         jal(target.imm32_);
       } else {
         Branch(NegateCondition(cond), 2, rs, rt);
-        nop();
-        jal(target.imm32_);  // will generate only one instruction.
+        jal(target.imm32_);  // Will generate only one instruction.
       }
     } else {  // MustUseAt(target)
-      li(at, rt);
+      li(at, target);
       if (cond == cc_always) {
         jalr(at);
       } else {
         Branch(NegateCondition(cond), 2, rs, rt);
-        nop();
-        jalr(at);  // will generate only one instruction.
+        jalr(at);  // Will generate only one instruction.
       }
     }
   }
+  // Emit a nop in the branch delay slot.
+  nop();
 }
 
 void MacroAssembler::StackLimitCheck(Label* on_stack_overflow) {
@@ -787,12 +791,73 @@
 }
 
 
+#ifdef ENABLE_DEBUGGER_SUPPORT
+  // ---------------------------------------------------------------------------
+  // Debugger Support
+
+  void MacroAssembler::DebugBreak() {
+    UNIMPLEMENTED_MIPS();
+  }
+#endif
+
+
 // ---------------------------------------------------------------------------
 // Exception handling
 
 void MacroAssembler::PushTryHandler(CodeLocation try_location,
                                     HandlerType type) {
-  UNIMPLEMENTED_MIPS();
+  // Adjust this code if not the case.
+  ASSERT(StackHandlerConstants::kSize == 4 * kPointerSize);
+  // The return address is passed in register ra.
+  if (try_location == IN_JAVASCRIPT) {
+    if (type == TRY_CATCH_HANDLER) {
+      li(t0, Operand(StackHandler::TRY_CATCH));
+    } else {
+      li(t0, Operand(StackHandler::TRY_FINALLY));
+    }
+    ASSERT(StackHandlerConstants::kStateOffset == 1 * kPointerSize
+           && StackHandlerConstants::kFPOffset == 2 * kPointerSize
+           && StackHandlerConstants::kPCOffset == 3 * kPointerSize
+           && StackHandlerConstants::kNextOffset == 0 * kPointerSize);
+    // Save the current handler as the next handler.
+    LoadExternalReference(t2, ExternalReference(Top::k_handler_address));
+    lw(t1, MemOperand(t2));
+
+    addiu(sp, sp, -StackHandlerConstants::kSize);
+    sw(ra, MemOperand(sp, 12));
+    sw(fp, MemOperand(sp, 8));
+    sw(t0, MemOperand(sp, 4));
+    sw(t1, MemOperand(sp, 0));
+
+    // Link this handler as the new current one.
+    sw(sp, MemOperand(t2));
+
+  } else {
+    // Must preserve a0-a3, and s0 (argv).
+    ASSERT(try_location == IN_JS_ENTRY);
+    ASSERT(StackHandlerConstants::kStateOffset == 1 * kPointerSize
+           && StackHandlerConstants::kFPOffset == 2 * kPointerSize
+           && StackHandlerConstants::kPCOffset == 3 * kPointerSize
+           && StackHandlerConstants::kNextOffset == 0 * kPointerSize);
+
+    // The frame pointer does not point to a JS frame so we save NULL
+    // for fp. We expect the code throwing an exception to check fp
+    // before dereferencing it to restore the context.
+    li(t0, Operand(StackHandler::ENTRY));
+
+    // Save the current handler as the next handler.
+    LoadExternalReference(t2, ExternalReference(Top::k_handler_address));
+    lw(t1, MemOperand(t2));
+
+    addiu(sp, sp, -StackHandlerConstants::kSize);
+    sw(ra, MemOperand(sp, 12));
+    sw(zero_reg, MemOperand(sp, 8));
+    sw(t0, MemOperand(sp, 4));
+    sw(t1, MemOperand(sp, 0));
+
+    // Link this handler as the new current one.
+    sw(sp, MemOperand(t2));
+  }
 }
 
 
@@ -802,12 +867,233 @@
 
 
 
-// ---------------------------------------------------------------------------
+// -----------------------------------------------------------------------------
 // Activation frames
 
+void MacroAssembler::SetupAlignedCall(Register scratch, int arg_count) {
+  Label extra_push, end;
+
+  andi(scratch, sp, 7);
+
+  // We check for args and receiver size on the stack, all of them word sized.
+  // We add one for sp, that we also want to store on the stack.
+  if (((arg_count + 1) % kPointerSizeLog2) == 0) {
+    Branch(ne, &extra_push, at, Operand(zero_reg));
+  } else {  // ((arg_count + 1) % 2) == 1
+    Branch(eq, &extra_push, at, Operand(zero_reg));
+  }
+
+  // Save sp on the stack.
+  mov(scratch, sp);
+  Push(scratch);
+  b(&end);
+
+  // Align before saving sp on the stack.
+  bind(&extra_push);
+  mov(scratch, sp);
+  addiu(sp, sp, -8);
+  sw(scratch, MemOperand(sp));
+
+  // The stack is aligned and sp is stored on the top.
+  bind(&end);
+}
+
+
+void MacroAssembler::ReturnFromAlignedCall() {
+  lw(sp, MemOperand(sp));
+}
+
+
+// -----------------------------------------------------------------------------
+// JavaScript invokes
+
+void MacroAssembler::InvokePrologue(const ParameterCount& expected,
+                                    const ParameterCount& actual,
+                                    Handle<Code> code_constant,
+                                    Register code_reg,
+                                    Label* done,
+                                    InvokeFlag flag) {
+  bool definitely_matches = false;
+  Label regular_invoke;
+
+  // Check whether the expected and actual arguments count match. If not,
+  // setup registers according to contract with ArgumentsAdaptorTrampoline:
+  //  a0: actual arguments count
+  //  a1: function (passed through to callee)
+  //  a2: expected arguments count
+  //  a3: callee code entry
+
+  // The code below is made a lot easier because the calling code already sets
+  // up actual and expected registers according to the contract if values are
+  // passed in registers.
+  ASSERT(actual.is_immediate() || actual.reg().is(a0));
+  ASSERT(expected.is_immediate() || expected.reg().is(a2));
+  ASSERT((!code_constant.is_null() && code_reg.is(no_reg)) || code_reg.is(a3));
+
+  if (expected.is_immediate()) {
+    ASSERT(actual.is_immediate());
+    if (expected.immediate() == actual.immediate()) {
+      definitely_matches = true;
+    } else {
+      li(a0, Operand(actual.immediate()));
+      const int sentinel = SharedFunctionInfo::kDontAdaptArgumentsSentinel;
+      if (expected.immediate() == sentinel) {
+        // Don't worry about adapting arguments for builtins that
+        // don't want that done. Skip adaption code by making it look
+        // like we have a match between expected and actual number of
+        // arguments.
+        definitely_matches = true;
+      } else {
+        li(a2, Operand(expected.immediate()));
+      }
+    }
+  } else if (actual.is_immediate()) {
+    Branch(eq, &regular_invoke, expected.reg(), Operand(actual.immediate()));
+    li(a0, Operand(actual.immediate()));
+  } else {
+    Branch(eq, &regular_invoke, expected.reg(), Operand(actual.reg()));
+  }
+
+  if (!definitely_matches) {
+    if (!code_constant.is_null()) {
+      li(a3, Operand(code_constant));
+      addiu(a3, a3, Code::kHeaderSize - kHeapObjectTag);
+    }
+
+    ExternalReference adaptor(Builtins::ArgumentsAdaptorTrampoline);
+    if (flag == CALL_FUNCTION) {
+      CallBuiltin(adaptor);
+      b(done);
+      nop();
+    } else {
+      JumpToBuiltin(adaptor);
+    }
+    bind(&regular_invoke);
+  }
+}
+
+void MacroAssembler::InvokeCode(Register code,
+                                const ParameterCount& expected,
+                                const ParameterCount& actual,
+                                InvokeFlag flag) {
+  Label done;
+
+  InvokePrologue(expected, actual, Handle<Code>::null(), code, &done, flag);
+  if (flag == CALL_FUNCTION) {
+    Call(code);
+  } else {
+    ASSERT(flag == JUMP_FUNCTION);
+    Jump(code);
+  }
+  // Continue here if InvokePrologue does handle the invocation due to
+  // mismatched parameter counts.
+  bind(&done);
+}
+
+
+void MacroAssembler::InvokeCode(Handle<Code> code,
+                                const ParameterCount& expected,
+                                const ParameterCount& actual,
+                                RelocInfo::Mode rmode,
+                                InvokeFlag flag) {
+  Label done;
+
+  InvokePrologue(expected, actual, code, no_reg, &done, flag);
+  if (flag == CALL_FUNCTION) {
+    Call(code, rmode);
+  } else {
+    Jump(code, rmode);
+  }
+  // Continue here if InvokePrologue does handle the invocation due to
+  // mismatched parameter counts.
+  bind(&done);
+}
+
+
+void MacroAssembler::InvokeFunction(Register function,
+                                    const ParameterCount& actual,
+                                    InvokeFlag flag) {
+  // Contract with called JS functions requires that function is passed in a1.
+  ASSERT(function.is(a1));
+  Register expected_reg = a2;
+  Register code_reg = a3;
+
+  lw(code_reg, FieldMemOperand(a1, JSFunction::kSharedFunctionInfoOffset));
+  lw(cp, FieldMemOperand(a1, JSFunction::kContextOffset));
+  lw(expected_reg,
+      FieldMemOperand(code_reg,
+                      SharedFunctionInfo::kFormalParameterCountOffset));
+  lw(code_reg,
+      MemOperand(code_reg, SharedFunctionInfo::kCodeOffset - kHeapObjectTag));
+  addiu(code_reg, code_reg, Code::kHeaderSize - kHeapObjectTag);
+
+  ParameterCount expected(expected_reg);
+  InvokeCode(code_reg, expected, actual, flag);
+}
+
+
+// ---------------------------------------------------------------------------
+// Support functions.
+
+  void MacroAssembler::GetObjectType(Register function,
+                                     Register map,
+                                     Register type_reg) {
+    lw(map, FieldMemOperand(function, HeapObject::kMapOffset));
+    lbu(type_reg, FieldMemOperand(map, Map::kInstanceTypeOffset));
+  }
+
+
+  void MacroAssembler::CallBuiltin(ExternalReference builtin_entry) {
+    // Load builtin address.
+    LoadExternalReference(t9, builtin_entry);
+    lw(t9, MemOperand(t9));  // Deref address.
+    addiu(t9, t9, Code::kHeaderSize - kHeapObjectTag);
+    // Call and allocate arguments slots.
+    jalr(t9);
+    // Use the branch delay slot to allocated argument slots.
+    addiu(sp, sp, -StandardFrameConstants::kRArgsSlotsSize);
+    addiu(sp, sp, StandardFrameConstants::kRArgsSlotsSize);
+  }
+
+
+  void MacroAssembler::CallBuiltin(Register target) {
+    // Target already holds target address.
+    // Call and allocate arguments slots.
+    jalr(target);
+    // Use the branch delay slot to allocated argument slots.
+    addiu(sp, sp, -StandardFrameConstants::kRArgsSlotsSize);
+    addiu(sp, sp, StandardFrameConstants::kRArgsSlotsSize);
+  }
+
+
+  void MacroAssembler::JumpToBuiltin(ExternalReference builtin_entry) {
+    // Load builtin address.
+    LoadExternalReference(t9, builtin_entry);
+    lw(t9, MemOperand(t9));  // Deref address.
+    addiu(t9, t9, Code::kHeaderSize - kHeapObjectTag);
+    // Call and allocate arguments slots.
+    jr(t9);
+    // Use the branch delay slot to allocated argument slots.
+    addiu(sp, sp, -StandardFrameConstants::kRArgsSlotsSize);
+  }
+
+
+  void MacroAssembler::JumpToBuiltin(Register target) {
+    // t9 already holds target address.
+    // Call and allocate arguments slots.
+    jr(t9);
+    // Use the branch delay slot to allocated argument slots.
+    addiu(sp, sp, -StandardFrameConstants::kRArgsSlotsSize);
+  }
+
+
+// -----------------------------------------------------------------------------
+// Runtime calls
+
 void MacroAssembler::CallStub(CodeStub* stub, Condition cond,
                               Register r1, const Operand& r2) {
-  UNIMPLEMENTED_MIPS();
+  ASSERT(allow_stub_calls());  // Stub calls are not allowed in some stubs.
+  Call(stub->GetCode(), RelocInfo::CODE_TARGET, cond, r1, r2);
 }
 
 
@@ -816,24 +1102,56 @@
 }
 
 
+void MacroAssembler::IllegalOperation(int num_arguments) {
+  if (num_arguments > 0) {
+    addiu(sp, sp, num_arguments * kPointerSize);
+  }
+  LoadRoot(v0, Heap::kUndefinedValueRootIndex);
+}
+
+
 void MacroAssembler::CallRuntime(Runtime::Function* f, int num_arguments) {
-  UNIMPLEMENTED_MIPS();
+  // All parameters are on the stack. v0 has the return value after call.
+
+  // If the expected number of arguments of the runtime function is
+  // constant, we check that the actual number of arguments match the
+  // expectation.
+  if (f->nargs >= 0 && f->nargs != num_arguments) {
+    IllegalOperation(num_arguments);
+    return;
+  }
+
+  // TODO(1236192): Most runtime routines don't need the number of
+  // arguments passed in because it is constant. At some point we
+  // should remove this need and make the runtime routine entry code
+  // smarter.
+  li(a0, num_arguments);
+  LoadExternalReference(a1, ExternalReference(f));
+  CEntryStub stub(1);
+  CallStub(&stub);
 }
 
 
 void MacroAssembler::CallRuntime(Runtime::FunctionId fid, int num_arguments) {
+  CallRuntime(Runtime::FunctionForId(fid), num_arguments);
+}
+
+
+void MacroAssembler::TailCallExternalReference(const ExternalReference& ext,
+                                               int num_arguments,
+                                               int result_size) {
   UNIMPLEMENTED_MIPS();
 }
 
 
-void MacroAssembler::TailCallRuntime(const ExternalReference& ext,
+void MacroAssembler::TailCallRuntime(Runtime::FunctionId fid,
                                      int num_arguments,
                                      int result_size) {
-  UNIMPLEMENTED_MIPS();
+  TailCallExternalReference(ExternalReference(fid), num_arguments, result_size);
 }
 
 
-void MacroAssembler::JumpToRuntime(const ExternalReference& builtin) {
+void MacroAssembler::JumpToExternalReference(const ExternalReference& builtin) {
   UNIMPLEMENTED_MIPS();
 }
 
@@ -874,6 +1192,8 @@
 }
 
 
+// -----------------------------------------------------------------------------
+// Debugging
 
 void MacroAssembler::Assert(Condition cc, const char* msg,
                             Register rs, Operand rt) {
@@ -891,5 +1211,113 @@
   UNIMPLEMENTED_MIPS();
 }
 
+
+void MacroAssembler::EnterFrame(StackFrame::Type type) {
+  addiu(sp, sp, -5 * kPointerSize);
+  li(t0, Operand(Smi::FromInt(type)));
+  li(t1, Operand(CodeObject()));
+  sw(ra, MemOperand(sp, 4 * kPointerSize));
+  sw(fp, MemOperand(sp, 3 * kPointerSize));
+  sw(cp, MemOperand(sp, 2 * kPointerSize));
+  sw(t0, MemOperand(sp, 1 * kPointerSize));
+  sw(t1, MemOperand(sp, 0 * kPointerSize));
+  addiu(fp, sp, 3 * kPointerSize);
+}
+
+
+void MacroAssembler::LeaveFrame(StackFrame::Type type) {
+  mov(sp, fp);
+  lw(fp, MemOperand(sp, 0 * kPointerSize));
+  lw(ra, MemOperand(sp, 1 * kPointerSize));
+  addiu(sp, sp, 2 * kPointerSize);
+}
+
+
+void MacroAssembler::EnterExitFrame(ExitFrame::Mode mode,
+                                    Register hold_argc,
+                                    Register hold_argv,
+                                    Register hold_function) {
+  // Compute the argv pointer and keep it in a callee-saved register.
+  // a0 is argc.
+  sll(t0, a0, kPointerSizeLog2);
+  add(hold_argv, sp, t0);
+  addi(hold_argv, hold_argv, -kPointerSize);
+
+  // Compute callee's stack pointer before making changes and save it as
+  // t1 register so that it is restored as sp register on exit, thereby
+  // popping the args.
+  // t1 = sp + kPointerSize * #args
+  add(t1, sp, t0);
+
+  // Align the stack at this point.
+  AlignStack(0);
+
+  // Save registers.
+  addiu(sp, sp, -12);
+  sw(t1, MemOperand(sp, 8));
+  sw(ra, MemOperand(sp, 4));
+  sw(fp, MemOperand(sp, 0));
+  mov(fp, sp);  // Setup new frame pointer.
+
+  // Push debug marker.
+  if (mode == ExitFrame::MODE_DEBUG) {
+    Push(zero_reg);
+  } else {
+    li(t0, Operand(CodeObject()));
+    Push(t0);
+  }
+
+  // Save the frame pointer and the context in top.
+  LoadExternalReference(t0, ExternalReference(Top::k_c_entry_fp_address));
+  sw(fp, MemOperand(t0));
+  LoadExternalReference(t0, ExternalReference(Top::k_context_address));
+  sw(cp, MemOperand(t0));
+
+  // Setup argc and the builtin function in callee-saved registers.
+  mov(hold_argc, a0);
+  mov(hold_function, a1);
+}
+
+
+void MacroAssembler::LeaveExitFrame(ExitFrame::Mode mode) {
+  // Clear top frame.
+  LoadExternalReference(t0, ExternalReference(Top::k_c_entry_fp_address));
+  sw(zero_reg, MemOperand(t0));
+
+  // Restore current context from top and clear it in debug mode.
+  LoadExternalReference(t0, ExternalReference(Top::k_context_address));
+  lw(cp, MemOperand(t0));
+#ifdef DEBUG
+  sw(a3, MemOperand(t0));
+#endif
+
+  // Pop the arguments, restore registers, and return.
+  mov(sp, fp);  // Respect ABI stack constraint.
+  lw(fp, MemOperand(sp, 0));
+  lw(ra, MemOperand(sp, 4));
+  lw(sp, MemOperand(sp, 8));
+  jr(ra);
+  nop();  // Branch delay slot nop.
+}
+
+
+void MacroAssembler::AlignStack(int offset) {
+  // On MIPS an offset of 0 aligns to 0 modulo 8 bytes,
+  //     and an offset of 1 aligns to 4 modulo 8 bytes.
+  int activation_frame_alignment = OS::ActivationFrameAlignment();
+  if (activation_frame_alignment != kPointerSize) {
+    // This code needs to be made more general if this assert doesn't hold.
+    ASSERT(activation_frame_alignment == 2 * kPointerSize);
+    if (offset == 0) {
+      andi(t0, sp, activation_frame_alignment - 1);
+      Push(zero_reg, eq, t0, zero_reg);
+    } else {
+      andi(t0, sp, activation_frame_alignment - 1);
+      addiu(t0, t0, -4);
+      Push(zero_reg, eq, t0, zero_reg);
+    }
+  }
+}
+
 } }  // namespace v8::internal