OLD | NEW |
1 // Copyright 2014 the V8 project authors. All rights reserved. | 1 // Copyright 2014 the V8 project authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "src/execution.h" | 5 #include "src/execution.h" |
6 | 6 |
7 #include "src/bootstrapper.h" | 7 #include "src/bootstrapper.h" |
8 #include "src/codegen.h" | 8 #include "src/codegen.h" |
9 #include "src/deoptimizer.h" | 9 #include "src/deoptimizer.h" |
10 #include "src/isolate-inl.h" | 10 #include "src/isolate-inl.h" |
11 #include "src/vm-state-inl.h" | 11 #include "src/vm-state-inl.h" |
12 | 12 |
13 namespace v8 { | 13 namespace v8 { |
14 namespace internal { | 14 namespace internal { |
15 | 15 |
16 StackGuard::StackGuard() | 16 StackGuard::StackGuard() |
17 : isolate_(NULL) { | 17 : isolate_(NULL) { |
18 } | 18 } |
19 | 19 |
20 | 20 |
21 void StackGuard::set_interrupt_limits(const ExecutionAccess& lock) { | 21 void StackGuard::set_interrupt_limits(const ExecutionAccess& lock) { |
22 ASSERT(isolate_ != NULL); | 22 ASSERT(isolate_ != NULL); |
23 // Ignore attempts to interrupt when interrupts are postponed. | |
24 if (should_postpone_interrupts(lock)) return; | |
25 thread_local_.jslimit_ = kInterruptLimit; | 23 thread_local_.jslimit_ = kInterruptLimit; |
26 thread_local_.climit_ = kInterruptLimit; | 24 thread_local_.climit_ = kInterruptLimit; |
27 isolate_->heap()->SetStackLimits(); | 25 isolate_->heap()->SetStackLimits(); |
28 } | 26 } |
29 | 27 |
30 | 28 |
31 void StackGuard::reset_limits(const ExecutionAccess& lock) { | 29 void StackGuard::reset_limits(const ExecutionAccess& lock) { |
32 ASSERT(isolate_ != NULL); | 30 ASSERT(isolate_ != NULL); |
33 thread_local_.jslimit_ = thread_local_.real_jslimit_; | 31 thread_local_.jslimit_ = thread_local_.real_jslimit_; |
34 thread_local_.climit_ = thread_local_.real_climit_; | 32 thread_local_.climit_ = thread_local_.real_climit_; |
(...skipping 295 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
330 thread_local_.real_jslimit_ = jslimit; | 328 thread_local_.real_jslimit_ = jslimit; |
331 } | 329 } |
332 | 330 |
333 | 331 |
334 void StackGuard::DisableInterrupts() { | 332 void StackGuard::DisableInterrupts() { |
335 ExecutionAccess access(isolate_); | 333 ExecutionAccess access(isolate_); |
336 reset_limits(access); | 334 reset_limits(access); |
337 } | 335 } |
338 | 336 |
339 | 337 |
340 bool StackGuard::CheckInterrupt(int flagbit) { | 338 void StackGuard::PushPostponeInterruptsScope(PostponeInterruptsScope* scope) { |
341 ExecutionAccess access(isolate_); | 339 ExecutionAccess access(isolate_); |
342 return thread_local_.interrupt_flags_ & flagbit; | 340 scope->prev_ = thread_local_.postpone_interrupts_; |
| 341 thread_local_.postpone_interrupts_ = scope; |
343 } | 342 } |
344 | 343 |
345 | 344 |
346 void StackGuard::RequestInterrupt(int flagbit) { | 345 void StackGuard::PopPostponeInterruptsScope() { |
347 ExecutionAccess access(isolate_); | 346 ExecutionAccess access(isolate_); |
348 thread_local_.interrupt_flags_ |= flagbit; | 347 PostponeInterruptsScope* top = thread_local_.postpone_interrupts_; |
| 348 thread_local_.interrupt_flags_ |= top->intercepted_flags_; |
| 349 thread_local_.postpone_interrupts_ = top->prev_; |
| 350 if (has_pending_interrupts(access)) set_interrupt_limits(access); |
| 351 } |
| 352 |
| 353 |
| 354 bool StackGuard::CheckInterrupt(InterruptFlag flag) { |
| 355 ExecutionAccess access(isolate_); |
| 356 return thread_local_.interrupt_flags_ & flag; |
| 357 } |
| 358 |
| 359 |
| 360 void StackGuard::RequestInterrupt(InterruptFlag flag) { |
| 361 ExecutionAccess access(isolate_); |
| 362 // Check the chain of PostponeInterruptsScopes for interception. |
| 363 if (thread_local_.postpone_interrupts_ && |
| 364 thread_local_.postpone_interrupts_->Intercept(flag)) { |
| 365 return; |
| 366 } |
| 367 |
| 368 // Not intercepted. Set as active interrupt flag. |
| 369 thread_local_.interrupt_flags_ |= flag; |
349 set_interrupt_limits(access); | 370 set_interrupt_limits(access); |
350 } | 371 } |
351 | 372 |
352 | 373 |
353 void StackGuard::ClearInterrupt(int flagbit) { | 374 void StackGuard::ClearInterrupt(InterruptFlag flag) { |
354 ExecutionAccess access(isolate_); | 375 ExecutionAccess access(isolate_); |
355 thread_local_.interrupt_flags_ &= ~flagbit; | 376 // Clear the interrupt flag from the chain of PostponeInterruptsScopes. |
356 if (!should_postpone_interrupts(access) && !has_pending_interrupts(access)) { | 377 for (PostponeInterruptsScope* current = thread_local_.postpone_interrupts_; |
357 reset_limits(access); | 378 current != NULL; |
| 379 current = current->prev_) { |
| 380 current->intercepted_flags_ &= ~flag; |
358 } | 381 } |
| 382 |
| 383 // Clear the interrupt flag from the active interrupt flags. |
| 384 thread_local_.interrupt_flags_ &= ~flag; |
| 385 if (!has_pending_interrupts(access)) reset_limits(access); |
359 } | 386 } |
360 | 387 |
361 | 388 |
362 bool StackGuard::CheckAndClearInterrupt(InterruptFlag flag) { | 389 bool StackGuard::CheckAndClearInterrupt(InterruptFlag flag) { |
363 ExecutionAccess access(isolate_); | 390 ExecutionAccess access(isolate_); |
364 int flagbit = 1 << flag; | 391 bool result = (thread_local_.interrupt_flags_ & flag); |
365 bool result = (thread_local_.interrupt_flags_ & flagbit); | 392 thread_local_.interrupt_flags_ &= ~flag; |
366 thread_local_.interrupt_flags_ &= ~flagbit; | 393 if (!has_pending_interrupts(access)) reset_limits(access); |
367 if (!should_postpone_interrupts(access) && !has_pending_interrupts(access)) { | |
368 reset_limits(access); | |
369 } | |
370 return result; | 394 return result; |
371 } | 395 } |
372 | 396 |
373 | 397 |
374 char* StackGuard::ArchiveStackGuard(char* to) { | 398 char* StackGuard::ArchiveStackGuard(char* to) { |
375 ExecutionAccess access(isolate_); | 399 ExecutionAccess access(isolate_); |
376 MemCopy(to, reinterpret_cast<char*>(&thread_local_), sizeof(ThreadLocal)); | 400 MemCopy(to, reinterpret_cast<char*>(&thread_local_), sizeof(ThreadLocal)); |
377 ThreadLocal blank; | 401 ThreadLocal blank; |
378 | 402 |
379 // Set the stack limits using the old thread_local_. | 403 // Set the stack limits using the old thread_local_. |
(...skipping 21 matching lines...) Expand all Loading... |
401 isolate_->FindOrAllocatePerThreadDataForThisThread(); | 425 isolate_->FindOrAllocatePerThreadDataForThisThread(); |
402 per_thread->set_stack_limit(thread_local_.real_climit_); | 426 per_thread->set_stack_limit(thread_local_.real_climit_); |
403 } | 427 } |
404 | 428 |
405 | 429 |
406 void StackGuard::ThreadLocal::Clear() { | 430 void StackGuard::ThreadLocal::Clear() { |
407 real_jslimit_ = kIllegalLimit; | 431 real_jslimit_ = kIllegalLimit; |
408 jslimit_ = kIllegalLimit; | 432 jslimit_ = kIllegalLimit; |
409 real_climit_ = kIllegalLimit; | 433 real_climit_ = kIllegalLimit; |
410 climit_ = kIllegalLimit; | 434 climit_ = kIllegalLimit; |
411 nesting_ = 0; | 435 postpone_interrupts_ = NULL; |
412 postpone_interrupts_nesting_ = 0; | |
413 interrupt_flags_ = 0; | 436 interrupt_flags_ = 0; |
414 } | 437 } |
415 | 438 |
416 | 439 |
417 bool StackGuard::ThreadLocal::Initialize(Isolate* isolate) { | 440 bool StackGuard::ThreadLocal::Initialize(Isolate* isolate) { |
418 bool should_set_stack_limits = false; | 441 bool should_set_stack_limits = false; |
419 if (real_climit_ == kIllegalLimit) { | 442 if (real_climit_ == kIllegalLimit) { |
420 // Takes the address of the limit variable in order to find out where | 443 // Takes the address of the limit variable in order to find out where |
421 // the top of stack is right now. | 444 // the top of stack is right now. |
422 const uintptr_t kLimitSize = FLAG_stack_size * KB; | 445 const uintptr_t kLimitSize = FLAG_stack_size * KB; |
423 uintptr_t limit = reinterpret_cast<uintptr_t>(&limit) - kLimitSize; | 446 uintptr_t limit = reinterpret_cast<uintptr_t>(&limit) - kLimitSize; |
424 ASSERT(reinterpret_cast<uintptr_t>(&limit) > kLimitSize); | 447 ASSERT(reinterpret_cast<uintptr_t>(&limit) > kLimitSize); |
425 real_jslimit_ = SimulatorStack::JsLimitFromCLimit(isolate, limit); | 448 real_jslimit_ = SimulatorStack::JsLimitFromCLimit(isolate, limit); |
426 jslimit_ = SimulatorStack::JsLimitFromCLimit(isolate, limit); | 449 jslimit_ = SimulatorStack::JsLimitFromCLimit(isolate, limit); |
427 real_climit_ = limit; | 450 real_climit_ = limit; |
428 climit_ = limit; | 451 climit_ = limit; |
429 should_set_stack_limits = true; | 452 should_set_stack_limits = true; |
430 } | 453 } |
431 nesting_ = 0; | 454 postpone_interrupts_ = NULL; |
432 postpone_interrupts_nesting_ = 0; | |
433 interrupt_flags_ = 0; | 455 interrupt_flags_ = 0; |
434 return should_set_stack_limits; | 456 return should_set_stack_limits; |
435 } | 457 } |
436 | 458 |
437 | 459 |
438 void StackGuard::ClearThread(const ExecutionAccess& lock) { | 460 void StackGuard::ClearThread(const ExecutionAccess& lock) { |
439 thread_local_.Clear(); | 461 thread_local_.Clear(); |
440 isolate_->heap()->SetStackLimits(); | 462 isolate_->heap()->SetStackLimits(); |
441 } | 463 } |
442 | 464 |
(...skipping 198 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
641 Handle<Object> result; | 663 Handle<Object> result; |
642 if (!maybe_result.ToHandle(&result) || !result->IsString()) { | 664 if (!maybe_result.ToHandle(&result) || !result->IsString()) { |
643 return isolate->factory()->empty_string(); | 665 return isolate->factory()->empty_string(); |
644 } | 666 } |
645 | 667 |
646 return Handle<String>::cast(result); | 668 return Handle<String>::cast(result); |
647 } | 669 } |
648 | 670 |
649 | 671 |
650 Object* StackGuard::HandleInterrupts() { | 672 Object* StackGuard::HandleInterrupts() { |
651 { | |
652 ExecutionAccess access(isolate_); | |
653 if (should_postpone_interrupts(access)) { | |
654 return isolate_->heap()->undefined_value(); | |
655 } | |
656 } | |
657 | |
658 if (CheckAndClearInterrupt(GC_REQUEST)) { | 673 if (CheckAndClearInterrupt(GC_REQUEST)) { |
659 isolate_->heap()->CollectAllGarbage(Heap::kNoGCFlags, "GC interrupt"); | 674 isolate_->heap()->CollectAllGarbage(Heap::kNoGCFlags, "GC interrupt"); |
660 } | 675 } |
661 | 676 |
662 if (CheckDebugBreak() || CheckDebugCommand()) { | 677 if (CheckDebugBreak() || CheckDebugCommand()) { |
663 isolate_->debug()->HandleDebugBreak(); | 678 isolate_->debug()->HandleDebugBreak(); |
664 } | 679 } |
665 | 680 |
666 if (CheckAndClearInterrupt(TERMINATE_EXECUTION)) { | 681 if (CheckAndClearInterrupt(TERMINATE_EXECUTION)) { |
667 return isolate_->TerminateExecution(); | 682 return isolate_->TerminateExecution(); |
(...skipping 14 matching lines...) Expand all Loading... |
682 } | 697 } |
683 | 698 |
684 isolate_->counters()->stack_interrupts()->Increment(); | 699 isolate_->counters()->stack_interrupts()->Increment(); |
685 isolate_->counters()->runtime_profiler_ticks()->Increment(); | 700 isolate_->counters()->runtime_profiler_ticks()->Increment(); |
686 isolate_->runtime_profiler()->OptimizeNow(); | 701 isolate_->runtime_profiler()->OptimizeNow(); |
687 | 702 |
688 return isolate_->heap()->undefined_value(); | 703 return isolate_->heap()->undefined_value(); |
689 } | 704 } |
690 | 705 |
691 } } // namespace v8::internal | 706 } } // namespace v8::internal |
OLD | NEW |