LCOV - code coverage report
Current view: top level - src - v8threads.cc (source / functions) Hit Total Coverage
Test: app.info Lines: 143 167 85.6 %
Date: 2019-04-17 Functions: 20 31 64.5 %

          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        8430 : void Locker::Initialize(v8::Isolate* isolate) {
      30             :   DCHECK_NOT_NULL(isolate);
      31        8430 :   has_lock_ = false;
      32        8430 :   top_level_ = true;
      33        8430 :   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       16859 :   if (!isolate_->thread_manager()->IsLockedByCurrentThread()) {
      38        6917 :     isolate_->thread_manager()->Lock();
      39        6928 :     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        6928 :     if (isolate_->thread_manager()->RestoreThread()) {
      44        1010 :       top_level_ = false;
      45             :     } else {
      46        5918 :       internal::ExecutionAccess access(isolate_);
      47       11836 :       isolate_->stack_guard()->ClearThread(access);
      48        5918 :       isolate_->thread_manager()->InitThread(access);
      49             :     }
      50             :   }
      51             :   DCHECK(isolate_->thread_manager()->IsLockedByCurrentThread());
      52        8440 : }
      53             : 
      54             : 
      55        3056 : bool Locker::IsLocked(v8::Isolate* isolate) {
      56             :   DCHECK_NOT_NULL(isolate);
      57             :   i::Isolate* internal_isolate = reinterpret_cast<i::Isolate*>(isolate);
      58        3056 :   return internal_isolate->thread_manager()->IsLockedByCurrentThread();
      59             : }
      60             : 
      61             : 
      62   475228027 : bool Locker::IsActive() {
      63   475228027 :   return !!base::Relaxed_Load(&g_locker_was_ever_used_);
      64             : }
      65             : 
      66             : 
      67       16878 : Locker::~Locker() {
      68             :   DCHECK(isolate_->thread_manager()->IsLockedByCurrentThread());
      69        8439 :   if (has_lock_) {
      70        6928 :     if (top_level_) {
      71        5918 :       isolate_->thread_manager()->FreeThreadResources();
      72             :     } else {
      73        1010 :       isolate_->thread_manager()->ArchiveThread();
      74             :     }
      75        6928 :     isolate_->thread_manager()->Unlock();
      76             :   }
      77        8439 : }
      78             : 
      79             : 
      80       33375 : void Unlocker::Initialize(v8::Isolate* isolate) {
      81             :   DCHECK_NOT_NULL(isolate);
      82       33375 :   isolate_ = reinterpret_cast<i::Isolate*>(isolate);
      83             :   DCHECK(isolate_->thread_manager()->IsLockedByCurrentThread());
      84       33375 :   isolate_->thread_manager()->ArchiveThread();
      85       33375 :   isolate_->thread_manager()->Unlock();
      86       33375 : }
      87             : 
      88             : 
      89       66750 : Unlocker::~Unlocker() {
      90             :   DCHECK(!isolate_->thread_manager()->IsLockedByCurrentThread());
      91       33375 :   isolate_->thread_manager()->Lock();
      92       33375 :   isolate_->thread_manager()->RestoreThread();
      93       33375 : }
      94             : 
      95             : 
      96             : namespace internal {
      97             : 
      98           0 : void ThreadManager::InitThread(const ExecutionAccess& lock) {
      99       23672 :   isolate_->stack_guard()->InitThread(lock);
     100       11836 :   isolate_->debug()->InitThread(lock);
     101           0 : }
     102             : 
     103       40303 : bool ThreadManager::RestoreThread() {
     104             :   DCHECK(IsLockedByCurrentThread());
     105             :   // First check whether the current thread has been 'lazily archived', i.e.
     106             :   // not archived at all.  If that is the case we put the state storage we
     107             :   // had prepared back in the free list, since we didn't need it after all.
     108       40303 :   if (lazily_archived_thread_ == ThreadId::Current()) {
     109        1922 :     lazily_archived_thread_ = ThreadId::Invalid();
     110             :     Isolate::PerIsolateThreadData* per_thread =
     111        1922 :         isolate_->FindPerThreadDataForThisThread();
     112             :     DCHECK_NOT_NULL(per_thread);
     113             :     DCHECK(per_thread->thread_state() == lazily_archived_thread_state_);
     114        1922 :     lazily_archived_thread_state_->set_id(ThreadId::Invalid());
     115        1922 :     lazily_archived_thread_state_->LinkInto(ThreadState::FREE_LIST);
     116        1922 :     lazily_archived_thread_state_ = nullptr;
     117             :     per_thread->set_thread_state(nullptr);
     118        1922 :     return true;
     119             :   }
     120             : 
     121             :   // Make sure that the preemption thread cannot modify the thread state while
     122             :   // it is being archived or restored.
     123       38381 :   ExecutionAccess access(isolate_);
     124             : 
     125             :   // If there is another thread that was lazily archived then we have to really
     126             :   // archive it now.
     127       38381 :   if (lazily_archived_thread_.IsValid()) {
     128       32463 :     EagerlyArchiveThread();
     129             :   }
     130             :   Isolate::PerIsolateThreadData* per_thread =
     131       38381 :       isolate_->FindPerThreadDataForThisThread();
     132       38381 :   if (per_thread == nullptr || per_thread->thread_state() == nullptr) {
     133             :     // This is a new thread.
     134             :     InitThread(access);
     135        5918 :     return false;
     136             :   }
     137             :   ThreadState* state = per_thread->thread_state();
     138             :   char* from = state->data();
     139       32463 :   from = isolate_->handle_scope_implementer()->RestoreThread(from);
     140       32463 :   from = isolate_->RestoreThread(from);
     141       32463 :   from = Relocatable::RestoreState(isolate_, from);
     142       32463 :   from = isolate_->debug()->RestoreDebug(from);
     143       64926 :   from = isolate_->stack_guard()->RestoreStackGuard(from);
     144       32463 :   from = isolate_->regexp_stack()->RestoreStack(from);
     145       32463 :   from = isolate_->bootstrapper()->RestoreState(from);
     146             :   per_thread->set_thread_state(nullptr);
     147       32463 :   if (state->terminate_on_restore()) {
     148           0 :     isolate_->stack_guard()->RequestTerminateExecution();
     149             :     state->set_terminate_on_restore(false);
     150             :   }
     151             :   state->set_id(ThreadId::Invalid());
     152             :   state->Unlink();
     153             :   state->LinkInto(ThreadState::FREE_LIST);
     154       32463 :   return true;
     155             : }
     156             : 
     157             : 
     158       40291 : void ThreadManager::Lock() {
     159       40291 :   mutex_.Lock();
     160             :   mutex_owner_.store(ThreadId::Current(), std::memory_order_relaxed);
     161             :   DCHECK(IsLockedByCurrentThread());
     162       40303 : }
     163             : 
     164             : 
     165           0 : void ThreadManager::Unlock() {
     166             :   mutex_owner_.store(ThreadId::Invalid(), std::memory_order_relaxed);
     167       40303 :   mutex_.Unlock();
     168           0 : }
     169             : 
     170             : 
     171        1126 : static int ArchiveSpacePerThread() {
     172        1126 :   return HandleScopeImplementer::ArchiveSpacePerThread() +
     173        1126 :                         Isolate::ArchiveSpacePerThread() +
     174        1126 :                           Debug::ArchiveSpacePerThread() +
     175        1126 :                      StackGuard::ArchiveSpacePerThread() +
     176        1126 :                     RegExpStack::ArchiveSpacePerThread() +
     177        1126 :                    Bootstrapper::ArchiveSpacePerThread() +
     178        1126 :                     Relocatable::ArchiveSpacePerThread();
     179             : }
     180             : 
     181           0 : ThreadState::ThreadState(ThreadManager* thread_manager)
     182             :     : id_(ThreadId::Invalid()),
     183             :       terminate_on_restore_(false),
     184             :       data_(nullptr),
     185             :       next_(this),
     186             :       previous_(this),
     187      125968 :       thread_manager_(thread_manager) {}
     188             : 
     189      125939 : ThreadState::~ThreadState() {
     190      125939 :   DeleteArray<char>(data_);
     191           0 : }
     192             : 
     193             : 
     194           0 : void ThreadState::AllocateSpace() {
     195        1126 :   data_ = NewArray<char>(ArchiveSpacePerThread());
     196           0 : }
     197             : 
     198             : 
     199           0 : void ThreadState::Unlink() {
     200       66848 :   next_->previous_ = previous_;
     201       66848 :   previous_->next_ = next_;
     202           0 : }
     203             : 
     204             : 
     205           0 : void ThreadState::LinkInto(List list) {
     206             :   ThreadState* flying_anchor =
     207       34385 :       list == FREE_LIST ? thread_manager_->free_anchor_
     208       66848 :                         : thread_manager_->in_use_anchor_;
     209       66848 :   next_ = flying_anchor->next_;
     210       66848 :   previous_ = flying_anchor;
     211       66848 :   flying_anchor->next_ = this;
     212       66848 :   next_->previous_ = this;
     213           0 : }
     214             : 
     215             : 
     216       34385 : ThreadState* ThreadManager::GetFreeThreadState() {
     217       34385 :   ThreadState* gotten = free_anchor_->next_;
     218       34385 :   if (gotten == free_anchor_) {
     219        1126 :     ThreadState* new_thread_state = new ThreadState(this);
     220             :     new_thread_state->AllocateSpace();
     221        1126 :     return new_thread_state;
     222             :   }
     223             :   return gotten;
     224             : }
     225             : 
     226             : 
     227             : // Gets the first in the list of archived threads.
     228         522 : ThreadState* ThreadManager::FirstThreadStateInUse() {
     229      366728 :   return in_use_anchor_->Next();
     230             : }
     231             : 
     232             : 
     233           0 : ThreadState* ThreadState::Next() {
     234      372928 :   if (next_ == thread_manager_->in_use_anchor_) return nullptr;
     235           0 :   return next_;
     236             : }
     237             : 
     238             : // Thread ids must start with 1, because in TLS having thread id 0 can't
     239             : // be distinguished from not having a thread id at all (since NULL is
     240             : // defined as 0.)
     241       62420 : ThreadManager::ThreadManager(Isolate* isolate)
     242             :     : mutex_owner_(ThreadId::Invalid()),
     243             :       lazily_archived_thread_(ThreadId::Invalid()),
     244             :       lazily_archived_thread_state_(nullptr),
     245             :       free_anchor_(nullptr),
     246             :       in_use_anchor_(nullptr),
     247      124840 :       isolate_(isolate) {
     248      124841 :   free_anchor_ = new ThreadState(this);
     249      124842 :   in_use_anchor_ = new ThreadState(this);
     250       62421 : }
     251             : 
     252             : 
     253      124813 : ThreadManager::~ThreadManager() {
     254       62406 :   DeleteThreadStateList(free_anchor_);
     255       62407 :   DeleteThreadStateList(in_use_anchor_);
     256       62407 : }
     257             : 
     258             : 
     259      124813 : void ThreadManager::DeleteThreadStateList(ThreadState* anchor) {
     260             :   // The list starts and ends with the anchor.
     261      124813 :   for (ThreadState* current = anchor->next_; current != anchor;) {
     262        1126 :     ThreadState* next = current->next_;
     263        2252 :     delete current;
     264             :     current = next;
     265             :   }
     266      249626 :   delete anchor;
     267      124814 : }
     268             : 
     269             : 
     270       34385 : void ThreadManager::ArchiveThread() {
     271             :   DCHECK_EQ(lazily_archived_thread_, ThreadId::Invalid());
     272             :   DCHECK(!IsArchived());
     273             :   DCHECK(IsLockedByCurrentThread());
     274       34385 :   ThreadState* state = GetFreeThreadState();
     275             :   state->Unlink();
     276             :   Isolate::PerIsolateThreadData* per_thread =
     277       34385 :       isolate_->FindOrAllocatePerThreadDataForThisThread();
     278             :   per_thread->set_thread_state(state);
     279       34385 :   lazily_archived_thread_ = ThreadId::Current();
     280       34385 :   lazily_archived_thread_state_ = state;
     281             :   DCHECK_EQ(state->id(), ThreadId::Invalid());
     282             :   state->set_id(CurrentId());
     283             :   DCHECK_NE(state->id(), ThreadId::Invalid());
     284       34385 : }
     285             : 
     286             : 
     287       32463 : void ThreadManager::EagerlyArchiveThread() {
     288             :   DCHECK(IsLockedByCurrentThread());
     289       32463 :   ThreadState* state = lazily_archived_thread_state_;
     290             :   state->LinkInto(ThreadState::IN_USE_LIST);
     291             :   char* to = state->data();
     292             :   // Ensure that data containing GC roots are archived first, and handle them
     293             :   // in ThreadManager::Iterate(RootVisitor*).
     294       32463 :   to = isolate_->handle_scope_implementer()->ArchiveThread(to);
     295       32463 :   to = isolate_->ArchiveThread(to);
     296       32463 :   to = Relocatable::ArchiveState(isolate_, to);
     297       32463 :   to = isolate_->debug()->ArchiveDebug(to);
     298       64926 :   to = isolate_->stack_guard()->ArchiveStackGuard(to);
     299       32463 :   to = isolate_->regexp_stack()->ArchiveStack(to);
     300       32463 :   to = isolate_->bootstrapper()->ArchiveState(to);
     301       32463 :   lazily_archived_thread_ = ThreadId::Invalid();
     302       32463 :   lazily_archived_thread_state_ = nullptr;
     303       32463 : }
     304             : 
     305             : 
     306        5918 : void ThreadManager::FreeThreadResources() {
     307             :   DCHECK(!isolate_->has_pending_exception());
     308             :   DCHECK(!isolate_->external_caught_exception());
     309             :   DCHECK_NULL(isolate_->try_catch_handler());
     310        5918 :   isolate_->handle_scope_implementer()->FreeThreadResources();
     311        5918 :   isolate_->FreeThreadResources();
     312        5918 :   isolate_->debug()->FreeThreadResources();
     313        5918 :   isolate_->stack_guard()->FreeThreadResources();
     314        5918 :   isolate_->regexp_stack()->FreeThreadResources();
     315        5918 :   isolate_->bootstrapper()->FreeThreadResources();
     316        5918 : }
     317             : 
     318             : 
     319           0 : bool ThreadManager::IsArchived() {
     320             :   Isolate::PerIsolateThreadData* data =
     321           0 :       isolate_->FindPerThreadDataForThisThread();
     322           0 :   return data != nullptr && data->thread_state() != nullptr;
     323             : }
     324             : 
     325      277915 : void ThreadManager::Iterate(RootVisitor* v) {
     326             :   // Expecting no threads during serialization/deserialization
     327      290481 :   for (ThreadState* state = FirstThreadStateInUse(); state != nullptr;
     328             :        state = state->Next()) {
     329             :     char* data = state->data();
     330        6283 :     data = HandleScopeImplementer::Iterate(v, data);
     331        6283 :     data = isolate_->Iterate(v, data);
     332        6283 :     data = Relocatable::Iterate(v, data);
     333             :   }
     334      277915 : }
     335             : 
     336             : 
     337       87769 : void ThreadManager::IterateArchivedThreads(ThreadVisitor* v) {
     338       88647 :   for (ThreadState* state = FirstThreadStateInUse(); state != nullptr;
     339             :        state = state->Next()) {
     340             :     char* data = state->data();
     341         439 :     data += HandleScopeImplementer::ArchiveSpacePerThread();
     342         439 :     isolate_->IterateThread(v, data);
     343             :   }
     344       87769 : }
     345             : 
     346             : 
     347           0 : ThreadId ThreadManager::CurrentId() {
     348           0 :   return ThreadId::Current();
     349             : }
     350             : 
     351             : 
     352           0 : void ThreadManager::TerminateExecution(ThreadId thread_id) {
     353           0 :   for (ThreadState* state = FirstThreadStateInUse(); state != nullptr;
     354             :        state = state->Next()) {
     355           0 :     if (thread_id == state->id()) {
     356             :       state->set_terminate_on_restore(true);
     357             :     }
     358             :   }
     359           0 : }
     360             : 
     361             : 
     362             : }  // namespace internal
     363      121996 : }  // namespace v8

Generated by: LCOV version 1.10