Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(415)

Side by Side Diff: src/store-buffer.cc

Issue 6745033: On store buffer overflow we mark individidual pages for... (Closed) Base URL: http://v8.googlecode.com/svn/branches/experimental/gc/
Patch Set: '' Created 9 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 // Copyright 2011 the V8 project authors. All rights reserved. 1 // Copyright 2011 the V8 project authors. All rights reserved.
2 // Redistribution and use in source and binary forms, with or without 2 // Redistribution and use in source and binary forms, with or without
3 // modification, are permitted provided that the following conditions are 3 // modification, are permitted provided that the following conditions are
4 // met: 4 // met:
5 // 5 //
6 // * Redistributions of source code must retain the above copyright 6 // * Redistributions of source code must retain the above copyright
7 // notice, this list of conditions and the following disclaimer. 7 // notice, this list of conditions and the following disclaimer.
8 // * Redistributions in binary form must reproduce the above 8 // * Redistributions in binary form must reproduce the above
9 // copyright notice, this list of conditions and the following 9 // copyright notice, this list of conditions and the following
10 // disclaimer in the documentation and/or other materials provided 10 // disclaimer in the documentation and/or other materials provided
11 // with the distribution. 11 // with the distribution.
12 // * Neither the name of Google Inc. nor the names of its 12 // * Neither the name of Google Inc. nor the names of its
13 // contributors may be used to endorse or promote products derived 13 // contributors may be used to endorse or promote products derived
14 // from this software without specific prior written permission. 14 // from this software without specific prior written permission.
15 // 15 //
16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 27
28 #include "v8-counters.h" 28 #include "v8.h"
29
29 #include "store-buffer.h" 30 #include "store-buffer.h"
30 #include "store-buffer-inl.h" 31 #include "store-buffer-inl.h"
32 #include "v8-counters.h"
31 33
32 namespace v8 { 34 namespace v8 {
33 namespace internal { 35 namespace internal {
34 36
35 Address* StoreBuffer::start_ = NULL; 37 Address* StoreBuffer::start_ = NULL;
36 Address* StoreBuffer::limit_ = NULL; 38 Address* StoreBuffer::limit_ = NULL;
37 Address* StoreBuffer::old_start_ = NULL; 39 Address* StoreBuffer::old_start_ = NULL;
38 Address* StoreBuffer::old_limit_ = NULL; 40 Address* StoreBuffer::old_limit_ = NULL;
39 Address* StoreBuffer::old_top_ = NULL; 41 Address* StoreBuffer::old_top_ = NULL;
40 uintptr_t* StoreBuffer::hash_map_1_ = NULL; 42 uintptr_t* StoreBuffer::hash_map_1_ = NULL;
41 uintptr_t* StoreBuffer::hash_map_2_ = NULL; 43 uintptr_t* StoreBuffer::hash_map_2_ = NULL;
42 VirtualMemory* StoreBuffer::virtual_memory_ = NULL; 44 VirtualMemory* StoreBuffer::virtual_memory_ = NULL;
43 StoreBuffer::StoreBufferMode StoreBuffer::store_buffer_mode_ =
44 kStoreBufferFunctional;
45 bool StoreBuffer::old_buffer_is_sorted_ = false; 45 bool StoreBuffer::old_buffer_is_sorted_ = false;
46 bool StoreBuffer::old_buffer_is_filtered_ = false;
46 bool StoreBuffer::during_gc_ = false; 47 bool StoreBuffer::during_gc_ = false;
48 bool StoreBuffer::may_move_store_buffer_entries_ = true;
47 bool StoreBuffer::store_buffer_rebuilding_enabled_ = false; 49 bool StoreBuffer::store_buffer_rebuilding_enabled_ = false;
48 bool StoreBuffer::may_move_store_buffer_entries_ = true; 50 StoreBufferCallback StoreBuffer::callback_ = NULL;
49 51
50 void StoreBuffer::Setup() { 52 void StoreBuffer::Setup() {
51 virtual_memory_ = new VirtualMemory(kStoreBufferSize * 3); 53 virtual_memory_ = new VirtualMemory(kStoreBufferSize * 3);
52 uintptr_t start_as_int = 54 uintptr_t start_as_int =
53 reinterpret_cast<uintptr_t>(virtual_memory_->address()); 55 reinterpret_cast<uintptr_t>(virtual_memory_->address());
54 start_ = 56 start_ =
55 reinterpret_cast<Address*>(RoundUp(start_as_int, kStoreBufferSize * 2)); 57 reinterpret_cast<Address*>(RoundUp(start_as_int, kStoreBufferSize * 2));
56 limit_ = start_ + (kStoreBufferSize / sizeof(*start_)); 58 limit_ = start_ + (kStoreBufferSize / sizeof(*start_));
57 59
58 old_top_ = old_start_ = new Address[kOldStoreBufferLength]; 60 old_top_ = old_start_ = new Address[kOldStoreBufferLength];
(...skipping 76 matching lines...) Expand 10 before | Expand all | Expand 10 after
135 if (Heap::InNewSpace(*reinterpret_cast<Object**>(current))) { 137 if (Heap::InNewSpace(*reinterpret_cast<Object**>(current))) {
136 *write++ = current; 138 *write++ = current;
137 } 139 }
138 } 140 }
139 previous = current; 141 previous = current;
140 } 142 }
141 old_top_ = write; 143 old_top_ = write;
142 } 144 }
143 145
144 146
147 void StoreBuffer::HandleFullness() {
148 if (old_buffer_is_filtered_) return;
149 ASSERT(may_move_store_buffer_entries_);
150 Compact();
151
152 old_buffer_is_filtered_ = true;
153 bool page_has_scan_on_scavenge_flag = false;
154
155 PointerChunkIterator it;
156 MemoryChunk* chunk;
157 while ((chunk = it.next()) != NULL) {
158 if (chunk->scan_on_scavenge()) page_has_scan_on_scavenge_flag = true;
159 }
160
161 if (page_has_scan_on_scavenge_flag) {
162 FilterScanOnScavengeEntries();
163 }
164
165 // If filtering out the entries from scan_on_scavenge pages got us down to
166 // less than half full, then we are satisfied with that.
167 if (old_limit_ - old_top_ > old_top_ - old_start_) return;
168
169 // Sample 1 entry in 97 and filter out the pages where we estimate that more
170 // than 1 in 8 pointers are to new space.
171 ExemptPopularPages(97, ((Page::kPageSize / kPointerSize) / 97) / 8);
Vyacheslav Egorov (Chromium) 2011/03/28 15:13:19 this looks like a repeatable pattern. loop with ar
Erik Corry 2011/03/28 15:56:07 Done.
172 if (old_limit_ - old_top_ > old_top_ - old_start_) return;
173
174 // Sample more finely and reduce the threshold for exempting pages from the
175 // store buffer.
176 ExemptPopularPages(23, ((Page::kPageSize / kPointerSize) / 23) / 16);
177 if (old_limit_ - old_top_ > old_top_ - old_start_) return;
178 ExemptPopularPages(7, ((Page::kPageSize / kPointerSize) / 7) / 32);
179 if (old_limit_ - old_top_ > old_top_ - old_start_) return;
180 ExemptPopularPages(3, ((Page::kPageSize / kPointerSize) / 3) / 256);
181 if (old_limit_ - old_top_ > old_top_ - old_start_) return;
182
183 // As a last resort we mark all pages as being exempt from the store buffer.
184 ExemptPopularPages(1, 0);
185 ASSERT(old_top_ == old_start_);
186 }
187
188
189 // Sample the store buffer to see if some pages are taking up a lot of space
190 // in the store buffer.
191 void StoreBuffer::ExemptPopularPages(int prime_sample_step, int threshold) {
192 PointerChunkIterator it;
193 MemoryChunk* chunk;
194 while ((chunk = it.next()) != NULL) {
195 chunk->set_store_buffer_counter(0);
196 }
197 bool created_new_scan_on_scavenge_pages = false;
198 MemoryChunk* previous_chunk = NULL;
199 for (Address* p = old_start_; p < old_top_; p += prime_sample_step) {
200 Address addr = *p;
201 MemoryChunk* containing_chunk = NULL;
202 if (previous_chunk != NULL && previous_chunk->Contains(addr)) {
203 containing_chunk = previous_chunk;
204 } else {
205 containing_chunk = MemoryChunk::FromAnyPointerAddress(addr);
206 }
207 int old_counter = containing_chunk->store_buffer_counter();
208 if (old_counter == threshold) {
209 containing_chunk->set_scan_on_scavenge(true);
210 created_new_scan_on_scavenge_pages = true;
211 }
212 containing_chunk->set_store_buffer_counter(old_counter + 1);
213 previous_chunk = containing_chunk;
214 }
215 if (created_new_scan_on_scavenge_pages) {
216 FilterScanOnScavengeEntries();
217 }
218 old_buffer_is_filtered_ = true;
219 }
220
221
222 void StoreBuffer::FilterScanOnScavengeEntries() {
223 Address* new_top = old_start_;
224 MemoryChunk* previous_chunk = NULL;
225 for (Address* p = old_start_; p < old_top_; p++) {
226 Address addr = *p;
227 MemoryChunk* containing_chunk = NULL;
228 if (previous_chunk != NULL && previous_chunk->Contains(addr)) {
229 containing_chunk = previous_chunk;
230 } else {
231 containing_chunk = MemoryChunk::FromAnyPointerAddress(addr);
Vyacheslav Egorov (Chromium) 2011/03/28 15:13:19 This code can be pretty slow on certain patterns.
Erik Corry 2011/03/28 15:56:07 Yes.
232 previous_chunk = containing_chunk;
233 }
234 if (!containing_chunk->scan_on_scavenge()) {
235 *new_top++ = addr;
236 }
237 }
238 old_top_ = new_top;
239 }
240
241
145 void StoreBuffer::SortUniq() { 242 void StoreBuffer::SortUniq() {
146 Compact(); 243 Compact();
147 if (old_buffer_is_sorted_) return; 244 if (old_buffer_is_sorted_) return;
148 if (store_buffer_mode() == kStoreBufferDisabled) {
149 old_top_ = old_start_;
150 return;
151 }
152 ZapHashTables(); 245 ZapHashTables();
153 qsort(reinterpret_cast<void*>(old_start_), 246 qsort(reinterpret_cast<void*>(old_start_),
154 old_top_ - old_start_, 247 old_top_ - old_start_,
155 sizeof(*old_top_), 248 sizeof(*old_top_),
156 &CompareAddresses); 249 &CompareAddresses);
157 Uniq(); 250 Uniq();
158 251
159 old_buffer_is_sorted_ = true; 252 old_buffer_is_sorted_ = true;
160 } 253 }
161 254
162 255
163 void StoreBuffer::PrepareForIteration() { 256 bool StoreBuffer::PrepareForIteration() {
164 Compact(); 257 Compact();
165 if (store_buffer_mode() == kStoreBufferDisabled) { 258 PointerChunkIterator it;
166 old_top_ = old_start_; 259 MemoryChunk* chunk;
167 return; 260 bool page_has_scan_on_scavenge_flag = false;
261 while ((chunk = it.next()) != NULL) {
262 if (chunk->scan_on_scavenge()) page_has_scan_on_scavenge_flag = true;
263 }
264
265 if (page_has_scan_on_scavenge_flag) {
266 FilterScanOnScavengeEntries();
168 } 267 }
169 ZapHashTables(); 268 ZapHashTables();
269 return page_has_scan_on_scavenge_flag;
170 } 270 }
171 271
172 272
173 #ifdef DEBUG 273 #ifdef DEBUG
174 void StoreBuffer::Clean() { 274 void StoreBuffer::Clean() {
175 if (store_buffer_mode() == kStoreBufferDisabled) {
176 old_top_ = old_start_; // Just clear the cache.
177 return;
178 }
179 ZapHashTables(); 275 ZapHashTables();
180 Uniq(); // Also removes things that no longer point to new space. 276 Uniq(); // Also removes things that no longer point to new space.
181 CheckForFullBuffer(); 277 CheckForFullBuffer();
182 } 278 }
183 279
184 280
185 static bool Zapped(char* start, int size) { 281 static bool Zapped(char* start, int size) {
186 for (int i = 0; i < size; i++) { 282 for (int i = 0; i < size; i++) {
187 if (start[i] != 0) return false; 283 if (start[i] != 0) return false;
188 } 284 }
189 return true; 285 return true;
190 } 286 }
191 287
192 288
193 bool StoreBuffer::HashTablesAreZapped() { 289 bool StoreBuffer::HashTablesAreZapped() {
194 return Zapped(reinterpret_cast<char*>(hash_map_1_), 290 return Zapped(reinterpret_cast<char*>(hash_map_1_),
195 sizeof(uintptr_t) * kHashMapLength) && 291 sizeof(uintptr_t) * kHashMapLength) &&
196 Zapped(reinterpret_cast<char*>(hash_map_2_), 292 Zapped(reinterpret_cast<char*>(hash_map_2_),
197 sizeof(uintptr_t) * kHashMapLength); 293 sizeof(uintptr_t) * kHashMapLength);
198 } 294 }
199 295
200 296
201 static Address* in_store_buffer_1_element_cache = NULL; 297 static Address* in_store_buffer_1_element_cache = NULL;
202 298
203 299
204 bool StoreBuffer::CellIsInStoreBuffer(Address cell_address) { 300 bool StoreBuffer::CellIsInStoreBuffer(Address cell_address) {
205 if (!FLAG_enable_slow_asserts) return true; 301 if (!FLAG_enable_slow_asserts) return true;
206 if (store_buffer_mode() != kStoreBufferFunctional) return true;
207 if (in_store_buffer_1_element_cache != NULL && 302 if (in_store_buffer_1_element_cache != NULL &&
208 *in_store_buffer_1_element_cache == cell_address) { 303 *in_store_buffer_1_element_cache == cell_address) {
209 return true; 304 return true;
210 } 305 }
211 Address* top = reinterpret_cast<Address*>(Heap::store_buffer_top()); 306 Address* top = reinterpret_cast<Address*>(Heap::store_buffer_top());
212 for (Address* current = top - 1; current >= start_; current--) { 307 for (Address* current = top - 1; current >= start_; current--) {
213 if (*current == cell_address) { 308 if (*current == cell_address) {
214 in_store_buffer_1_element_cache = current; 309 in_store_buffer_1_element_cache = current;
215 return true; 310 return true;
216 } 311 }
(...skipping 18 matching lines...) Expand all
235 sizeof(uintptr_t) * kHashMapLength); 330 sizeof(uintptr_t) * kHashMapLength);
236 } 331 }
237 332
238 333
239 void StoreBuffer::GCPrologue(GCType type, GCCallbackFlags flags) { 334 void StoreBuffer::GCPrologue(GCType type, GCCallbackFlags flags) {
240 ZapHashTables(); 335 ZapHashTables();
241 during_gc_ = true; 336 during_gc_ = true;
242 } 337 }
243 338
244 339
245 void StoreBuffer::Verify() { 340 void StoreBuffer::Verify() {
Vyacheslav Egorov (Chromium) 2011/03/28 15:13:19 I think we should have a way to verify store-buffe
Erik Corry 2011/03/28 15:56:07 I will consider this for another change.
246 #ifdef DEBUG
247 if (FLAG_verify_heap &&
248 StoreBuffer::store_buffer_mode() == kStoreBufferFunctional) {
249 Heap::OldPointerSpaceCheckStoreBuffer(Heap::WATERMARK_SHOULD_BE_VALID);
250 Heap::MapSpaceCheckStoreBuffer(Heap::WATERMARK_SHOULD_BE_VALID);
251 Heap::LargeObjectSpaceCheckStoreBuffer();
252 }
253 #endif
254 } 341 }
255 342
256 343
257 void StoreBuffer::GCEpilogue(GCType type, GCCallbackFlags flags) { 344 void StoreBuffer::GCEpilogue(GCType type, GCCallbackFlags flags) {
258 during_gc_ = false; 345 during_gc_ = false;
259 if (store_buffer_mode() == kStoreBufferBeingRebuilt) {
260 set_store_buffer_mode(kStoreBufferFunctional);
261 }
262 Verify(); 346 Verify();
263 } 347 }
264 348
265 349
266 void StoreBuffer::IteratePointersToNewSpace(ObjectSlotCallback callback) { 350 void StoreBuffer::IteratePointersToNewSpace(ObjectSlotCallback callback) {
267 if (store_buffer_mode() == kStoreBufferFunctional) { 351 // We do not sort or remove duplicated entries from the store buffer because
268 // We do not sort or remove duplicated entries from the store buffer because 352 // we expect that callback will rebuild the store buffer thus removing
269 // we expect that callback will rebuild the store buffer thus removing 353 // all duplicates and pointers to old space.
270 // all duplicates and pointers to old space. 354 bool some_pages_to_scan = PrepareForIteration();
271 PrepareForIteration(); 355
356 Address* limit = old_top_;
357 old_top_ = old_start_;
358 {
359 DontMoveStoreBufferEntriesScope scope;
360 for (Address* current = old_start_; current < limit; current++) {
361 #ifdef DEBUG
362 Address* saved_top = old_top_;
363 #endif
364 Object** cell = reinterpret_cast<Object**>(*current);
365 Object* object = *cell;
366 // May be invalid if object is not in new space.
367 HeapObject* heap_object = reinterpret_cast<HeapObject*>(object);
368 if (Heap::InFromSpace(object)) {
369 callback(reinterpret_cast<HeapObject**>(cell), heap_object);
370 }
371 ASSERT(old_top_ == saved_top + 1 || old_top_ == saved_top);
372 }
272 } 373 }
273 if (store_buffer_mode() != kStoreBufferFunctional) { 374 // We are done scanning all the pointers that were in the store buffer, but
274 old_top_ = old_start_; 375 // there may be some pages marked scan_on_scavenge that have pointers to new
275 ZapHashTables(); 376 // space that are not in the store buffer. We must scan them now. As we
276 Heap::public_set_store_buffer_top(start_); 377 // scan, the surviving pointers to new space will be added to the store
277 set_store_buffer_mode(kStoreBufferBeingRebuilt); 378 // buffer. If there are still a lot of pointers to new space then we will
278 Heap::IteratePointers(Heap::old_pointer_space(), 379 // keep the scan_on_scavenge flag on the page and discard the pointers that
279 &Heap::IteratePointersToNewSpace, 380 // were added to the store buffer. If there are not many pointers to new
280 callback, 381 // space left on the page we will keep the pointers in the store buffer and
281 Heap::WATERMARK_SHOULD_BE_VALID); 382 // remove the flag from the page.
282 383 if (some_pages_to_scan) {
283 Heap::IteratePointers(Heap::map_space(), 384 if (callback_ != NULL) {
284 &Heap::IteratePointersFromMapsToNewSpace, 385 (*callback_)(NULL, kStoreBufferStartScanningPagesEvent);
285 callback, 386 }
286 Heap::WATERMARK_SHOULD_BE_VALID); 387 PointerChunkIterator it;
287 388 MemoryChunk* chunk;
288 Heap::lo_space()->IteratePointersToNewSpace(callback); 389 while ((chunk = it.next()) != NULL) {
289 } else { 390 if (chunk->scan_on_scavenge()) {
290 Address* limit = old_top_; 391 if (callback_ != NULL) {
291 old_top_ = old_start_; 392 (*callback_)(chunk, kStoreBufferScanningPageEvent);
292 {
293 DontMoveStoreBufferEntriesScope scope;
294 for (Address* current = old_start_; current < limit; current++) {
295 #ifdef DEBUG
296 Address* saved_top = old_top_;
297 #endif
298 Object** cell = reinterpret_cast<Object**>(*current);
299 Object* object = *cell;
300 // May be invalid if object is not in new space.
301 HeapObject* heap_object = reinterpret_cast<HeapObject*>(object);
302 if (Heap::InFromSpace(object)) {
303 callback(reinterpret_cast<HeapObject**>(cell), heap_object);
304 } 393 }
305 ASSERT(old_top_ == saved_top + 1 || old_top_ == saved_top); 394 if (chunk->owner() == Heap::lo_space()) {
395 LargePage* large_page = reinterpret_cast<LargePage*>(chunk);
396 HeapObject* array = large_page->GetObject();
397 if (array->IsFixedArray()) {
Vyacheslav Egorov (Chromium) 2011/03/28 15:13:19 maybe you should assert that array is actually a f
Erik Corry 2011/03/28 15:56:07 Done.
398 Address start = array->address();
399 Address object_end = start + array->Size();
400 Heap::IteratePointersToNewSpace(start, object_end, callback);
401 }
402 } else {
403 Page* page = reinterpret_cast<Page*>(chunk);
404 Heap::IteratePointersOnPage(
405 reinterpret_cast<PagedSpace*>(page->owner()),
406 &Heap::IteratePointersToNewSpace,
407 callback,
408 page);
409 }
306 } 410 }
307 } 411 }
412 (*callback_)(NULL, kStoreBufferScanningPageEvent);
308 } 413 }
309 } 414 }
310 415
311 416
312 void StoreBuffer::Compact() { 417 void StoreBuffer::Compact() {
313 Address* top = reinterpret_cast<Address*>(Heap::store_buffer_top()); 418 Address* top = reinterpret_cast<Address*>(Heap::store_buffer_top());
314 419
315 if (top == start_) return; 420 if (top == start_) return;
316 421
317 // There's no check of the limit in the loop below so we check here for 422 // There's no check of the limit in the loop below so we check here for
318 // the worst case (compaction doesn't eliminate any pointers). 423 // the worst case (compaction doesn't eliminate any pointers).
319 ASSERT(top <= limit_); 424 ASSERT(top <= limit_);
320 Heap::public_set_store_buffer_top(start_); 425 Heap::public_set_store_buffer_top(start_);
321 if (top - start_ > old_limit_ - old_top_) { 426 if (top - start_ > old_limit_ - old_top_) {
322 CheckForFullBuffer(); 427 HandleFullness();
323 } 428 }
324 if (store_buffer_mode() == kStoreBufferDisabled) return;
325 ASSERT(may_move_store_buffer_entries_); 429 ASSERT(may_move_store_buffer_entries_);
326 // Goes through the addresses in the store buffer attempting to remove 430 // Goes through the addresses in the store buffer attempting to remove
327 // duplicates. In the interest of speed this is a lossy operation. Some 431 // duplicates. In the interest of speed this is a lossy operation. Some
328 // duplicates will remain. We have two hash tables with different hash 432 // duplicates will remain. We have two hash tables with different hash
329 // functions to reduce the number of unnecessary clashes. 433 // functions to reduce the number of unnecessary clashes.
330 for (Address* current = start_; current < top; current++) { 434 for (Address* current = start_; current < top; current++) {
435 ASSERT(!Heap::cell_space()->Contains(*current));
436 ASSERT(!Heap::code_space()->Contains(*current));
437 ASSERT(!Heap::old_data_space()->Contains(*current));
331 uintptr_t int_addr = reinterpret_cast<uintptr_t>(*current); 438 uintptr_t int_addr = reinterpret_cast<uintptr_t>(*current);
332 // Shift out the last bits including any tags. 439 // Shift out the last bits including any tags.
333 int_addr >>= kPointerSizeLog2; 440 int_addr >>= kPointerSizeLog2;
334 int hash1 = 441 int hash1 =
335 ((int_addr ^ (int_addr >> kHashMapLengthLog2)) & (kHashMapLength - 1)); 442 ((int_addr ^ (int_addr >> kHashMapLengthLog2)) & (kHashMapLength - 1));
336 if (hash_map_1_[hash1] == int_addr) continue; 443 if (hash_map_1_[hash1] == int_addr) continue;
337 int hash2 = 444 int hash2 =
338 ((int_addr - (int_addr >> kHashMapLengthLog2)) & (kHashMapLength - 1)); 445 ((int_addr - (int_addr >> kHashMapLengthLog2)) & (kHashMapLength - 1));
339 hash2 ^= hash2 >> (kHashMapLengthLog2 * 2); 446 hash2 ^= hash2 >> (kHashMapLengthLog2 * 2);
340 if (hash_map_2_[hash2] == int_addr) continue; 447 if (hash_map_2_[hash2] == int_addr) continue;
341 if (hash_map_1_[hash1] == 0) { 448 if (hash_map_1_[hash1] == 0) {
342 hash_map_1_[hash1] = int_addr; 449 hash_map_1_[hash1] = int_addr;
343 } else if (hash_map_2_[hash2] == 0) { 450 } else if (hash_map_2_[hash2] == 0) {
344 hash_map_2_[hash2] = int_addr; 451 hash_map_2_[hash2] = int_addr;
345 } else { 452 } else {
346 // Rather than slowing down we just throw away some entries. This will 453 // Rather than slowing down we just throw away some entries. This will
347 // cause some duplicates to remain undetected. 454 // cause some duplicates to remain undetected.
348 hash_map_1_[hash1] = int_addr; 455 hash_map_1_[hash1] = int_addr;
349 hash_map_2_[hash2] = 0; 456 hash_map_2_[hash2] = 0;
350 } 457 }
351 old_buffer_is_sorted_ = false; 458 old_buffer_is_sorted_ = false;
459 old_buffer_is_filtered_ = false;
352 *old_top_++ = reinterpret_cast<Address>(int_addr << kPointerSizeLog2); 460 *old_top_++ = reinterpret_cast<Address>(int_addr << kPointerSizeLog2);
353 ASSERT(old_top_ <= old_limit_); 461 ASSERT(old_top_ <= old_limit_);
354 } 462 }
355 Counters::store_buffer_compactions.Increment(); 463 Counters::store_buffer_compactions.Increment();
356 CheckForFullBuffer(); 464 CheckForFullBuffer();
357 } 465 }
358 466
359 467
360 void StoreBuffer::CheckForFullBuffer() { 468 void StoreBuffer::CheckForFullBuffer() {
361 if (old_limit_ - old_top_ < kStoreBufferSize * 2) { 469 if (old_limit_ - old_top_ < kStoreBufferSize * 2) {
362 // After compression we don't have enough space that we can be sure that 470 HandleFullness();
363 // the next two compressions will have enough space in the buffer. We
364 // start by trying a more agressive compression. If this frees up at least
365 // half the space then we can keep going, otherwise it is time to brake.
366 if (!during_gc_) {
367 SortUniq();
368 }
369 if (old_limit_ - old_top_ > old_top_ - old_start_) {
370 return;
371 }
372 // TODO(gc): Set an interrupt to do a GC on the next back edge.
373 // TODO(gc): Allocate the rest of new space to force a GC on the next
374 // allocation.
375 // TODO(gc): Make the disabling of the store buffer dependendent on
376 // those two measures failing:
377 // After compression not enough space was freed up in the store buffer. We
378 // might as well stop sorting and trying to eliminate duplicates.
379 Counters::store_buffer_overflows.Increment();
380 set_store_buffer_mode(kStoreBufferDisabled);
381 } 471 }
382 } 472 }
383 473
384 } } // namespace v8::internal 474 } } // namespace v8::internal
OLDNEW
« src/spaces.h ('K') | « src/store-buffer.h ('k') | src/store-buffer-inl.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698