OLD | NEW |
1 // Copyright 2011 the V8 project authors. All rights reserved. | 1 // Copyright 2011 the V8 project authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #ifndef V8_STORE_BUFFER_H_ | 5 #ifndef V8_STORE_BUFFER_H_ |
6 #define V8_STORE_BUFFER_H_ | 6 #define V8_STORE_BUFFER_H_ |
7 | 7 |
8 #include "src/allocation.h" | 8 #include "src/allocation.h" |
9 #include "src/base/logging.h" | 9 #include "src/base/logging.h" |
10 #include "src/base/platform/platform.h" | 10 #include "src/base/platform/platform.h" |
11 #include "src/cancelable-task.h" | 11 #include "src/cancelable-task.h" |
12 #include "src/globals.h" | 12 #include "src/globals.h" |
13 #include "src/heap/remembered-set.h" | 13 #include "src/heap/remembered-set.h" |
14 #include "src/heap/slot-set.h" | 14 #include "src/heap/slot-set.h" |
15 | 15 |
16 namespace v8 { | 16 namespace v8 { |
17 namespace internal { | 17 namespace internal { |
18 | 18 |
19 // Intermediate buffer that accumulates old-to-new stores from the generated | 19 // Intermediate buffer that accumulates old-to-new stores from the generated |
20 // code. Moreover, it stores invalid old-to-new slots with two entries. | 20 // code. Moreover, it stores invalid old-to-new slots with two entries. |
21 // The first is a tagged address of the start of the invalid range, the second | 21 // The first is a tagged address of the start of the invalid range, the second |
22 // one is the end address of the invalid range or null if there is just one slot | 22 // one is the end address of the invalid range or null if there is just one slot |
23 // that needs to be removed from the remembered set. On buffer overflow the | 23 // that needs to be removed from the remembered set. On buffer overflow the |
24 // slots are moved to the remembered set. | 24 // slots are moved to the remembered set. |
25 class StoreBuffer { | 25 class StoreBuffer { |
26 public: | 26 public: |
| 27 enum StoreBufferMode { IN_GC, NOT_IN_GC }; |
| 28 |
27 static const int kStoreBufferSize = 1 << (11 + kPointerSizeLog2); | 29 static const int kStoreBufferSize = 1 << (11 + kPointerSizeLog2); |
28 static const int kStoreBufferMask = kStoreBufferSize - 1; | 30 static const int kStoreBufferMask = kStoreBufferSize - 1; |
29 static const int kStoreBuffers = 2; | 31 static const int kStoreBuffers = 2; |
30 static const intptr_t kDeletionTag = 1; | 32 static const intptr_t kDeletionTag = 1; |
31 | 33 |
32 V8_EXPORT_PRIVATE static void StoreBufferOverflow(Isolate* isolate); | 34 V8_EXPORT_PRIVATE static void StoreBufferOverflow(Isolate* isolate); |
33 | 35 |
34 explicit StoreBuffer(Heap* heap); | 36 explicit StoreBuffer(Heap* heap); |
35 void SetUp(); | 37 void SetUp(); |
36 void TearDown(); | 38 void TearDown(); |
(...skipping 30 matching lines...) Expand all Loading... |
67 // Deletions coming from the GC are directly deleted from the remembered | 69 // Deletions coming from the GC are directly deleted from the remembered |
68 // set. Deletions coming from the runtime are added to the store buffer | 70 // set. Deletions coming from the runtime are added to the store buffer |
69 // to allow concurrent processing. | 71 // to allow concurrent processing. |
70 deletion_callback(this, start, end); | 72 deletion_callback(this, start, end); |
71 } | 73 } |
72 | 74 |
73 static void DeleteDuringGarbageCollection(StoreBuffer* store_buffer, | 75 static void DeleteDuringGarbageCollection(StoreBuffer* store_buffer, |
74 Address start, Address end) { | 76 Address start, Address end) { |
75 // In GC the store buffer has to be empty at any time. | 77 // In GC the store buffer has to be empty at any time. |
76 DCHECK(store_buffer->Empty()); | 78 DCHECK(store_buffer->Empty()); |
77 DCHECK(store_buffer->heap()->gc_state() != Heap::NOT_IN_GC); | 79 DCHECK(store_buffer->mode() != StoreBuffer::NOT_IN_GC); |
78 Page* page = Page::FromAddress(start); | 80 Page* page = Page::FromAddress(start); |
79 if (end) { | 81 if (end) { |
80 RememberedSet<OLD_TO_NEW>::RemoveRange(page, start, end, | 82 RememberedSet<OLD_TO_NEW>::RemoveRange(page, start, end, |
81 SlotSet::PREFREE_EMPTY_BUCKETS); | 83 SlotSet::PREFREE_EMPTY_BUCKETS); |
82 } else { | 84 } else { |
83 RememberedSet<OLD_TO_NEW>::Remove(page, start); | 85 RememberedSet<OLD_TO_NEW>::Remove(page, start); |
84 } | 86 } |
85 } | 87 } |
86 | 88 |
87 static void DeleteDuringRuntime(StoreBuffer* store_buffer, Address start, | 89 static void DeleteDuringRuntime(StoreBuffer* store_buffer, Address start, |
88 Address end) { | 90 Address end) { |
89 DCHECK(store_buffer->heap()->gc_state() == Heap::NOT_IN_GC); | 91 DCHECK(store_buffer->mode() == StoreBuffer::NOT_IN_GC); |
90 store_buffer->InsertDeletionIntoStoreBuffer(start, end); | 92 store_buffer->InsertDeletionIntoStoreBuffer(start, end); |
91 } | 93 } |
92 | 94 |
93 void InsertDeletionIntoStoreBuffer(Address start, Address end) { | 95 void InsertDeletionIntoStoreBuffer(Address start, Address end) { |
94 if (top_ + sizeof(Address) * 2 > limit_[current_]) { | 96 if (top_ + sizeof(Address) * 2 > limit_[current_]) { |
95 StoreBufferOverflow(heap_->isolate()); | 97 StoreBufferOverflow(heap_->isolate()); |
96 } | 98 } |
97 *top_ = MarkDeletionAddress(start); | 99 *top_ = MarkDeletionAddress(start); |
98 top_++; | 100 top_++; |
99 *top_ = end; | 101 *top_ = end; |
100 top_++; | 102 top_++; |
101 } | 103 } |
102 | 104 |
103 static void InsertDuringGarbageCollection(StoreBuffer* store_buffer, | 105 static void InsertDuringGarbageCollection(StoreBuffer* store_buffer, |
104 Address slot) { | 106 Address slot) { |
105 DCHECK(store_buffer->heap()->gc_state() != Heap::NOT_IN_GC); | 107 DCHECK(store_buffer->mode() != StoreBuffer::NOT_IN_GC); |
106 RememberedSet<OLD_TO_NEW>::Insert(Page::FromAddress(slot), slot); | 108 RememberedSet<OLD_TO_NEW>::Insert(Page::FromAddress(slot), slot); |
107 } | 109 } |
108 | 110 |
109 static void InsertDuringRuntime(StoreBuffer* store_buffer, Address slot) { | 111 static void InsertDuringRuntime(StoreBuffer* store_buffer, Address slot) { |
110 DCHECK(store_buffer->heap()->gc_state() == Heap::NOT_IN_GC); | 112 DCHECK(store_buffer->mode() == StoreBuffer::NOT_IN_GC); |
111 store_buffer->InsertIntoStoreBuffer(slot); | 113 store_buffer->InsertIntoStoreBuffer(slot); |
112 } | 114 } |
113 | 115 |
114 void InsertIntoStoreBuffer(Address slot) { | 116 void InsertIntoStoreBuffer(Address slot) { |
115 if (top_ + sizeof(Address) > limit_[current_]) { | 117 if (top_ + sizeof(Address) > limit_[current_]) { |
116 StoreBufferOverflow(heap_->isolate()); | 118 StoreBufferOverflow(heap_->isolate()); |
117 } | 119 } |
118 *top_ = slot; | 120 *top_ = slot; |
119 top_++; | 121 top_++; |
120 } | 122 } |
121 | 123 |
122 void InsertEntry(Address slot) { | 124 void InsertEntry(Address slot) { |
123 // Insertions coming from the GC are directly inserted into the remembered | 125 // Insertions coming from the GC are directly inserted into the remembered |
124 // set. Insertions coming from the runtime are added to the store buffer to | 126 // set. Insertions coming from the runtime are added to the store buffer to |
125 // allow concurrent processing. | 127 // allow concurrent processing. |
126 insertion_callback(this, slot); | 128 insertion_callback(this, slot); |
127 } | 129 } |
128 | 130 |
129 void SetMode(Heap::HeapState state) { | 131 void SetMode(StoreBufferMode mode) { |
130 if (state == Heap::NOT_IN_GC) { | 132 mode_ = mode; |
| 133 if (mode == NOT_IN_GC) { |
131 insertion_callback = &InsertDuringRuntime; | 134 insertion_callback = &InsertDuringRuntime; |
132 deletion_callback = &DeleteDuringRuntime; | 135 deletion_callback = &DeleteDuringRuntime; |
133 } else { | 136 } else { |
134 insertion_callback = &InsertDuringGarbageCollection; | 137 insertion_callback = &InsertDuringGarbageCollection; |
135 deletion_callback = &DeleteDuringGarbageCollection; | 138 deletion_callback = &DeleteDuringGarbageCollection; |
136 } | 139 } |
137 } | 140 } |
138 | 141 |
139 // Used by the concurrent processing thread to transfer entries from the | 142 // Used by the concurrent processing thread to transfer entries from the |
140 // store buffer to the remembered set. | 143 // store buffer to the remembered set. |
(...skipping 27 matching lines...) Expand all Loading... |
168 virtual ~Task() {} | 171 virtual ~Task() {} |
169 | 172 |
170 private: | 173 private: |
171 void RunInternal() override { | 174 void RunInternal() override { |
172 store_buffer_->ConcurrentlyProcessStoreBuffer(); | 175 store_buffer_->ConcurrentlyProcessStoreBuffer(); |
173 } | 176 } |
174 StoreBuffer* store_buffer_; | 177 StoreBuffer* store_buffer_; |
175 DISALLOW_COPY_AND_ASSIGN(Task); | 178 DISALLOW_COPY_AND_ASSIGN(Task); |
176 }; | 179 }; |
177 | 180 |
| 181 StoreBufferMode mode() const { return mode_; } |
| 182 |
178 void FlipStoreBuffers(); | 183 void FlipStoreBuffers(); |
179 | 184 |
180 Heap* heap_; | 185 Heap* heap_; |
181 | 186 |
182 Address* top_; | 187 Address* top_; |
183 | 188 |
184 // The start and the limit of the buffer that contains store slots | 189 // The start and the limit of the buffer that contains store slots |
185 // added from the generated code. We have two chunks of store buffers. | 190 // added from the generated code. We have two chunks of store buffers. |
186 // Whenever one fills up, we notify a concurrent processing thread and | 191 // Whenever one fills up, we notify a concurrent processing thread and |
187 // use the other empty one in the meantime. | 192 // use the other empty one in the meantime. |
188 Address* start_[kStoreBuffers]; | 193 Address* start_[kStoreBuffers]; |
189 Address* limit_[kStoreBuffers]; | 194 Address* limit_[kStoreBuffers]; |
190 | 195 |
191 // At most one lazy_top_ pointer is set at any time. | 196 // At most one lazy_top_ pointer is set at any time. |
192 Address* lazy_top_[kStoreBuffers]; | 197 Address* lazy_top_[kStoreBuffers]; |
193 base::Mutex mutex_; | 198 base::Mutex mutex_; |
194 | 199 |
195 // We only want to have at most one concurrent processing tas running. | 200 // We only want to have at most one concurrent processing tas running. |
196 bool task_running_; | 201 bool task_running_; |
197 | 202 |
198 // Points to the current buffer in use. | 203 // Points to the current buffer in use. |
199 int current_; | 204 int current_; |
200 | 205 |
| 206 // During GC, entries are directly added to the remembered set without |
| 207 // going through the store buffer. This is signaled by a special |
| 208 // IN_GC mode. |
| 209 StoreBufferMode mode_; |
| 210 |
201 base::VirtualMemory* virtual_memory_; | 211 base::VirtualMemory* virtual_memory_; |
202 | 212 |
203 // Callbacks are more efficient than reading out the gc state for every | 213 // Callbacks are more efficient than reading out the gc state for every |
204 // store buffer operation. | 214 // store buffer operation. |
205 void (*insertion_callback)(StoreBuffer*, Address); | 215 void (*insertion_callback)(StoreBuffer*, Address); |
206 void (*deletion_callback)(StoreBuffer*, Address, Address); | 216 void (*deletion_callback)(StoreBuffer*, Address, Address); |
207 }; | 217 }; |
208 | 218 |
209 } // namespace internal | 219 } // namespace internal |
210 } // namespace v8 | 220 } // namespace v8 |
211 | 221 |
212 #endif // V8_STORE_BUFFER_H_ | 222 #endif // V8_STORE_BUFFER_H_ |
OLD | NEW |