Chromium Code Reviews| 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 #include <algorithm> | 5 #include <algorithm> |
| 6 | 6 |
| 7 #include "src/v8.h" | 7 #include "src/v8.h" |
| 8 | 8 |
| 9 #include "src/base/atomicops.h" | 9 #include "src/base/atomicops.h" |
| 10 #include "src/counters.h" | 10 #include "src/counters.h" |
| (...skipping 97 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 108 } | 108 } |
| 109 | 109 |
| 110 | 110 |
| 111 void StoreBuffer::Uniq() { | 111 void StoreBuffer::Uniq() { |
| 112 // Remove adjacent duplicates and cells that do not point at new space. | 112 // Remove adjacent duplicates and cells that do not point at new space. |
| 113 Address previous = NULL; | 113 Address previous = NULL; |
| 114 Address* write = old_start_; | 114 Address* write = old_start_; |
| 115 DCHECK(may_move_store_buffer_entries_); | 115 DCHECK(may_move_store_buffer_entries_); |
| 116 for (Address* read = old_start_; read < old_top_; read++) { | 116 for (Address* read = old_start_; read < old_top_; read++) { |
| 117 Address current = *read; | 117 Address current = *read; |
| 118 DCHECK_NOT_NULL(current); | |
| 118 if (current != previous) { | 119 if (current != previous) { |
| 119 Object* object = reinterpret_cast<Object*>( | 120 Object* object = reinterpret_cast<Object*>( |
| 120 base::NoBarrier_Load(reinterpret_cast<base::AtomicWord*>(current))); | 121 base::NoBarrier_Load(reinterpret_cast<base::AtomicWord*>(current))); |
| 121 if (heap_->InNewSpace(object)) { | 122 if (heap_->InNewSpace(object)) { |
| 122 *write++ = current; | 123 *write++ = current; |
| 123 } | 124 } |
| 124 } | 125 } |
| 125 previous = current; | 126 previous = current; |
| 126 } | 127 } |
| 127 old_top_ = write; | 128 old_top_ = write; |
| (...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 195 void StoreBuffer::ExemptPopularPages(int prime_sample_step, int threshold) { | 196 void StoreBuffer::ExemptPopularPages(int prime_sample_step, int threshold) { |
| 196 PointerChunkIterator it(heap_); | 197 PointerChunkIterator it(heap_); |
| 197 MemoryChunk* chunk; | 198 MemoryChunk* chunk; |
| 198 while ((chunk = it.next()) != NULL) { | 199 while ((chunk = it.next()) != NULL) { |
| 199 chunk->set_store_buffer_counter(0); | 200 chunk->set_store_buffer_counter(0); |
| 200 } | 201 } |
| 201 bool created_new_scan_on_scavenge_pages = false; | 202 bool created_new_scan_on_scavenge_pages = false; |
| 202 MemoryChunk* previous_chunk = NULL; | 203 MemoryChunk* previous_chunk = NULL; |
| 203 for (Address* p = old_start_; p < old_top_; p += prime_sample_step) { | 204 for (Address* p = old_start_; p < old_top_; p += prime_sample_step) { |
| 204 Address addr = *p; | 205 Address addr = *p; |
| 206 if (addr == NULL) continue; | |
| 205 MemoryChunk* containing_chunk = NULL; | 207 MemoryChunk* containing_chunk = NULL; |
| 206 if (previous_chunk != NULL && previous_chunk->Contains(addr)) { | 208 if (previous_chunk != NULL && previous_chunk->Contains(addr)) { |
| 207 containing_chunk = previous_chunk; | 209 containing_chunk = previous_chunk; |
| 208 } else { | 210 } else { |
| 209 containing_chunk = MemoryChunk::FromAnyPointerAddress(heap_, addr); | 211 containing_chunk = MemoryChunk::FromAnyPointerAddress(heap_, addr); |
| 210 } | 212 } |
| 211 int old_counter = containing_chunk->store_buffer_counter(); | 213 int old_counter = containing_chunk->store_buffer_counter(); |
| 212 if (old_counter >= threshold) { | 214 if (old_counter >= threshold) { |
| 213 containing_chunk->set_scan_on_scavenge(true); | 215 containing_chunk->set_scan_on_scavenge(true); |
| 214 created_new_scan_on_scavenge_pages = true; | 216 created_new_scan_on_scavenge_pages = true; |
| 215 } | 217 } |
| 216 containing_chunk->set_store_buffer_counter(old_counter + 1); | 218 containing_chunk->set_store_buffer_counter(old_counter + 1); |
| 217 previous_chunk = containing_chunk; | 219 previous_chunk = containing_chunk; |
| 218 } | 220 } |
| 219 if (created_new_scan_on_scavenge_pages) { | 221 if (created_new_scan_on_scavenge_pages) { |
| 220 Filter(MemoryChunk::SCAN_ON_SCAVENGE); | 222 Filter(MemoryChunk::SCAN_ON_SCAVENGE); |
| 221 } | 223 } |
| 222 old_buffer_is_filtered_ = true; | 224 old_buffer_is_filtered_ = true; |
| 223 } | 225 } |
| 224 | 226 |
| 225 | 227 |
| 226 void StoreBuffer::Filter(int flag) { | 228 void StoreBuffer::Filter(int flag) { |
| 227 Address* new_top = old_start_; | 229 Address* new_top = old_start_; |
| 228 MemoryChunk* previous_chunk = NULL; | 230 MemoryChunk* previous_chunk = NULL; |
| 229 for (Address* p = old_start_; p < old_top_; p++) { | 231 for (Address* p = old_start_; p < old_top_; p++) { |
| 230 Address addr = *p; | 232 Address addr = *p; |
| 233 if (addr == NULL) continue; | |
| 231 MemoryChunk* containing_chunk = NULL; | 234 MemoryChunk* containing_chunk = NULL; |
| 232 if (previous_chunk != NULL && previous_chunk->Contains(addr)) { | 235 if (previous_chunk != NULL && previous_chunk->Contains(addr)) { |
| 233 containing_chunk = previous_chunk; | 236 containing_chunk = previous_chunk; |
| 234 } else { | 237 } else { |
| 235 containing_chunk = MemoryChunk::FromAnyPointerAddress(heap_, addr); | 238 containing_chunk = MemoryChunk::FromAnyPointerAddress(heap_, addr); |
| 236 previous_chunk = containing_chunk; | 239 previous_chunk = containing_chunk; |
| 237 } | 240 } |
| 238 if (!containing_chunk->IsFlagSet(flag)) { | 241 if (!containing_chunk->IsFlagSet(flag)) { |
| 239 *new_top++ = addr; | 242 *new_top++ = addr; |
| 240 } | 243 } |
| 241 } | 244 } |
| 242 old_top_ = new_top; | 245 old_top_ = new_top; |
| 243 | 246 |
| 244 // Filtering hash sets are inconsistent with the store buffer after this | 247 // Filtering hash sets are inconsistent with the store buffer after this |
| 245 // operation. | 248 // operation. |
| 246 ClearFilteringHashSets(); | 249 ClearFilteringHashSets(); |
| 247 } | 250 } |
| 248 | 251 |
| 249 | 252 |
| 253 void StoreBuffer::RemoveSlots(Address start_address, Address end_address) { | |
| 254 struct IsValueInRangePredicate { | |
| 255 Address start_address_; | |
| 256 Address end_address_; | |
| 257 | |
| 258 IsValueInRangePredicate(Address start_address, Address end_address) | |
| 259 : start_address_(start_address), end_address_(end_address) {} | |
| 260 | |
| 261 bool operator()(Address addr) { | |
| 262 return start_address_ <= addr && addr < end_address_; | |
| 263 } | |
| 264 }; | |
| 265 | |
| 266 IsValueInRangePredicate predicate(start_address, end_address); | |
| 267 const Address kRemovedSlot = NULL; | |
|
Hannes Payer (out of office)
2015/03/05 21:34:43
The NULL value is not much fun. Maybe we should po
Igor Sheludko
2015/03/06 09:06:59
Good point!
| |
| 268 | |
| 269 { | |
| 270 Address* top = reinterpret_cast<Address*>(heap_->store_buffer_top()); | |
| 271 std::replace_if(start_, top, predicate, kRemovedSlot); | |
| 272 } | |
| 273 | |
| 274 if (old_buffer_is_sorted_) { | |
| 275 // Remove slots from an old buffer preserving the order. | |
| 276 Address* lower = std::lower_bound(old_start_, old_top_, start_address); | |
| 277 if (lower != old_top_) { | |
| 278 Address* upper = std::lower_bound(lower, old_top_, end_address); | |
| 279 // Remove [lower, upper) from the buffer. | |
| 280 if (upper == old_top_) { | |
| 281 old_top_ = lower; | |
| 282 } else { | |
| 283 Address* new_top = lower; | |
| 284 for (Address* p = upper; p < old_top_; p++) { | |
| 285 *new_top++ = *p; | |
| 286 } | |
| 287 old_top_ = new_top; | |
|
Hannes Payer (out of office)
2015/03/05 21:34:43
Why do you set old_top_ here, the old top should r
Igor Sheludko
2015/03/06 09:06:59
Sorry, I didn't get the question. Added more comme
| |
| 288 } | |
| 289 } | |
| 290 } else { | |
| 291 std::replace_if(old_start_, old_top_, predicate, kRemovedSlot); | |
| 292 } | |
| 293 } | |
| 294 | |
| 295 | |
| 250 void StoreBuffer::SortUniq() { | 296 void StoreBuffer::SortUniq() { |
| 251 Compact(); | 297 Compact(); |
| 252 if (old_buffer_is_sorted_) return; | 298 if (old_buffer_is_sorted_) return; |
| 253 std::sort(old_start_, old_top_); | 299 std::sort(old_start_, old_top_); |
| 254 Uniq(); | 300 Uniq(); |
| 255 | 301 |
| 256 old_buffer_is_sorted_ = true; | 302 old_buffer_is_sorted_ = true; |
| 257 | 303 |
| 258 // Filtering hash sets are inconsistent with the store buffer after this | 304 // Filtering hash sets are inconsistent with the store buffer after this |
| 259 // operation. | 305 // operation. |
| (...skipping 30 matching lines...) Expand all Loading... | |
| 290 ClearFilteringHashSets(); | 336 ClearFilteringHashSets(); |
| 291 Uniq(); // Also removes things that no longer point to new space. | 337 Uniq(); // Also removes things that no longer point to new space. |
| 292 EnsureSpace(kStoreBufferSize / 2); | 338 EnsureSpace(kStoreBufferSize / 2); |
| 293 } | 339 } |
| 294 | 340 |
| 295 | 341 |
| 296 static Address* in_store_buffer_1_element_cache = NULL; | 342 static Address* in_store_buffer_1_element_cache = NULL; |
| 297 | 343 |
| 298 | 344 |
| 299 bool StoreBuffer::CellIsInStoreBuffer(Address cell_address) { | 345 bool StoreBuffer::CellIsInStoreBuffer(Address cell_address) { |
| 300 if (!FLAG_enable_slow_asserts) return true; | 346 DCHECK_NOT_NULL(cell_address); |
| 347 Address* top = reinterpret_cast<Address*>(heap_->store_buffer_top()); | |
| 301 if (in_store_buffer_1_element_cache != NULL && | 348 if (in_store_buffer_1_element_cache != NULL && |
| 302 *in_store_buffer_1_element_cache == cell_address) { | 349 *in_store_buffer_1_element_cache == cell_address) { |
| 303 return true; | 350 // Check if the cache still points into the active part of the buffer. |
| 351 if ((start_ <= in_store_buffer_1_element_cache && | |
| 352 in_store_buffer_1_element_cache < top) || | |
| 353 (old_start_ <= in_store_buffer_1_element_cache && | |
| 354 in_store_buffer_1_element_cache < old_top_)) { | |
| 355 return true; | |
| 356 } | |
| 304 } | 357 } |
| 305 Address* top = reinterpret_cast<Address*>(heap_->store_buffer_top()); | |
| 306 for (Address* current = top - 1; current >= start_; current--) { | 358 for (Address* current = top - 1; current >= start_; current--) { |
| 307 if (*current == cell_address) { | 359 if (*current == cell_address) { |
| 308 in_store_buffer_1_element_cache = current; | 360 in_store_buffer_1_element_cache = current; |
| 309 return true; | 361 return true; |
| 310 } | 362 } |
| 311 } | 363 } |
| 312 for (Address* current = old_top_ - 1; current >= old_start_; current--) { | 364 for (Address* current = old_top_ - 1; current >= old_start_; current--) { |
| 313 if (*current == cell_address) { | 365 if (*current == cell_address) { |
| 314 in_store_buffer_1_element_cache = current; | 366 in_store_buffer_1_element_cache = current; |
| 315 return true; | 367 return true; |
| (...skipping 101 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 417 } | 469 } |
| 418 | 470 |
| 419 | 471 |
| 420 void StoreBuffer::IteratePointersInStoreBuffer(ObjectSlotCallback slot_callback, | 472 void StoreBuffer::IteratePointersInStoreBuffer(ObjectSlotCallback slot_callback, |
| 421 bool clear_maps) { | 473 bool clear_maps) { |
| 422 Address* limit = old_top_; | 474 Address* limit = old_top_; |
| 423 old_top_ = old_start_; | 475 old_top_ = old_start_; |
| 424 { | 476 { |
| 425 DontMoveStoreBufferEntriesScope scope(this); | 477 DontMoveStoreBufferEntriesScope scope(this); |
| 426 for (Address* current = old_start_; current < limit; current++) { | 478 for (Address* current = old_start_; current < limit; current++) { |
| 479 Address addr = *current; | |
| 480 if (addr == NULL) continue; | |
| 427 #ifdef DEBUG | 481 #ifdef DEBUG |
| 428 Address* saved_top = old_top_; | 482 Address* saved_top = old_top_; |
| 429 #endif | 483 #endif |
| 430 ProcessOldToNewSlot(*current, slot_callback, clear_maps); | 484 ProcessOldToNewSlot(addr, slot_callback, clear_maps); |
| 431 DCHECK(old_top_ == saved_top + 1 || old_top_ == saved_top); | 485 DCHECK(old_top_ == saved_top + 1 || old_top_ == saved_top); |
| 432 } | 486 } |
| 433 } | 487 } |
| 434 } | 488 } |
| 435 | 489 |
| 436 | 490 |
| 437 void StoreBuffer::IteratePointersToNewSpace(ObjectSlotCallback slot_callback) { | 491 void StoreBuffer::IteratePointersToNewSpace(ObjectSlotCallback slot_callback) { |
| 438 IteratePointersToNewSpace(slot_callback, false); | 492 IteratePointersToNewSpace(slot_callback, false); |
| 439 } | 493 } |
| 440 | 494 |
| (...skipping 134 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 575 DCHECK(top <= limit_); | 629 DCHECK(top <= limit_); |
| 576 heap_->public_set_store_buffer_top(start_); | 630 heap_->public_set_store_buffer_top(start_); |
| 577 EnsureSpace(top - start_); | 631 EnsureSpace(top - start_); |
| 578 DCHECK(may_move_store_buffer_entries_); | 632 DCHECK(may_move_store_buffer_entries_); |
| 579 // Goes through the addresses in the store buffer attempting to remove | 633 // Goes through the addresses in the store buffer attempting to remove |
| 580 // duplicates. In the interest of speed this is a lossy operation. Some | 634 // duplicates. In the interest of speed this is a lossy operation. Some |
| 581 // duplicates will remain. We have two hash sets with different hash | 635 // duplicates will remain. We have two hash sets with different hash |
| 582 // functions to reduce the number of unnecessary clashes. | 636 // functions to reduce the number of unnecessary clashes. |
| 583 hash_sets_are_empty_ = false; // Hash sets are in use. | 637 hash_sets_are_empty_ = false; // Hash sets are in use. |
| 584 for (Address* current = start_; current < top; current++) { | 638 for (Address* current = start_; current < top; current++) { |
| 585 DCHECK(!heap_->cell_space()->Contains(*current)); | 639 Address addr = *current; |
| 586 DCHECK(!heap_->code_space()->Contains(*current)); | 640 if (addr == NULL) continue; |
| 587 DCHECK(!heap_->old_data_space()->Contains(*current)); | 641 DCHECK(!heap_->cell_space()->Contains(addr)); |
| 588 uintptr_t int_addr = reinterpret_cast<uintptr_t>(*current); | 642 DCHECK(!heap_->code_space()->Contains(addr)); |
| 643 DCHECK(!heap_->old_data_space()->Contains(addr)); | |
| 644 uintptr_t int_addr = reinterpret_cast<uintptr_t>(addr); | |
| 589 // Shift out the last bits including any tags. | 645 // Shift out the last bits including any tags. |
| 590 int_addr >>= kPointerSizeLog2; | 646 int_addr >>= kPointerSizeLog2; |
| 591 // The upper part of an address is basically random because of ASLR and OS | 647 // The upper part of an address is basically random because of ASLR and OS |
| 592 // non-determinism, so we use only the bits within a page for hashing to | 648 // non-determinism, so we use only the bits within a page for hashing to |
| 593 // make v8's behavior (more) deterministic. | 649 // make v8's behavior (more) deterministic. |
| 594 uintptr_t hash_addr = | 650 uintptr_t hash_addr = |
| 595 int_addr & (Page::kPageAlignmentMask >> kPointerSizeLog2); | 651 int_addr & (Page::kPageAlignmentMask >> kPointerSizeLog2); |
| 596 int hash1 = ((hash_addr ^ (hash_addr >> kHashSetLengthLog2)) & | 652 int hash1 = ((hash_addr ^ (hash_addr >> kHashSetLengthLog2)) & |
| 597 (kHashSetLength - 1)); | 653 (kHashSetLength - 1)); |
| 598 if (hash_set_1_[hash1] == int_addr) continue; | 654 if (hash_set_1_[hash1] == int_addr) continue; |
| (...skipping 13 matching lines...) Expand all Loading... | |
| 612 } | 668 } |
| 613 old_buffer_is_sorted_ = false; | 669 old_buffer_is_sorted_ = false; |
| 614 old_buffer_is_filtered_ = false; | 670 old_buffer_is_filtered_ = false; |
| 615 *old_top_++ = reinterpret_cast<Address>(int_addr << kPointerSizeLog2); | 671 *old_top_++ = reinterpret_cast<Address>(int_addr << kPointerSizeLog2); |
| 616 DCHECK(old_top_ <= old_limit_); | 672 DCHECK(old_top_ <= old_limit_); |
| 617 } | 673 } |
| 618 heap_->isolate()->counters()->store_buffer_compactions()->Increment(); | 674 heap_->isolate()->counters()->store_buffer_compactions()->Increment(); |
| 619 } | 675 } |
| 620 } | 676 } |
| 621 } // namespace v8::internal | 677 } // namespace v8::internal |
| OLD | NEW |