| 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 |