LCOV - code coverage report
Current view: top level - src - v8threads.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 149 168 88.7 %
Date: 2017-10-20 Functions: 21 29 72.4 %

          Line data    Source code
       1             : // Copyright 2012 the V8 project authors. All rights reserved.
       2             : // Use of this source code is governed by a BSD-style license that can be
       3             : // found in the LICENSE file.
       4             : 
       5             : #include "src/v8threads.h"
       6             : 
       7             : #include "src/api.h"
       8             : #include "src/bootstrapper.h"
       9             : #include "src/debug/debug.h"
      10             : #include "src/execution.h"
      11             : #include "src/isolate-inl.h"
      12             : #include "src/regexp/regexp-stack.h"
      13             : #include "src/visitors.h"
      14             : 
      15             : namespace v8 {
      16             : 
      17             : 
      18             : namespace {
      19             : 
      20             : // Track whether this V8 instance has ever called v8::Locker. This allows the
      21             : // API code to verify that the lock is always held when V8 is being entered.
      22             : base::Atomic32 g_locker_was_ever_used_ = 0;
      23             : 
      24             : }  // namespace
      25             : 
      26             : 
      27             : // Once the Locker is initialized, the current thread will be guaranteed to have
      28             : // the lock for a given isolate.
      29        8355 : void Locker::Initialize(v8::Isolate* isolate) {
      30             :   DCHECK_NOT_NULL(isolate);
      31        8355 :   has_lock_ = false;
      32        8355 :   top_level_ = true;
      33        8355 :   isolate_ = reinterpret_cast<i::Isolate*>(isolate);
      34             :   // Record that the Locker has been used at least once.
      35             :   base::Relaxed_Store(&g_locker_was_ever_used_, 1);
      36             :   // Get the big lock if necessary.
      37       22074 :   if (!isolate_->thread_manager()->IsLockedByCurrentThread()) {
      38       13706 :     isolate_->thread_manager()->Lock();
      39        6866 :     has_lock_ = true;
      40             : 
      41             :     // This may be a locker within an unlocker in which case we have to
      42             :     // get the saved state for this thread and restore it.
      43       13732 :     if (isolate_->thread_manager()->RestoreThread()) {
      44        1010 :       top_level_ = false;
      45             :     } else {
      46        5856 :       internal::ExecutionAccess access(isolate_);
      47        5856 :       isolate_->stack_guard()->ClearThread(access);
      48        5856 :       isolate_->stack_guard()->InitThread(access);
      49             :     }
      50             :   }
      51             :   DCHECK(isolate_->thread_manager()->IsLockedByCurrentThread());
      52        8378 : }
      53             : 
      54             : 
      55        3056 : bool Locker::IsLocked(v8::Isolate* isolate) {
      56             :   DCHECK_NOT_NULL(isolate);
      57        3056 :   i::Isolate* internal_isolate = reinterpret_cast<i::Isolate*>(isolate);
      58        3056 :   return internal_isolate->thread_manager()->IsLockedByCurrentThread();
      59             : }
      60             : 
      61             : 
      62   608367614 : bool Locker::IsActive() {
      63   608367614 :   return !!base::Relaxed_Load(&g_locker_was_ever_used_);
      64             : }
      65             : 
      66             : 
      67        8377 : Locker::~Locker() {
      68             :   DCHECK(isolate_->thread_manager()->IsLockedByCurrentThread());
      69        8377 :   if (has_lock_) {
      70        6866 :     if (top_level_) {
      71       13732 :       isolate_->thread_manager()->FreeThreadResources();
      72             :     } else {
      73        2020 :       isolate_->thread_manager()->ArchiveThread();
      74             :     }
      75       13732 :     isolate_->thread_manager()->Unlock();
      76             :   }
      77        8377 : }
      78             : 
      79             : 
      80       25139 : void Unlocker::Initialize(v8::Isolate* isolate) {
      81             :   DCHECK_NOT_NULL(isolate);
      82       25139 :   isolate_ = reinterpret_cast<i::Isolate*>(isolate);
      83             :   DCHECK(isolate_->thread_manager()->IsLockedByCurrentThread());
      84       50278 :   isolate_->thread_manager()->ArchiveThread();
      85       50278 :   isolate_->thread_manager()->Unlock();
      86       25139 : }
      87             : 
      88             : 
      89       25139 : Unlocker::~Unlocker() {
      90             :   DCHECK(!isolate_->thread_manager()->IsLockedByCurrentThread());
      91       50278 :   isolate_->thread_manager()->Lock();
      92       50278 :   isolate_->thread_manager()->RestoreThread();
      93       25139 : }
      94             : 
      95             : 
      96             : namespace internal {
      97             : 
      98             : 
      99       32005 : bool ThreadManager::RestoreThread() {
     100             :   DCHECK(IsLockedByCurrentThread());
     101             :   // First check whether the current thread has been 'lazily archived', i.e.
     102             :   // not archived at all.  If that is the case we put the state storage we
     103             :   // had prepared back in the free list, since we didn't need it after all.
     104       64010 :   if (lazily_archived_thread_.Equals(ThreadId::Current())) {
     105        1986 :     lazily_archived_thread_ = ThreadId::Invalid();
     106             :     Isolate::PerIsolateThreadData* per_thread =
     107       98638 :         isolate_->FindPerThreadDataForThisThread();
     108             :     DCHECK_NOT_NULL(per_thread);
     109             :     DCHECK(per_thread->thread_state() == lazily_archived_thread_state_);
     110        1986 :     lazily_archived_thread_state_->set_id(ThreadId::Invalid());
     111        1986 :     lazily_archived_thread_state_->LinkInto(ThreadState::FREE_LIST);
     112        1986 :     lazily_archived_thread_state_ = nullptr;
     113             :     per_thread->set_thread_state(nullptr);
     114        1986 :     return true;
     115             :   }
     116             : 
     117             :   // Make sure that the preemption thread cannot modify the thread state while
     118             :   // it is being archived or restored.
     119       30019 :   ExecutionAccess access(isolate_);
     120             : 
     121             :   // If there is another thread that was lazily archived then we have to really
     122             :   // archive it now.
     123       30019 :   if (lazily_archived_thread_.IsValid()) {
     124       24163 :     EagerlyArchiveThread();
     125             :   }
     126       48676 :   Isolate::PerIsolateThreadData* per_thread =
     127       30019 :       isolate_->FindPerThreadDataForThisThread();
     128       54532 :   if (per_thread == nullptr || per_thread->thread_state() == nullptr) {
     129             :     // This is a new thread.
     130        5856 :     isolate_->stack_guard()->InitThread(access);
     131        5856 :     return false;
     132             :   }
     133       48326 :   ThreadState* state = per_thread->thread_state();
     134             :   char* from = state->data();
     135       48326 :   from = isolate_->handle_scope_implementer()->RestoreThread(from);
     136       24163 :   from = isolate_->RestoreThread(from);
     137       24163 :   from = Relocatable::RestoreState(isolate_, from);
     138       48326 :   from = isolate_->debug()->RestoreDebug(from);
     139       24163 :   from = isolate_->stack_guard()->RestoreStackGuard(from);
     140       48326 :   from = isolate_->regexp_stack()->RestoreStack(from);
     141       48326 :   from = isolate_->bootstrapper()->RestoreState(from);
     142             :   per_thread->set_thread_state(nullptr);
     143       24163 :   if (state->terminate_on_restore()) {
     144           0 :     isolate_->stack_guard()->RequestTerminateExecution();
     145             :     state->set_terminate_on_restore(false);
     146             :   }
     147             :   state->set_id(ThreadId::Invalid());
     148             :   state->Unlink();
     149             :   state->LinkInto(ThreadState::FREE_LIST);
     150       24163 :   return true;
     151             : }
     152             : 
     153             : 
     154       31992 : void ThreadManager::Lock() {
     155       31992 :   mutex_.Lock();
     156       32005 :   mutex_owner_ = ThreadId::Current();
     157             :   DCHECK(IsLockedByCurrentThread());
     158       32005 : }
     159             : 
     160             : 
     161       32005 : void ThreadManager::Unlock() {
     162       32005 :   mutex_owner_ = ThreadId::Invalid();
     163       32005 :   mutex_.Unlock();
     164       32005 : }
     165             : 
     166             : 
     167        1118 : static int ArchiveSpacePerThread() {
     168        1118 :   return HandleScopeImplementer::ArchiveSpacePerThread() +
     169        1118 :                         Isolate::ArchiveSpacePerThread() +
     170        1118 :                           Debug::ArchiveSpacePerThread() +
     171        1118 :                      StackGuard::ArchiveSpacePerThread() +
     172        1118 :                     RegExpStack::ArchiveSpacePerThread() +
     173        1118 :                    Bootstrapper::ArchiveSpacePerThread() +
     174        1118 :                     Relocatable::ArchiveSpacePerThread();
     175             : }
     176             : 
     177           0 : ThreadState::ThreadState(ThreadManager* thread_manager)
     178             :     : id_(ThreadId::Invalid()),
     179             :       terminate_on_restore_(false),
     180             :       data_(nullptr),
     181             :       next_(this),
     182             :       previous_(this),
     183      111116 :       thread_manager_(thread_manager) {}
     184             : 
     185           0 : ThreadState::~ThreadState() {
     186      107848 :   DeleteArray<char>(data_);
     187           0 : }
     188             : 
     189             : 
     190        1118 : void ThreadState::AllocateSpace() {
     191        1118 :   data_ = NewArray<char>(ArchiveSpacePerThread());
     192        1118 : }
     193             : 
     194             : 
     195           0 : void ThreadState::Unlink() {
     196       50312 :   next_->previous_ = previous_;
     197       50312 :   previous_->next_ = next_;
     198           0 : }
     199             : 
     200             : 
     201           0 : void ThreadState::LinkInto(List list) {
     202             :   ThreadState* flying_anchor =
     203             :       list == FREE_LIST ? thread_manager_->free_anchor_
     204       50312 :                         : thread_manager_->in_use_anchor_;
     205       50312 :   next_ = flying_anchor->next_;
     206       50312 :   previous_ = flying_anchor;
     207       50312 :   flying_anchor->next_ = this;
     208       50312 :   next_->previous_ = this;
     209           0 : }
     210             : 
     211             : 
     212       26149 : ThreadState* ThreadManager::GetFreeThreadState() {
     213       26149 :   ThreadState* gotten = free_anchor_->next_;
     214       26149 :   if (gotten == free_anchor_) {
     215        1118 :     ThreadState* new_thread_state = new ThreadState(this);
     216        1118 :     new_thread_state->AllocateSpace();
     217        1118 :     return new_thread_state;
     218             :   }
     219             :   return gotten;
     220             : }
     221             : 
     222             : 
     223             : // Gets the first in the list of archived threads.
     224         161 : ThreadState* ThreadManager::FirstThreadStateInUse() {
     225      308090 :   return in_use_anchor_->Next();
     226             : }
     227             : 
     228             : 
     229           0 : ThreadState* ThreadState::Next() {
     230      406449 :   if (next_ == thread_manager_->in_use_anchor_) return nullptr;
     231           0 :   return next_;
     232             : }
     233             : 
     234             : // Thread ids must start with 1, because in TLS having thread id 0 can't
     235             : // be distinguished from not having a thread id at all (since NULL is
     236             : // defined as 0.)
     237       54999 : ThreadManager::ThreadManager()
     238             :     : mutex_owner_(ThreadId::Invalid()),
     239             :       lazily_archived_thread_(ThreadId::Invalid()),
     240             :       lazily_archived_thread_state_(nullptr),
     241             :       free_anchor_(nullptr),
     242      164997 :       in_use_anchor_(nullptr) {
     243      109998 :   free_anchor_ = new ThreadState(this);
     244      109998 :   in_use_anchor_ = new ThreadState(this);
     245       54999 : }
     246             : 
     247             : 
     248      106730 : ThreadManager::~ThreadManager() {
     249       53365 :   DeleteThreadStateList(free_anchor_);
     250       53365 :   DeleteThreadStateList(in_use_anchor_);
     251       53365 : }
     252             : 
     253             : 
     254      106730 : void ThreadManager::DeleteThreadStateList(ThreadState* anchor) {
     255             :   // The list starts and ends with the anchor.
     256      214578 :   for (ThreadState* current = anchor->next_; current != anchor;) {
     257        1118 :     ThreadState* next = current->next_;
     258        2236 :     delete current;
     259             :     current = next;
     260             :   }
     261      213460 :   delete anchor;
     262      106730 : }
     263             : 
     264             : 
     265       26149 : void ThreadManager::ArchiveThread() {
     266             :   DCHECK(lazily_archived_thread_.Equals(ThreadId::Invalid()));
     267             :   DCHECK(!IsArchived());
     268             :   DCHECK(IsLockedByCurrentThread());
     269       26149 :   ThreadState* state = GetFreeThreadState();
     270             :   state->Unlink();
     271             :   Isolate::PerIsolateThreadData* per_thread =
     272       26149 :       isolate_->FindOrAllocatePerThreadDataForThisThread();
     273             :   per_thread->set_thread_state(state);
     274       26149 :   lazily_archived_thread_ = ThreadId::Current();
     275       26149 :   lazily_archived_thread_state_ = state;
     276             :   DCHECK(state->id().Equals(ThreadId::Invalid()));
     277             :   state->set_id(CurrentId());
     278             :   DCHECK(!state->id().Equals(ThreadId::Invalid()));
     279       26149 : }
     280             : 
     281             : 
     282       24163 : void ThreadManager::EagerlyArchiveThread() {
     283             :   DCHECK(IsLockedByCurrentThread());
     284       48326 :   ThreadState* state = lazily_archived_thread_state_;
     285             :   state->LinkInto(ThreadState::IN_USE_LIST);
     286             :   char* to = state->data();
     287             :   // Ensure that data containing GC roots are archived first, and handle them
     288             :   // in ThreadManager::Iterate(RootVisitor*).
     289       96652 :   to = isolate_->handle_scope_implementer()->ArchiveThread(to);
     290       24163 :   to = isolate_->ArchiveThread(to);
     291       24163 :   to = Relocatable::ArchiveState(isolate_, to);
     292       48326 :   to = isolate_->debug()->ArchiveDebug(to);
     293       24163 :   to = isolate_->stack_guard()->ArchiveStackGuard(to);
     294       48326 :   to = isolate_->regexp_stack()->ArchiveStack(to);
     295       48326 :   to = isolate_->bootstrapper()->ArchiveState(to);
     296       24163 :   lazily_archived_thread_ = ThreadId::Invalid();
     297       24163 :   lazily_archived_thread_state_ = nullptr;
     298       24163 : }
     299             : 
     300             : 
     301        5856 : void ThreadManager::FreeThreadResources() {
     302             :   DCHECK(!isolate_->has_pending_exception());
     303             :   DCHECK(!isolate_->external_caught_exception());
     304             :   DCHECK_NULL(isolate_->try_catch_handler());
     305       17568 :   isolate_->handle_scope_implementer()->FreeThreadResources();
     306        5856 :   isolate_->FreeThreadResources();
     307             :   isolate_->debug()->FreeThreadResources();
     308        5856 :   isolate_->stack_guard()->FreeThreadResources();
     309        5856 :   isolate_->regexp_stack()->FreeThreadResources();
     310       11712 :   isolate_->bootstrapper()->FreeThreadResources();
     311        5856 : }
     312             : 
     313             : 
     314           0 : bool ThreadManager::IsArchived() {
     315           0 :   Isolate::PerIsolateThreadData* data =
     316           0 :       isolate_->FindPerThreadDataForThisThread();
     317           0 :   return data != nullptr && data->thread_state() != nullptr;
     318             : }
     319             : 
     320      232423 : void ThreadManager::Iterate(RootVisitor* v) {
     321             :   // Expecting no threads during serialization/deserialization
     322      470840 :   for (ThreadState* state = FirstThreadStateInUse(); state != nullptr;
     323             :        state = state->Next()) {
     324             :     char* data = state->data();
     325        5994 :     data = HandleScopeImplementer::Iterate(v, data);
     326        5994 :     data = isolate_->Iterate(v, data);
     327        5994 :     data = Relocatable::Iterate(v, data);
     328             :   }
     329      232423 : }
     330             : 
     331             : 
     332       75345 : void ThreadManager::IterateArchivedThreads(ThreadVisitor* v) {
     333      243216 :   for (ThreadState* state = FirstThreadStateInUse(); state != nullptr;
     334             :        state = state->Next()) {
     335             :     char* data = state->data();
     336       92526 :     data += HandleScopeImplementer::ArchiveSpacePerThread();
     337       92526 :     isolate_->IterateThread(v, data);
     338             :   }
     339       75345 : }
     340             : 
     341             : 
     342           0 : ThreadId ThreadManager::CurrentId() {
     343       26149 :   return ThreadId::Current();
     344             : }
     345             : 
     346             : 
     347           0 : void ThreadManager::TerminateExecution(ThreadId thread_id) {
     348           0 :   for (ThreadState* state = FirstThreadStateInUse(); state != nullptr;
     349             :        state = state->Next()) {
     350           0 :     if (thread_id.Equals(state->id())) {
     351             :       state->set_terminate_on_restore(true);
     352             :     }
     353             :   }
     354           0 : }
     355             : 
     356             : 
     357             : }  // namespace internal
     358             : }  // namespace v8

Generated by: LCOV version 1.10