Commit 5c1ae4ba authored by chunyang.dai's avatar chunyang.dai Committed by Commit bot

X87: Move stack unwinding logic into the runtime.

port 4acbc93d (r26957)

original commit message:

   Move stack unwinding logic into the runtime.

BUG=

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

Cr-Commit-Position: refs/heads/master@{#27000}
parent c11c0bdb
......@@ -865,6 +865,55 @@ void RestParamAccessStub::GenerateNew(MacroAssembler* masm) {
}
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 eax to
// contain the current pending exception, don't clobber it.
ExternalReference find_handler(Runtime::kFindExceptionHandler, isolate);
{
FrameScope scope(masm, StackFrame::MANUAL);
__ PrepareCallCFunction(3, eax);
__ mov(Operand(esp, 0 * kPointerSize), Immediate(0)); // argc.
__ mov(Operand(esp, 1 * kPointerSize), Immediate(0)); // argv.
__ mov(Operand(esp, 2 * kPointerSize),
Immediate(ExternalReference::isolate_address(isolate)));
__ CallCFunction(find_handler, 3);
}
// Retrieve the handler context, SP and FP.
__ mov(esi, Operand::StaticVariable(pending_handler_context_address));
__ mov(esp, Operand::StaticVariable(pending_handler_sp_address));
__ mov(ebp, Operand::StaticVariable(pending_handler_fp_address));
// If the handler is a JS frame, restore the context to the frame.
// (kind == ENTRY) == (ebp == 0) == (esi == 0), so we could test either
// ebp or esi.
Label skip;
__ test(esi, esi);
__ j(zero, &skip, Label::kNear);
__ mov(Operand(ebp, StandardFrameConstants::kContextOffset), esi);
__ bind(&skip);
// Compute the handler entry address and jump to it.
__ mov(edi, Operand::StaticVariable(pending_handler_code_address));
__ mov(edx, Operand::StaticVariable(pending_handler_offset_address));
__ lea(edi, FieldOperand(edi, edx, times_1, Code::kHeaderSize));
__ jmp(edi);
}
void RegExpExecStub::Generate(MacroAssembler* masm) {
// Just jump directly to runtime if native RegExp is not selected at compile
// time or if regexp entry in generated code is turned off runtime switch or
......@@ -1146,22 +1195,10 @@ void RegExpExecStub::Generate(MacroAssembler* masm) {
__ mov(eax, Operand::StaticVariable(pending_exception));
__ cmp(edx, eax);
__ j(equal, &runtime);
// For exception, throw the exception again.
// Clear the pending exception variable.
__ mov(Operand::StaticVariable(pending_exception), edx);
// Special handling of termination exceptions which are uncatchable
// by javascript code.
__ cmp(eax, factory->termination_exception());
Label throw_termination_exception;
__ j(equal, &throw_termination_exception, Label::kNear);
// Handle normal exception by following handler chain.
__ Throw(eax);
__ bind(&throw_termination_exception);
__ ThrowUncatchable(eax);
// For exception, throw the exception again.
__ EnterExitFrame(false);
ThrowPendingException(masm);
__ bind(&failure);
// For failure to match, return null.
......@@ -2208,15 +2245,14 @@ void CEntryStub::Generate(MacroAssembler* masm) {
__ cmp(eax, isolate()->factory()->exception());
__ j(equal, &exception_returned);
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) {
__ push(edx);
__ mov(edx, Immediate(isolate()->factory()->the_hole_value()));
Label okay;
ExternalReference pending_exception_address(
Isolate::kPendingExceptionAddress, isolate());
__ cmp(edx, Operand::StaticVariable(pending_exception_address));
// Cannot use check here as it attempts to generate call into runtime.
__ j(equal, &okay, Label::kNear);
......@@ -2231,25 +2267,7 @@ void CEntryStub::Generate(MacroAssembler* masm) {
// Handling of exception.
__ bind(&exception_returned);
// Retrieve the pending exception.
__ mov(eax, Operand::StaticVariable(pending_exception_address));
// Clear the pending exception.
__ mov(edx, Immediate(isolate()->factory()->the_hole_value()));
__ mov(Operand::StaticVariable(pending_exception_address), edx);
// Special handling of termination exceptions which are uncatchable
// by javascript code.
Label throw_termination_exception;
__ cmp(eax, isolate()->factory()->termination_exception());
__ j(equal, &throw_termination_exception);
// Handle normal exception.
__ Throw(eax);
__ bind(&throw_termination_exception);
__ ThrowUncatchable(eax);
ThrowPendingException(masm);
}
......
......@@ -1032,103 +1032,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.
// eax = exception, edi = code object, edx = state.
mov(ebx, FieldOperand(edi, Code::kHandlerTableOffset));
shr(edx, StackHandler::kKindWidth);
mov(edx, FieldOperand(ebx, edx, times_4, FixedArray::kHeaderSize));
SmiUntag(edx);
lea(edi, FieldOperand(edi, edx, times_1, Code::kHeaderSize));
jmp(edi);
}
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 eax.
if (!value.is(eax)) {
mov(eax, value);
}
// Drop the stack pointer to the top of the top handler.
ExternalReference handler_address(Isolate::kHandlerAddress, isolate());
mov(esp, Operand::StaticVariable(handler_address));
// Restore the next handler.
pop(Operand::StaticVariable(handler_address));
// Remove the code object and state, compute the handler address in edi.
pop(edi); // Code object.
pop(edx); // Index and state.
// Restore the context and frame pointer.
pop(esi); // Context.
pop(ebp); // Frame pointer.
// If the handler is a JS frame, restore the context to the frame.
// (kind == ENTRY) == (ebp == 0) == (esi == 0), so we could test either
// ebp or esi.
Label skip;
test(esi, esi);
j(zero, &skip, Label::kNear);
mov(Operand(ebp, StandardFrameConstants::kContextOffset), esi);
bind(&skip);
JumpToHandlerEntry();
}
void MacroAssembler::ThrowUncatchable(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 eax.
if (!value.is(eax)) {
mov(eax, value);
}
// Drop the stack pointer to the top of the top stack handler.
ExternalReference handler_address(Isolate::kHandlerAddress, isolate());
mov(esp, Operand::StaticVariable(handler_address));
// Unwind the handlers until the top ENTRY handler is found.
Label fetch_next, check_kind;
jmp(&check_kind, Label::kNear);
bind(&fetch_next);
mov(esp, Operand(esp, StackHandlerConstants::kNextOffset));
bind(&check_kind);
STATIC_ASSERT(StackHandler::JS_ENTRY == 0);
test(Operand(esp, StackHandlerConstants::kStateOffset),
Immediate(StackHandler::KindField::kMask));
j(not_zero, &fetch_next);
// Set the top handler address to next handler past the top ENTRY handler.
pop(Operand::StaticVariable(handler_address));
// Remove the code object and state, compute the handler address in edi.
pop(edi); // Code object.
pop(edx); // Index and state.
// Clear the context pointer and frame pointer (0 was saved in the handler).
pop(esi);
pop(ebp);
JumpToHandlerEntry();
}
void MacroAssembler::CheckAccessGlobalProxy(Register holder_reg,
Register scratch1,
Register scratch2,
......
......@@ -541,12 +541,6 @@ class MacroAssembler: public Assembler {
// Unlink the stack handler on top of the stack from the try handler chain.
void PopTryHandler();
// Throw to the top handler in the try hander chain.
void Throw(Register value);
// Throw past all JS frames to the top JS entry frame.
void ThrowUncatchable(Register value);
// ---------------------------------------------------------------------------
// Inline caching support
......@@ -970,10 +964,6 @@ class MacroAssembler: public Assembler {
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.
Operand SafepointRegisterSlot(Register reg);
static int SafepointRegisterStackIndex(int reg_code);
......
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