summaryrefslogtreecommitdiff
path: root/deps/v8/src/heap/collection-barrier.cc
blob: 3cf8f41c4334f0cc0e75cafb970f5fe6d47283b2 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
// Copyright 2020 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "src/heap/collection-barrier.h"

#include "src/base/platform/mutex.h"
#include "src/base/platform/time.h"
#include "src/common/globals.h"
#include "src/execution/isolate.h"
#include "src/handles/handles.h"
#include "src/heap/gc-tracer.h"
#include "src/heap/heap-inl.h"
#include "src/heap/heap.h"
#include "src/heap/local-heap.h"
#include "src/heap/parked-scope.h"

namespace v8 {
namespace internal {

bool CollectionBarrier::WasGCRequested() {
  return collection_requested_.load();
}

bool CollectionBarrier::TryRequestGC() {
  base::MutexGuard guard(&mutex_);
  if (shutdown_requested_) return false;
  bool was_already_requested = collection_requested_.exchange(true);

  if (!was_already_requested) {
    CHECK(!timer_.IsStarted());
    timer_.Start();
  }

  return true;
}

class BackgroundCollectionInterruptTask : public CancelableTask {
 public:
  explicit BackgroundCollectionInterruptTask(Heap* heap)
      : CancelableTask(heap->isolate()), heap_(heap) {}

  ~BackgroundCollectionInterruptTask() override = default;
  BackgroundCollectionInterruptTask(const BackgroundCollectionInterruptTask&) =
      delete;
  BackgroundCollectionInterruptTask& operator=(
      const BackgroundCollectionInterruptTask&) = delete;

 private:
  // v8::internal::CancelableTask overrides.
  void RunInternal() override { heap_->CheckCollectionRequested(); }

  Heap* heap_;
};

void CollectionBarrier::NotifyShutdownRequested() {
  base::MutexGuard guard(&mutex_);
  if (timer_.IsStarted()) timer_.Stop();
  shutdown_requested_ = true;
  cv_wakeup_.NotifyAll();
}

void CollectionBarrier::ResumeThreadsAwaitingCollection() {
  base::MutexGuard guard(&mutex_);
  DCHECK(!timer_.IsStarted());
  collection_requested_.store(false);
  block_for_collection_ = false;
  collection_performed_ = true;
  cv_wakeup_.NotifyAll();
}

void CollectionBarrier::CancelCollectionAndResumeThreads() {
  base::MutexGuard guard(&mutex_);
  if (timer_.IsStarted()) timer_.Stop();
  collection_requested_.store(false);
  block_for_collection_ = false;
  collection_performed_ = false;
  cv_wakeup_.NotifyAll();
}

bool CollectionBarrier::AwaitCollectionBackground(LocalHeap* local_heap) {
  bool first_thread;

  {
    // Update flag before parking this thread, this guarantees that the flag is
    // set before the next GC.
    base::MutexGuard guard(&mutex_);
    if (shutdown_requested_) return false;

    // Collection was cancelled by the main thread.
    if (!collection_requested_.load()) return false;

    first_thread = !block_for_collection_;
    block_for_collection_ = true;
    CHECK(timer_.IsStarted());
  }

  // The first thread needs to activate the stack guard and post the task.
  if (first_thread) ActivateStackGuardAndPostTask();

  ParkedScope scope(local_heap);
  base::MutexGuard guard(&mutex_);

  while (block_for_collection_) {
    if (shutdown_requested_) return false;
    cv_wakeup_.Wait(&mutex_);
  }

  // Collection may have been cancelled while blocking for it.
  return collection_performed_;
}

void CollectionBarrier::ActivateStackGuardAndPostTask() {
  Isolate* isolate = heap_->isolate();
  ExecutionAccess access(isolate);
  isolate->stack_guard()->RequestGC();

  V8::GetCurrentPlatform()
      ->GetForegroundTaskRunner(reinterpret_cast<v8::Isolate*>(isolate))
      ->PostTask(std::make_unique<BackgroundCollectionInterruptTask>(heap_));
}

void CollectionBarrier::StopTimeToCollectionTimer() {
  if (collection_requested_.load()) {
    base::MutexGuard guard(&mutex_);
    // The first thread that requests the GC, starts the timer first and *then*
    // parks itself. Since we are in a safepoint here, the timer is always
    // initialized here already.
    CHECK(timer_.IsStarted());
    base::TimeDelta delta = timer_.Elapsed();
    TRACE_EVENT_INSTANT1(TRACE_DISABLED_BY_DEFAULT("v8.gc"),
                         "V8.GC.TimeToCollectionOnBackground",
                         TRACE_EVENT_SCOPE_THREAD, "duration",
                         delta.InMillisecondsF());
    heap_->isolate()
        ->counters()
        ->gc_time_to_collection_on_background()
        ->AddTimedSample(delta);
    timer_.Stop();
  }
}

}  // namespace internal
}  // namespace v8