Revert "Add mechanism to postpone interrupts selectively."

This reverts commit r22073.

TBR=yurys@chromium.org

Review URL: https://codereview.chromium.org/362493002

git-svn-id: https://v8.googlecode.com/svn/branches/bleeding_edge@22074 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
This commit is contained in:
yangguo@chromium.org 2014-06-30 06:45:23 +00:00
parent 326bc2a533
commit 965f7037c8
5 changed files with 70 additions and 156 deletions

View File

@ -20,6 +20,8 @@ StackGuard::StackGuard()
void StackGuard::set_interrupt_limits(const ExecutionAccess& lock) { void StackGuard::set_interrupt_limits(const ExecutionAccess& lock) {
ASSERT(isolate_ != NULL); ASSERT(isolate_ != NULL);
// Ignore attempts to interrupt when interrupts are postponed.
if (should_postpone_interrupts(lock)) return;
thread_local_.jslimit_ = kInterruptLimit; thread_local_.jslimit_ = kInterruptLimit;
thread_local_.climit_ = kInterruptLimit; thread_local_.climit_ = kInterruptLimit;
isolate_->heap()->SetStackLimits(); isolate_->heap()->SetStackLimits();
@ -335,62 +337,36 @@ void StackGuard::DisableInterrupts() {
} }
void StackGuard::PushPostponeInterruptsScope(PostponeInterruptsScope* scope) { bool StackGuard::CheckInterrupt(int flagbit) {
ExecutionAccess access(isolate_); ExecutionAccess access(isolate_);
scope->prev_ = thread_local_.postpone_interrupts_; return thread_local_.interrupt_flags_ & flagbit;
thread_local_.postpone_interrupts_ = scope;
} }
void StackGuard::PopPostponeInterruptsScope() { void StackGuard::RequestInterrupt(int flagbit) {
ExecutionAccess access(isolate_); ExecutionAccess access(isolate_);
PostponeInterruptsScope* top = thread_local_.postpone_interrupts_; thread_local_.interrupt_flags_ |= flagbit;
thread_local_.interrupt_flags_ |= top->intercepted_flags_;
thread_local_.postpone_interrupts_ = top->prev_;
if (has_pending_interrupts(access)) set_interrupt_limits(access);
}
bool StackGuard::CheckInterrupt(InterruptFlag flag) {
ExecutionAccess access(isolate_);
return thread_local_.interrupt_flags_ & flag;
}
void StackGuard::RequestInterrupt(InterruptFlag flag) {
ExecutionAccess access(isolate_);
// Check the chain of PostponeInterruptsScopes for interception.
if (thread_local_.postpone_interrupts_ &&
thread_local_.postpone_interrupts_->Intercept(flag)) {
return;
}
// Not intercepted. Set as active interrupt flag.
thread_local_.interrupt_flags_ |= flag;
set_interrupt_limits(access); set_interrupt_limits(access);
} }
void StackGuard::ClearInterrupt(InterruptFlag flag) { void StackGuard::ClearInterrupt(int flagbit) {
ExecutionAccess access(isolate_); ExecutionAccess access(isolate_);
// Clear the interrupt flag from the chain of PostponeInterruptsScopes. thread_local_.interrupt_flags_ &= ~flagbit;
for (PostponeInterruptsScope* current = thread_local_.postpone_interrupts_; if (!should_postpone_interrupts(access) && !has_pending_interrupts(access)) {
current != NULL; reset_limits(access);
current = current->prev_) {
current->intercepted_flags_ &= ~flag;
} }
// Clear the interrupt flag from the active interrupt flags.
thread_local_.interrupt_flags_ &= ~flag;
if (!has_pending_interrupts(access)) reset_limits(access);
} }
bool StackGuard::CheckAndClearInterrupt(InterruptFlag flag) { bool StackGuard::CheckAndClearInterrupt(InterruptFlag flag) {
ExecutionAccess access(isolate_); ExecutionAccess access(isolate_);
bool result = (thread_local_.interrupt_flags_ & flag); int flagbit = 1 << flag;
thread_local_.interrupt_flags_ &= ~flag; bool result = (thread_local_.interrupt_flags_ & flagbit);
if (!has_pending_interrupts(access)) reset_limits(access); thread_local_.interrupt_flags_ &= ~flagbit;
if (!should_postpone_interrupts(access) && !has_pending_interrupts(access)) {
reset_limits(access);
}
return result; return result;
} }
@ -432,7 +408,8 @@ void StackGuard::ThreadLocal::Clear() {
jslimit_ = kIllegalLimit; jslimit_ = kIllegalLimit;
real_climit_ = kIllegalLimit; real_climit_ = kIllegalLimit;
climit_ = kIllegalLimit; climit_ = kIllegalLimit;
postpone_interrupts_ = NULL; nesting_ = 0;
postpone_interrupts_nesting_ = 0;
interrupt_flags_ = 0; interrupt_flags_ = 0;
} }
@ -451,7 +428,8 @@ bool StackGuard::ThreadLocal::Initialize(Isolate* isolate) {
climit_ = limit; climit_ = limit;
should_set_stack_limits = true; should_set_stack_limits = true;
} }
postpone_interrupts_ = NULL; nesting_ = 0;
postpone_interrupts_nesting_ = 0;
interrupt_flags_ = 0; interrupt_flags_ = 0;
return should_set_stack_limits; return should_set_stack_limits;
} }
@ -670,6 +648,13 @@ Handle<String> Execution::GetStackTraceLine(Handle<Object> recv,
Object* StackGuard::HandleInterrupts() { Object* StackGuard::HandleInterrupts() {
{
ExecutionAccess access(isolate_);
if (should_postpone_interrupts(access)) {
return isolate_->heap()->undefined_value();
}
}
if (CheckAndClearInterrupt(GC_REQUEST)) { if (CheckAndClearInterrupt(GC_REQUEST)) {
isolate_->heap()->CollectAllGarbage(Heap::kNoGCFlags, "GC interrupt"); isolate_->heap()->CollectAllGarbage(Heap::kNoGCFlags, "GC interrupt");
} }

View File

@ -122,7 +122,6 @@ class Execution V8_FINAL : public AllStatic {
class ExecutionAccess; class ExecutionAccess;
class PostponeInterruptsScope;
// StackGuard contains the handling of the limits that are used to limit the // StackGuard contains the handling of the limits that are used to limit the
@ -147,31 +146,21 @@ class StackGuard V8_FINAL {
void ClearThread(const ExecutionAccess& lock); void ClearThread(const ExecutionAccess& lock);
#define INTERRUPT_LIST(V) \ #define INTERRUPT_LIST(V) \
V(DEBUGBREAK, DebugBreak, 0) \ V(DEBUGBREAK, DebugBreak) \
V(DEBUGCOMMAND, DebugCommand, 1) \ V(DEBUGCOMMAND, DebugCommand) \
V(TERMINATE_EXECUTION, TerminateExecution, 2) \ V(TERMINATE_EXECUTION, TerminateExecution) \
V(GC_REQUEST, GC, 3) \ V(GC_REQUEST, GC) \
V(INSTALL_CODE, InstallCode, 4) \ V(INSTALL_CODE, InstallCode) \
V(API_INTERRUPT, ApiInterrupt, 5) \ V(API_INTERRUPT, ApiInterrupt) \
V(DEOPT_MARKED_ALLOCATION_SITES, DeoptMarkedAllocationSites, 6) V(DEOPT_MARKED_ALLOCATION_SITES, DeoptMarkedAllocationSites)
#define V(NAME, Name, id) \ #define V(NAME, Name) \
inline bool Check##Name() { return CheckInterrupt(NAME); } \ inline bool Check##Name() { return CheckInterrupt(1 << NAME); } \
inline void Request##Name() { RequestInterrupt(NAME); } \ inline void Request##Name() { RequestInterrupt(1 << NAME); } \
inline void Clear##Name() { ClearInterrupt(NAME); } inline void Clear##Name() { ClearInterrupt(1 << NAME); }
INTERRUPT_LIST(V) INTERRUPT_LIST(V)
#undef V #undef V
// Flag used to set the interrupt causes.
enum InterruptFlag {
#define V(NAME, Name, id) NAME = (1 << id),
INTERRUPT_LIST(V)
#undef V
#define V(NAME, Name, id) NAME |
ALL_INTERRUPTS = INTERRUPT_LIST(V) 0
#undef V
};
// This provides an asynchronous read of the stack limits for the current // 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 // thread. There are no locks protecting this, but it is assumed that you
// have the global V8 lock if you are using multiple V8 threads. // have the global V8 lock if you are using multiple V8 threads.
@ -201,16 +190,32 @@ class StackGuard V8_FINAL {
private: private:
StackGuard(); StackGuard();
bool CheckInterrupt(InterruptFlag flag); // Flag used to set the interrupt causes.
void RequestInterrupt(InterruptFlag flag); enum InterruptFlag {
void ClearInterrupt(InterruptFlag flag); #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); bool CheckAndClearInterrupt(InterruptFlag flag);
// You should hold the ExecutionAccess lock when calling this method. // You should hold the ExecutionAccess lock when calling this method.
bool has_pending_interrupts(const ExecutionAccess& lock) { bool has_pending_interrupts(const ExecutionAccess& lock) {
// Sanity check: We shouldn't be asking about pending interrupts
// unless we're not postponing them anymore.
ASSERT(!should_postpone_interrupts(lock));
return thread_local_.interrupt_flags_ != 0; return thread_local_.interrupt_flags_ != 0;
} }
// You should hold the ExecutionAccess lock when calling this method.
bool should_postpone_interrupts(const ExecutionAccess& lock) {
return thread_local_.postpone_interrupts_nesting_ > 0;
}
// You should hold the ExecutionAccess lock when calling this method. // You should hold the ExecutionAccess lock when calling this method.
inline void set_interrupt_limits(const ExecutionAccess& lock); inline void set_interrupt_limits(const ExecutionAccess& lock);
@ -230,9 +235,6 @@ class StackGuard V8_FINAL {
static const uintptr_t kIllegalLimit = 0xfffffff8; static const uintptr_t kIllegalLimit = 0xfffffff8;
#endif #endif
void PushPostponeInterruptsScope(PostponeInterruptsScope* scope);
void PopPostponeInterruptsScope();
class ThreadLocal V8_FINAL { class ThreadLocal V8_FINAL {
public: public:
ThreadLocal() { Clear(); } ThreadLocal() { Clear(); }
@ -257,7 +259,8 @@ class StackGuard V8_FINAL {
uintptr_t real_climit_; // Actual C++ stack limit set for the VM. uintptr_t real_climit_; // Actual C++ stack limit set for the VM.
uintptr_t climit_; uintptr_t climit_;
PostponeInterruptsScope* postpone_interrupts_; int nesting_;
int postpone_interrupts_nesting_;
int interrupt_flags_; int interrupt_flags_;
}; };

View File

@ -2371,15 +2371,4 @@ bool StackLimitCheck::JsHasOverflowed() const {
} }
bool PostponeInterruptsScope::Intercept(StackGuard::InterruptFlag flag) {
// First check whether the previous scope intercepts.
if (prev_ && prev_->Intercept(flag)) return true;
// Then check whether this scope intercepts.
if ((flag & intercept_mask_)) {
intercepted_flags_ |= flag;
return true;
}
return false;
}
} } // namespace v8::internal } } // namespace v8::internal

View File

@ -1420,29 +1420,22 @@ class StackLimitCheck BASE_EMBEDDED {
// account. // account.
class PostponeInterruptsScope BASE_EMBEDDED { class PostponeInterruptsScope BASE_EMBEDDED {
public: public:
PostponeInterruptsScope(Isolate* isolate, explicit PostponeInterruptsScope(Isolate* isolate)
int intercept_mask = StackGuard::ALL_INTERRUPTS) : stack_guard_(isolate->stack_guard()), isolate_(isolate) {
: stack_guard_(isolate->stack_guard()), ExecutionAccess access(isolate_);
intercept_mask_(intercept_mask), stack_guard_->thread_local_.postpone_interrupts_nesting_++;
intercepted_flags_(0) { stack_guard_->DisableInterrupts();
stack_guard_->PushPostponeInterruptsScope(this);
} }
~PostponeInterruptsScope() { ~PostponeInterruptsScope() {
stack_guard_->PopPostponeInterruptsScope(); ExecutionAccess access(isolate_);
if (--stack_guard_->thread_local_.postpone_interrupts_nesting_ == 0) {
stack_guard_->EnableInterrupts();
}
} }
// Find the bottom-most scope that intercepts this interrupt.
// Return whether the interrupt has been intercepted.
bool Intercept(StackGuard::InterruptFlag flag);
private: private:
StackGuard* stack_guard_; StackGuard* stack_guard_;
int intercept_mask_; Isolate* isolate_;
int intercepted_flags_;
PostponeInterruptsScope* prev_;
friend class StackGuard;
}; };

View File

@ -403,59 +403,3 @@ TEST(TerminateFromOtherThreadWhileMicrotaskRunning) {
delete semaphore; delete semaphore;
semaphore = NULL; semaphore = NULL;
} }
static int callback_counter = 0;
static void CounterCallback(v8::Isolate* isolate, void* data) {
callback_counter++;
}
TEST(PostponeTerminateException) {
v8::Isolate* isolate = CcTest::isolate();
v8::HandleScope scope(isolate);
v8::Handle<v8::ObjectTemplate> global =
CreateGlobalTemplate(CcTest::isolate(), TerminateCurrentThread, DoLoop);
v8::Handle<v8::Context> context =
v8::Context::New(CcTest::isolate(), NULL, global);
v8::Context::Scope context_scope(context);
v8::TryCatch try_catch;
static const char* terminate_and_loop =
"terminate(); for (var i = 0; i < 10000; i++);";
{ // Postpone terminate execution interrupts.
i::PostponeInterruptsScope p1(CcTest::i_isolate(),
i::StackGuard::TERMINATE_EXECUTION) ;
// API interrupts should still be triggered.
CcTest::isolate()->RequestInterrupt(&CounterCallback, NULL);
CHECK_EQ(0, callback_counter);
CompileRun(terminate_and_loop);
CHECK(!try_catch.HasTerminated());
CHECK_EQ(1, callback_counter);
{ // Postpone API interrupts as well.
i::PostponeInterruptsScope p2(CcTest::i_isolate(),
i::StackGuard::API_INTERRUPT);
// None of the two interrupts should trigger.
CcTest::isolate()->RequestInterrupt(&CounterCallback, NULL);
CompileRun(terminate_and_loop);
CHECK(!try_catch.HasTerminated());
CHECK_EQ(1, callback_counter);
}
// Now the previously requested API interrupt should trigger.
CompileRun(terminate_and_loop);
CHECK(!try_catch.HasTerminated());
CHECK_EQ(2, callback_counter);
}
// Now the previously requested terminate execution interrupt should trigger.
CompileRun("for (var i = 0; i < 10000; i++);");
CHECK(try_catch.HasTerminated());
CHECK_EQ(2, callback_counter);
}