Clean up stack guard interrupts.
R=jkummerow@chromium.org Review URL: https://codereview.chromium.org/264233005 git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@21208 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
parent
6eaf7826ac
commit
c02ad39c10
21
src/api.cc
21
src/api.cc
@ -6464,7 +6464,8 @@ void V8::SetAutorunMicrotasks(Isolate* isolate, bool autorun) {
|
||||
|
||||
|
||||
void V8::TerminateExecution(Isolate* isolate) {
|
||||
reinterpret_cast<i::Isolate*>(isolate)->stack_guard()->TerminateExecution();
|
||||
i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
|
||||
i_isolate->stack_guard()->RequestTerminateExecution();
|
||||
}
|
||||
|
||||
|
||||
@ -6477,18 +6478,24 @@ bool V8::IsExecutionTerminating(Isolate* isolate) {
|
||||
|
||||
void V8::CancelTerminateExecution(Isolate* isolate) {
|
||||
i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(isolate);
|
||||
i_isolate->stack_guard()->CancelTerminateExecution();
|
||||
i_isolate->stack_guard()->ClearTerminateExecution();
|
||||
i_isolate->CancelTerminateExecution();
|
||||
}
|
||||
|
||||
|
||||
void Isolate::RequestInterrupt(InterruptCallback callback, void* data) {
|
||||
reinterpret_cast<i::Isolate*>(this)->stack_guard()->RequestInterrupt(
|
||||
callback, data);
|
||||
i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(this);
|
||||
i_isolate->set_api_interrupt_callback(callback);
|
||||
i_isolate->set_api_interrupt_callback_data(data);
|
||||
i_isolate->stack_guard()->RequestApiInterrupt();
|
||||
}
|
||||
|
||||
|
||||
void Isolate::ClearInterrupt() {
|
||||
reinterpret_cast<i::Isolate*>(this)->stack_guard()->ClearInterrupt();
|
||||
i::Isolate* i_isolate = reinterpret_cast<i::Isolate*>(this);
|
||||
i_isolate->stack_guard()->ClearApiInterrupt();
|
||||
i_isolate->set_api_interrupt_callback(NULL);
|
||||
i_isolate->set_api_interrupt_callback_data(NULL);
|
||||
}
|
||||
|
||||
|
||||
@ -6810,13 +6817,13 @@ bool Debug::SetDebugEventListener(v8::Handle<v8::Object> that,
|
||||
|
||||
|
||||
void Debug::DebugBreak(Isolate* isolate) {
|
||||
reinterpret_cast<i::Isolate*>(isolate)->stack_guard()->DebugBreak();
|
||||
reinterpret_cast<i::Isolate*>(isolate)->stack_guard()->RequestDebugBreak();
|
||||
}
|
||||
|
||||
|
||||
void Debug::CancelDebugBreak(Isolate* isolate) {
|
||||
i::Isolate* internal_isolate = reinterpret_cast<i::Isolate*>(isolate);
|
||||
internal_isolate->stack_guard()->Continue(i::DEBUGBREAK);
|
||||
internal_isolate->stack_guard()->ClearDebugBreak();
|
||||
}
|
||||
|
||||
|
||||
|
@ -1071,7 +1071,7 @@ int RegExpMacroAssemblerARM::CheckStackGuardState(Address* return_address,
|
||||
ASSERT(*return_address <=
|
||||
re_code->instruction_start() + re_code->instruction_size());
|
||||
|
||||
Object* result = Execution::HandleStackGuardInterrupt(isolate);
|
||||
Object* result = isolate->stack_guard()->HandleInterrupts();
|
||||
|
||||
if (*code_handle != re_code) { // Return address no longer valid
|
||||
int delta = code_handle->address() - re_code->address();
|
||||
|
@ -1315,7 +1315,7 @@ int RegExpMacroAssemblerARM64::CheckStackGuardState(Address* return_address,
|
||||
ASSERT(*return_address <=
|
||||
re_code->instruction_start() + re_code->instruction_size());
|
||||
|
||||
Object* result = Execution::HandleStackGuardInterrupt(isolate);
|
||||
Object* result = isolate->stack_guard()->HandleInterrupts();
|
||||
|
||||
if (*code_handle != re_code) { // Return address no longer valid
|
||||
int delta = code_handle->address() - re_code->address();
|
||||
|
44
src/debug.cc
44
src/debug.cc
@ -526,7 +526,7 @@ void Debug::ThreadInit() {
|
||||
thread_local_.after_break_target_ = 0;
|
||||
// TODO(isolates): frames_are_dropped_?
|
||||
thread_local_.debugger_entry_ = NULL;
|
||||
thread_local_.pending_interrupts_ = 0;
|
||||
thread_local_.has_pending_interrupt_ = false;
|
||||
thread_local_.restarter_frame_function_pointer_ = NULL;
|
||||
}
|
||||
|
||||
@ -860,13 +860,6 @@ void Debug::Unload() {
|
||||
}
|
||||
|
||||
|
||||
// Set the flag indicating that preemption happened during debugging.
|
||||
void Debug::PreemptionWhileInDebugger() {
|
||||
ASSERT(InDebugger());
|
||||
Debug::set_interrupts_pending(PREEMPT);
|
||||
}
|
||||
|
||||
|
||||
Object* Debug::Break(Arguments args) {
|
||||
Heap* heap = isolate_->heap();
|
||||
HandleScope scope(isolate_);
|
||||
@ -2961,7 +2954,7 @@ void Debugger::ProcessDebugEvent(v8::DebugEvent event,
|
||||
|
||||
// Clear any pending debug break if this is a real break.
|
||||
if (!auto_continue) {
|
||||
isolate_->debug()->clear_interrupt_pending(DEBUGBREAK);
|
||||
isolate_->debug()->set_has_pending_interrupt(false);
|
||||
}
|
||||
|
||||
// Create the execution state.
|
||||
@ -3107,7 +3100,7 @@ void Debugger::NotifyMessageHandler(v8::DebugEvent event,
|
||||
// added. It should be enough to clear the flag only once while we are in the
|
||||
// debugger.
|
||||
ASSERT(isolate_->debug()->InDebugger());
|
||||
isolate_->stack_guard()->Continue(DEBUGCOMMAND);
|
||||
isolate_->stack_guard()->ClearDebugCommand();
|
||||
|
||||
// Notify the debugger that a debug event has occurred unless auto continue is
|
||||
// active in which case no event is send.
|
||||
@ -3355,7 +3348,7 @@ void Debugger::ProcessCommand(Vector<const uint16_t> command,
|
||||
|
||||
// Set the debug command break flag to have the command processed.
|
||||
if (!isolate_->debug()->InDebugger()) {
|
||||
isolate_->stack_guard()->DebugCommand();
|
||||
isolate_->stack_guard()->RequestDebugCommand();
|
||||
}
|
||||
|
||||
MessageDispatchHelperThread* dispatch_thread;
|
||||
@ -3383,7 +3376,7 @@ void Debugger::EnqueueDebugCommand(v8::Debug::ClientData* client_data) {
|
||||
|
||||
// Set the debug command break flag to have the command processed.
|
||||
if (!isolate_->debug()->InDebugger()) {
|
||||
isolate_->stack_guard()->DebugCommand();
|
||||
isolate_->stack_guard()->RequestDebugCommand();
|
||||
}
|
||||
}
|
||||
|
||||
@ -3486,9 +3479,6 @@ EnterDebugger::EnterDebugger(Isolate* isolate)
|
||||
has_js_frames_(!it_.done()),
|
||||
save_(isolate_) {
|
||||
Debug* debug = isolate_->debug();
|
||||
ASSERT(prev_ != NULL || !debug->is_interrupt_pending(PREEMPT));
|
||||
ASSERT(prev_ != NULL || !debug->is_interrupt_pending(DEBUGBREAK));
|
||||
|
||||
// Link recursive debugger entry.
|
||||
debug->set_debugger_entry(this);
|
||||
|
||||
@ -3529,30 +3519,24 @@ EnterDebugger::~EnterDebugger() {
|
||||
if (!isolate_->has_pending_exception()) {
|
||||
// Try to avoid any pending debug break breaking in the clear mirror
|
||||
// cache JavaScript code.
|
||||
if (isolate_->stack_guard()->IsDebugBreak()) {
|
||||
debug->set_interrupts_pending(DEBUGBREAK);
|
||||
isolate_->stack_guard()->Continue(DEBUGBREAK);
|
||||
if (isolate_->stack_guard()->CheckDebugBreak()) {
|
||||
debug->set_has_pending_interrupt(true);
|
||||
isolate_->stack_guard()->ClearDebugBreak();
|
||||
}
|
||||
debug->ClearMirrorCache();
|
||||
}
|
||||
|
||||
// Request preemption and debug break when leaving the last debugger entry
|
||||
// if any of these where recorded while debugging.
|
||||
if (debug->is_interrupt_pending(PREEMPT)) {
|
||||
// This re-scheduling of preemption is to avoid starvation in some
|
||||
// debugging scenarios.
|
||||
debug->clear_interrupt_pending(PREEMPT);
|
||||
isolate_->stack_guard()->Preempt();
|
||||
}
|
||||
if (debug->is_interrupt_pending(DEBUGBREAK)) {
|
||||
debug->clear_interrupt_pending(DEBUGBREAK);
|
||||
isolate_->stack_guard()->DebugBreak();
|
||||
// Request debug break when leaving the last debugger entry
|
||||
// if one was recorded while debugging.
|
||||
if (debug->has_pending_interrupt()) {
|
||||
debug->set_has_pending_interrupt(false);
|
||||
isolate_->stack_guard()->RequestDebugBreak();
|
||||
}
|
||||
|
||||
// If there are commands in the queue when leaving the debugger request
|
||||
// that these commands are processed.
|
||||
if (isolate_->debugger()->HasCommands()) {
|
||||
isolate_->stack_guard()->DebugCommand();
|
||||
isolate_->stack_guard()->RequestDebugCommand();
|
||||
}
|
||||
|
||||
// If leaving the debugger with the debugger no longer active unload it.
|
||||
|
16
src/debug.h
16
src/debug.h
@ -216,7 +216,6 @@ class Debug {
|
||||
void Unload();
|
||||
bool IsLoaded() { return !debug_context_.is_null(); }
|
||||
bool InDebugger() { return thread_local_.debugger_entry_ != NULL; }
|
||||
void PreemptionWhileInDebugger();
|
||||
|
||||
Object* Break(Arguments args);
|
||||
bool SetBreakPoint(Handle<JSFunction> function,
|
||||
@ -317,18 +316,13 @@ class Debug {
|
||||
}
|
||||
|
||||
// Check whether any of the specified interrupts are pending.
|
||||
bool is_interrupt_pending(InterruptFlag what) {
|
||||
return (thread_local_.pending_interrupts_ & what) != 0;
|
||||
bool has_pending_interrupt() {
|
||||
return thread_local_.has_pending_interrupt_;
|
||||
}
|
||||
|
||||
// Set specified interrupts as pending.
|
||||
void set_interrupts_pending(InterruptFlag what) {
|
||||
thread_local_.pending_interrupts_ |= what;
|
||||
}
|
||||
|
||||
// Clear specified interrupts from pending.
|
||||
void clear_interrupt_pending(InterruptFlag what) {
|
||||
thread_local_.pending_interrupts_ &= ~static_cast<int>(what);
|
||||
void set_has_pending_interrupt(bool value) {
|
||||
thread_local_.has_pending_interrupt_ = value;
|
||||
}
|
||||
|
||||
// Getter and setter for the disable break state.
|
||||
@ -585,7 +579,7 @@ class Debug {
|
||||
EnterDebugger* debugger_entry_;
|
||||
|
||||
// Pending interrupts scheduled while debugging.
|
||||
int pending_interrupts_;
|
||||
bool has_pending_interrupt_;
|
||||
|
||||
// When restarter frame is on stack, stores the address
|
||||
// of the pointer to function being restarted. Otherwise (most of the time)
|
||||
|
319
src/execution.cc
319
src/execution.cc
@ -366,190 +366,37 @@ void StackGuard::DisableInterrupts() {
|
||||
}
|
||||
|
||||
|
||||
bool StackGuard::ShouldPostponeInterrupts() {
|
||||
bool StackGuard::CheckInterrupt(int flagbit) {
|
||||
ExecutionAccess access(isolate_);
|
||||
return should_postpone_interrupts(access);
|
||||
return thread_local_.interrupt_flags_ & flagbit;
|
||||
}
|
||||
|
||||
|
||||
bool StackGuard::IsInterrupted() {
|
||||
void StackGuard::RequestInterrupt(int flagbit) {
|
||||
ExecutionAccess access(isolate_);
|
||||
return (thread_local_.interrupt_flags_ & INTERRUPT) != 0;
|
||||
}
|
||||
|
||||
|
||||
void StackGuard::Interrupt() {
|
||||
ExecutionAccess access(isolate_);
|
||||
thread_local_.interrupt_flags_ |= INTERRUPT;
|
||||
thread_local_.interrupt_flags_ |= flagbit;
|
||||
set_interrupt_limits(access);
|
||||
}
|
||||
|
||||
|
||||
bool StackGuard::IsPreempted() {
|
||||
void StackGuard::ClearInterrupt(int flagbit) {
|
||||
ExecutionAccess access(isolate_);
|
||||
return thread_local_.interrupt_flags_ & PREEMPT;
|
||||
}
|
||||
|
||||
|
||||
void StackGuard::Preempt() {
|
||||
ExecutionAccess access(isolate_);
|
||||
thread_local_.interrupt_flags_ |= PREEMPT;
|
||||
set_interrupt_limits(access);
|
||||
}
|
||||
|
||||
|
||||
bool StackGuard::IsTerminateExecution() {
|
||||
ExecutionAccess access(isolate_);
|
||||
return (thread_local_.interrupt_flags_ & TERMINATE) != 0;
|
||||
}
|
||||
|
||||
|
||||
void StackGuard::CancelTerminateExecution() {
|
||||
ExecutionAccess access(isolate_);
|
||||
Continue(TERMINATE);
|
||||
isolate_->CancelTerminateExecution();
|
||||
}
|
||||
|
||||
|
||||
void StackGuard::TerminateExecution() {
|
||||
ExecutionAccess access(isolate_);
|
||||
thread_local_.interrupt_flags_ |= TERMINATE;
|
||||
set_interrupt_limits(access);
|
||||
}
|
||||
|
||||
|
||||
bool StackGuard::IsGCRequest() {
|
||||
ExecutionAccess access(isolate_);
|
||||
return (thread_local_.interrupt_flags_ & GC_REQUEST) != 0;
|
||||
}
|
||||
|
||||
|
||||
void StackGuard::RequestGC() {
|
||||
ExecutionAccess access(isolate_);
|
||||
thread_local_.interrupt_flags_ |= GC_REQUEST;
|
||||
if (thread_local_.postpone_interrupts_nesting_ == 0) {
|
||||
thread_local_.jslimit_ = thread_local_.climit_ = kInterruptLimit;
|
||||
isolate_->heap()->SetStackLimits();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool StackGuard::IsInstallCodeRequest() {
|
||||
ExecutionAccess access(isolate_);
|
||||
return (thread_local_.interrupt_flags_ & INSTALL_CODE) != 0;
|
||||
}
|
||||
|
||||
|
||||
void StackGuard::RequestInstallCode() {
|
||||
ExecutionAccess access(isolate_);
|
||||
thread_local_.interrupt_flags_ |= INSTALL_CODE;
|
||||
if (thread_local_.postpone_interrupts_nesting_ == 0) {
|
||||
thread_local_.jslimit_ = thread_local_.climit_ = kInterruptLimit;
|
||||
isolate_->heap()->SetStackLimits();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
bool StackGuard::IsFullDeopt() {
|
||||
ExecutionAccess access(isolate_);
|
||||
return (thread_local_.interrupt_flags_ & FULL_DEOPT) != 0;
|
||||
}
|
||||
|
||||
|
||||
void StackGuard::FullDeopt() {
|
||||
ExecutionAccess access(isolate_);
|
||||
thread_local_.interrupt_flags_ |= FULL_DEOPT;
|
||||
set_interrupt_limits(access);
|
||||
}
|
||||
|
||||
|
||||
bool StackGuard::IsDeoptMarkedAllocationSites() {
|
||||
ExecutionAccess access(isolate_);
|
||||
return (thread_local_.interrupt_flags_ & DEOPT_MARKED_ALLOCATION_SITES) != 0;
|
||||
}
|
||||
|
||||
|
||||
void StackGuard::DeoptMarkedAllocationSites() {
|
||||
ExecutionAccess access(isolate_);
|
||||
thread_local_.interrupt_flags_ |= DEOPT_MARKED_ALLOCATION_SITES;
|
||||
set_interrupt_limits(access);
|
||||
}
|
||||
|
||||
|
||||
bool StackGuard::IsDebugBreak() {
|
||||
ExecutionAccess access(isolate_);
|
||||
return thread_local_.interrupt_flags_ & DEBUGBREAK;
|
||||
}
|
||||
|
||||
|
||||
void StackGuard::DebugBreak() {
|
||||
ExecutionAccess access(isolate_);
|
||||
thread_local_.interrupt_flags_ |= DEBUGBREAK;
|
||||
set_interrupt_limits(access);
|
||||
}
|
||||
|
||||
|
||||
bool StackGuard::IsDebugCommand() {
|
||||
ExecutionAccess access(isolate_);
|
||||
return thread_local_.interrupt_flags_ & DEBUGCOMMAND;
|
||||
}
|
||||
|
||||
|
||||
void StackGuard::DebugCommand() {
|
||||
ExecutionAccess access(isolate_);
|
||||
thread_local_.interrupt_flags_ |= DEBUGCOMMAND;
|
||||
set_interrupt_limits(access);
|
||||
}
|
||||
|
||||
|
||||
void StackGuard::Continue(InterruptFlag after_what) {
|
||||
ExecutionAccess access(isolate_);
|
||||
thread_local_.interrupt_flags_ &= ~static_cast<int>(after_what);
|
||||
thread_local_.interrupt_flags_ &= ~flagbit;
|
||||
if (!should_postpone_interrupts(access) && !has_pending_interrupts(access)) {
|
||||
reset_limits(access);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void StackGuard::RequestInterrupt(InterruptCallback callback, void* data) {
|
||||
ExecutionAccess access(isolate_);
|
||||
thread_local_.interrupt_flags_ |= API_INTERRUPT;
|
||||
thread_local_.interrupt_callback_ = callback;
|
||||
thread_local_.interrupt_callback_data_ = data;
|
||||
set_interrupt_limits(access);
|
||||
}
|
||||
|
||||
|
||||
void StackGuard::ClearInterrupt() {
|
||||
thread_local_.interrupt_callback_ = 0;
|
||||
thread_local_.interrupt_callback_data_ = 0;
|
||||
Continue(API_INTERRUPT);
|
||||
}
|
||||
|
||||
|
||||
bool StackGuard::IsAPIInterrupt() {
|
||||
ExecutionAccess access(isolate_);
|
||||
return thread_local_.interrupt_flags_ & API_INTERRUPT;
|
||||
}
|
||||
|
||||
|
||||
void StackGuard::InvokeInterruptCallback() {
|
||||
InterruptCallback callback = 0;
|
||||
void* data = 0;
|
||||
|
||||
{
|
||||
ExecutionAccess access(isolate_);
|
||||
callback = thread_local_.interrupt_callback_;
|
||||
data = thread_local_.interrupt_callback_data_;
|
||||
thread_local_.interrupt_callback_ = NULL;
|
||||
thread_local_.interrupt_callback_data_ = NULL;
|
||||
}
|
||||
|
||||
if (callback != NULL) {
|
||||
VMState<EXTERNAL> state(isolate_);
|
||||
HandleScope handle_scope(isolate_);
|
||||
callback(reinterpret_cast<v8::Isolate*>(isolate_), data);
|
||||
bool StackGuard::CheckAndClearInterrupt(InterruptFlag flag,
|
||||
const ExecutionAccess& lock) {
|
||||
int flagbit = 1 << flag;
|
||||
bool result = (thread_local_.interrupt_flags_ & flagbit);
|
||||
thread_local_.interrupt_flags_ &= ~flagbit;
|
||||
if (!should_postpone_interrupts(lock) && !has_pending_interrupts(lock)) {
|
||||
reset_limits(lock);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
@ -594,8 +441,6 @@ void StackGuard::ThreadLocal::Clear() {
|
||||
nesting_ = 0;
|
||||
postpone_interrupts_nesting_ = 0;
|
||||
interrupt_flags_ = 0;
|
||||
interrupt_callback_ = NULL;
|
||||
interrupt_callback_data_ = NULL;
|
||||
}
|
||||
|
||||
|
||||
@ -616,8 +461,6 @@ bool StackGuard::ThreadLocal::Initialize(Isolate* isolate) {
|
||||
nesting_ = 0;
|
||||
postpone_interrupts_nesting_ = 0;
|
||||
interrupt_flags_ = 0;
|
||||
interrupt_callback_ = NULL;
|
||||
interrupt_callback_data_ = NULL;
|
||||
return should_set_stack_limits;
|
||||
}
|
||||
|
||||
@ -834,93 +677,52 @@ Handle<String> Execution::GetStackTraceLine(Handle<Object> recv,
|
||||
}
|
||||
|
||||
|
||||
static Object* RuntimePreempt(Isolate* isolate) {
|
||||
// Clear the preempt request flag.
|
||||
isolate->stack_guard()->Continue(PREEMPT);
|
||||
|
||||
if (isolate->debug()->InDebugger()) {
|
||||
// If currently in the debugger don't do any actual preemption but record
|
||||
// that preemption occoured while in the debugger.
|
||||
isolate->debug()->PreemptionWhileInDebugger();
|
||||
} else {
|
||||
// Perform preemption.
|
||||
v8::Unlocker unlocker(reinterpret_cast<v8::Isolate*>(isolate));
|
||||
Thread::YieldCPU();
|
||||
}
|
||||
|
||||
return isolate->heap()->undefined_value();
|
||||
}
|
||||
|
||||
|
||||
Object* Execution::DebugBreakHelper(Isolate* isolate) {
|
||||
void Execution::DebugBreakHelper(Isolate* isolate) {
|
||||
// Just continue if breaks are disabled.
|
||||
if (isolate->debug()->disable_break()) {
|
||||
return isolate->heap()->undefined_value();
|
||||
}
|
||||
if (isolate->debug()->disable_break()) return;
|
||||
|
||||
// Ignore debug break during bootstrapping.
|
||||
if (isolate->bootstrapper()->IsActive()) {
|
||||
return isolate->heap()->undefined_value();
|
||||
}
|
||||
if (isolate->bootstrapper()->IsActive()) return;
|
||||
|
||||
// Ignore debug break if debugger is not active.
|
||||
if (!isolate->debugger()->IsDebuggerActive()) {
|
||||
return isolate->heap()->undefined_value();
|
||||
}
|
||||
if (!isolate->debugger()->IsDebuggerActive()) return;
|
||||
|
||||
StackLimitCheck check(isolate);
|
||||
if (check.HasOverflowed()) {
|
||||
return isolate->heap()->undefined_value();
|
||||
}
|
||||
if (check.HasOverflowed()) return;
|
||||
|
||||
{
|
||||
JavaScriptFrameIterator it(isolate);
|
||||
{ JavaScriptFrameIterator it(isolate);
|
||||
ASSERT(!it.done());
|
||||
Object* fun = it.frame()->function();
|
||||
if (fun && fun->IsJSFunction()) {
|
||||
// Don't stop in builtin functions.
|
||||
if (JSFunction::cast(fun)->IsBuiltin()) {
|
||||
return isolate->heap()->undefined_value();
|
||||
}
|
||||
if (JSFunction::cast(fun)->IsBuiltin()) return;
|
||||
GlobalObject* global = JSFunction::cast(fun)->context()->global_object();
|
||||
// Don't stop in debugger functions.
|
||||
if (isolate->debug()->IsDebugGlobal(global)) {
|
||||
return isolate->heap()->undefined_value();
|
||||
}
|
||||
if (isolate->debug()->IsDebugGlobal(global)) return;
|
||||
}
|
||||
}
|
||||
|
||||
// Collect the break state before clearing the flags.
|
||||
bool debug_command_only =
|
||||
isolate->stack_guard()->IsDebugCommand() &&
|
||||
!isolate->stack_guard()->IsDebugBreak();
|
||||
bool debug_command_only = isolate->stack_guard()->CheckDebugCommand() &&
|
||||
!isolate->stack_guard()->CheckDebugBreak();
|
||||
|
||||
// Clear the debug break request flag.
|
||||
isolate->stack_guard()->Continue(DEBUGBREAK);
|
||||
isolate->stack_guard()->ClearDebugBreak();
|
||||
|
||||
ProcessDebugMessages(isolate, debug_command_only);
|
||||
|
||||
// Return to continue execution.
|
||||
return isolate->heap()->undefined_value();
|
||||
Execution::ProcessDebugMessages(isolate, debug_command_only);
|
||||
}
|
||||
|
||||
|
||||
void Execution::ProcessDebugMessages(Isolate* isolate,
|
||||
bool debug_command_only) {
|
||||
// Clear the debug command request flag.
|
||||
isolate->stack_guard()->Continue(DEBUGCOMMAND);
|
||||
isolate->stack_guard()->ClearDebugCommand();
|
||||
|
||||
StackLimitCheck check(isolate);
|
||||
if (check.HasOverflowed()) {
|
||||
return;
|
||||
}
|
||||
if (check.HasOverflowed()) return;
|
||||
|
||||
HandleScope scope(isolate);
|
||||
// Enter the debugger. Just continue if we fail to enter the debugger.
|
||||
EnterDebugger debugger(isolate);
|
||||
if (debugger.FailedToEnter()) {
|
||||
return;
|
||||
}
|
||||
if (debugger.FailedToEnter()) return;
|
||||
|
||||
// Notify the debug event listeners. Indicate auto continue if the break was
|
||||
// a debug command break.
|
||||
@ -929,52 +731,45 @@ void Execution::ProcessDebugMessages(Isolate* isolate,
|
||||
}
|
||||
|
||||
|
||||
Object* Execution::HandleStackGuardInterrupt(Isolate* isolate) {
|
||||
StackGuard* stack_guard = isolate->stack_guard();
|
||||
if (stack_guard->ShouldPostponeInterrupts()) {
|
||||
return isolate->heap()->undefined_value();
|
||||
Object* StackGuard::HandleInterrupts() {
|
||||
ExecutionAccess access(isolate_);
|
||||
if (should_postpone_interrupts(access)) {
|
||||
return isolate_->heap()->undefined_value();
|
||||
}
|
||||
|
||||
if (stack_guard->IsAPIInterrupt()) {
|
||||
stack_guard->InvokeInterruptCallback();
|
||||
stack_guard->Continue(API_INTERRUPT);
|
||||
if (CheckAndClearInterrupt(API_INTERRUPT, access)) {
|
||||
isolate_->InvokeApiInterruptCallback();
|
||||
}
|
||||
|
||||
if (stack_guard->IsGCRequest()) {
|
||||
isolate->heap()->CollectAllGarbage(Heap::kNoGCFlags,
|
||||
"StackGuard GC request");
|
||||
stack_guard->Continue(GC_REQUEST);
|
||||
if (CheckAndClearInterrupt(GC_REQUEST, access)) {
|
||||
isolate_->heap()->CollectAllGarbage(Heap::kNoGCFlags, "GC interrupt");
|
||||
}
|
||||
|
||||
isolate->counters()->stack_interrupts()->Increment();
|
||||
isolate->counters()->runtime_profiler_ticks()->Increment();
|
||||
if (stack_guard->IsDebugBreak() || stack_guard->IsDebugCommand()) {
|
||||
DebugBreakHelper(isolate);
|
||||
if (CheckDebugBreak() || CheckDebugCommand()) {
|
||||
Execution::DebugBreakHelper(isolate_);
|
||||
}
|
||||
if (stack_guard->IsPreempted()) RuntimePreempt(isolate);
|
||||
if (stack_guard->IsTerminateExecution()) {
|
||||
stack_guard->Continue(TERMINATE);
|
||||
return isolate->TerminateExecution();
|
||||
|
||||
if (CheckAndClearInterrupt(TERMINATE_EXECUTION, access)) {
|
||||
return isolate_->TerminateExecution();
|
||||
}
|
||||
if (stack_guard->IsInterrupted()) {
|
||||
stack_guard->Continue(INTERRUPT);
|
||||
return isolate->StackOverflow();
|
||||
|
||||
if (CheckAndClearInterrupt(FULL_DEOPT, access)) {
|
||||
Deoptimizer::DeoptimizeAll(isolate_);
|
||||
}
|
||||
if (stack_guard->IsFullDeopt()) {
|
||||
stack_guard->Continue(FULL_DEOPT);
|
||||
Deoptimizer::DeoptimizeAll(isolate);
|
||||
|
||||
if (CheckAndClearInterrupt(DEOPT_MARKED_ALLOCATION_SITES, access)) {
|
||||
isolate_->heap()->DeoptMarkedAllocationSites();
|
||||
}
|
||||
if (stack_guard->IsDeoptMarkedAllocationSites()) {
|
||||
stack_guard->Continue(DEOPT_MARKED_ALLOCATION_SITES);
|
||||
isolate->heap()->DeoptMarkedAllocationSites();
|
||||
|
||||
if (CheckAndClearInterrupt(INSTALL_CODE, access)) {
|
||||
ASSERT(isolate_->concurrent_recompilation_enabled());
|
||||
isolate_->optimizing_compiler_thread()->InstallOptimizedFunctions();
|
||||
}
|
||||
if (stack_guard->IsInstallCodeRequest()) {
|
||||
ASSERT(isolate->concurrent_recompilation_enabled());
|
||||
stack_guard->Continue(INSTALL_CODE);
|
||||
isolate->optimizing_compiler_thread()->InstallOptimizedFunctions();
|
||||
}
|
||||
isolate->runtime_profiler()->OptimizeNow();
|
||||
return isolate->heap()->undefined_value();
|
||||
|
||||
isolate_->counters()->stack_interrupts()->Increment();
|
||||
isolate_->counters()->runtime_profiler_ticks()->Increment();
|
||||
isolate_->runtime_profiler()->OptimizeNow();
|
||||
return isolate_->heap()->undefined_value();
|
||||
}
|
||||
|
||||
} } // namespace v8::internal
|
||||
|
@ -10,21 +10,6 @@
|
||||
namespace v8 {
|
||||
namespace internal {
|
||||
|
||||
// Flag used to set the interrupt causes.
|
||||
enum InterruptFlag {
|
||||
INTERRUPT = 1 << 0,
|
||||
DEBUGBREAK = 1 << 1,
|
||||
DEBUGCOMMAND = 1 << 2,
|
||||
PREEMPT = 1 << 3,
|
||||
TERMINATE = 1 << 4,
|
||||
GC_REQUEST = 1 << 5,
|
||||
FULL_DEOPT = 1 << 6,
|
||||
INSTALL_CODE = 1 << 7,
|
||||
API_INTERRUPT = 1 << 8,
|
||||
DEOPT_MARKED_ALLOCATION_SITES = 1 << 9
|
||||
};
|
||||
|
||||
|
||||
class Execution V8_FINAL : public AllStatic {
|
||||
public:
|
||||
// Call a function, the caller supplies a receiver and an array
|
||||
@ -119,13 +104,9 @@ class Execution V8_FINAL : public AllStatic {
|
||||
Handle<Object> pos,
|
||||
Handle<Object> is_global);
|
||||
|
||||
static Object* DebugBreakHelper(Isolate* isolate);
|
||||
static void DebugBreakHelper(Isolate* isolate);
|
||||
static void ProcessDebugMessages(Isolate* isolate, bool debug_command_only);
|
||||
|
||||
// If the stack guard is triggered, but it is not an actual
|
||||
// stack overflow, then handle the interruption accordingly.
|
||||
static Object* HandleStackGuardInterrupt(Isolate* isolate);
|
||||
|
||||
// Get a function delegate (or undefined) for the given non-function
|
||||
// object. Used for support calling objects as functions.
|
||||
static Handle<Object> GetFunctionDelegate(Isolate* isolate,
|
||||
@ -171,31 +152,23 @@ class StackGuard V8_FINAL {
|
||||
void ClearThread(const ExecutionAccess& lock);
|
||||
|
||||
bool IsStackOverflow();
|
||||
bool IsPreempted();
|
||||
void Preempt();
|
||||
bool IsInterrupted();
|
||||
void Interrupt();
|
||||
bool IsTerminateExecution();
|
||||
void TerminateExecution();
|
||||
void CancelTerminateExecution();
|
||||
bool IsDebugBreak();
|
||||
void DebugBreak();
|
||||
bool IsDebugCommand();
|
||||
void DebugCommand();
|
||||
bool IsGCRequest();
|
||||
void RequestGC();
|
||||
bool IsInstallCodeRequest();
|
||||
void RequestInstallCode();
|
||||
bool IsFullDeopt();
|
||||
void FullDeopt();
|
||||
bool IsDeoptMarkedAllocationSites();
|
||||
void DeoptMarkedAllocationSites();
|
||||
void Continue(InterruptFlag after_what);
|
||||
|
||||
void RequestInterrupt(InterruptCallback callback, void* data);
|
||||
void ClearInterrupt();
|
||||
bool IsAPIInterrupt();
|
||||
void InvokeInterruptCallback();
|
||||
#define INTERRUPT_LIST(V) \
|
||||
V(DEBUGBREAK, DebugBreak) \
|
||||
V(DEBUGCOMMAND, DebugCommand) \
|
||||
V(TERMINATE_EXECUTION, TerminateExecution) \
|
||||
V(GC_REQUEST, GC) \
|
||||
V(FULL_DEOPT, FullDeopt) \
|
||||
V(INSTALL_CODE, InstallCode) \
|
||||
V(API_INTERRUPT, ApiInterrupt) \
|
||||
V(DEOPT_MARKED_ALLOCATION_SITES, DeoptMarkedAllocationSites)
|
||||
|
||||
#define V(NAME, Name) \
|
||||
inline bool Check##Name() { return CheckInterrupt(1 << NAME); } \
|
||||
inline void Request##Name() { RequestInterrupt(1 << NAME); } \
|
||||
inline void Clear##Name() { ClearInterrupt(1 << NAME); }
|
||||
INTERRUPT_LIST(V)
|
||||
#undef V
|
||||
|
||||
// This provides an asynchronous read of the stack limits for the current
|
||||
// thread. There are no locks protecting this, but it is assumed that you
|
||||
@ -218,11 +191,29 @@ class StackGuard V8_FINAL {
|
||||
Address address_of_real_jslimit() {
|
||||
return reinterpret_cast<Address>(&thread_local_.real_jslimit_);
|
||||
}
|
||||
bool ShouldPostponeInterrupts();
|
||||
|
||||
// If the stack guard is triggered, but it is not an actual
|
||||
// stack overflow, then handle the interruption accordingly.
|
||||
Object* HandleInterrupts();
|
||||
|
||||
private:
|
||||
StackGuard();
|
||||
|
||||
// Flag used to set the interrupt causes.
|
||||
enum InterruptFlag {
|
||||
#define V(NAME, Name) NAME,
|
||||
INTERRUPT_LIST(V)
|
||||
#undef V
|
||||
NUMBER_OF_INTERRUPTS
|
||||
};
|
||||
|
||||
bool CheckInterrupt(int flagbit);
|
||||
void RequestInterrupt(int flagbit);
|
||||
void ClearInterrupt(int flagbit);
|
||||
bool CheckAndClearInterrupt(InterruptFlag flag, const ExecutionAccess& lock);
|
||||
|
||||
void InvokeApiInterruptCallback();
|
||||
|
||||
// You should hold the ExecutionAccess lock when calling this method.
|
||||
bool has_pending_interrupts(const ExecutionAccess& lock) {
|
||||
// Sanity check: We shouldn't be asking about pending interrupts
|
||||
@ -282,9 +273,6 @@ class StackGuard V8_FINAL {
|
||||
int nesting_;
|
||||
int postpone_interrupts_nesting_;
|
||||
int interrupt_flags_;
|
||||
|
||||
InterruptCallback interrupt_callback_;
|
||||
void* interrupt_callback_data_;
|
||||
};
|
||||
|
||||
// TODO(isolates): Technically this could be calculated directly from a
|
||||
|
@ -514,7 +514,7 @@ void Heap::ProcessPretenuringFeedback() {
|
||||
}
|
||||
|
||||
if (trigger_deoptimization) {
|
||||
isolate_->stack_guard()->DeoptMarkedAllocationSites();
|
||||
isolate_->stack_guard()->RequestDeoptMarkedAllocationSites();
|
||||
}
|
||||
|
||||
FlushAllocationSitesScratchpad();
|
||||
@ -1113,7 +1113,7 @@ bool Heap::PerformGarbageCollection(
|
||||
// code which should be tenured in local pretenuring mode.
|
||||
if (FLAG_pretenuring) {
|
||||
if (!FLAG_allocation_site_pretenuring) {
|
||||
isolate_->stack_guard()->FullDeopt();
|
||||
isolate_->stack_guard()->RequestFullDeopt();
|
||||
}
|
||||
}
|
||||
} else if (new_space_high_promotion_mode_active_ &&
|
||||
@ -1130,7 +1130,7 @@ bool Heap::PerformGarbageCollection(
|
||||
// Trigger deoptimization here to turn off global pretenuring as soon as
|
||||
// possible.
|
||||
if (FLAG_pretenuring && !FLAG_allocation_site_pretenuring) {
|
||||
isolate_->stack_guard()->FullDeopt();
|
||||
isolate_->stack_guard()->RequestFullDeopt();
|
||||
}
|
||||
}
|
||||
|
||||
@ -1749,7 +1749,7 @@ void Heap::ResetAllAllocationSitesDependentCode(PretenureFlag flag) {
|
||||
}
|
||||
cur = casted->weak_next();
|
||||
}
|
||||
if (marked) isolate_->stack_guard()->DeoptMarkedAllocationSites();
|
||||
if (marked) isolate_->stack_guard()->RequestDeoptMarkedAllocationSites();
|
||||
}
|
||||
|
||||
|
||||
|
@ -1103,7 +1103,7 @@ int RegExpMacroAssemblerIA32::CheckStackGuardState(Address* return_address,
|
||||
ASSERT(*return_address <=
|
||||
re_code->instruction_start() + re_code->instruction_size());
|
||||
|
||||
Object* result = Execution::HandleStackGuardInterrupt(isolate);
|
||||
Object* result = isolate->stack_guard()->HandleInterrupts();
|
||||
|
||||
if (*code_handle != re_code) { // Return address no longer valid
|
||||
int delta = code_handle->address() - re_code->address();
|
||||
|
@ -797,7 +797,7 @@ void IncrementalMarking::Abort() {
|
||||
}
|
||||
}
|
||||
}
|
||||
heap_->isolate()->stack_guard()->Continue(GC_REQUEST);
|
||||
heap_->isolate()->stack_guard()->ClearGC();
|
||||
state_ = STOPPED;
|
||||
is_compacting_ = false;
|
||||
}
|
||||
@ -814,7 +814,7 @@ void IncrementalMarking::Finalize() {
|
||||
RecordWriteStub::STORE_BUFFER_ONLY);
|
||||
DeactivateIncrementalWriteBarrier();
|
||||
ASSERT(marking_deque_.IsEmpty());
|
||||
heap_->isolate()->stack_guard()->Continue(GC_REQUEST);
|
||||
heap_->isolate()->stack_guard()->ClearGC();
|
||||
}
|
||||
|
||||
|
||||
|
@ -835,6 +835,20 @@ void Isolate::CancelTerminateExecution() {
|
||||
}
|
||||
|
||||
|
||||
void Isolate::InvokeApiInterruptCallback() {
|
||||
InterruptCallback callback = api_interrupt_callback_;
|
||||
void* data = api_interrupt_callback_data_;
|
||||
api_interrupt_callback_ = NULL;
|
||||
api_interrupt_callback_data_ = NULL;
|
||||
|
||||
if (callback != NULL) {
|
||||
VMState<EXTERNAL> state(this);
|
||||
HandleScope handle_scope(this);
|
||||
callback(reinterpret_cast<v8::Isolate*>(this), data);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Object* Isolate::Throw(Object* exception, MessageLocation* location) {
|
||||
DoThrow(exception, location);
|
||||
return heap()->exception();
|
||||
|
@ -359,6 +359,8 @@ typedef List<HeapObject*> DebugObjectCache;
|
||||
V(int, max_available_threads, 0) \
|
||||
V(uint32_t, per_isolate_assert_data, 0xFFFFFFFFu) \
|
||||
V(DebuggerAgent*, debugger_agent_instance, NULL) \
|
||||
V(InterruptCallback, api_interrupt_callback, NULL) \
|
||||
V(void*, api_interrupt_callback_data, NULL) \
|
||||
ISOLATE_INIT_SIMULATOR_LIST(V)
|
||||
|
||||
#define THREAD_LOCAL_TOP_ACCESSOR(type, name) \
|
||||
@ -758,6 +760,8 @@ class Isolate {
|
||||
Object* TerminateExecution();
|
||||
void CancelTerminateExecution();
|
||||
|
||||
void InvokeApiInterruptCallback();
|
||||
|
||||
// Administration
|
||||
void Iterate(ObjectVisitor* v);
|
||||
void Iterate(ObjectVisitor* v, ThreadLocalTop* t);
|
||||
|
@ -1130,7 +1130,7 @@ int RegExpMacroAssemblerMIPS::CheckStackGuardState(Address* return_address,
|
||||
ASSERT(*return_address <=
|
||||
re_code->instruction_start() + re_code->instruction_size());
|
||||
|
||||
Object* result = Execution::HandleStackGuardInterrupt(isolate);
|
||||
Object* result = isolate->stack_guard()->HandleInterrupts();
|
||||
|
||||
if (*code_handle != re_code) { // Return address no longer valid.
|
||||
int delta = code_handle->address() - re_code->address();
|
||||
|
@ -9601,7 +9601,7 @@ RUNTIME_FUNCTION(RuntimeHidden_StackGuard) {
|
||||
return isolate->StackOverflow();
|
||||
}
|
||||
|
||||
return Execution::HandleStackGuardInterrupt(isolate);
|
||||
return isolate->stack_guard()->HandleInterrupts();
|
||||
}
|
||||
|
||||
|
||||
@ -9625,7 +9625,7 @@ RUNTIME_FUNCTION(RuntimeHidden_TryInstallOptimizedCode) {
|
||||
RUNTIME_FUNCTION(RuntimeHidden_Interrupt) {
|
||||
SealHandleScope shs(isolate);
|
||||
ASSERT(args.length() == 0);
|
||||
return Execution::HandleStackGuardInterrupt(isolate);
|
||||
return isolate->stack_guard()->HandleInterrupts();
|
||||
}
|
||||
|
||||
|
||||
@ -10804,7 +10804,8 @@ RUNTIME_FUNCTION(Runtime_LookupAccessor) {
|
||||
RUNTIME_FUNCTION(Runtime_DebugBreak) {
|
||||
SealHandleScope shs(isolate);
|
||||
ASSERT(args.length() == 0);
|
||||
return Execution::DebugBreakHelper(isolate);
|
||||
Execution::DebugBreakHelper(isolate);
|
||||
return isolate->heap()->undefined_value();
|
||||
}
|
||||
|
||||
|
||||
@ -10841,7 +10842,7 @@ RUNTIME_FUNCTION(Runtime_SetDebugEventListener) {
|
||||
RUNTIME_FUNCTION(Runtime_Break) {
|
||||
SealHandleScope shs(isolate);
|
||||
ASSERT(args.length() == 0);
|
||||
isolate->stack_guard()->DebugBreak();
|
||||
isolate->stack_guard()->RequestDebugBreak();
|
||||
return isolate->heap()->undefined_value();
|
||||
}
|
||||
|
||||
|
@ -145,7 +145,7 @@ bool ThreadManager::RestoreThread() {
|
||||
from = isolate_->bootstrapper()->RestoreState(from);
|
||||
per_thread->set_thread_state(NULL);
|
||||
if (state->terminate_on_restore()) {
|
||||
isolate_->stack_guard()->TerminateExecution();
|
||||
isolate_->stack_guard()->RequestTerminateExecution();
|
||||
state->set_terminate_on_restore(false);
|
||||
}
|
||||
state->set_id(ThreadId::Invalid());
|
||||
|
@ -1210,7 +1210,7 @@ int RegExpMacroAssemblerX64::CheckStackGuardState(Address* return_address,
|
||||
ASSERT(*return_address <=
|
||||
re_code->instruction_start() + re_code->instruction_size());
|
||||
|
||||
Object* result = Execution::HandleStackGuardInterrupt(isolate);
|
||||
Object* result = isolate->stack_guard()->HandleInterrupts();
|
||||
|
||||
if (*code_handle != re_code) { // Return address no longer valid
|
||||
intptr_t delta = code_handle->address() - re_code->address();
|
||||
|
@ -6834,18 +6834,18 @@ static void BreakMessageHandler(const v8::Debug::Message& message) {
|
||||
} else if (message.IsEvent() && message.GetEvent() == v8::AfterCompile) {
|
||||
i::HandleScope scope(isolate);
|
||||
|
||||
bool is_debug_break = isolate->stack_guard()->IsDebugBreak();
|
||||
bool is_debug_break = isolate->stack_guard()->CheckDebugBreak();
|
||||
// Force DebugBreak flag while serializer is working.
|
||||
isolate->stack_guard()->DebugBreak();
|
||||
isolate->stack_guard()->RequestDebugBreak();
|
||||
|
||||
// Force serialization to trigger some internal JS execution.
|
||||
message.GetJSON();
|
||||
|
||||
// Restore previous state.
|
||||
if (is_debug_break) {
|
||||
isolate->stack_guard()->DebugBreak();
|
||||
isolate->stack_guard()->RequestDebugBreak();
|
||||
} else {
|
||||
isolate->stack_guard()->Continue(i::DEBUGBREAK);
|
||||
isolate->stack_guard()->ClearDebugBreak();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user