• 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/collection-barrier.h"
6 
7 #include "src/base/platform/mutex.h"
8 #include "src/base/platform/time.h"
9 #include "src/common/globals.h"
10 #include "src/execution/isolate.h"
11 #include "src/handles/handles.h"
12 #include "src/heap/heap-inl.h"
13 #include "src/heap/heap.h"
14 #include "src/heap/local-heap.h"
15 #include "src/heap/parked-scope.h"
16 
17 namespace v8 {
18 namespace internal {
19 
WasGCRequested()20 bool CollectionBarrier::WasGCRequested() {
21   return collection_requested_.load();
22 }
23 
TryRequestGC()24 bool CollectionBarrier::TryRequestGC() {
25   base::MutexGuard guard(&mutex_);
26   if (shutdown_requested_) return false;
27   bool was_already_requested = collection_requested_.exchange(true);
28 
29   if (!was_already_requested) {
30     CHECK(!timer_.IsStarted());
31     timer_.Start();
32   }
33 
34   return true;
35 }
36 
37 class BackgroundCollectionInterruptTask : public CancelableTask {
38  public:
BackgroundCollectionInterruptTask(Heap * heap)39   explicit BackgroundCollectionInterruptTask(Heap* heap)
40       : CancelableTask(heap->isolate()), heap_(heap) {}
41 
42   ~BackgroundCollectionInterruptTask() override = default;
43   BackgroundCollectionInterruptTask(const BackgroundCollectionInterruptTask&) =
44       delete;
45   BackgroundCollectionInterruptTask& operator=(
46       const BackgroundCollectionInterruptTask&) = delete;
47 
48  private:
49   // v8::internal::CancelableTask overrides.
RunInternal()50   void RunInternal() override { heap_->CheckCollectionRequested(); }
51 
52   Heap* heap_;
53 };
54 
NotifyShutdownRequested()55 void CollectionBarrier::NotifyShutdownRequested() {
56   base::MutexGuard guard(&mutex_);
57   if (timer_.IsStarted()) timer_.Stop();
58   shutdown_requested_ = true;
59   cv_wakeup_.NotifyAll();
60 }
61 
ResumeThreadsAwaitingCollection()62 void CollectionBarrier::ResumeThreadsAwaitingCollection() {
63   base::MutexGuard guard(&mutex_);
64   DCHECK(!timer_.IsStarted());
65   collection_requested_.store(false);
66   block_for_collection_ = false;
67   collection_performed_ = true;
68   cv_wakeup_.NotifyAll();
69 }
70 
CancelCollectionAndResumeThreads()71 void CollectionBarrier::CancelCollectionAndResumeThreads() {
72   base::MutexGuard guard(&mutex_);
73   if (timer_.IsStarted()) timer_.Stop();
74   collection_requested_.store(false);
75   block_for_collection_ = false;
76   collection_performed_ = false;
77   cv_wakeup_.NotifyAll();
78 }
79 
AwaitCollectionBackground(LocalHeap * local_heap)80 bool CollectionBarrier::AwaitCollectionBackground(LocalHeap* local_heap) {
81   bool first_thread;
82 
83   {
84     // Update flag before parking this thread, this guarantees that the flag is
85     // set before the next GC.
86     base::MutexGuard guard(&mutex_);
87     if (shutdown_requested_) return false;
88 
89     // Collection was cancelled by the main thread.
90     if (!collection_requested_.load()) return false;
91 
92     first_thread = !block_for_collection_;
93     block_for_collection_ = true;
94     CHECK(timer_.IsStarted());
95   }
96 
97   // The first thread needs to activate the stack guard and post the task.
98   if (first_thread) ActivateStackGuardAndPostTask();
99 
100   ParkedScope scope(local_heap);
101   base::MutexGuard guard(&mutex_);
102 
103   while (block_for_collection_) {
104     if (shutdown_requested_) return false;
105     cv_wakeup_.Wait(&mutex_);
106   }
107 
108   // Collection may have been cancelled while blocking for it.
109   return collection_performed_;
110 }
111 
ActivateStackGuardAndPostTask()112 void CollectionBarrier::ActivateStackGuardAndPostTask() {
113   Isolate* isolate = heap_->isolate();
114   ExecutionAccess access(isolate);
115   isolate->stack_guard()->RequestGC();
116 
117   V8::GetCurrentPlatform()
118       ->GetForegroundTaskRunner(reinterpret_cast<v8::Isolate*>(isolate))
119       ->PostTask(std::make_unique<BackgroundCollectionInterruptTask>(heap_));
120 }
121 
StopTimeToCollectionTimer()122 void CollectionBarrier::StopTimeToCollectionTimer() {
123   if (collection_requested_.load()) {
124     base::MutexGuard guard(&mutex_);
125     // The first thread that requests the GC, starts the timer first and *then*
126     // parks itself. Since we are in a safepoint here, the timer is always
127     // initialized here already.
128     CHECK(timer_.IsStarted());
129     base::TimeDelta delta = timer_.Elapsed();
130     TRACE_EVENT_INSTANT1(TRACE_DISABLED_BY_DEFAULT("v8.gc"),
131                          "V8.GC.TimeToCollectionOnBackground",
132                          TRACE_EVENT_SCOPE_THREAD, "duration",
133                          delta.InMillisecondsF());
134     heap_->isolate()
135         ->counters()
136         ->gc_time_to_collection_on_background()
137         ->AddTimedSample(delta);
138     timer_.Stop();
139   }
140 }
141 
142 }  // namespace internal
143 }  // namespace v8
144