Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(59)

Side by Side Diff: src/execution.cc

Issue 264233005: Clean up stack guard interrupts. (Closed) Base URL: https://v8.googlecode.com/svn/branches/bleeding_edge
Patch Set: addressed comments Created 6 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « src/execution.h ('k') | src/heap.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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 "execution.h" 5 #include "execution.h"
6 6
7 #include "bootstrapper.h" 7 #include "bootstrapper.h"
8 #include "codegen.h" 8 #include "codegen.h"
9 #include "deoptimizer.h" 9 #include "deoptimizer.h"
10 #include "isolate-inl.h" 10 #include "isolate-inl.h"
(...skipping 348 matching lines...) Expand 10 before | Expand all | Expand 10 after
359 thread_local_.real_jslimit_ = jslimit; 359 thread_local_.real_jslimit_ = jslimit;
360 } 360 }
361 361
362 362
363 void StackGuard::DisableInterrupts() { 363 void StackGuard::DisableInterrupts() {
364 ExecutionAccess access(isolate_); 364 ExecutionAccess access(isolate_);
365 reset_limits(access); 365 reset_limits(access);
366 } 366 }
367 367
368 368
369 bool StackGuard::ShouldPostponeInterrupts() { 369 bool StackGuard::CheckInterrupt(int flagbit) {
370 ExecutionAccess access(isolate_); 370 ExecutionAccess access(isolate_);
371 return should_postpone_interrupts(access); 371 return thread_local_.interrupt_flags_ & flagbit;
372 } 372 }
373 373
374 374
375 bool StackGuard::IsInterrupted() { 375 void StackGuard::RequestInterrupt(int flagbit) {
376 ExecutionAccess access(isolate_); 376 ExecutionAccess access(isolate_);
377 return (thread_local_.interrupt_flags_ & INTERRUPT) != 0; 377 thread_local_.interrupt_flags_ |= flagbit;
378 }
379
380
381 void StackGuard::Interrupt() {
382 ExecutionAccess access(isolate_);
383 thread_local_.interrupt_flags_ |= INTERRUPT;
384 set_interrupt_limits(access); 378 set_interrupt_limits(access);
385 } 379 }
386 380
387 381
388 bool StackGuard::IsPreempted() { 382 void StackGuard::ClearInterrupt(int flagbit) {
389 ExecutionAccess access(isolate_); 383 ExecutionAccess access(isolate_);
390 return thread_local_.interrupt_flags_ & PREEMPT; 384 thread_local_.interrupt_flags_ &= ~flagbit;
391 }
392
393
394 void StackGuard::Preempt() {
395 ExecutionAccess access(isolate_);
396 thread_local_.interrupt_flags_ |= PREEMPT;
397 set_interrupt_limits(access);
398 }
399
400
401 bool StackGuard::IsTerminateExecution() {
402 ExecutionAccess access(isolate_);
403 return (thread_local_.interrupt_flags_ & TERMINATE) != 0;
404 }
405
406
407 void StackGuard::CancelTerminateExecution() {
408 ExecutionAccess access(isolate_);
409 Continue(TERMINATE);
410 isolate_->CancelTerminateExecution();
411 }
412
413
414 void StackGuard::TerminateExecution() {
415 ExecutionAccess access(isolate_);
416 thread_local_.interrupt_flags_ |= TERMINATE;
417 set_interrupt_limits(access);
418 }
419
420
421 bool StackGuard::IsGCRequest() {
422 ExecutionAccess access(isolate_);
423 return (thread_local_.interrupt_flags_ & GC_REQUEST) != 0;
424 }
425
426
427 void StackGuard::RequestGC() {
428 ExecutionAccess access(isolate_);
429 thread_local_.interrupt_flags_ |= GC_REQUEST;
430 if (thread_local_.postpone_interrupts_nesting_ == 0) {
431 thread_local_.jslimit_ = thread_local_.climit_ = kInterruptLimit;
432 isolate_->heap()->SetStackLimits();
433 }
434 }
435
436
437 bool StackGuard::IsInstallCodeRequest() {
438 ExecutionAccess access(isolate_);
439 return (thread_local_.interrupt_flags_ & INSTALL_CODE) != 0;
440 }
441
442
443 void StackGuard::RequestInstallCode() {
444 ExecutionAccess access(isolate_);
445 thread_local_.interrupt_flags_ |= INSTALL_CODE;
446 if (thread_local_.postpone_interrupts_nesting_ == 0) {
447 thread_local_.jslimit_ = thread_local_.climit_ = kInterruptLimit;
448 isolate_->heap()->SetStackLimits();
449 }
450 }
451
452
453 bool StackGuard::IsFullDeopt() {
454 ExecutionAccess access(isolate_);
455 return (thread_local_.interrupt_flags_ & FULL_DEOPT) != 0;
456 }
457
458
459 void StackGuard::FullDeopt() {
460 ExecutionAccess access(isolate_);
461 thread_local_.interrupt_flags_ |= FULL_DEOPT;
462 set_interrupt_limits(access);
463 }
464
465
466 bool StackGuard::IsDeoptMarkedAllocationSites() {
467 ExecutionAccess access(isolate_);
468 return (thread_local_.interrupt_flags_ & DEOPT_MARKED_ALLOCATION_SITES) != 0;
469 }
470
471
472 void StackGuard::DeoptMarkedAllocationSites() {
473 ExecutionAccess access(isolate_);
474 thread_local_.interrupt_flags_ |= DEOPT_MARKED_ALLOCATION_SITES;
475 set_interrupt_limits(access);
476 }
477
478
479 bool StackGuard::IsDebugBreak() {
480 ExecutionAccess access(isolate_);
481 return thread_local_.interrupt_flags_ & DEBUGBREAK;
482 }
483
484
485 void StackGuard::DebugBreak() {
486 ExecutionAccess access(isolate_);
487 thread_local_.interrupt_flags_ |= DEBUGBREAK;
488 set_interrupt_limits(access);
489 }
490
491
492 bool StackGuard::IsDebugCommand() {
493 ExecutionAccess access(isolate_);
494 return thread_local_.interrupt_flags_ & DEBUGCOMMAND;
495 }
496
497
498 void StackGuard::DebugCommand() {
499 ExecutionAccess access(isolate_);
500 thread_local_.interrupt_flags_ |= DEBUGCOMMAND;
501 set_interrupt_limits(access);
502 }
503
504
505 void StackGuard::Continue(InterruptFlag after_what) {
506 ExecutionAccess access(isolate_);
507 thread_local_.interrupt_flags_ &= ~static_cast<int>(after_what);
508 if (!should_postpone_interrupts(access) && !has_pending_interrupts(access)) { 385 if (!should_postpone_interrupts(access) && !has_pending_interrupts(access)) {
509 reset_limits(access); 386 reset_limits(access);
510 } 387 }
511 } 388 }
512 389
513 390
514 void StackGuard::RequestInterrupt(InterruptCallback callback, void* data) { 391 bool StackGuard::CheckAndClearInterrupt(InterruptFlag flag,
515 ExecutionAccess access(isolate_); 392 const ExecutionAccess& lock) {
516 thread_local_.interrupt_flags_ |= API_INTERRUPT; 393 int flagbit = 1 << flag;
517 thread_local_.interrupt_callback_ = callback; 394 bool result = (thread_local_.interrupt_flags_ & flagbit);
518 thread_local_.interrupt_callback_data_ = data; 395 thread_local_.interrupt_flags_ &= ~flagbit;
519 set_interrupt_limits(access); 396 if (!should_postpone_interrupts(lock) && !has_pending_interrupts(lock)) {
397 reset_limits(lock);
398 }
399 return result;
520 } 400 }
521 401
522 402
523 void StackGuard::ClearInterrupt() {
524 thread_local_.interrupt_callback_ = 0;
525 thread_local_.interrupt_callback_data_ = 0;
526 Continue(API_INTERRUPT);
527 }
528
529
530 bool StackGuard::IsAPIInterrupt() {
531 ExecutionAccess access(isolate_);
532 return thread_local_.interrupt_flags_ & API_INTERRUPT;
533 }
534
535
536 void StackGuard::InvokeInterruptCallback() {
537 InterruptCallback callback = 0;
538 void* data = 0;
539
540 {
541 ExecutionAccess access(isolate_);
542 callback = thread_local_.interrupt_callback_;
543 data = thread_local_.interrupt_callback_data_;
544 thread_local_.interrupt_callback_ = NULL;
545 thread_local_.interrupt_callback_data_ = NULL;
546 }
547
548 if (callback != NULL) {
549 VMState<EXTERNAL> state(isolate_);
550 HandleScope handle_scope(isolate_);
551 callback(reinterpret_cast<v8::Isolate*>(isolate_), data);
552 }
553 }
554
555
556 char* StackGuard::ArchiveStackGuard(char* to) { 403 char* StackGuard::ArchiveStackGuard(char* to) {
557 ExecutionAccess access(isolate_); 404 ExecutionAccess access(isolate_);
558 OS::MemCopy(to, reinterpret_cast<char*>(&thread_local_), sizeof(ThreadLocal)); 405 OS::MemCopy(to, reinterpret_cast<char*>(&thread_local_), sizeof(ThreadLocal));
559 ThreadLocal blank; 406 ThreadLocal blank;
560 407
561 // Set the stack limits using the old thread_local_. 408 // Set the stack limits using the old thread_local_.
562 // TODO(isolates): This was the old semantics of constructing a ThreadLocal 409 // TODO(isolates): This was the old semantics of constructing a ThreadLocal
563 // (as the ctor called SetStackLimits, which looked at the 410 // (as the ctor called SetStackLimits, which looked at the
564 // current thread_local_ from StackGuard)-- but is this 411 // current thread_local_ from StackGuard)-- but is this
565 // really what was intended? 412 // really what was intended?
(...skipping 21 matching lines...) Expand all
587 434
588 435
589 void StackGuard::ThreadLocal::Clear() { 436 void StackGuard::ThreadLocal::Clear() {
590 real_jslimit_ = kIllegalLimit; 437 real_jslimit_ = kIllegalLimit;
591 jslimit_ = kIllegalLimit; 438 jslimit_ = kIllegalLimit;
592 real_climit_ = kIllegalLimit; 439 real_climit_ = kIllegalLimit;
593 climit_ = kIllegalLimit; 440 climit_ = kIllegalLimit;
594 nesting_ = 0; 441 nesting_ = 0;
595 postpone_interrupts_nesting_ = 0; 442 postpone_interrupts_nesting_ = 0;
596 interrupt_flags_ = 0; 443 interrupt_flags_ = 0;
597 interrupt_callback_ = NULL;
598 interrupt_callback_data_ = NULL;
599 } 444 }
600 445
601 446
602 bool StackGuard::ThreadLocal::Initialize(Isolate* isolate) { 447 bool StackGuard::ThreadLocal::Initialize(Isolate* isolate) {
603 bool should_set_stack_limits = false; 448 bool should_set_stack_limits = false;
604 if (real_climit_ == kIllegalLimit) { 449 if (real_climit_ == kIllegalLimit) {
605 // Takes the address of the limit variable in order to find out where 450 // Takes the address of the limit variable in order to find out where
606 // the top of stack is right now. 451 // the top of stack is right now.
607 const uintptr_t kLimitSize = FLAG_stack_size * KB; 452 const uintptr_t kLimitSize = FLAG_stack_size * KB;
608 uintptr_t limit = reinterpret_cast<uintptr_t>(&limit) - kLimitSize; 453 uintptr_t limit = reinterpret_cast<uintptr_t>(&limit) - kLimitSize;
609 ASSERT(reinterpret_cast<uintptr_t>(&limit) > kLimitSize); 454 ASSERT(reinterpret_cast<uintptr_t>(&limit) > kLimitSize);
610 real_jslimit_ = SimulatorStack::JsLimitFromCLimit(isolate, limit); 455 real_jslimit_ = SimulatorStack::JsLimitFromCLimit(isolate, limit);
611 jslimit_ = SimulatorStack::JsLimitFromCLimit(isolate, limit); 456 jslimit_ = SimulatorStack::JsLimitFromCLimit(isolate, limit);
612 real_climit_ = limit; 457 real_climit_ = limit;
613 climit_ = limit; 458 climit_ = limit;
614 should_set_stack_limits = true; 459 should_set_stack_limits = true;
615 } 460 }
616 nesting_ = 0; 461 nesting_ = 0;
617 postpone_interrupts_nesting_ = 0; 462 postpone_interrupts_nesting_ = 0;
618 interrupt_flags_ = 0; 463 interrupt_flags_ = 0;
619 interrupt_callback_ = NULL;
620 interrupt_callback_data_ = NULL;
621 return should_set_stack_limits; 464 return should_set_stack_limits;
622 } 465 }
623 466
624 467
625 void StackGuard::ClearThread(const ExecutionAccess& lock) { 468 void StackGuard::ClearThread(const ExecutionAccess& lock) {
626 thread_local_.Clear(); 469 thread_local_.Clear();
627 isolate_->heap()->SetStackLimits(); 470 isolate_->heap()->SetStackLimits();
628 } 471 }
629 472
630 473
(...skipping 196 matching lines...) Expand 10 before | Expand all | Expand 10 after
827 args); 670 args);
828 Handle<Object> result; 671 Handle<Object> result;
829 if (!maybe_result.ToHandle(&result) || !result->IsString()) { 672 if (!maybe_result.ToHandle(&result) || !result->IsString()) {
830 return isolate->factory()->empty_string(); 673 return isolate->factory()->empty_string();
831 } 674 }
832 675
833 return Handle<String>::cast(result); 676 return Handle<String>::cast(result);
834 } 677 }
835 678
836 679
837 static Object* RuntimePreempt(Isolate* isolate) { 680 void Execution::DebugBreakHelper(Isolate* isolate) {
838 // Clear the preempt request flag.
839 isolate->stack_guard()->Continue(PREEMPT);
840
841 if (isolate->debug()->InDebugger()) {
842 // If currently in the debugger don't do any actual preemption but record
843 // that preemption occoured while in the debugger.
844 isolate->debug()->PreemptionWhileInDebugger();
845 } else {
846 // Perform preemption.
847 v8::Unlocker unlocker(reinterpret_cast<v8::Isolate*>(isolate));
848 Thread::YieldCPU();
849 }
850
851 return isolate->heap()->undefined_value();
852 }
853
854
855 Object* Execution::DebugBreakHelper(Isolate* isolate) {
856 // Just continue if breaks are disabled. 681 // Just continue if breaks are disabled.
857 if (isolate->debug()->disable_break()) { 682 if (isolate->debug()->disable_break()) return;
858 return isolate->heap()->undefined_value();
859 }
860 683
861 // Ignore debug break during bootstrapping. 684 // Ignore debug break during bootstrapping.
862 if (isolate->bootstrapper()->IsActive()) { 685 if (isolate->bootstrapper()->IsActive()) return;
863 return isolate->heap()->undefined_value();
864 }
865 686
866 // Ignore debug break if debugger is not active. 687 // Ignore debug break if debugger is not active.
867 if (!isolate->debugger()->IsDebuggerActive()) { 688 if (!isolate->debugger()->IsDebuggerActive()) return;
868 return isolate->heap()->undefined_value();
869 }
870 689
871 StackLimitCheck check(isolate); 690 StackLimitCheck check(isolate);
872 if (check.HasOverflowed()) { 691 if (check.HasOverflowed()) return;
873 return isolate->heap()->undefined_value();
874 }
875 692
876 { 693 { JavaScriptFrameIterator it(isolate);
877 JavaScriptFrameIterator it(isolate);
878 ASSERT(!it.done()); 694 ASSERT(!it.done());
879 Object* fun = it.frame()->function(); 695 Object* fun = it.frame()->function();
880 if (fun && fun->IsJSFunction()) { 696 if (fun && fun->IsJSFunction()) {
881 // Don't stop in builtin functions. 697 // Don't stop in builtin functions.
882 if (JSFunction::cast(fun)->IsBuiltin()) { 698 if (JSFunction::cast(fun)->IsBuiltin()) return;
883 return isolate->heap()->undefined_value();
884 }
885 GlobalObject* global = JSFunction::cast(fun)->context()->global_object(); 699 GlobalObject* global = JSFunction::cast(fun)->context()->global_object();
886 // Don't stop in debugger functions. 700 // Don't stop in debugger functions.
887 if (isolate->debug()->IsDebugGlobal(global)) { 701 if (isolate->debug()->IsDebugGlobal(global)) return;
888 return isolate->heap()->undefined_value();
889 }
890 } 702 }
891 } 703 }
892 704
893 // Collect the break state before clearing the flags. 705 // Collect the break state before clearing the flags.
894 bool debug_command_only = 706 bool debug_command_only = isolate->stack_guard()->CheckDebugCommand() &&
895 isolate->stack_guard()->IsDebugCommand() && 707 !isolate->stack_guard()->CheckDebugBreak();
896 !isolate->stack_guard()->IsDebugBreak();
897 708
898 // Clear the debug break request flag. 709 isolate->stack_guard()->ClearDebugBreak();
899 isolate->stack_guard()->Continue(DEBUGBREAK);
900 710
901 ProcessDebugMessages(isolate, debug_command_only); 711 Execution::ProcessDebugMessages(isolate, debug_command_only);
902
903 // Return to continue execution.
904 return isolate->heap()->undefined_value();
905 } 712 }
906 713
907 714
908 void Execution::ProcessDebugMessages(Isolate* isolate, 715 void Execution::ProcessDebugMessages(Isolate* isolate,
909 bool debug_command_only) { 716 bool debug_command_only) {
910 // Clear the debug command request flag. 717 isolate->stack_guard()->ClearDebugCommand();
911 isolate->stack_guard()->Continue(DEBUGCOMMAND);
912 718
913 StackLimitCheck check(isolate); 719 StackLimitCheck check(isolate);
914 if (check.HasOverflowed()) { 720 if (check.HasOverflowed()) return;
915 return;
916 }
917 721
918 HandleScope scope(isolate); 722 HandleScope scope(isolate);
919 // Enter the debugger. Just continue if we fail to enter the debugger. 723 // Enter the debugger. Just continue if we fail to enter the debugger.
920 EnterDebugger debugger(isolate); 724 EnterDebugger debugger(isolate);
921 if (debugger.FailedToEnter()) { 725 if (debugger.FailedToEnter()) return;
922 return;
923 }
924 726
925 // Notify the debug event listeners. Indicate auto continue if the break was 727 // Notify the debug event listeners. Indicate auto continue if the break was
926 // a debug command break. 728 // a debug command break.
927 isolate->debugger()->OnDebugBreak(isolate->factory()->undefined_value(), 729 isolate->debugger()->OnDebugBreak(isolate->factory()->undefined_value(),
928 debug_command_only); 730 debug_command_only);
929 } 731 }
930 732
931 733
932 Object* Execution::HandleStackGuardInterrupt(Isolate* isolate) { 734 Object* StackGuard::HandleInterrupts() {
933 StackGuard* stack_guard = isolate->stack_guard(); 735 ExecutionAccess access(isolate_);
yurys 2014/05/29 08:42:07 Scope of this lock seems too coarse. Do we really
934 if (stack_guard->ShouldPostponeInterrupts()) { 736 if (should_postpone_interrupts(access)) {
935 return isolate->heap()->undefined_value(); 737 return isolate_->heap()->undefined_value();
936 } 738 }
937 739
938 if (stack_guard->IsAPIInterrupt()) { 740 if (CheckAndClearInterrupt(API_INTERRUPT, access)) {
939 stack_guard->InvokeInterruptCallback(); 741 isolate_->InvokeApiInterruptCallback();
940 stack_guard->Continue(API_INTERRUPT);
941 } 742 }
942 743
943 if (stack_guard->IsGCRequest()) { 744 if (CheckAndClearInterrupt(GC_REQUEST, access)) {
944 isolate->heap()->CollectAllGarbage(Heap::kNoGCFlags, 745 isolate_->heap()->CollectAllGarbage(Heap::kNoGCFlags, "GC interrupt");
945 "StackGuard GC request");
946 stack_guard->Continue(GC_REQUEST);
947 } 746 }
948 747
949 isolate->counters()->stack_interrupts()->Increment(); 748 if (CheckDebugBreak() || CheckDebugCommand()) {
950 isolate->counters()->runtime_profiler_ticks()->Increment(); 749 Execution::DebugBreakHelper(isolate_);
951 if (stack_guard->IsDebugBreak() || stack_guard->IsDebugCommand()) {
952 DebugBreakHelper(isolate);
953 } 750 }
954 if (stack_guard->IsPreempted()) RuntimePreempt(isolate); 751
955 if (stack_guard->IsTerminateExecution()) { 752 if (CheckAndClearInterrupt(TERMINATE_EXECUTION, access)) {
956 stack_guard->Continue(TERMINATE); 753 return isolate_->TerminateExecution();
957 return isolate->TerminateExecution();
958 } 754 }
959 if (stack_guard->IsInterrupted()) { 755
960 stack_guard->Continue(INTERRUPT); 756 if (CheckAndClearInterrupt(FULL_DEOPT, access)) {
961 return isolate->StackOverflow(); 757 Deoptimizer::DeoptimizeAll(isolate_);
962 } 758 }
963 if (stack_guard->IsFullDeopt()) { 759
964 stack_guard->Continue(FULL_DEOPT); 760 if (CheckAndClearInterrupt(DEOPT_MARKED_ALLOCATION_SITES, access)) {
965 Deoptimizer::DeoptimizeAll(isolate); 761 isolate_->heap()->DeoptMarkedAllocationSites();
966 } 762 }
967 if (stack_guard->IsDeoptMarkedAllocationSites()) { 763
968 stack_guard->Continue(DEOPT_MARKED_ALLOCATION_SITES); 764 if (CheckAndClearInterrupt(INSTALL_CODE, access)) {
969 isolate->heap()->DeoptMarkedAllocationSites(); 765 ASSERT(isolate_->concurrent_recompilation_enabled());
766 isolate_->optimizing_compiler_thread()->InstallOptimizedFunctions();
970 } 767 }
971 if (stack_guard->IsInstallCodeRequest()) { 768
972 ASSERT(isolate->concurrent_recompilation_enabled()); 769 isolate_->counters()->stack_interrupts()->Increment();
973 stack_guard->Continue(INSTALL_CODE); 770 isolate_->counters()->runtime_profiler_ticks()->Increment();
974 isolate->optimizing_compiler_thread()->InstallOptimizedFunctions(); 771 isolate_->runtime_profiler()->OptimizeNow();
975 } 772 return isolate_->heap()->undefined_value();
976 isolate->runtime_profiler()->OptimizeNow();
977 return isolate->heap()->undefined_value();
978 } 773 }
979 774
980 } } // namespace v8::internal 775 } } // namespace v8::internal
OLDNEW
« no previous file with comments | « src/execution.h ('k') | src/heap.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698