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 // Intercept already requested interrupts. |
| 341 int intercepted = thread_local_.interrupt_flags_ & scope->intercept_mask_; |
| 342 scope->intercepted_flags_ = intercepted; |
| 343 thread_local_.interrupt_flags_ &= ~intercepted; |
| 344 if (!has_pending_interrupts(access)) reset_limits(access); |
| 345 // Add scope to the chain. |
| 346 scope->prev_ = thread_local_.postpone_interrupts_; |
| 347 thread_local_.postpone_interrupts_ = scope; |
343 } | 348 } |
344 | 349 |
345 | 350 |
346 void StackGuard::RequestInterrupt(int flagbit) { | 351 void StackGuard::PopPostponeInterruptsScope() { |
347 ExecutionAccess access(isolate_); | 352 ExecutionAccess access(isolate_); |
348 thread_local_.interrupt_flags_ |= flagbit; | 353 PostponeInterruptsScope* top = thread_local_.postpone_interrupts_; |
| 354 // Make intercepted interrupts active. |
| 355 ASSERT((thread_local_.interrupt_flags_ & top->intercept_mask_) == 0); |
| 356 thread_local_.interrupt_flags_ |= top->intercepted_flags_; |
| 357 if (has_pending_interrupts(access)) set_interrupt_limits(access); |
| 358 // Remove scope from chain. |
| 359 thread_local_.postpone_interrupts_ = top->prev_; |
| 360 } |
| 361 |
| 362 |
| 363 bool StackGuard::CheckInterrupt(InterruptFlag flag) { |
| 364 ExecutionAccess access(isolate_); |
| 365 return thread_local_.interrupt_flags_ & flag; |
| 366 } |
| 367 |
| 368 |
| 369 void StackGuard::RequestInterrupt(InterruptFlag flag) { |
| 370 ExecutionAccess access(isolate_); |
| 371 // Check the chain of PostponeInterruptsScopes for interception. |
| 372 if (thread_local_.postpone_interrupts_ && |
| 373 thread_local_.postpone_interrupts_->Intercept(flag)) { |
| 374 return; |
| 375 } |
| 376 |
| 377 // Not intercepted. Set as active interrupt flag. |
| 378 thread_local_.interrupt_flags_ |= flag; |
349 set_interrupt_limits(access); | 379 set_interrupt_limits(access); |
350 } | 380 } |
351 | 381 |
352 | 382 |
353 void StackGuard::ClearInterrupt(int flagbit) { | 383 void StackGuard::ClearInterrupt(InterruptFlag flag) { |
354 ExecutionAccess access(isolate_); | 384 ExecutionAccess access(isolate_); |
355 thread_local_.interrupt_flags_ &= ~flagbit; | 385 // Clear the interrupt flag from the chain of PostponeInterruptsScopes. |
356 if (!should_postpone_interrupts(access) && !has_pending_interrupts(access)) { | 386 for (PostponeInterruptsScope* current = thread_local_.postpone_interrupts_; |
357 reset_limits(access); | 387 current != NULL; |
| 388 current = current->prev_) { |
| 389 current->intercepted_flags_ &= ~flag; |
358 } | 390 } |
| 391 |
| 392 // Clear the interrupt flag from the active interrupt flags. |
| 393 thread_local_.interrupt_flags_ &= ~flag; |
| 394 if (!has_pending_interrupts(access)) reset_limits(access); |
359 } | 395 } |
360 | 396 |
361 | 397 |
362 bool StackGuard::CheckAndClearInterrupt(InterruptFlag flag) { | 398 bool StackGuard::CheckAndClearInterrupt(InterruptFlag flag) { |
363 ExecutionAccess access(isolate_); | 399 ExecutionAccess access(isolate_); |
364 int flagbit = 1 << flag; | 400 bool result = (thread_local_.interrupt_flags_ & flag); |
365 bool result = (thread_local_.interrupt_flags_ & flagbit); | 401 thread_local_.interrupt_flags_ &= ~flag; |
366 thread_local_.interrupt_flags_ &= ~flagbit; | 402 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; | 403 return result; |
371 } | 404 } |
372 | 405 |
373 | 406 |
374 char* StackGuard::ArchiveStackGuard(char* to) { | 407 char* StackGuard::ArchiveStackGuard(char* to) { |
375 ExecutionAccess access(isolate_); | 408 ExecutionAccess access(isolate_); |
376 MemCopy(to, reinterpret_cast<char*>(&thread_local_), sizeof(ThreadLocal)); | 409 MemCopy(to, reinterpret_cast<char*>(&thread_local_), sizeof(ThreadLocal)); |
377 ThreadLocal blank; | 410 ThreadLocal blank; |
378 | 411 |
379 // Set the stack limits using the old thread_local_. | 412 // Set the stack limits using the old thread_local_. |
(...skipping 21 matching lines...) Expand all Loading... |
401 isolate_->FindOrAllocatePerThreadDataForThisThread(); | 434 isolate_->FindOrAllocatePerThreadDataForThisThread(); |
402 per_thread->set_stack_limit(thread_local_.real_climit_); | 435 per_thread->set_stack_limit(thread_local_.real_climit_); |
403 } | 436 } |
404 | 437 |
405 | 438 |
406 void StackGuard::ThreadLocal::Clear() { | 439 void StackGuard::ThreadLocal::Clear() { |
407 real_jslimit_ = kIllegalLimit; | 440 real_jslimit_ = kIllegalLimit; |
408 jslimit_ = kIllegalLimit; | 441 jslimit_ = kIllegalLimit; |
409 real_climit_ = kIllegalLimit; | 442 real_climit_ = kIllegalLimit; |
410 climit_ = kIllegalLimit; | 443 climit_ = kIllegalLimit; |
411 nesting_ = 0; | 444 postpone_interrupts_ = NULL; |
412 postpone_interrupts_nesting_ = 0; | |
413 interrupt_flags_ = 0; | 445 interrupt_flags_ = 0; |
414 } | 446 } |
415 | 447 |
416 | 448 |
417 bool StackGuard::ThreadLocal::Initialize(Isolate* isolate) { | 449 bool StackGuard::ThreadLocal::Initialize(Isolate* isolate) { |
418 bool should_set_stack_limits = false; | 450 bool should_set_stack_limits = false; |
419 if (real_climit_ == kIllegalLimit) { | 451 if (real_climit_ == kIllegalLimit) { |
420 // Takes the address of the limit variable in order to find out where | 452 // Takes the address of the limit variable in order to find out where |
421 // the top of stack is right now. | 453 // the top of stack is right now. |
422 const uintptr_t kLimitSize = FLAG_stack_size * KB; | 454 const uintptr_t kLimitSize = FLAG_stack_size * KB; |
423 uintptr_t limit = reinterpret_cast<uintptr_t>(&limit) - kLimitSize; | 455 uintptr_t limit = reinterpret_cast<uintptr_t>(&limit) - kLimitSize; |
424 ASSERT(reinterpret_cast<uintptr_t>(&limit) > kLimitSize); | 456 ASSERT(reinterpret_cast<uintptr_t>(&limit) > kLimitSize); |
425 real_jslimit_ = SimulatorStack::JsLimitFromCLimit(isolate, limit); | 457 real_jslimit_ = SimulatorStack::JsLimitFromCLimit(isolate, limit); |
426 jslimit_ = SimulatorStack::JsLimitFromCLimit(isolate, limit); | 458 jslimit_ = SimulatorStack::JsLimitFromCLimit(isolate, limit); |
427 real_climit_ = limit; | 459 real_climit_ = limit; |
428 climit_ = limit; | 460 climit_ = limit; |
429 should_set_stack_limits = true; | 461 should_set_stack_limits = true; |
430 } | 462 } |
431 nesting_ = 0; | 463 postpone_interrupts_ = NULL; |
432 postpone_interrupts_nesting_ = 0; | |
433 interrupt_flags_ = 0; | 464 interrupt_flags_ = 0; |
434 return should_set_stack_limits; | 465 return should_set_stack_limits; |
435 } | 466 } |
436 | 467 |
437 | 468 |
438 void StackGuard::ClearThread(const ExecutionAccess& lock) { | 469 void StackGuard::ClearThread(const ExecutionAccess& lock) { |
439 thread_local_.Clear(); | 470 thread_local_.Clear(); |
440 isolate_->heap()->SetStackLimits(); | 471 isolate_->heap()->SetStackLimits(); |
441 } | 472 } |
442 | 473 |
(...skipping 198 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
641 Handle<Object> result; | 672 Handle<Object> result; |
642 if (!maybe_result.ToHandle(&result) || !result->IsString()) { | 673 if (!maybe_result.ToHandle(&result) || !result->IsString()) { |
643 return isolate->factory()->empty_string(); | 674 return isolate->factory()->empty_string(); |
644 } | 675 } |
645 | 676 |
646 return Handle<String>::cast(result); | 677 return Handle<String>::cast(result); |
647 } | 678 } |
648 | 679 |
649 | 680 |
650 Object* StackGuard::HandleInterrupts() { | 681 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)) { | 682 if (CheckAndClearInterrupt(GC_REQUEST)) { |
659 isolate_->heap()->CollectAllGarbage(Heap::kNoGCFlags, "GC interrupt"); | 683 isolate_->heap()->CollectAllGarbage(Heap::kNoGCFlags, "GC interrupt"); |
660 } | 684 } |
661 | 685 |
662 if (CheckDebugBreak() || CheckDebugCommand()) { | 686 if (CheckDebugBreak() || CheckDebugCommand()) { |
663 isolate_->debug()->HandleDebugBreak(); | 687 isolate_->debug()->HandleDebugBreak(); |
664 } | 688 } |
665 | 689 |
666 if (CheckAndClearInterrupt(TERMINATE_EXECUTION)) { | 690 if (CheckAndClearInterrupt(TERMINATE_EXECUTION)) { |
667 return isolate_->TerminateExecution(); | 691 return isolate_->TerminateExecution(); |
(...skipping 14 matching lines...) Expand all Loading... |
682 } | 706 } |
683 | 707 |
684 isolate_->counters()->stack_interrupts()->Increment(); | 708 isolate_->counters()->stack_interrupts()->Increment(); |
685 isolate_->counters()->runtime_profiler_ticks()->Increment(); | 709 isolate_->counters()->runtime_profiler_ticks()->Increment(); |
686 isolate_->runtime_profiler()->OptimizeNow(); | 710 isolate_->runtime_profiler()->OptimizeNow(); |
687 | 711 |
688 return isolate_->heap()->undefined_value(); | 712 return isolate_->heap()->undefined_value(); |
689 } | 713 } |
690 | 714 |
691 } } // namespace v8::internal | 715 } } // namespace v8::internal |
OLD | NEW |