Commit 978c7a82 authored by balazs.kilvady's avatar balazs.kilvady Committed by Commit bot

MIPS: Move stack unwinding logic into the runtime.

Port 4acbc93d

BUG=

Review URL: https://codereview.chromium.org/974873002

Cr-Commit-Position: refs/heads/master@{#26967}
parent 0705045b
......@@ -1036,6 +1036,59 @@ void CEntryStub::GenerateAheadOfTime(Isolate* isolate) {
}
static void ThrowPendingException(MacroAssembler* masm) {
Isolate* isolate = masm->isolate();
ExternalReference pending_handler_context_address(
Isolate::kPendingHandlerContextAddress, isolate);
ExternalReference pending_handler_code_address(
Isolate::kPendingHandlerCodeAddress, isolate);
ExternalReference pending_handler_offset_address(
Isolate::kPendingHandlerOffsetAddress, isolate);
ExternalReference pending_handler_fp_address(
Isolate::kPendingHandlerFPAddress, isolate);
ExternalReference pending_handler_sp_address(
Isolate::kPendingHandlerSPAddress, isolate);
// Ask the runtime for help to determine the handler. This will set v0 to
// contain the current pending exception, don't clobber it.
ExternalReference find_handler(Runtime::kFindExceptionHandler, isolate);
{
FrameScope scope(masm, StackFrame::MANUAL);
__ PrepareCallCFunction(3, 0, a0);
__ mov(a0, zero_reg);
__ mov(a1, zero_reg);
__ li(a2, Operand(ExternalReference::isolate_address(isolate)));
__ CallCFunction(find_handler, 3);
}
// Retrieve the handler context, SP and FP.
__ li(cp, Operand(pending_handler_context_address));
__ lw(cp, MemOperand(cp));
__ li(sp, Operand(pending_handler_sp_address));
__ lw(sp, MemOperand(sp));
__ li(fp, Operand(pending_handler_fp_address));
__ lw(fp, MemOperand(fp));
// If the handler is a JS frame, restore the context to the frame.
// (kind == ENTRY) == (fp == 0) == (cp == 0), so we could test either fp
// or cp.
Label zero;
__ Branch(&zero, eq, cp, Operand(zero_reg));
__ sw(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
__ bind(&zero);
// Compute the handler entry address and jump to it.
__ li(a1, Operand(pending_handler_code_address));
__ lw(a1, MemOperand(a1));
__ li(a2, Operand(pending_handler_offset_address));
__ lw(a2, MemOperand(a2));
__ Addu(a1, a1, Operand(Code::kHeaderSize - kHeapObjectTag));
__ Addu(t9, a1, a2);
__ Jump(t9);
}
void CEntryStub::Generate(MacroAssembler* masm) {
// Called from JavaScript; parameters are on stack as if calling JS function
// a0: number of arguments including receiver
......@@ -1121,13 +1174,12 @@ void CEntryStub::Generate(MacroAssembler* masm) {
__ LoadRoot(t0, Heap::kExceptionRootIndex);
__ Branch(&exception_returned, eq, t0, Operand(v0));
ExternalReference pending_exception_address(
Isolate::kPendingExceptionAddress, isolate());
// Check that there is no pending exception, otherwise we
// should have returned the exception sentinel.
if (FLAG_debug_code) {
Label okay;
ExternalReference pending_exception_address(
Isolate::kPendingExceptionAddress, isolate());
__ li(a2, Operand(pending_exception_address));
__ lw(a2, MemOperand(a2));
__ LoadRoot(t0, Heap::kTheHoleValueRootIndex);
......@@ -1146,26 +1198,7 @@ void CEntryStub::Generate(MacroAssembler* masm) {
// Handling of exception.
__ bind(&exception_returned);
// Retrieve the pending exception.
__ li(a2, Operand(pending_exception_address));
__ lw(v0, MemOperand(a2));
// Clear the pending exception.
__ li(a3, Operand(isolate()->factory()->the_hole_value()));
__ sw(a3, MemOperand(a2));
// Special handling of termination exceptions which are uncatchable
// by javascript code.
Label throw_termination_exception;
__ LoadRoot(t0, Heap::kTerminationExceptionRootIndex);
__ Branch(&throw_termination_exception, eq, v0, Operand(t0));
// Handle normal exception.
__ Throw(v0);
__ bind(&throw_termination_exception);
__ ThrowUncatchable(v0);
ThrowPendingException(masm);
}
......@@ -2338,17 +2371,9 @@ void RegExpExecStub::Generate(MacroAssembler* masm) {
__ lw(v0, MemOperand(a2, 0));
__ Branch(&runtime, eq, v0, Operand(a1));
__ sw(a1, MemOperand(a2, 0)); // Clear pending exception.
// Check if the exception is a termination. If so, throw as uncatchable.
__ LoadRoot(a0, Heap::kTerminationExceptionRootIndex);
Label termination_exception;
__ Branch(&termination_exception, eq, v0, Operand(a0));
__ Throw(v0);
__ bind(&termination_exception);
__ ThrowUncatchable(v0);
// For exception, throw the exception again.
__ EnterExitFrame(false);
ThrowPendingException(masm);
__ bind(&failure);
// For failure and exception return null.
......
......@@ -3270,101 +3270,6 @@ void MacroAssembler::PopTryHandler() {
}
void MacroAssembler::JumpToHandlerEntry() {
// Compute the handler entry address and jump to it. The handler table is
// a fixed array of (smi-tagged) code offsets.
// v0 = exception, a1 = code object, a2 = state.
lw(a3, FieldMemOperand(a1, Code::kHandlerTableOffset)); // Handler table.
Addu(a3, a3, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
srl(a2, a2, StackHandler::kKindWidth); // Handler index.
sll(a2, a2, kPointerSizeLog2);
Addu(a2, a3, a2);
lw(a2, MemOperand(a2)); // Smi-tagged offset.
Addu(a1, a1, Operand(Code::kHeaderSize - kHeapObjectTag)); // Code start.
sra(t9, a2, kSmiTagSize);
Addu(t9, t9, a1);
Jump(t9); // Jump.
}
void MacroAssembler::Throw(Register value) {
// Adjust this code if not the case.
STATIC_ASSERT(StackHandlerConstants::kSize == 5 * kPointerSize);
STATIC_ASSERT(StackHandlerConstants::kNextOffset == 0);
STATIC_ASSERT(StackHandlerConstants::kCodeOffset == 1 * kPointerSize);
STATIC_ASSERT(StackHandlerConstants::kStateOffset == 2 * kPointerSize);
STATIC_ASSERT(StackHandlerConstants::kContextOffset == 3 * kPointerSize);
STATIC_ASSERT(StackHandlerConstants::kFPOffset == 4 * kPointerSize);
// The exception is expected in v0.
Move(v0, value);
// Drop the stack pointer to the top of the top handler.
li(a3, Operand(ExternalReference(Isolate::kHandlerAddress,
isolate())));
lw(sp, MemOperand(a3));
// Restore the next handler.
pop(a2);
sw(a2, MemOperand(a3));
// Get the code object (a1) and state (a2). Restore the context and frame
// pointer.
MultiPop(a1.bit() | a2.bit() | cp.bit() | fp.bit());
// If the handler is a JS frame, restore the context to the frame.
// (kind == ENTRY) == (fp == 0) == (cp == 0), so we could test either fp
// or cp.
Label done;
Branch(&done, eq, cp, Operand(zero_reg));
sw(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
bind(&done);
JumpToHandlerEntry();
}
void MacroAssembler::ThrowUncatchable(Register value) {
// Adjust this code if not the case.
STATIC_ASSERT(StackHandlerConstants::kSize == 5 * kPointerSize);
STATIC_ASSERT(StackHandlerConstants::kNextOffset == 0 * kPointerSize);
STATIC_ASSERT(StackHandlerConstants::kCodeOffset == 1 * kPointerSize);
STATIC_ASSERT(StackHandlerConstants::kStateOffset == 2 * kPointerSize);
STATIC_ASSERT(StackHandlerConstants::kContextOffset == 3 * kPointerSize);
STATIC_ASSERT(StackHandlerConstants::kFPOffset == 4 * kPointerSize);
// The exception is expected in v0.
if (!value.is(v0)) {
mov(v0, value);
}
// Drop the stack pointer to the top of the top stack handler.
li(a3, Operand(ExternalReference(Isolate::kHandlerAddress, isolate())));
lw(sp, MemOperand(a3));
// Unwind the handlers until the ENTRY handler is found.
Label fetch_next, check_kind;
jmp(&check_kind);
bind(&fetch_next);
lw(sp, MemOperand(sp, StackHandlerConstants::kNextOffset));
bind(&check_kind);
STATIC_ASSERT(StackHandler::JS_ENTRY == 0);
lw(a2, MemOperand(sp, StackHandlerConstants::kStateOffset));
And(a2, a2, Operand(StackHandler::KindField::kMask));
Branch(&fetch_next, ne, a2, Operand(zero_reg));
// Set the top handler address to next handler past the top ENTRY handler.
pop(a2);
sw(a2, MemOperand(a3));
// Get the code object (a1) and state (a2). Clear the context and frame
// pointer (0 was saved in the handler).
MultiPop(a1.bit() | a2.bit() | cp.bit() | fp.bit());
JumpToHandlerEntry();
}
void MacroAssembler::Allocate(int object_size,
Register result,
Register scratch1,
......
......@@ -970,13 +970,6 @@ class MacroAssembler: public Assembler {
// Must preserve the result register.
void PopTryHandler();
// Passes thrown value to the handler of top of the try handler chain.
void Throw(Register value);
// Propagates an uncatchable exception to the top of the current JS stack's
// handler chain.
void ThrowUncatchable(Register value);
// Copies a fixed number of fields of heap objects from src to dst.
void CopyFields(Register dst, Register src, RegList temps, int field_count);
......@@ -1654,10 +1647,6 @@ const Operand& rt = Operand(zero_reg), BranchDelaySlot bd = PROTECT
Register bitmap_reg,
Register mask_reg);
// Helper for throwing exceptions. Compute a handler address and jump to
// it. See the implementation for register usage.
void JumpToHandlerEntry();
// Compute memory operands for safepoint stack slots.
static int SafepointRegisterStackIndex(int reg_code);
MemOperand SafepointRegisterSlot(Register reg);
......
......@@ -1032,6 +1032,59 @@ void CEntryStub::GenerateAheadOfTime(Isolate* isolate) {
}
static void ThrowPendingException(MacroAssembler* masm) {
Isolate* isolate = masm->isolate();
ExternalReference pending_handler_context_address(
Isolate::kPendingHandlerContextAddress, isolate);
ExternalReference pending_handler_code_address(
Isolate::kPendingHandlerCodeAddress, isolate);
ExternalReference pending_handler_offset_address(
Isolate::kPendingHandlerOffsetAddress, isolate);
ExternalReference pending_handler_fp_address(
Isolate::kPendingHandlerFPAddress, isolate);
ExternalReference pending_handler_sp_address(
Isolate::kPendingHandlerSPAddress, isolate);
// Ask the runtime for help to determine the handler. This will set v0 to
// contain the current pending exception, don't clobber it.
ExternalReference find_handler(Runtime::kFindExceptionHandler, isolate);
{
FrameScope scope(masm, StackFrame::MANUAL);
__ PrepareCallCFunction(3, 0, a0);
__ mov(a0, zero_reg);
__ mov(a1, zero_reg);
__ li(a2, Operand(ExternalReference::isolate_address(isolate)));
__ CallCFunction(find_handler, 3);
}
// Retrieve the handler context, SP and FP.
__ li(cp, Operand(pending_handler_context_address));
__ ld(cp, MemOperand(cp));
__ li(sp, Operand(pending_handler_sp_address));
__ ld(sp, MemOperand(sp));
__ li(fp, Operand(pending_handler_fp_address));
__ ld(fp, MemOperand(fp));
// If the handler is a JS frame, restore the context to the frame.
// (kind == ENTRY) == (fp == 0) == (cp == 0), so we could test either fp
// or cp.
Label zero;
__ Branch(&zero, eq, cp, Operand(zero_reg));
__ sd(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
__ bind(&zero);
// Compute the handler entry address and jump to it.
__ li(a1, Operand(pending_handler_code_address));
__ ld(a1, MemOperand(a1));
__ li(a2, Operand(pending_handler_offset_address));
__ ld(a2, MemOperand(a2));
__ Daddu(a1, a1, Operand(Code::kHeaderSize - kHeapObjectTag));
__ Daddu(t9, a1, a2);
__ Jump(t9);
}
void CEntryStub::Generate(MacroAssembler* masm) {
// Called from JavaScript; parameters are on stack as if calling JS function
// a0: number of arguments including receiver
......@@ -1116,13 +1169,12 @@ void CEntryStub::Generate(MacroAssembler* masm) {
__ LoadRoot(a4, Heap::kExceptionRootIndex);
__ Branch(&exception_returned, eq, a4, Operand(v0));
ExternalReference pending_exception_address(
Isolate::kPendingExceptionAddress, isolate());
// Check that there is no pending exception, otherwise we
// should have returned the exception sentinel.
if (FLAG_debug_code) {
Label okay;
ExternalReference pending_exception_address(
Isolate::kPendingExceptionAddress, isolate());
__ li(a2, Operand(pending_exception_address));
__ ld(a2, MemOperand(a2));
__ LoadRoot(a4, Heap::kTheHoleValueRootIndex);
......@@ -1141,26 +1193,7 @@ void CEntryStub::Generate(MacroAssembler* masm) {
// Handling of exception.
__ bind(&exception_returned);
// Retrieve the pending exception.
__ li(a2, Operand(pending_exception_address));
__ ld(v0, MemOperand(a2));
// Clear the pending exception.
__ li(a3, Operand(isolate()->factory()->the_hole_value()));
__ sd(a3, MemOperand(a2));
// Special handling of termination exceptions which are uncatchable
// by javascript code.
Label throw_termination_exception;
__ LoadRoot(a4, Heap::kTerminationExceptionRootIndex);
__ Branch(&throw_termination_exception, eq, v0, Operand(a4));
// Handle normal exception.
__ Throw(v0);
__ bind(&throw_termination_exception);
__ ThrowUncatchable(v0);
ThrowPendingException(masm);
}
......@@ -2374,17 +2407,9 @@ void RegExpExecStub::Generate(MacroAssembler* masm) {
__ ld(v0, MemOperand(a2, 0));
__ Branch(&runtime, eq, v0, Operand(a1));
__ sd(a1, MemOperand(a2, 0)); // Clear pending exception.
// Check if the exception is a termination. If so, throw as uncatchable.
__ LoadRoot(a0, Heap::kTerminationExceptionRootIndex);
Label termination_exception;
__ Branch(&termination_exception, eq, v0, Operand(a0));
__ Throw(v0);
__ bind(&termination_exception);
__ ThrowUncatchable(v0);
// For exception, throw the exception again.
__ EnterExitFrame(false);
ThrowPendingException(masm);
__ bind(&failure);
// For failure and exception return null.
......
......@@ -3261,101 +3261,6 @@ void MacroAssembler::PopTryHandler() {
}
void MacroAssembler::JumpToHandlerEntry() {
// Compute the handler entry address and jump to it. The handler table is
// a fixed array of (smi-tagged) code offsets.
// v0 = exception, a1 = code object, a2 = state.
ld(a3, FieldMemOperand(a1, Code::kHandlerTableOffset));
Daddu(a3, a3, Operand(FixedArray::kHeaderSize - kHeapObjectTag));
dsrl(a2, a2, StackHandler::kKindWidth); // Handler index.
dsll(a2, a2, kPointerSizeLog2);
Daddu(a2, a3, a2);
ld(a2, MemOperand(a2)); // Smi-tagged offset.
Daddu(a1, a1, Operand(Code::kHeaderSize - kHeapObjectTag)); // Code start.
dsra32(t9, a2, 0);
Daddu(t9, t9, a1);
Jump(t9); // Jump.
}
void MacroAssembler::Throw(Register value) {
// Adjust this code if not the case.
STATIC_ASSERT(StackHandlerConstants::kSize == 5 * kPointerSize);
STATIC_ASSERT(StackHandlerConstants::kNextOffset == 0);
STATIC_ASSERT(StackHandlerConstants::kCodeOffset == 1 * kPointerSize);
STATIC_ASSERT(StackHandlerConstants::kStateOffset == 2 * kPointerSize);
STATIC_ASSERT(StackHandlerConstants::kContextOffset == 3 * kPointerSize);
STATIC_ASSERT(StackHandlerConstants::kFPOffset == 4 * kPointerSize);
// The exception is expected in v0.
Move(v0, value);
// Drop the stack pointer to the top of the top handler.
li(a3, Operand(ExternalReference(Isolate::kHandlerAddress,
isolate())));
ld(sp, MemOperand(a3));
// Restore the next handler.
pop(a2);
sd(a2, MemOperand(a3));
// Get the code object (a1) and state (a2). Restore the context and frame
// pointer.
MultiPop(a1.bit() | a2.bit() | cp.bit() | fp.bit());
// If the handler is a JS frame, restore the context to the frame.
// (kind == ENTRY) == (fp == 0) == (cp == 0), so we could test either fp
// or cp.
Label done;
Branch(&done, eq, cp, Operand(zero_reg));
sd(cp, MemOperand(fp, StandardFrameConstants::kContextOffset));
bind(&done);
JumpToHandlerEntry();
}
void MacroAssembler::ThrowUncatchable(Register value) {
// Adjust this code if not the case.
STATIC_ASSERT(StackHandlerConstants::kSize == 5 * kPointerSize);
STATIC_ASSERT(StackHandlerConstants::kNextOffset == 0 * kPointerSize);
STATIC_ASSERT(StackHandlerConstants::kCodeOffset == 1 * kPointerSize);
STATIC_ASSERT(StackHandlerConstants::kStateOffset == 2 * kPointerSize);
STATIC_ASSERT(StackHandlerConstants::kContextOffset == 3 * kPointerSize);
STATIC_ASSERT(StackHandlerConstants::kFPOffset == 4 * kPointerSize);
// The exception is expected in v0.
if (!value.is(v0)) {
mov(v0, value);
}
// Drop the stack pointer to the top of the top stack handler.
li(a3, Operand(ExternalReference(Isolate::kHandlerAddress, isolate())));
ld(sp, MemOperand(a3));
// Unwind the handlers until the ENTRY handler is found.
Label fetch_next, check_kind;
jmp(&check_kind);
bind(&fetch_next);
ld(sp, MemOperand(sp, StackHandlerConstants::kNextOffset));
bind(&check_kind);
STATIC_ASSERT(StackHandler::JS_ENTRY == 0);
ld(a2, MemOperand(sp, StackHandlerConstants::kStateOffset));
And(a2, a2, Operand(StackHandler::KindField::kMask));
Branch(&fetch_next, ne, a2, Operand(zero_reg));
// Set the top handler address to next handler past the top ENTRY handler.
pop(a2);
sd(a2, MemOperand(a3));
// Get the code object (a1) and state (a2). Clear the context and frame
// pointer (0 was saved in the handler).
MultiPop(a1.bit() | a2.bit() | cp.bit() | fp.bit());
JumpToHandlerEntry();
}
void MacroAssembler::Allocate(int object_size,
Register result,
Register scratch1,
......
......@@ -1000,13 +1000,6 @@ class MacroAssembler: public Assembler {
// Must preserve the result register.
void PopTryHandler();
// Passes thrown value to the handler of top of the try handler chain.
void Throw(Register value);
// Propagates an uncatchable exception to the top of the current JS stack's
// handler chain.
void ThrowUncatchable(Register value);
// Copies a fixed number of fields of heap objects from src to dst.
void CopyFields(Register dst, Register src, RegList temps, int field_count);
......@@ -1723,10 +1716,6 @@ const Operand& rt = Operand(zero_reg), BranchDelaySlot bd = PROTECT
Register bitmap_reg,
Register mask_reg);
// Helper for throwing exceptions. Compute a handler address and jump to
// it. See the implementation for register usage.
void JumpToHandlerEntry();
// Compute memory operands for safepoint stack slots.
static int SafepointRegisterStackIndex(int reg_code);
MemOperand SafepointRegisterSlot(Register reg);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment