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:
yangguo@chromium.org 2014-05-09 09:13:12 +00:00
parent 6eaf7826ac
commit c02ad39c10
17 changed files with 165 additions and 378 deletions

View File

@ -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();
}

View File

@ -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();

View File

@ -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();

View File

@ -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.

View File

@ -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)

View File

@ -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

View File

@ -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

View File

@ -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();
}

View File

@ -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();

View File

@ -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();
}

View File

@ -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();

View File

@ -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);

View File

@ -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();

View File

@ -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();
}

View File

@ -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());

View File

@ -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();

View File

@ -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();
}
}
}