From: yangguo@chromium.org Date: Fri, 9 May 2014 09:13:12 +0000 (+0000) Subject: Clean up stack guard interrupts. X-Git-Tag: upstream/4.7.83~9216 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=c02ad39c10f88b77983c4edf429169036395f841;p=platform%2Fupstream%2Fv8.git 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 --- diff --git a/src/api.cc b/src/api.cc index 44b12abcd..feade6851 100644 --- a/src/api.cc +++ b/src/api.cc @@ -6464,7 +6464,8 @@ void V8::SetAutorunMicrotasks(Isolate* isolate, bool autorun) { void V8::TerminateExecution(Isolate* isolate) { - reinterpret_cast(isolate)->stack_guard()->TerminateExecution(); + i::Isolate* i_isolate = reinterpret_cast(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(isolate); - i_isolate->stack_guard()->CancelTerminateExecution(); + i_isolate->stack_guard()->ClearTerminateExecution(); + i_isolate->CancelTerminateExecution(); } void Isolate::RequestInterrupt(InterruptCallback callback, void* data) { - reinterpret_cast(this)->stack_guard()->RequestInterrupt( - callback, data); + i::Isolate* i_isolate = reinterpret_cast(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(this)->stack_guard()->ClearInterrupt(); + i::Isolate* i_isolate = reinterpret_cast(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 that, void Debug::DebugBreak(Isolate* isolate) { - reinterpret_cast(isolate)->stack_guard()->DebugBreak(); + reinterpret_cast(isolate)->stack_guard()->RequestDebugBreak(); } void Debug::CancelDebugBreak(Isolate* isolate) { i::Isolate* internal_isolate = reinterpret_cast(isolate); - internal_isolate->stack_guard()->Continue(i::DEBUGBREAK); + internal_isolate->stack_guard()->ClearDebugBreak(); } diff --git a/src/arm/regexp-macro-assembler-arm.cc b/src/arm/regexp-macro-assembler-arm.cc index e511554ef..2355ff09b 100644 --- a/src/arm/regexp-macro-assembler-arm.cc +++ b/src/arm/regexp-macro-assembler-arm.cc @@ -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(); diff --git a/src/arm64/regexp-macro-assembler-arm64.cc b/src/arm64/regexp-macro-assembler-arm64.cc index 97040cf75..db2509af4 100644 --- a/src/arm64/regexp-macro-assembler-arm64.cc +++ b/src/arm64/regexp-macro-assembler-arm64.cc @@ -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(); diff --git a/src/debug.cc b/src/debug.cc index bb5890866..717d1d9eb 100644 --- a/src/debug.cc +++ b/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 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. diff --git a/src/debug.h b/src/debug.h index 21fcb51b4..d66075de5 100644 --- a/src/debug.h +++ b/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 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(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) diff --git a/src/execution.cc b/src/execution.cc index b74ef4d62..ee6cb970c 100644 --- a/src/execution.cc +++ b/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; - set_interrupt_limits(access); -} - - -bool StackGuard::IsPreempted() { - ExecutionAccess access(isolate_); - return thread_local_.interrupt_flags_ & PREEMPT; -} - - -void StackGuard::Preempt() { - ExecutionAccess access(isolate_); - thread_local_.interrupt_flags_ |= PREEMPT; + thread_local_.interrupt_flags_ |= flagbit; set_interrupt_limits(access); } -bool StackGuard::IsTerminateExecution() { +void StackGuard::ClearInterrupt(int flagbit) { 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(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 state(isolate_); - HandleScope handle_scope(isolate_); - callback(reinterpret_cast(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 Execution::GetStackTraceLine(Handle 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(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(); - - // Clear the debug break request flag. - isolate->stack_guard()->Continue(DEBUGBREAK); + bool debug_command_only = isolate->stack_guard()->CheckDebugCommand() && + !isolate->stack_guard()->CheckDebugBreak(); - ProcessDebugMessages(isolate, debug_command_only); + isolate->stack_guard()->ClearDebugBreak(); - // 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 (stack_guard->IsPreempted()) RuntimePreempt(isolate); - if (stack_guard->IsTerminateExecution()) { - stack_guard->Continue(TERMINATE); - return isolate->TerminateExecution(); + if (CheckDebugBreak() || CheckDebugCommand()) { + Execution::DebugBreakHelper(isolate_); } - if (stack_guard->IsInterrupted()) { - stack_guard->Continue(INTERRUPT); - return isolate->StackOverflow(); + + if (CheckAndClearInterrupt(TERMINATE_EXECUTION, access)) { + return isolate_->TerminateExecution(); } - if (stack_guard->IsFullDeopt()) { - stack_guard->Continue(FULL_DEOPT); - Deoptimizer::DeoptimizeAll(isolate); + + if (CheckAndClearInterrupt(FULL_DEOPT, access)) { + Deoptimizer::DeoptimizeAll(isolate_); } - if (stack_guard->IsDeoptMarkedAllocationSites()) { - stack_guard->Continue(DEOPT_MARKED_ALLOCATION_SITES); - isolate->heap()->DeoptMarkedAllocationSites(); + + if (CheckAndClearInterrupt(DEOPT_MARKED_ALLOCATION_SITES, access)) { + isolate_->heap()->DeoptMarkedAllocationSites(); } - if (stack_guard->IsInstallCodeRequest()) { - ASSERT(isolate->concurrent_recompilation_enabled()); - stack_guard->Continue(INSTALL_CODE); - isolate->optimizing_compiler_thread()->InstallOptimizedFunctions(); + + if (CheckAndClearInterrupt(INSTALL_CODE, access)) { + ASSERT(isolate_->concurrent_recompilation_enabled()); + 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 diff --git a/src/execution.h b/src/execution.h index c165faba0..6d0b15f21 100644 --- a/src/execution.h +++ b/src/execution.h @@ -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 pos, Handle 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 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
(&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 diff --git a/src/heap.cc b/src/heap.cc index a282b0c5c..d0e290252 100644 --- a/src/heap.cc +++ b/src/heap.cc @@ -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(); } diff --git a/src/ia32/regexp-macro-assembler-ia32.cc b/src/ia32/regexp-macro-assembler-ia32.cc index 22c620e7c..4d1f23512 100644 --- a/src/ia32/regexp-macro-assembler-ia32.cc +++ b/src/ia32/regexp-macro-assembler-ia32.cc @@ -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(); diff --git a/src/incremental-marking.cc b/src/incremental-marking.cc index 2b6765c72..0cf6a9e1d 100644 --- a/src/incremental-marking.cc +++ b/src/incremental-marking.cc @@ -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(); } diff --git a/src/isolate.cc b/src/isolate.cc index dd7235ba4..06df1f67c 100644 --- a/src/isolate.cc +++ b/src/isolate.cc @@ -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 state(this); + HandleScope handle_scope(this); + callback(reinterpret_cast(this), data); + } +} + + Object* Isolate::Throw(Object* exception, MessageLocation* location) { DoThrow(exception, location); return heap()->exception(); diff --git a/src/isolate.h b/src/isolate.h index 97854f22e..35307ccf7 100644 --- a/src/isolate.h +++ b/src/isolate.h @@ -359,6 +359,8 @@ typedef List 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); diff --git a/src/mips/regexp-macro-assembler-mips.cc b/src/mips/regexp-macro-assembler-mips.cc index 7c8fde900..1ce9ea351 100644 --- a/src/mips/regexp-macro-assembler-mips.cc +++ b/src/mips/regexp-macro-assembler-mips.cc @@ -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(); diff --git a/src/runtime.cc b/src/runtime.cc index 743b34b53..d2dc1eb43 100644 --- a/src/runtime.cc +++ b/src/runtime.cc @@ -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(); } diff --git a/src/v8threads.cc b/src/v8threads.cc index 410d0b133..8dc8e9aef 100644 --- a/src/v8threads.cc +++ b/src/v8threads.cc @@ -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()); diff --git a/src/x64/regexp-macro-assembler-x64.cc b/src/x64/regexp-macro-assembler-x64.cc index 6a9a264f9..a71a91f64 100644 --- a/src/x64/regexp-macro-assembler-x64.cc +++ b/src/x64/regexp-macro-assembler-x64.cc @@ -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(); diff --git a/test/cctest/test-debug.cc b/test/cctest/test-debug.cc index 85e4512ea..2171e9c74 100644 --- a/test/cctest/test-debug.cc +++ b/test/cctest/test-debug.cc @@ -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(); } } }