• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2020 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/heap/safepoint.h"
6 
7 #include "src/handles/local-handles.h"
8 #include "src/handles/persistent-handles.h"
9 #include "src/heap/gc-tracer.h"
10 #include "src/heap/heap-inl.h"
11 #include "src/heap/local-heap.h"
12 
13 namespace v8 {
14 namespace internal {
15 
GlobalSafepoint(Heap * heap)16 GlobalSafepoint::GlobalSafepoint(Heap* heap)
17     : heap_(heap), local_heaps_head_(nullptr), active_safepoint_scopes_(0) {}
18 
EnterSafepointScope()19 void GlobalSafepoint::EnterSafepointScope() {
20   if (!FLAG_local_heaps) return;
21 
22   if (++active_safepoint_scopes_ > 1) return;
23 
24   TimedHistogramScope timer(heap_->isolate()->counters()->stop_the_world());
25   TRACE_GC(heap_->tracer(), GCTracer::Scope::STOP_THE_WORLD);
26 
27   local_heaps_mutex_.Lock();
28   local_heap_of_this_thread_ = LocalHeap::Current();
29 
30   barrier_.Arm();
31 
32   for (LocalHeap* current = local_heaps_head_; current;
33        current = current->next_) {
34     if (current == local_heap_of_this_thread_) {
35       continue;
36     }
37     current->RequestSafepoint();
38   }
39 
40   for (LocalHeap* current = local_heaps_head_; current;
41        current = current->next_) {
42     if (current == local_heap_of_this_thread_) {
43       DCHECK(current->is_main_thread());
44       continue;
45     }
46     DCHECK(!current->is_main_thread());
47     current->state_mutex_.Lock();
48 
49     while (current->state_ == LocalHeap::ThreadState::Running) {
50       current->state_change_.Wait(&current->state_mutex_);
51     }
52   }
53 }
54 
LeaveSafepointScope()55 void GlobalSafepoint::LeaveSafepointScope() {
56   if (!FLAG_local_heaps) return;
57 
58   DCHECK_GT(active_safepoint_scopes_, 0);
59   if (--active_safepoint_scopes_ > 0) return;
60 
61   DCHECK_EQ(local_heap_of_this_thread_, LocalHeap::Current());
62 
63   for (LocalHeap* current = local_heaps_head_; current;
64        current = current->next_) {
65     if (current == local_heap_of_this_thread_) {
66       continue;
67     }
68     current->state_mutex_.Unlock();
69   }
70 
71   barrier_.Disarm();
72 
73   local_heap_of_this_thread_ = nullptr;
74   local_heaps_mutex_.Unlock();
75 }
76 
EnterFromThread(LocalHeap * local_heap)77 void GlobalSafepoint::EnterFromThread(LocalHeap* local_heap) {
78   {
79     base::MutexGuard guard(&local_heap->state_mutex_);
80     DCHECK_EQ(local_heap->state_, LocalHeap::ThreadState::Running);
81     local_heap->state_ = LocalHeap::ThreadState::Safepoint;
82     local_heap->state_change_.NotifyAll();
83   }
84 
85   barrier_.Wait();
86 
87   {
88     base::MutexGuard guard(&local_heap->state_mutex_);
89     local_heap->state_ = LocalHeap::ThreadState::Running;
90   }
91 }
92 
Arm()93 void GlobalSafepoint::Barrier::Arm() {
94   base::MutexGuard guard(&mutex_);
95   CHECK(!armed_);
96   armed_ = true;
97 }
98 
Disarm()99 void GlobalSafepoint::Barrier::Disarm() {
100   base::MutexGuard guard(&mutex_);
101   CHECK(armed_);
102   armed_ = false;
103   cond_.NotifyAll();
104 }
105 
Wait()106 void GlobalSafepoint::Barrier::Wait() {
107   base::MutexGuard guard(&mutex_);
108   while (armed_) {
109     cond_.Wait(&mutex_);
110   }
111 }
112 
SafepointScope(Heap * heap)113 SafepointScope::SafepointScope(Heap* heap) : safepoint_(heap->safepoint()) {
114   safepoint_->EnterSafepointScope();
115 }
116 
~SafepointScope()117 SafepointScope::~SafepointScope() { safepoint_->LeaveSafepointScope(); }
118 
ContainsLocalHeap(LocalHeap * local_heap)119 bool GlobalSafepoint::ContainsLocalHeap(LocalHeap* local_heap) {
120   base::MutexGuard guard(&local_heaps_mutex_);
121   LocalHeap* current = local_heaps_head_;
122 
123   while (current) {
124     if (current == local_heap) return true;
125     current = current->next_;
126   }
127 
128   return false;
129 }
130 
ContainsAnyLocalHeap()131 bool GlobalSafepoint::ContainsAnyLocalHeap() {
132   base::MutexGuard guard(&local_heaps_mutex_);
133   return local_heaps_head_ != nullptr;
134 }
135 
Iterate(RootVisitor * visitor)136 void GlobalSafepoint::Iterate(RootVisitor* visitor) {
137   DCHECK(IsActive());
138   for (LocalHeap* current = local_heaps_head_; current;
139        current = current->next_) {
140     current->handles()->Iterate(visitor);
141   }
142 }
143 
144 }  // namespace internal
145 }  // namespace v8
146