Line data Source code
1 : // Copyright 2017 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/concurrent-marking.h"
6 :
7 : #include <stack>
8 : #include <unordered_map>
9 :
10 : #include "src/heap/heap-inl.h"
11 : #include "src/heap/heap.h"
12 : #include "src/heap/marking.h"
13 : #include "src/isolate.h"
14 : #include "src/locked-queue-inl.h"
15 : #include "src/utils-inl.h"
16 : #include "src/utils.h"
17 : #include "src/v8.h"
18 :
19 : namespace v8 {
20 : namespace internal {
21 :
22 : class ConcurrentMarkingMarkbits {
23 : public:
24 0 : ConcurrentMarkingMarkbits() {}
25 0 : ~ConcurrentMarkingMarkbits() {
26 0 : for (auto chunk_bitmap : bitmap_) {
27 : FreeBitmap(chunk_bitmap.second);
28 : }
29 0 : }
30 0 : bool Mark(HeapObject* obj) {
31 0 : Address address = obj->address();
32 0 : MemoryChunk* chunk = MemoryChunk::FromAddress(address);
33 0 : if (bitmap_.count(chunk) == 0) {
34 0 : bitmap_[chunk] = AllocateBitmap();
35 : }
36 : MarkBit mark_bit =
37 0 : bitmap_[chunk]->MarkBitFromIndex(chunk->AddressToMarkbitIndex(address));
38 0 : if (mark_bit.Get()) return false;
39 : mark_bit.Set();
40 0 : return true;
41 : }
42 :
43 : Bitmap* AllocateBitmap() {
44 0 : return static_cast<Bitmap*>(calloc(1, Bitmap::kSize));
45 : }
46 :
47 0 : void FreeBitmap(Bitmap* bitmap) { free(bitmap); }
48 :
49 : private:
50 : std::unordered_map<MemoryChunk*, Bitmap*> bitmap_;
51 : };
52 :
53 0 : class ConcurrentMarkingVisitor : public ObjectVisitor {
54 : public:
55 0 : ConcurrentMarkingVisitor() : bytes_marked_(0) {}
56 :
57 0 : void VisitPointers(HeapObject* host, Object** start, Object** end) override {
58 0 : for (Object** p = start; p < end; p++) {
59 0 : if (!(*p)->IsHeapObject()) continue;
60 0 : MarkObject(HeapObject::cast(*p));
61 : }
62 0 : }
63 :
64 0 : void MarkObject(HeapObject* obj) {
65 0 : if (markbits_.Mark(obj)) {
66 0 : bytes_marked_ += obj->Size();
67 : marking_stack_.push(obj);
68 : }
69 0 : }
70 :
71 0 : void MarkTransitively() {
72 0 : while (!marking_stack_.empty()) {
73 0 : HeapObject* obj = marking_stack_.top();
74 : marking_stack_.pop();
75 0 : obj->Iterate(this);
76 : }
77 0 : }
78 :
79 : size_t bytes_marked() { return bytes_marked_; }
80 :
81 : private:
82 : size_t bytes_marked_;
83 : std::stack<HeapObject*> marking_stack_;
84 : ConcurrentMarkingMarkbits markbits_;
85 : };
86 :
87 : class ConcurrentMarking::Task : public CancelableTask {
88 : public:
89 0 : Task(Heap* heap, std::vector<HeapObject*>* root_set,
90 : base::Semaphore* on_finish)
91 : : CancelableTask(heap->isolate()),
92 : heap_(heap),
93 : on_finish_(on_finish),
94 0 : root_set_(root_set) {}
95 :
96 0 : virtual ~Task() {}
97 :
98 : private:
99 : // v8::internal::CancelableTask overrides.
100 0 : void RunInternal() override {
101 0 : double time_ms = heap_->MonotonicallyIncreasingTimeInMs();
102 : {
103 : TimedScope scope(&time_ms);
104 0 : for (HeapObject* obj : *root_set_) {
105 0 : marking_visitor_.MarkObject(obj);
106 : }
107 0 : marking_visitor_.MarkTransitively();
108 : }
109 0 : if (FLAG_trace_concurrent_marking) {
110 : heap_->isolate()->PrintWithTimestamp(
111 : "concurrently marked %dKB in %.2fms\n",
112 0 : static_cast<int>(marking_visitor_.bytes_marked() / KB), time_ms);
113 : }
114 0 : on_finish_->Signal();
115 0 : }
116 :
117 : Heap* heap_;
118 : base::Semaphore* on_finish_;
119 : ConcurrentMarkingVisitor marking_visitor_;
120 : std::vector<HeapObject*>* root_set_;
121 : DISALLOW_COPY_AND_ASSIGN(Task);
122 : };
123 :
124 60782 : ConcurrentMarking::ConcurrentMarking(Heap* heap)
125 60782 : : heap_(heap), pending_task_semaphore_(0), is_task_pending_(false) {
126 : // Concurrent marking does not work with double unboxing.
127 : STATIC_ASSERT(!(V8_CONCURRENT_MARKING && V8_DOUBLE_FIELDS_UNBOXING));
128 : // The runtime flag should be set only if the compile time flag was set.
129 60782 : CHECK(!FLAG_concurrent_marking || V8_CONCURRENT_MARKING);
130 60782 : }
131 :
132 118570 : ConcurrentMarking::~ConcurrentMarking() {}
133 :
134 0 : void ConcurrentMarking::AddRoot(HeapObject* object) {
135 0 : root_set_.push_back(object);
136 0 : }
137 :
138 0 : void ConcurrentMarking::StartTask() {
139 0 : if (!FLAG_concurrent_marking) return;
140 0 : is_task_pending_ = true;
141 :
142 0 : V8::GetCurrentPlatform()->CallOnBackgroundThread(
143 0 : new Task(heap_, &root_set_, &pending_task_semaphore_),
144 0 : v8::Platform::kShortRunningTask);
145 : }
146 :
147 0 : void ConcurrentMarking::WaitForTaskToComplete() {
148 0 : if (!FLAG_concurrent_marking) return;
149 0 : pending_task_semaphore_.Wait();
150 0 : is_task_pending_ = false;
151 : root_set_.clear();
152 : }
153 :
154 53346 : void ConcurrentMarking::EnsureTaskCompleted() {
155 53346 : if (IsTaskPending()) {
156 : WaitForTaskToComplete();
157 : }
158 53346 : }
159 :
160 : } // namespace internal
161 : } // namespace v8
|