JumpToFrame refactor

- Refactor the JumpToExceptionHandle code so that it is now built from
  two pieces: JumpToFrame and RunExceptionHandler.

- Refactor the Simulator::Longjmp() code so that it is no longer
  exception-specific.  Instead it uses the RunExceptionHandler stub.

This makes it so that the JumpToFrame stub and Simulator::JumpToFrame
have the same semantics.  This will make it easier to land the Rewind
changes I am working on.

There are some oddities for dbc.

BUG=
R=johnmccutchan@google.com

Review URL: https://codereview.chromium.org/2503653002 .
This commit is contained in:
Todd Turnidge 2016-11-14 14:38:21 -08:00
parent 1d5df9bc8c
commit 5ed13d3298
21 changed files with 235 additions and 147 deletions

View file

@ -210,12 +210,19 @@ static void JumpToExceptionHandler(Thread* thread,
uword frame_pointer,
const Object& exception_object,
const Object& stacktrace_object) {
// The no_gc StackResource is unwound through the tear down of
// stack resources below.
NoSafepointScope no_safepoint;
RawObject* raw_exception = exception_object.raw();
RawObject* raw_stacktrace = stacktrace_object.raw();
thread->set_active_exception(exception_object);
thread->set_active_stacktrace(stacktrace_object);
thread->set_resume_pc(program_counter);
uword run_exception_pc = StubCode::RunExceptionHandler_entry()->EntryPoint();
Exceptions::JumpToFrame(thread, run_exception_pc, stack_pointer,
frame_pointer);
}
void Exceptions::JumpToFrame(Thread* thread,
uword program_counter,
uword stack_pointer,
uword frame_pointer) {
#if !defined(TARGET_ARCH_DBC)
MallocGrowableArray<PendingLazyDeopt>* pending_deopts =
thread->isolate()->pending_deopts();
@ -284,8 +291,8 @@ static void JumpToExceptionHandler(Thread* thread,
// exception object in the kExceptionObjectReg register and the stacktrace
// object (may be raw null) in the kStackTraceObjectReg register.
Simulator::Current()->Longjmp(program_counter, stack_pointer, frame_pointer,
raw_exception, raw_stacktrace, thread);
Simulator::Current()->JumpToFrame(program_counter, stack_pointer,
frame_pointer, thread);
#else
// Prepare for unwinding frames by destroying all the stack resources
// in the previous frames.
@ -294,18 +301,16 @@ static void JumpToExceptionHandler(Thread* thread,
// Call a stub to set up the exception object in kExceptionObjectReg,
// to set up the stacktrace object in kStackTraceObjectReg, and to
// continue execution at the given pc in the given frame.
typedef void (*ExcpHandler)(uword, uword, uword, RawObject*, RawObject*,
Thread*);
typedef void (*ExcpHandler)(uword, uword, uword, Thread*);
ExcpHandler func = reinterpret_cast<ExcpHandler>(
StubCode::JumpToExceptionHandler_entry()->EntryPoint());
StubCode::JumpToFrame_entry()->EntryPoint());
// Unpoison the stack before we tear it down in the generated stub code.
uword current_sp = Thread::GetCurrentStackPointer() - 1024;
ASAN_UNPOISON(reinterpret_cast<void*>(current_sp),
stack_pointer - current_sp);
func(program_counter, stack_pointer, frame_pointer, raw_exception,
raw_stacktrace, thread);
func(program_counter, stack_pointer, frame_pointer, thread);
#endif
UNREACHABLE();
}

View file

@ -80,6 +80,11 @@ class Exceptions : AllStatic {
// otherwise returns a RawError.
static RawObject* Create(ExceptionType type, const Array& arguments);
static void JumpToFrame(Thread* thread,
uword program_counter,
uword stack_pointer,
uword frame_pointer);
private:
DISALLOW_COPY_AND_ASSIGN(Exceptions);
};

View file

@ -1104,11 +1104,10 @@ void Profiler::SampleThread(Thread* thread,
return;
}
if (StubCode::HasBeenInitialized() &&
StubCode::InJumpToExceptionHandlerStub(state.pc)) {
// The JumpToExceptionHandler stub manually adjusts the stack pointer,
// frame pointer, and some isolate state before jumping to a catch entry.
// It is not safe to walk the stack when executing this stub.
if (StubCode::HasBeenInitialized() && StubCode::InJumpToFrameStub(state.pc)) {
// The JumpToFrame stub manually adjusts the stack pointer, frame
// pointer, and some isolate state. It is not safe to walk the
// stack when executing this stub.
AtomicOperations::IncrementInt64By(
&counters_.bail_out_jump_to_exception_handler, 1);
return;

View file

@ -3891,12 +3891,7 @@ int64_t Simulator::Call(int32_t entry,
}
void Simulator::Longjmp(uword pc,
uword sp,
uword fp,
RawObject* raw_exception,
RawObject* raw_stacktrace,
Thread* thread) {
void Simulator::JumpToFrame(uword pc, uword sp, uword fp, Thread* thread) {
// Walk over all setjmp buffers (simulated --> C++ transitions)
// and try to find the setjmp associated with the simulated stack pointer.
SimulatorSetjmpBuffer* buf = last_setjmp_buffer();
@ -3919,10 +3914,6 @@ void Simulator::Longjmp(uword pc,
thread->set_vm_tag(VMTag::kDartTagId);
// Clear top exit frame.
thread->set_top_exit_frame_info(0);
ASSERT(raw_exception != Object::null());
set_register(kExceptionObjectReg, bit_cast<int32_t>(raw_exception));
set_register(kStackTraceObjectReg, bit_cast<int32_t>(raw_stacktrace));
// Restore pool pointer.
int32_t code =
*reinterpret_cast<int32_t*>(fp + kPcMarkerSlotFromFp * kWordSize);

View file

@ -127,12 +127,7 @@ class Simulator {
static uword FunctionForRedirect(uword redirect);
void Longjmp(uword pc,
uword sp,
uword fp,
RawObject* raw_exception,
RawObject* raw_stacktrace,
Thread* thread);
void JumpToFrame(uword pc, uword sp, uword fp, Thread* thread);
private:
// Known bad pc value to ensure that the simulator does not execute

View file

@ -3602,12 +3602,7 @@ int64_t Simulator::Call(int64_t entry,
}
void Simulator::Longjmp(uword pc,
uword sp,
uword fp,
RawObject* raw_exception,
RawObject* raw_stacktrace,
Thread* thread) {
void Simulator::JumpToFrame(uword pc, uword sp, uword fp, Thread* thread) {
// Walk over all setjmp buffers (simulated --> C++ transitions)
// and try to find the setjmp associated with the simulated stack pointer.
SimulatorSetjmpBuffer* buf = last_setjmp_buffer();
@ -3630,10 +3625,6 @@ void Simulator::Longjmp(uword pc,
thread->set_vm_tag(VMTag::kDartTagId);
// Clear top exit frame.
thread->set_top_exit_frame_info(0);
ASSERT(raw_exception != Object::null());
set_register(NULL, kExceptionObjectReg, bit_cast<int64_t>(raw_exception));
set_register(NULL, kStackTraceObjectReg, bit_cast<int64_t>(raw_stacktrace));
// Restore pool pointer.
int64_t code =
*reinterpret_cast<int64_t*>(fp + kPcMarkerSlotFromFp * kWordSize);

View file

@ -124,12 +124,7 @@ class Simulator {
static uword FunctionForRedirect(uword redirect);
void Longjmp(uword pc,
uword sp,
uword fp,
RawObject* raw_exception,
RawObject* raw_stacktrace,
Thread* thread);
void JumpToFrame(uword pc, uword sp, uword fp, Thread* thread);
private:
// Known bad pc value to ensure that the simulator does not execute

View file

@ -3691,12 +3691,7 @@ RawObject* Simulator::Call(const Code& code,
}
void Simulator::Longjmp(uword pc,
uword sp,
uword fp,
RawObject* raw_exception,
RawObject* raw_stacktrace,
Thread* thread) {
void Simulator::JumpToFrame(uword pc, uword sp, uword fp, Thread* thread) {
// Walk over all setjmp buffers (simulated --> C++ transitions)
// and try to find the setjmp associated with the simulated stack pointer.
SimulatorSetjmpBuffer* buf = last_setjmp_buffer();
@ -3716,12 +3711,22 @@ void Simulator::Longjmp(uword pc,
// Clear top exit frame.
thread->set_top_exit_frame_info(0);
ASSERT(raw_exception != Object::null());
sp_ = reinterpret_cast<RawObject**>(sp);
fp_ = reinterpret_cast<RawObject**>(fp);
pc_ = pc;
special_[kExceptionSpecialIndex] = raw_exception;
special_[kStacktraceSpecialIndex] = raw_stacktrace;
if (pc == StubCode::RunExceptionHandler_entry()->EntryPoint()) {
// Instead of executing the RunException stub, we implement its
// behavior here.
RawObject* raw_exception = thread->active_exception();
RawObject* raw_stacktrace = thread->active_stacktrace();
ASSERT(raw_exception != Object::null());
special_[kExceptionSpecialIndex] = raw_exception;
special_[kStacktraceSpecialIndex] = raw_stacktrace;
pc_ = thread->resume_pc();
} else {
pc_ = pc;
}
buf->Longjmp();
UNREACHABLE();
}

View file

@ -64,12 +64,7 @@ class Simulator {
const Array& arguments,
Thread* thread);
void Longjmp(uword pc,
uword sp,
uword fp,
RawObject* raw_exception,
RawObject* raw_stacktrace,
Thread* thread);
void JumpToFrame(uword pc, uword sp, uword fp, Thread* thread);
uword get_sp() const { return reinterpret_cast<uword>(sp_); }
uword get_fp() const { return reinterpret_cast<uword>(fp_); }

View file

@ -2479,12 +2479,7 @@ int64_t Simulator::Call(int32_t entry,
}
void Simulator::Longjmp(uword pc,
uword sp,
uword fp,
RawObject* raw_exception,
RawObject* raw_stacktrace,
Thread* thread) {
void Simulator::JumpToFrame(uword pc, uword sp, uword fp, Thread* thread) {
// Walk over all setjmp buffers (simulated --> C++ transitions)
// and try to find the setjmp associated with the simulated stack pointer.
SimulatorSetjmpBuffer* buf = last_setjmp_buffer();
@ -2507,10 +2502,6 @@ void Simulator::Longjmp(uword pc,
thread->set_vm_tag(VMTag::kDartTagId);
// Clear top exit frame.
thread->set_top_exit_frame_info(0);
ASSERT(raw_exception != Object::null());
set_register(kExceptionObjectReg, bit_cast<int32_t>(raw_exception));
set_register(kStackTraceObjectReg, bit_cast<int32_t>(raw_stacktrace));
// Restore pool pointer.
int32_t code =
*reinterpret_cast<int32_t*>(fp + kPcMarkerSlotFromFp * kWordSize);

View file

@ -139,12 +139,7 @@ class Simulator {
static uword FunctionForRedirect(uword redirect);
void Longjmp(uword pc,
uword sp,
uword fp,
RawObject* raw_exception,
RawObject* raw_stacktrace,
Thread* thread);
void JumpToFrame(uword pc, uword sp, uword fp, Thread* thread);
private:
// A pc value used to signal the simulator to stop execution. Generally

View file

@ -91,8 +91,8 @@ void StubCode::VisitObjectPointers(ObjectPointerVisitor* visitor) {}
bool StubCode::HasBeenInitialized() {
#if !defined(TARGET_ARCH_DBC)
// Use JumpToExceptionHandler and InvokeDart as canaries.
const StubEntry* entry_1 = StubCode::JumpToExceptionHandler_entry();
// Use JumpToHandler and InvokeDart as canaries.
const StubEntry* entry_1 = StubCode::JumpToFrame_entry();
const StubEntry* entry_2 = StubCode::InvokeDartCode_entry();
return (entry_1 != NULL) && (entry_2 != NULL);
#else
@ -115,11 +115,11 @@ bool StubCode::InInvocationStub(uword pc) {
}
bool StubCode::InJumpToExceptionHandlerStub(uword pc) {
bool StubCode::InJumpToFrameStub(uword pc) {
#if !defined(TARGET_ARCH_DBC)
ASSERT(HasBeenInitialized());
uword entry = StubCode::JumpToExceptionHandler_entry()->EntryPoint();
uword size = StubCode::JumpToExceptionHandlerSize();
uword entry = StubCode::JumpToFrame_entry()->EntryPoint();
uword size = StubCode::JumpToFrameSize();
return (pc >= entry) && (pc < (entry + size));
#else
// This stub does not exist on DBC.

View file

@ -25,7 +25,8 @@ class Deserializer;
#if !defined(TARGET_ARCH_DBC)
#define VM_STUB_CODE_LIST(V) \
V(GetStackPointer) \
V(JumpToExceptionHandler) \
V(JumpToFrame) \
V(RunExceptionHandler) \
V(UpdateStoreBuffer) \
V(PrintStopMessage) \
V(CallToRuntime) \
@ -73,6 +74,7 @@ class Deserializer;
#define VM_STUB_CODE_LIST(V) \
V(LazyCompile) \
V(OptimizeFunction) \
V(RunExceptionHandler) \
V(FixCallersTarget) \
V(Deoptimize) \
V(DeoptimizeLazyFromReturn) \
@ -138,8 +140,8 @@ class StubCode : public AllStatic {
// transitioning into dart code.
static bool InInvocationStub(uword pc);
// Check if the specified pc is in the jump to exception handler stub.
static bool InJumpToExceptionHandlerStub(uword pc);
// Check if the specified pc is in the jump to frame stub.
static bool InJumpToFrameStub(uword pc);
// Returns NULL if no stub found.
static const char* NameOfStub(uword entry_point);

View file

@ -1850,23 +1850,19 @@ void StubCode::GenerateGetStackPointerStub(Assembler* assembler) {
}
// Jump to the exception or error handler.
// Jump to a frame on the call stack.
// LR: return address.
// R0: program_counter.
// R1: stack_pointer.
// R2: frame_pointer.
// R3: error object.
// SP + 0: address of stacktrace object.
// SP + 4: thread.
// R3: thread.
// Does not return.
void StubCode::GenerateJumpToExceptionHandlerStub(Assembler* assembler) {
void StubCode::GenerateJumpToFrameStub(Assembler* assembler) {
ASSERT(kExceptionObjectReg == R0);
ASSERT(kStackTraceObjectReg == R1);
__ mov(IP, Operand(R1)); // Copy Stack pointer into IP.
__ mov(LR, Operand(R0)); // Program counter.
__ mov(R0, Operand(R3)); // Exception object.
__ ldr(R1, Address(SP, 0)); // StackTrace object.
__ ldr(THR, Address(SP, 4)); // Thread.
__ mov(THR, Operand(R3)); // Thread.
__ mov(FP, Operand(R2)); // Frame_pointer.
__ mov(SP, Operand(IP)); // Set Stack pointer.
// Set the tag.
@ -1878,6 +1874,27 @@ void StubCode::GenerateJumpToExceptionHandlerStub(Assembler* assembler) {
// Restore the pool pointer.
__ RestoreCodePointer();
__ LoadPoolPointer();
__ bx(LR); // Jump to continuation point.
}
// Run an exception handler. Execution comes from JumpToFrame
// stub or from the simulator.
//
// The arguments are stored in the Thread object.
// Does not return.
void StubCode::GenerateRunExceptionHandlerStub(Assembler* assembler) {
__ LoadFromOffset(kWord, LR, THR, Thread::resume_pc_offset());
__ LoadImmediate(R2, 0);
// Exception object.
__ LoadFromOffset(kWord, R0, THR, Thread::active_exception_offset());
__ StoreToOffset(kWord, R2, THR, Thread::active_exception_offset());
// Stacktrace object.
__ LoadFromOffset(kWord, R1, THR, Thread::active_stacktrace_offset());
__ StoreToOffset(kWord, R2, THR, Thread::active_stacktrace_offset());
__ bx(LR); // Jump to the exception handler code.
}

View file

@ -1902,24 +1902,20 @@ void StubCode::GenerateGetStackPointerStub(Assembler* assembler) {
}
// Jump to the exception or error handler.
// Jump to a frame on the call stack.
// LR: return address.
// R0: program_counter.
// R1: stack_pointer.
// R2: frame_pointer.
// R3: error object.
// R4: address of stacktrace object.
// R5: thread.
// R3: thread.
// Does not return.
void StubCode::GenerateJumpToExceptionHandlerStub(Assembler* assembler) {
void StubCode::GenerateJumpToFrameStub(Assembler* assembler) {
ASSERT(kExceptionObjectReg == R0);
ASSERT(kStackTraceObjectReg == R1);
__ mov(LR, R0); // Program counter.
__ mov(SP, R1); // Stack pointer.
__ mov(FP, R2); // Frame_pointer.
__ mov(R0, R3); // Exception object.
__ mov(R1, R4); // StackTrace object.
__ mov(THR, R5);
__ mov(THR, R3);
// Set the tag.
__ LoadImmediate(R2, VMTag::kDartTagId);
__ StoreToOffset(R2, THR, Thread::vm_tag_offset());
@ -1928,6 +1924,27 @@ void StubCode::GenerateJumpToExceptionHandlerStub(Assembler* assembler) {
// Restore the pool pointer.
__ RestoreCodePointer();
__ LoadPoolPointer();
__ ret(); // Jump to continuation point.
}
// Run an exception handler. Execution comes from JumpToFrame
// stub or from the simulator.
//
// The arguments are stored in the Thread object.
// Does not return.
void StubCode::GenerateRunExceptionHandlerStub(Assembler* assembler) {
__ LoadFromOffset(LR, THR, Thread::resume_pc_offset());
__ LoadImmediate(R2, 0);
// Exception object.
__ LoadFromOffset(R0, THR, Thread::active_exception_offset());
__ StoreToOffset(R2, THR, Thread::active_exception_offset());
// Stacktrace object.
__ LoadFromOffset(R1, THR, Thread::active_stacktrace_offset());
__ StoreToOffset(R2, THR, Thread::active_stacktrace_offset());
__ ret(); // Jump to the exception handler code.
}

View file

@ -41,6 +41,12 @@ void StubCode::GenerateOptimizeFunctionStub(Assembler* assembler) {
}
// Not executed, but used as a sentinel in Simulator::JumpToFrame.
void StubCode::GenerateRunExceptionHandlerStub(Assembler* assembler) {
__ Trap();
}
// TODO(vegorov) Don't generate this stub.
void StubCode::GenerateFixCallersTargetStub(Assembler* assembler) {
__ Trap();

View file

@ -1792,21 +1792,15 @@ void StubCode::GenerateGetStackPointerStub(Assembler* assembler) {
}
// Jump to the exception or error handler.
// Jump to a frame on the call stack.
// TOS + 0: return address
// TOS + 1: program_counter
// TOS + 2: stack_pointer
// TOS + 3: frame_pointer
// TOS + 4: exception object
// TOS + 5: stacktrace object
// TOS + 6: thread
// TOS + 4: thread
// No Result.
void StubCode::GenerateJumpToExceptionHandlerStub(Assembler* assembler) {
ASSERT(kExceptionObjectReg == EAX);
ASSERT(kStackTraceObjectReg == EDX);
__ movl(THR, Address(ESP, 6 * kWordSize)); // Load target thread.
__ movl(kStackTraceObjectReg, Address(ESP, 5 * kWordSize));
__ movl(kExceptionObjectReg, Address(ESP, 4 * kWordSize));
void StubCode::GenerateJumpToFrameStub(Assembler* assembler) {
__ movl(THR, Address(ESP, 4 * kWordSize)); // Load target thread.
__ movl(EBP, Address(ESP, 3 * kWordSize)); // Load target frame_pointer.
__ movl(EBX, Address(ESP, 1 * kWordSize)); // Load target PC into EBX.
__ movl(ESP, Address(ESP, 2 * kWordSize)); // Load target stack_pointer.
@ -1818,6 +1812,29 @@ void StubCode::GenerateJumpToExceptionHandlerStub(Assembler* assembler) {
}
// Run an exception handler. Execution comes from JumpToFrame stub.
//
// The arguments are stored in the Thread object.
// No result.
void StubCode::GenerateRunExceptionHandlerStub(Assembler* assembler) {
ASSERT(kExceptionObjectReg == EAX);
ASSERT(kStackTraceObjectReg == EDX);
__ movl(EBX, Address(THR, Thread::resume_pc_offset()));
// Load the exception from the current thread.
Address exception_addr(THR, Thread::active_exception_offset());
__ movl(kExceptionObjectReg, exception_addr);
__ movl(exception_addr, Immediate(0));
// Load the stacktrace from the current thread.
Address stacktrace_addr(THR, Thread::active_stacktrace_offset());
__ movl(kStackTraceObjectReg, stacktrace_addr);
__ movl(stacktrace_addr, Immediate(0));
__ jmp(EBX); // Jump to continuation point.
}
// Calls to the runtime to optimize the given function.
// EBX: function to be reoptimized.
// EDX: argument descriptor (preserved).

View file

@ -1985,19 +1985,13 @@ void StubCode::GenerateGetStackPointerStub(Assembler* assembler) {
// A0: program_counter.
// A1: stack_pointer.
// A2: frame_pointer.
// A3: error object.
// SP + 4*kWordSize: address of stacktrace object.
// SP + 5*kWordSize: address of thread.
// A3: thread.
// Does not return.
void StubCode::GenerateJumpToExceptionHandlerStub(Assembler* assembler) {
void StubCode::GenerateJumpToFrameStub(Assembler* assembler) {
ASSERT(kExceptionObjectReg == V0);
ASSERT(kStackTraceObjectReg == V1);
__ mov(V0, A3); // Exception object.
// MIPS ABI reserves stack space for all arguments. The StackTrace object is
// the last of five arguments, so it is first pushed on the stack.
__ lw(V1, Address(SP, 4 * kWordSize)); // StackTrace object.
__ mov(FP, A2); // Frame_pointer.
__ lw(THR, Address(SP, 5 * kWordSize)); // Thread.
__ mov(FP, A2); // Frame_pointer.
__ mov(THR, A3); // Thread.
// Set tag.
__ LoadImmediate(A2, VMTag::kDartTagId);
__ sw(A2, Assembler::VMTagAddress());
@ -2006,11 +2000,34 @@ void StubCode::GenerateJumpToExceptionHandlerStub(Assembler* assembler) {
// Restore pool pointer.
__ RestoreCodePointer();
__ LoadPoolPointer();
__ jr(A0); // Jump to the exception handler code.
__ jr(A0); // Jump to the program counter.
__ delay_slot()->mov(SP, A1); // Stack pointer.
}
// Run an exception handler. Execution comes from JumpToFrame
// stub or from the simulator.
//
// The arguments are stored in the Thread object.
// Does not return.
void StubCode::GenerateRunExceptionHandlerStub(Assembler* assembler) {
__ lw(A0, Address(THR, Thread::resume_pc_offset()));
__ LoadImmediate(A2, 0);
// Load the exception from the current thread.
Address exception_addr(THR, Thread::active_exception_offset());
__ lw(V0, exception_addr);
__ sw(A2, exception_addr);
// Load the stacktrace from the current thread.
Address stacktrace_addr(THR, Thread::active_stacktrace_offset());
__ lw(V1, stacktrace_addr);
__ jr(A0); // Jump to continuation point.
__ delay_slot()->sw(A2, stacktrace_addr);
}
// Calls to the runtime to optimize the given function.
// T0: function to be reoptimized.
// S4: argument descriptor (preserved).

View file

@ -1845,33 +1845,17 @@ void StubCode::GenerateGetStackPointerStub(Assembler* assembler) {
}
// Jump to the exception or error handler.
// Jump to a frame on the call stack.
// TOS + 0: return address
// Arg1: program counter
// Arg2: stack pointer
// Arg3: frame_pointer
// Arg4: exception object
// Arg5: stacktrace object
// Arg6: thread
// Arg4: thread
// No Result.
void StubCode::GenerateJumpToExceptionHandlerStub(Assembler* assembler) {
ASSERT(kExceptionObjectReg == RAX);
ASSERT(kStackTraceObjectReg == RDX);
ASSERT(CallingConventions::kArg4Reg != kStackTraceObjectReg);
ASSERT(CallingConventions::kArg1Reg != kStackTraceObjectReg);
#if defined(_WIN64)
Register stacktrace_reg = RBX;
__ movq(stacktrace_reg, Address(RSP, 5 * kWordSize));
__ movq(THR, Address(RSP, 6 * kWordSize));
#else
Register stacktrace_reg = CallingConventions::kArg5Reg;
__ movq(THR, CallingConventions::kArg6Reg);
#endif
void StubCode::GenerateJumpToFrameStub(Assembler* assembler) {
__ movq(THR, CallingConventions::kArg4Reg);
__ movq(RBP, CallingConventions::kArg3Reg);
__ movq(RSP, CallingConventions::kArg2Reg);
__ movq(kStackTraceObjectReg, stacktrace_reg);
__ movq(kExceptionObjectReg, CallingConventions::kArg4Reg);
// Set the tag.
__ movq(Assembler::VMTagAddress(), Immediate(VMTag::kDartTagId));
// Clear top exit frame.
@ -1879,7 +1863,31 @@ void StubCode::GenerateJumpToExceptionHandlerStub(Assembler* assembler) {
// Restore the pool pointer.
__ RestoreCodePointer();
__ LoadPoolPointer(PP);
__ jmp(CallingConventions::kArg1Reg); // Jump to the exception handler code.
__ jmp(CallingConventions::kArg1Reg); // Jump to program counter.
}
// Run an exception handler. Execution comes from JumpToFrame stub.
//
// The arguments are stored in the Thread object.
// No result.
void StubCode::GenerateRunExceptionHandlerStub(Assembler* assembler) {
ASSERT(kExceptionObjectReg == RAX);
ASSERT(kStackTraceObjectReg == RDX);
__ movq(CallingConventions::kArg1Reg,
Address(THR, Thread::resume_pc_offset()));
// Load the exception from the current thread.
Address exception_addr(THR, Thread::active_exception_offset());
__ movq(kExceptionObjectReg, exception_addr);
__ movq(exception_addr, Immediate(0));
// Load the stacktrace from the current thread.
Address stacktrace_addr(THR, Thread::active_stacktrace_offset());
__ movq(kStackTraceObjectReg, stacktrace_addr);
__ movq(stacktrace_addr, Immediate(0));
__ jmp(CallingConventions::kArg1Reg); // Jump to continuation point.
}

View file

@ -93,6 +93,9 @@ Thread::Thread(Isolate* isolate)
type_range_cache_(NULL),
deopt_id_(0),
pending_functions_(GrowableObjectArray::null()),
active_exception_(Object::null()),
active_stacktrace_(Object::null()),
resume_pc_(0),
sticky_error_(Error::null()),
compiler_stats_(NULL),
REUSABLE_HANDLE_LIST(REUSABLE_HANDLE_INITIALIZERS)
@ -215,6 +218,17 @@ void Thread::clear_pending_functions() {
}
void Thread::set_active_exception(const Object& value) {
ASSERT(!value.IsNull());
active_exception_ = value.raw();
}
void Thread::set_active_stacktrace(const Object& value) {
active_stacktrace_ = value.raw();
}
RawError* Thread::sticky_error() const {
return sticky_error_;
}
@ -606,6 +620,8 @@ void Thread::VisitObjectPointers(ObjectPointerVisitor* visitor,
reusable_handles_.VisitObjectPointers(visitor);
visitor->VisitPointer(reinterpret_cast<RawObject**>(&pending_functions_));
visitor->VisitPointer(reinterpret_cast<RawObject**>(&active_exception_));
visitor->VisitPointer(reinterpret_cast<RawObject**>(&active_stacktrace_));
visitor->VisitPointer(reinterpret_cast<RawObject**>(&sticky_error_));
// Visit the api local scope as it has all the api local handles.

View file

@ -471,6 +471,22 @@ class Thread : public BaseThread {
RawGrowableObjectArray* pending_functions();
void clear_pending_functions();
RawObject* active_exception() const { return active_exception_; }
void set_active_exception(const Object& value);
static intptr_t active_exception_offset() {
return OFFSET_OF(Thread, active_exception_);
}
RawObject* active_stacktrace() const { return active_stacktrace_; }
void set_active_stacktrace(const Object& value);
static intptr_t active_stacktrace_offset() {
return OFFSET_OF(Thread, active_stacktrace_);
}
uword resume_pc() const { return resume_pc_; }
void set_resume_pc(uword value) { resume_pc_ = value; }
static uword resume_pc_offset() { return OFFSET_OF(Thread, resume_pc_); }
RawError* sticky_error() const;
void set_sticky_error(const Error& value);
void clear_sticky_error();
@ -684,6 +700,11 @@ class Thread : public BaseThread {
intptr_t deopt_id_; // Compilation specific counter.
RawGrowableObjectArray* pending_functions_;
// JumpToExceptionHandler state:
RawObject* active_exception_;
RawObject* active_stacktrace_;
uword resume_pc_;
RawError* sticky_error_;
CompilerStats* compiler_stats_;