Clean up stack guard interrupts.
authoryangguo@chromium.org <yangguo@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Fri, 9 May 2014 09:13:12 +0000 (09:13 +0000)
committeryangguo@chromium.org <yangguo@chromium.org@ce2b1a6d-e550-0410-aec6-3dcde31c8c00>
Fri, 9 May 2014 09:13:12 +0000 (09:13 +0000)
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

17 files changed:
src/api.cc
src/arm/regexp-macro-assembler-arm.cc
src/arm64/regexp-macro-assembler-arm64.cc
src/debug.cc
src/debug.h
src/execution.cc
src/execution.h
src/heap.cc
src/ia32/regexp-macro-assembler-ia32.cc
src/incremental-marking.cc
src/isolate.cc
src/isolate.h
src/mips/regexp-macro-assembler-mips.cc
src/runtime.cc
src/v8threads.cc
src/x64/regexp-macro-assembler-x64.cc
test/cctest/test-debug.cc

index 44b12ab..feade68 100644 (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();
 }
 
 
index e511554..2355ff0 100644 (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();
index 97040cf..db2509a 100644 (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();
index bb58908..717d1d9 100644 (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.
index 21fcb51..d66075d 100644 (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)
index b74ef4d..ee6cb97 100644 (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;
-  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;
 }
 
 
@@ -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();
-
-  // 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
index c165fab..6d0b15f 100644 (file)
 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
index a282b0c..d0e2902 100644 (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();
 }
 
 
index 22c620e..4d1f235 100644 (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();
index 2b6765c..0cf6a9e 100644 (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();
 }
 
 
index dd7235b..06df1f6 100644 (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();
index 97854f2..35307cc 100644 (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);
index 7c8fde9..1ce9ea3 100644 (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();
index 743b34b..d2dc1eb 100644 (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();
 }
 
index 410d0b1..8dc8e9a 100644 (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());
index 6a9a264..a71a91f 100644 (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();
index 85e4512..2171e9c 100644 (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();
     }
   }
 }