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();
}
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);
}
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();
}
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();
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();
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;
}
}
-// 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_);
// 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.
// 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.
// 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;
// Set the debug command break flag to have the command processed.
if (!isolate_->debug()->InDebugger()) {
- isolate_->stack_guard()->DebugCommand();
+ isolate_->stack_guard()->RequestDebugCommand();
}
}
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);
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.
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,
}
// 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.
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)
}
-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<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;
}
nesting_ = 0;
postpone_interrupts_nesting_ = 0;
interrupt_flags_ = 0;
- interrupt_callback_ = NULL;
- interrupt_callback_data_ = NULL;
}
nesting_ = 0;
postpone_interrupts_nesting_ = 0;
interrupt_flags_ = 0;
- interrupt_callback_ = NULL;
- interrupt_callback_data_ = NULL;
return should_set_stack_limits;
}
}
-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();
-
- // 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.
}
-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
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
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,
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
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
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
}
if (trigger_deoptimization) {
- isolate_->stack_guard()->DeoptMarkedAllocationSites();
+ isolate_->stack_guard()->RequestDeoptMarkedAllocationSites();
}
FlushAllocationSitesScratchpad();
// 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_ &&
// 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();
}
}
}
cur = casted->weak_next();
}
- if (marked) isolate_->stack_guard()->DeoptMarkedAllocationSites();
+ if (marked) isolate_->stack_guard()->RequestDeoptMarkedAllocationSites();
}
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();
}
}
}
- heap_->isolate()->stack_guard()->Continue(GC_REQUEST);
+ heap_->isolate()->stack_guard()->ClearGC();
state_ = STOPPED;
is_compacting_ = false;
}
RecordWriteStub::STORE_BUFFER_ONLY);
DeactivateIncrementalWriteBarrier();
ASSERT(marking_deque_.IsEmpty());
- heap_->isolate()->stack_guard()->Continue(GC_REQUEST);
+ heap_->isolate()->stack_guard()->ClearGC();
}
}
+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();
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) \
Object* TerminateExecution();
void CancelTerminateExecution();
+ void InvokeApiInterruptCallback();
+
// Administration
void Iterate(ObjectVisitor* v);
void Iterate(ObjectVisitor* v, ThreadLocalTop* t);
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();
return isolate->StackOverflow();
}
- return Execution::HandleStackGuardInterrupt(isolate);
+ return isolate->stack_guard()->HandleInterrupts();
}
RUNTIME_FUNCTION(RuntimeHidden_Interrupt) {
SealHandleScope shs(isolate);
ASSERT(args.length() == 0);
- return Execution::HandleStackGuardInterrupt(isolate);
+ return isolate->stack_guard()->HandleInterrupts();
}
RUNTIME_FUNCTION(Runtime_DebugBreak) {
SealHandleScope shs(isolate);
ASSERT(args.length() == 0);
- return Execution::DebugBreakHelper(isolate);
+ Execution::DebugBreakHelper(isolate);
+ return isolate->heap()->undefined_value();
}
RUNTIME_FUNCTION(Runtime_Break) {
SealHandleScope shs(isolate);
ASSERT(args.length() == 0);
- isolate->stack_guard()->DebugBreak();
+ isolate->stack_guard()->RequestDebugBreak();
return isolate->heap()->undefined_value();
}
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());
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();
} 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();
}
}
}