Object* StackGuard::HandleInterrupts() {
- ExecutionAccess access(isolate_);
- if (should_postpone_interrupts(access)) {
- return isolate_->heap()->undefined_value();
- }
+ bool has_api_interrupt = false;
+ {
+ ExecutionAccess access(isolate_);
+ if (should_postpone_interrupts(access)) {
+ return isolate_->heap()->undefined_value();
+ }
- if (CheckAndClearInterrupt(API_INTERRUPT, access)) {
- isolate_->InvokeApiInterruptCallback();
- }
+ if (CheckAndClearInterrupt(GC_REQUEST, access)) {
+ isolate_->heap()->CollectAllGarbage(Heap::kNoGCFlags, "GC interrupt");
+ }
- if (CheckAndClearInterrupt(GC_REQUEST, access)) {
- isolate_->heap()->CollectAllGarbage(Heap::kNoGCFlags, "GC interrupt");
- }
+ if (CheckDebugBreak() || CheckDebugCommand()) {
+ Execution::DebugBreakHelper(isolate_);
+ }
- if (CheckDebugBreak() || CheckDebugCommand()) {
- Execution::DebugBreakHelper(isolate_);
- }
+ if (CheckAndClearInterrupt(TERMINATE_EXECUTION, access)) {
+ return isolate_->TerminateExecution();
+ }
- if (CheckAndClearInterrupt(TERMINATE_EXECUTION, access)) {
- return isolate_->TerminateExecution();
- }
+ if (CheckAndClearInterrupt(FULL_DEOPT, access)) {
+ Deoptimizer::DeoptimizeAll(isolate_);
+ }
- if (CheckAndClearInterrupt(FULL_DEOPT, access)) {
- Deoptimizer::DeoptimizeAll(isolate_);
- }
+ if (CheckAndClearInterrupt(DEOPT_MARKED_ALLOCATION_SITES, access)) {
+ isolate_->heap()->DeoptMarkedAllocationSites();
+ }
- if (CheckAndClearInterrupt(DEOPT_MARKED_ALLOCATION_SITES, access)) {
- isolate_->heap()->DeoptMarkedAllocationSites();
+ if (CheckAndClearInterrupt(INSTALL_CODE, access)) {
+ ASSERT(isolate_->concurrent_recompilation_enabled());
+ isolate_->optimizing_compiler_thread()->InstallOptimizedFunctions();
+ }
+
+ has_api_interrupt = CheckAndClearInterrupt(API_INTERRUPT, access);
+
+ isolate_->counters()->stack_interrupts()->Increment();
+ isolate_->counters()->runtime_profiler_ticks()->Increment();
+ isolate_->runtime_profiler()->OptimizeNow();
}
- if (CheckAndClearInterrupt(INSTALL_CODE, access)) {
- ASSERT(isolate_->concurrent_recompilation_enabled());
- isolate_->optimizing_compiler_thread()->InstallOptimizedFunctions();
+ if (has_api_interrupt) {
+ // Callback must be invoked outside of ExecusionAccess lock.
+ isolate_->InvokeApiInterruptCallback();
}
- isolate_->counters()->stack_interrupts()->Increment();
- isolate_->counters()->runtime_profiler_ticks()->Increment();
- isolate_->runtime_profiler()->OptimizeNow();
return isolate_->heap()->undefined_value();
}
virtual ~RequestInterruptTestBase() { }
+ virtual void StartInterruptThread() = 0;
+
virtual void TestBody() = 0;
void RunTest() {
- InterruptThread i_thread(this);
- i_thread.Start();
+ StartInterruptThread();
v8::HandleScope handle_scope(isolate_);
return should_continue_;
}
- protected:
static void ShouldContinueCallback(
const v8::FunctionCallbackInfo<Value>& info) {
RequestInterruptTestBase* test =
info.GetReturnValue().Set(test->ShouldContinue());
}
+ LocalContext env_;
+ v8::Isolate* isolate_;
+ i::Semaphore sem_;
+ int warmup_;
+ bool should_continue_;
+};
+
+
+class RequestInterruptTestBaseWithSimpleInterrupt
+ : public RequestInterruptTestBase {
+ public:
+ RequestInterruptTestBaseWithSimpleInterrupt() : i_thread(this) { }
+
+ virtual void StartInterruptThread() {
+ i_thread.Start();
+ }
+
+ private:
class InterruptThread : public i::Thread {
public:
explicit InterruptThread(RequestInterruptTestBase* test)
RequestInterruptTestBase* test_;
};
- LocalContext env_;
- v8::Isolate* isolate_;
- i::Semaphore sem_;
- int warmup_;
- bool should_continue_;
+ InterruptThread i_thread;
};
-class RequestInterruptTestWithFunctionCall : public RequestInterruptTestBase {
+class RequestInterruptTestWithFunctionCall
+ : public RequestInterruptTestBaseWithSimpleInterrupt {
public:
virtual void TestBody() {
Local<Function> func = Function::New(
};
-class RequestInterruptTestWithMethodCall : public RequestInterruptTestBase {
+class RequestInterruptTestWithMethodCall
+ : public RequestInterruptTestBaseWithSimpleInterrupt {
public:
virtual void TestBody() {
v8::Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate_);
};
-class RequestInterruptTestWithAccessor : public RequestInterruptTestBase {
+class RequestInterruptTestWithAccessor
+ : public RequestInterruptTestBaseWithSimpleInterrupt {
public:
virtual void TestBody() {
v8::Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate_);
};
-class RequestInterruptTestWithNativeAccessor : public RequestInterruptTestBase {
+class RequestInterruptTestWithNativeAccessor
+ : public RequestInterruptTestBaseWithSimpleInterrupt {
public:
virtual void TestBody() {
v8::Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate_);
class RequestInterruptTestWithMethodCallAndInterceptor
- : public RequestInterruptTestBase {
+ : public RequestInterruptTestBaseWithSimpleInterrupt {
public:
virtual void TestBody() {
v8::Local<v8::FunctionTemplate> t = v8::FunctionTemplate::New(isolate_);
};
-class RequestInterruptTestWithMathAbs : public RequestInterruptTestBase {
+class RequestInterruptTestWithMathAbs
+ : public RequestInterruptTestBaseWithSimpleInterrupt {
public:
virtual void TestBody() {
env_->Global()->Set(v8_str("WakeUpInterruptor"), Function::New(
}
+class ClearInterruptFromAnotherThread
+ : public RequestInterruptTestBase {
+ public:
+ ClearInterruptFromAnotherThread() : i_thread(this), sem2_(0) { }
+
+ virtual void StartInterruptThread() {
+ i_thread.Start();
+ }
+
+ virtual void TestBody() {
+ Local<Function> func = Function::New(
+ isolate_, ShouldContinueCallback, v8::External::New(isolate_, this));
+ env_->Global()->Set(v8_str("ShouldContinue"), func);
+
+ CompileRun("while (ShouldContinue()) { }");
+ }
+
+ private:
+ class InterruptThread : public i::Thread {
+ public:
+ explicit InterruptThread(ClearInterruptFromAnotherThread* test)
+ : Thread("RequestInterruptTest"), test_(test) {}
+
+ virtual void Run() {
+ test_->sem_.Wait();
+ test_->isolate_->RequestInterrupt(&OnInterrupt, test_);
+ test_->sem_.Wait();
+ test_->isolate_->ClearInterrupt();
+ test_->sem2_.Signal();
+ }
+
+ static void OnInterrupt(v8::Isolate* isolate, void* data) {
+ ClearInterruptFromAnotherThread* test =
+ reinterpret_cast<ClearInterruptFromAnotherThread*>(data);
+ test->sem_.Signal();
+ bool success = test->sem2_.WaitFor(i::TimeDelta::FromSeconds(2));
+ // Crash instead of timeout to make this failure more prominent.
+ CHECK(success);
+ test->should_continue_ = false;
+ }
+
+ private:
+ ClearInterruptFromAnotherThread* test_;
+ };
+
+ InterruptThread i_thread;
+ i::Semaphore sem2_;
+};
+
+
+TEST(ClearInterruptFromAnotherThread) {
+ ClearInterruptFromAnotherThread().RunTest();
+}
+
+
static Local<Value> function_new_expected_env;
static void FunctionNewCallback(const v8::FunctionCallbackInfo<Value>& info) {
CHECK_EQ(function_new_expected_env, info.Data());