Index: src/arm/macro-assembler-arm.cc |
diff --git a/src/arm/macro-assembler-arm.cc b/src/arm/macro-assembler-arm.cc |
index 5d8df1afac12bab369d3c32ecb1e9e4b5941c61b..0cb4eb27c50e510f144425943ce24ed52407ac2a 100644 |
--- a/src/arm/macro-assembler-arm.cc |
+++ b/src/arm/macro-assembler-arm.cc |
@@ -714,7 +714,8 @@ int MacroAssembler::ActivationFrameAlignment() { |
} |
-void MacroAssembler::LeaveExitFrame(bool save_doubles) { |
+void MacroAssembler::LeaveExitFrame(bool save_doubles, |
+ Register argument_count) { |
// Optionally restore all double registers. |
if (save_doubles) { |
for (int i = 0; i < DwVfpRegister::kNumRegisters; i++) { |
@@ -736,12 +737,12 @@ void MacroAssembler::LeaveExitFrame(bool save_doubles) { |
str(r3, MemOperand(ip)); |
#endif |
- // Tear down the exit frame, pop the arguments, and return. Callee-saved |
- // register r4 still holds argc. |
+ // Tear down the exit frame, pop the arguments, and return. |
mov(sp, Operand(fp)); |
ldm(ia_w, sp, fp.bit() | lr.bit()); |
- add(sp, sp, Operand(r4, LSL, kPointerSizeLog2)); |
- mov(pc, lr); |
+ if (argument_count.is_valid()) { |
+ add(sp, sp, Operand(argument_count, LSL, kPointerSizeLog2)); |
+ } |
} |
@@ -1005,6 +1006,117 @@ void MacroAssembler::PopTryHandler() { |
} |
+void MacroAssembler::Throw(Register value) { |
+ // r0 is expected to hold the exception. |
+ if (!value.is(r0)) { |
+ mov(r0, value); |
+ } |
+ |
+ // Adjust this code if not the case. |
+ STATIC_ASSERT(StackHandlerConstants::kSize == 4 * kPointerSize); |
+ |
+ // Drop the sp to the top of the handler. |
+ mov(r3, Operand(ExternalReference(Top::k_handler_address))); |
+ ldr(sp, MemOperand(r3)); |
+ |
+ // Restore the next handler and frame pointer, discard handler state. |
+ STATIC_ASSERT(StackHandlerConstants::kNextOffset == 0); |
+ pop(r2); |
+ str(r2, MemOperand(r3)); |
+ STATIC_ASSERT(StackHandlerConstants::kFPOffset == 2 * kPointerSize); |
+ ldm(ia_w, sp, r3.bit() | fp.bit()); // r3: discarded state. |
+ |
+ // 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, RelocInfo::NONE)); |
+ // Set cp to NULL if fp is NULL. |
+ mov(cp, Operand(0, RelocInfo::NONE), LeaveCC, eq); |
+ // Restore cp otherwise. |
+ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset), ne); |
+#ifdef DEBUG |
+ if (FLAG_debug_code) { |
+ mov(lr, Operand(pc)); |
+ } |
+#endif |
+ STATIC_ASSERT(StackHandlerConstants::kPCOffset == 3 * kPointerSize); |
+ pop(pc); |
+} |
+ |
+ |
+void MacroAssembler::ThrowUncatchable(UncatchableExceptionType type, |
+ Register value) { |
+ // Adjust this code if not the case. |
+ STATIC_ASSERT(StackHandlerConstants::kSize == 4 * kPointerSize); |
+ |
+ // r0 is expected to hold the exception. |
+ if (!value.is(r0)) { |
+ mov(r0, value); |
+ } |
+ |
+ // Drop sp to the top stack handler. |
+ mov(r3, Operand(ExternalReference(Top::k_handler_address))); |
+ ldr(sp, MemOperand(r3)); |
+ |
+ // Unwind the handlers until the ENTRY handler is found. |
+ Label loop, done; |
+ bind(&loop); |
+ // Load the type of the current stack handler. |
+ const int kStateOffset = StackHandlerConstants::kStateOffset; |
+ ldr(r2, MemOperand(sp, kStateOffset)); |
+ cmp(r2, Operand(StackHandler::ENTRY)); |
+ b(eq, &done); |
+ // Fetch the next handler in the list. |
+ const int kNextOffset = StackHandlerConstants::kNextOffset; |
+ ldr(sp, MemOperand(sp, kNextOffset)); |
+ jmp(&loop); |
+ bind(&done); |
+ |
+ // Set the top handler address to next handler past the current ENTRY handler. |
+ STATIC_ASSERT(StackHandlerConstants::kNextOffset == 0); |
+ pop(r2); |
+ str(r2, MemOperand(r3)); |
+ |
+ if (type == OUT_OF_MEMORY) { |
+ // Set external caught exception to false. |
+ ExternalReference external_caught(Top::k_external_caught_exception_address); |
+ mov(r0, Operand(false, RelocInfo::NONE)); |
+ mov(r2, Operand(external_caught)); |
+ str(r0, MemOperand(r2)); |
+ |
+ // Set pending exception and r0 to out of memory exception. |
+ Failure* out_of_memory = Failure::OutOfMemoryException(); |
+ mov(r0, Operand(reinterpret_cast<int32_t>(out_of_memory))); |
+ mov(r2, Operand(ExternalReference(Top::k_pending_exception_address))); |
+ str(r0, MemOperand(r2)); |
+ } |
+ |
+ // Stack layout at this point. See also StackHandlerConstants. |
+ // sp -> state (ENTRY) |
+ // fp |
+ // lr |
+ |
+ // Discard handler state (r2 is not used) and restore frame pointer. |
+ STATIC_ASSERT(StackHandlerConstants::kFPOffset == 2 * kPointerSize); |
+ ldm(ia_w, sp, r2.bit() | fp.bit()); // r2: discarded state. |
+ // 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, RelocInfo::NONE)); |
+ // Set cp to NULL if fp is NULL. |
+ mov(cp, Operand(0, RelocInfo::NONE), LeaveCC, eq); |
+ // Restore cp otherwise. |
+ ldr(cp, MemOperand(fp, StandardFrameConstants::kContextOffset), ne); |
+#ifdef DEBUG |
+ if (FLAG_debug_code) { |
+ mov(lr, Operand(pc)); |
+ } |
+#endif |
+ STATIC_ASSERT(StackHandlerConstants::kPCOffset == 3 * kPointerSize); |
+ pop(pc); |
+} |
+ |
+ |
void MacroAssembler::CheckAccessGlobalProxy(Register holder_reg, |
Register scratch, |
Label* miss) { |
@@ -1554,9 +1666,10 @@ MaybeObject* MacroAssembler::TryCallApiFunctionAndReturn( |
cmp(r4, r5); |
b(ne, &promote_scheduled_exception); |
- // LeaveExitFrame expects unwind space to be in r4. |
+ // LeaveExitFrame expects unwind space to be in a register. |
mov(r4, Operand(stack_space)); |
- LeaveExitFrame(false); |
+ LeaveExitFrame(false, r4); |
+ mov(pc, lr); |
bind(&promote_scheduled_exception); |
MaybeObject* result = TryTailCallExternalReference( |