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:
parent
326bc2a533
commit
965f7037c8
@ -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");
|
||||||
}
|
}
|
||||||
|
@ -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_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -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
|
||||||
|
@ -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;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -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);
|
|
||||||
}
|
|
||||||
|
Loading…
Reference in New Issue
Block a user