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 "src/store-buffer.h" | |
6 | |
7 #include <algorithm> | 5 #include <algorithm> |
8 | 6 |
9 #include "src/v8.h" | 7 #include "src/v8.h" |
10 | 8 |
11 #include "src/base/atomicops.h" | 9 #include "src/base/atomicops.h" |
12 #include "src/counters.h" | 10 #include "src/counters.h" |
13 #include "src/store-buffer-inl.h" | 11 #include "src/heap/store-buffer-inl.h" |
14 | 12 |
15 namespace v8 { | 13 namespace v8 { |
16 namespace internal { | 14 namespace internal { |
17 | 15 |
18 StoreBuffer::StoreBuffer(Heap* heap) | 16 StoreBuffer::StoreBuffer(Heap* heap) |
19 : heap_(heap), | 17 : heap_(heap), |
20 start_(NULL), | 18 start_(NULL), |
21 limit_(NULL), | 19 limit_(NULL), |
22 old_start_(NULL), | 20 old_start_(NULL), |
23 old_limit_(NULL), | 21 old_limit_(NULL), |
24 old_top_(NULL), | 22 old_top_(NULL), |
25 old_reserved_limit_(NULL), | 23 old_reserved_limit_(NULL), |
26 old_buffer_is_sorted_(false), | 24 old_buffer_is_sorted_(false), |
27 old_buffer_is_filtered_(false), | 25 old_buffer_is_filtered_(false), |
28 during_gc_(false), | 26 during_gc_(false), |
29 store_buffer_rebuilding_enabled_(false), | 27 store_buffer_rebuilding_enabled_(false), |
30 callback_(NULL), | 28 callback_(NULL), |
31 may_move_store_buffer_entries_(true), | 29 may_move_store_buffer_entries_(true), |
32 virtual_memory_(NULL), | 30 virtual_memory_(NULL), |
33 hash_set_1_(NULL), | 31 hash_set_1_(NULL), |
34 hash_set_2_(NULL), | 32 hash_set_2_(NULL), |
35 hash_sets_are_empty_(true) { | 33 hash_sets_are_empty_(true) {} |
36 } | |
37 | 34 |
38 | 35 |
39 void StoreBuffer::SetUp() { | 36 void StoreBuffer::SetUp() { |
40 virtual_memory_ = new base::VirtualMemory(kStoreBufferSize * 3); | 37 virtual_memory_ = new base::VirtualMemory(kStoreBufferSize * 3); |
41 uintptr_t start_as_int = | 38 uintptr_t start_as_int = |
42 reinterpret_cast<uintptr_t>(virtual_memory_->address()); | 39 reinterpret_cast<uintptr_t>(virtual_memory_->address()); |
43 start_ = | 40 start_ = |
44 reinterpret_cast<Address*>(RoundUp(start_as_int, kStoreBufferSize * 2)); | 41 reinterpret_cast<Address*>(RoundUp(start_as_int, kStoreBufferSize * 2)); |
45 limit_ = start_ + (kStoreBufferSize / kPointerSize); | 42 limit_ = start_ + (kStoreBufferSize / kPointerSize); |
46 | 43 |
47 old_virtual_memory_ = | 44 old_virtual_memory_ = |
48 new base::VirtualMemory(kOldStoreBufferLength * kPointerSize); | 45 new base::VirtualMemory(kOldStoreBufferLength * kPointerSize); |
49 old_top_ = old_start_ = | 46 old_top_ = old_start_ = |
50 reinterpret_cast<Address*>(old_virtual_memory_->address()); | 47 reinterpret_cast<Address*>(old_virtual_memory_->address()); |
51 // Don't know the alignment requirements of the OS, but it is certainly not | 48 // Don't know the alignment requirements of the OS, but it is certainly not |
52 // less than 0xfff. | 49 // less than 0xfff. |
53 DCHECK((reinterpret_cast<uintptr_t>(old_start_) & 0xfff) == 0); | 50 DCHECK((reinterpret_cast<uintptr_t>(old_start_) & 0xfff) == 0); |
54 int initial_length = | 51 int initial_length = |
55 static_cast<int>(base::OS::CommitPageSize() / kPointerSize); | 52 static_cast<int>(base::OS::CommitPageSize() / kPointerSize); |
56 DCHECK(initial_length > 0); | 53 DCHECK(initial_length > 0); |
57 DCHECK(initial_length <= kOldStoreBufferLength); | 54 DCHECK(initial_length <= kOldStoreBufferLength); |
58 old_limit_ = old_start_ + initial_length; | 55 old_limit_ = old_start_ + initial_length; |
59 old_reserved_limit_ = old_start_ + kOldStoreBufferLength; | 56 old_reserved_limit_ = old_start_ + kOldStoreBufferLength; |
60 | 57 |
61 CHECK(old_virtual_memory_->Commit( | 58 CHECK(old_virtual_memory_->Commit(reinterpret_cast<void*>(old_start_), |
62 reinterpret_cast<void*>(old_start_), | 59 (old_limit_ - old_start_) * kPointerSize, |
63 (old_limit_ - old_start_) * kPointerSize, | 60 false)); |
64 false)); | |
65 | 61 |
66 DCHECK(reinterpret_cast<Address>(start_) >= virtual_memory_->address()); | 62 DCHECK(reinterpret_cast<Address>(start_) >= virtual_memory_->address()); |
67 DCHECK(reinterpret_cast<Address>(limit_) >= virtual_memory_->address()); | 63 DCHECK(reinterpret_cast<Address>(limit_) >= virtual_memory_->address()); |
68 Address* vm_limit = reinterpret_cast<Address*>( | 64 Address* vm_limit = reinterpret_cast<Address*>( |
69 reinterpret_cast<char*>(virtual_memory_->address()) + | 65 reinterpret_cast<char*>(virtual_memory_->address()) + |
70 virtual_memory_->size()); | 66 virtual_memory_->size()); |
71 DCHECK(start_ <= vm_limit); | 67 DCHECK(start_ <= vm_limit); |
72 DCHECK(limit_ <= vm_limit); | 68 DCHECK(limit_ <= vm_limit); |
73 USE(vm_limit); | 69 USE(vm_limit); |
74 DCHECK((reinterpret_cast<uintptr_t>(limit_) & kStoreBufferOverflowBit) != 0); | 70 DCHECK((reinterpret_cast<uintptr_t>(limit_) & kStoreBufferOverflowBit) != 0); |
75 DCHECK((reinterpret_cast<uintptr_t>(limit_ - 1) & kStoreBufferOverflowBit) == | 71 DCHECK((reinterpret_cast<uintptr_t>(limit_ - 1) & kStoreBufferOverflowBit) == |
76 0); | 72 0); |
77 | 73 |
78 CHECK(virtual_memory_->Commit(reinterpret_cast<Address>(start_), | 74 CHECK(virtual_memory_->Commit(reinterpret_cast<Address>(start_), |
79 kStoreBufferSize, | 75 kStoreBufferSize, |
80 false)); // Not executable. | 76 false)); // Not executable. |
(...skipping 45 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
126 bool StoreBuffer::SpaceAvailable(intptr_t space_needed) { | 122 bool StoreBuffer::SpaceAvailable(intptr_t space_needed) { |
127 return old_limit_ - old_top_ >= space_needed; | 123 return old_limit_ - old_top_ >= space_needed; |
128 } | 124 } |
129 | 125 |
130 | 126 |
131 void StoreBuffer::EnsureSpace(intptr_t space_needed) { | 127 void StoreBuffer::EnsureSpace(intptr_t space_needed) { |
132 while (old_limit_ - old_top_ < space_needed && | 128 while (old_limit_ - old_top_ < space_needed && |
133 old_limit_ < old_reserved_limit_) { | 129 old_limit_ < old_reserved_limit_) { |
134 size_t grow = old_limit_ - old_start_; // Double size. | 130 size_t grow = old_limit_ - old_start_; // Double size. |
135 CHECK(old_virtual_memory_->Commit(reinterpret_cast<void*>(old_limit_), | 131 CHECK(old_virtual_memory_->Commit(reinterpret_cast<void*>(old_limit_), |
136 grow * kPointerSize, | 132 grow * kPointerSize, false)); |
137 false)); | |
138 old_limit_ += grow; | 133 old_limit_ += grow; |
139 } | 134 } |
140 | 135 |
141 if (SpaceAvailable(space_needed)) return; | 136 if (SpaceAvailable(space_needed)) return; |
142 | 137 |
143 if (old_buffer_is_filtered_) return; | 138 if (old_buffer_is_filtered_) return; |
144 DCHECK(may_move_store_buffer_entries_); | 139 DCHECK(may_move_store_buffer_entries_); |
145 Compact(); | 140 Compact(); |
146 | 141 |
147 old_buffer_is_filtered_ = true; | 142 old_buffer_is_filtered_ = true; |
(...skipping 13 matching lines...) Expand all Loading... |
161 } | 156 } |
162 | 157 |
163 if (SpaceAvailable(space_needed)) return; | 158 if (SpaceAvailable(space_needed)) return; |
164 | 159 |
165 // Sample 1 entry in 97 and filter out the pages where we estimate that more | 160 // Sample 1 entry in 97 and filter out the pages where we estimate that more |
166 // than 1 in 8 pointers are to new space. | 161 // than 1 in 8 pointers are to new space. |
167 static const int kSampleFinenesses = 5; | 162 static const int kSampleFinenesses = 5; |
168 static const struct Samples { | 163 static const struct Samples { |
169 int prime_sample_step; | 164 int prime_sample_step; |
170 int threshold; | 165 int threshold; |
171 } samples[kSampleFinenesses] = { | 166 } samples[kSampleFinenesses] = { |
172 { 97, ((Page::kPageSize / kPointerSize) / 97) / 8 }, | 167 {97, ((Page::kPageSize / kPointerSize) / 97) / 8}, |
173 { 23, ((Page::kPageSize / kPointerSize) / 23) / 16 }, | 168 {23, ((Page::kPageSize / kPointerSize) / 23) / 16}, |
174 { 7, ((Page::kPageSize / kPointerSize) / 7) / 32 }, | 169 {7, ((Page::kPageSize / kPointerSize) / 7) / 32}, |
175 { 3, ((Page::kPageSize / kPointerSize) / 3) / 256 }, | 170 {3, ((Page::kPageSize / kPointerSize) / 3) / 256}, |
176 { 1, 0} | 171 {1, 0}}; |
177 }; | |
178 for (int i = 0; i < kSampleFinenesses; i++) { | 172 for (int i = 0; i < kSampleFinenesses; i++) { |
179 ExemptPopularPages(samples[i].prime_sample_step, samples[i].threshold); | 173 ExemptPopularPages(samples[i].prime_sample_step, samples[i].threshold); |
180 // As a last resort we mark all pages as being exempt from the store buffer. | 174 // As a last resort we mark all pages as being exempt from the store buffer. |
181 DCHECK(i != (kSampleFinenesses - 1) || old_top_ == old_start_); | 175 DCHECK(i != (kSampleFinenesses - 1) || old_top_ == old_start_); |
182 if (SpaceAvailable(space_needed)) return; | 176 if (SpaceAvailable(space_needed)) return; |
183 } | 177 } |
184 UNREACHABLE(); | 178 UNREACHABLE(); |
185 } | 179 } |
186 | 180 |
187 | 181 |
(...skipping 122 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
310 return true; | 304 return true; |
311 } | 305 } |
312 } | 306 } |
313 return false; | 307 return false; |
314 } | 308 } |
315 #endif | 309 #endif |
316 | 310 |
317 | 311 |
318 void StoreBuffer::ClearFilteringHashSets() { | 312 void StoreBuffer::ClearFilteringHashSets() { |
319 if (!hash_sets_are_empty_) { | 313 if (!hash_sets_are_empty_) { |
320 memset(reinterpret_cast<void*>(hash_set_1_), | 314 memset(reinterpret_cast<void*>(hash_set_1_), 0, |
321 0, | |
322 sizeof(uintptr_t) * kHashSetLength); | 315 sizeof(uintptr_t) * kHashSetLength); |
323 memset(reinterpret_cast<void*>(hash_set_2_), | 316 memset(reinterpret_cast<void*>(hash_set_2_), 0, |
324 0, | |
325 sizeof(uintptr_t) * kHashSetLength); | 317 sizeof(uintptr_t) * kHashSetLength); |
326 hash_sets_are_empty_ = true; | 318 hash_sets_are_empty_ = true; |
327 } | 319 } |
328 } | 320 } |
329 | 321 |
330 | 322 |
331 void StoreBuffer::GCPrologue() { | 323 void StoreBuffer::GCPrologue() { |
332 ClearFilteringHashSets(); | 324 ClearFilteringHashSets(); |
333 during_gc_ = true; | 325 during_gc_ = true; |
334 } | 326 } |
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
369 during_gc_ = false; | 361 during_gc_ = false; |
370 #ifdef VERIFY_HEAP | 362 #ifdef VERIFY_HEAP |
371 if (FLAG_verify_heap) { | 363 if (FLAG_verify_heap) { |
372 Verify(); | 364 Verify(); |
373 } | 365 } |
374 #endif | 366 #endif |
375 } | 367 } |
376 | 368 |
377 | 369 |
378 void StoreBuffer::FindPointersToNewSpaceInRegion( | 370 void StoreBuffer::FindPointersToNewSpaceInRegion( |
379 Address start, | 371 Address start, Address end, ObjectSlotCallback slot_callback, |
380 Address end, | |
381 ObjectSlotCallback slot_callback, | |
382 bool clear_maps) { | 372 bool clear_maps) { |
383 for (Address slot_address = start; | 373 for (Address slot_address = start; slot_address < end; |
384 slot_address < end; | |
385 slot_address += kPointerSize) { | 374 slot_address += kPointerSize) { |
386 Object** slot = reinterpret_cast<Object**>(slot_address); | 375 Object** slot = reinterpret_cast<Object**>(slot_address); |
387 Object* object = reinterpret_cast<Object*>( | 376 Object* object = reinterpret_cast<Object*>( |
388 base::NoBarrier_Load(reinterpret_cast<base::AtomicWord*>(slot))); | 377 base::NoBarrier_Load(reinterpret_cast<base::AtomicWord*>(slot))); |
389 if (heap_->InNewSpace(object)) { | 378 if (heap_->InNewSpace(object)) { |
390 HeapObject* heap_object = reinterpret_cast<HeapObject*>(object); | 379 HeapObject* heap_object = reinterpret_cast<HeapObject*>(object); |
391 DCHECK(heap_object->IsHeapObject()); | 380 DCHECK(heap_object->IsHeapObject()); |
392 // The new space object was not promoted if it still contains a map | 381 // The new space object was not promoted if it still contains a map |
393 // pointer. Clear the map field now lazily. | 382 // pointer. Clear the map field now lazily. |
394 if (clear_maps) ClearDeadObject(heap_object); | 383 if (clear_maps) ClearDeadObject(heap_object); |
395 slot_callback(reinterpret_cast<HeapObject**>(slot), heap_object); | 384 slot_callback(reinterpret_cast<HeapObject**>(slot), heap_object); |
396 object = reinterpret_cast<Object*>( | 385 object = reinterpret_cast<Object*>( |
397 base::NoBarrier_Load(reinterpret_cast<base::AtomicWord*>(slot))); | 386 base::NoBarrier_Load(reinterpret_cast<base::AtomicWord*>(slot))); |
398 if (heap_->InNewSpace(object)) { | 387 if (heap_->InNewSpace(object)) { |
399 EnterDirectlyIntoStoreBuffer(slot_address); | 388 EnterDirectlyIntoStoreBuffer(slot_address); |
400 } | 389 } |
401 } | 390 } |
402 } | 391 } |
403 } | 392 } |
404 | 393 |
405 | 394 |
406 void StoreBuffer::IteratePointersInStoreBuffer( | 395 void StoreBuffer::IteratePointersInStoreBuffer(ObjectSlotCallback slot_callback, |
407 ObjectSlotCallback slot_callback, | 396 bool clear_maps) { |
408 bool clear_maps) { | |
409 Address* limit = old_top_; | 397 Address* limit = old_top_; |
410 old_top_ = old_start_; | 398 old_top_ = old_start_; |
411 { | 399 { |
412 DontMoveStoreBufferEntriesScope scope(this); | 400 DontMoveStoreBufferEntriesScope scope(this); |
413 for (Address* current = old_start_; current < limit; current++) { | 401 for (Address* current = old_start_; current < limit; current++) { |
414 #ifdef DEBUG | 402 #ifdef DEBUG |
415 Address* saved_top = old_top_; | 403 Address* saved_top = old_top_; |
416 #endif | 404 #endif |
417 Object** slot = reinterpret_cast<Object**>(*current); | 405 Object** slot = reinterpret_cast<Object**>(*current); |
418 Object* object = reinterpret_cast<Object*>( | 406 Object* object = reinterpret_cast<Object*>( |
(...skipping 171 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
590 hash_set_1_[hash1] = int_addr; | 578 hash_set_1_[hash1] = int_addr; |
591 hash_set_2_[hash2] = 0; | 579 hash_set_2_[hash2] = 0; |
592 } | 580 } |
593 old_buffer_is_sorted_ = false; | 581 old_buffer_is_sorted_ = false; |
594 old_buffer_is_filtered_ = false; | 582 old_buffer_is_filtered_ = false; |
595 *old_top_++ = reinterpret_cast<Address>(int_addr << kPointerSizeLog2); | 583 *old_top_++ = reinterpret_cast<Address>(int_addr << kPointerSizeLog2); |
596 DCHECK(old_top_ <= old_limit_); | 584 DCHECK(old_top_ <= old_limit_); |
597 } | 585 } |
598 heap_->isolate()->counters()->store_buffer_compactions()->Increment(); | 586 heap_->isolate()->counters()->store_buffer_compactions()->Increment(); |
599 } | 587 } |
600 | 588 } |
601 } } // namespace v8::internal | 589 } // namespace v8::internal |
OLD | NEW |