OLD | NEW |
1 // Copyright 2010 the V8 project authors. All rights reserved. | 1 // Copyright 2010 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 |
(...skipping 22 matching lines...) Expand all Loading... |
33 namespace internal { | 33 namespace internal { |
34 | 34 |
35 Address* StoreBuffer::start_ = NULL; | 35 Address* StoreBuffer::start_ = NULL; |
36 Address* StoreBuffer::limit_ = NULL; | 36 Address* StoreBuffer::limit_ = NULL; |
37 Address* StoreBuffer::old_start_ = NULL; | 37 Address* StoreBuffer::old_start_ = NULL; |
38 Address* StoreBuffer::old_limit_ = NULL; | 38 Address* StoreBuffer::old_limit_ = NULL; |
39 Address* StoreBuffer::old_top_ = NULL; | 39 Address* StoreBuffer::old_top_ = NULL; |
40 uintptr_t* StoreBuffer::hash_map_1_ = NULL; | 40 uintptr_t* StoreBuffer::hash_map_1_ = NULL; |
41 uintptr_t* StoreBuffer::hash_map_2_ = NULL; | 41 uintptr_t* StoreBuffer::hash_map_2_ = NULL; |
42 VirtualMemory* StoreBuffer::virtual_memory_ = NULL; | 42 VirtualMemory* StoreBuffer::virtual_memory_ = NULL; |
43 bool StoreBuffer::must_scan_entire_memory_ = false; | 43 StoreBuffer::StoreBufferMode StoreBuffer::store_buffer_mode_ = |
| 44 kStoreBufferFunctional; |
44 bool StoreBuffer::old_buffer_is_sorted_ = false; | 45 bool StoreBuffer::old_buffer_is_sorted_ = false; |
45 bool StoreBuffer::during_gc_ = false; | 46 bool StoreBuffer::during_gc_ = false; |
| 47 bool StoreBuffer::store_buffer_rebuilding_enabled_ = false; |
| 48 bool StoreBuffer::may_move_store_buffer_entries_ = true; |
46 | 49 |
47 void StoreBuffer::Setup() { | 50 void StoreBuffer::Setup() { |
48 virtual_memory_ = new VirtualMemory(kStoreBufferSize * 3); | 51 virtual_memory_ = new VirtualMemory(kStoreBufferSize * 3); |
49 uintptr_t start_as_int = | 52 uintptr_t start_as_int = |
50 reinterpret_cast<uintptr_t>(virtual_memory_->address()); | 53 reinterpret_cast<uintptr_t>(virtual_memory_->address()); |
51 start_ = | 54 start_ = |
52 reinterpret_cast<Address*>(RoundUp(start_as_int, kStoreBufferSize * 2)); | 55 reinterpret_cast<Address*>(RoundUp(start_as_int, kStoreBufferSize * 2)); |
53 limit_ = start_ + (kStoreBufferSize / sizeof(*start_)); | 56 limit_ = start_ + (kStoreBufferSize / sizeof(*start_)); |
54 | 57 |
55 old_top_ = old_start_ = new Address[kOldStoreBufferLength]; | 58 old_top_ = old_start_ = new Address[kOldStoreBufferLength]; |
(...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
119 return (a >> kPointerSizeLog2) - (b >> kPointerSizeLog2); | 122 return (a >> kPointerSizeLog2) - (b >> kPointerSizeLog2); |
120 } | 123 } |
121 #endif | 124 #endif |
122 | 125 |
123 | 126 |
124 void StoreBuffer::Uniq() { | 127 void StoreBuffer::Uniq() { |
125 ASSERT(HashTablesAreZapped()); | 128 ASSERT(HashTablesAreZapped()); |
126 // Remove adjacent duplicates and cells that do not point at new space. | 129 // Remove adjacent duplicates and cells that do not point at new space. |
127 Address previous = NULL; | 130 Address previous = NULL; |
128 Address* write = old_start_; | 131 Address* write = old_start_; |
| 132 ASSERT(may_move_store_buffer_entries_); |
129 for (Address* read = old_start_; read < old_top_; read++) { | 133 for (Address* read = old_start_; read < old_top_; read++) { |
130 Address current = *read; | 134 Address current = *read; |
131 if (current != previous) { | 135 if (current != previous) { |
132 if (Heap::InNewSpace(*reinterpret_cast<Address*>(current))) { | 136 if (Heap::InNewSpace(*reinterpret_cast<Object**>(current))) { |
133 *write++ = current; | 137 *write++ = current; |
134 } | 138 } |
135 } | 139 } |
136 previous = current; | 140 previous = current; |
137 } | 141 } |
138 old_top_ = write; | 142 old_top_ = write; |
139 } | 143 } |
140 | 144 |
141 | 145 |
142 void StoreBuffer::SortUniq() { | 146 void StoreBuffer::SortUniq() { |
143 Compact(); | 147 Compact(); |
144 if (old_buffer_is_sorted_) return; | 148 if (old_buffer_is_sorted_) return; |
| 149 if (store_buffer_mode_ == kStoreBufferDisabled) { |
| 150 old_top_ = old_start_; |
| 151 return; |
| 152 } |
145 ZapHashTables(); | 153 ZapHashTables(); |
146 qsort(reinterpret_cast<void*>(old_start_), | 154 qsort(reinterpret_cast<void*>(old_start_), |
147 old_top_ - old_start_, | 155 old_top_ - old_start_, |
148 sizeof(*old_top_), | 156 sizeof(*old_top_), |
149 &CompareAddresses); | 157 &CompareAddresses); |
150 Uniq(); | 158 Uniq(); |
151 | 159 |
152 old_buffer_is_sorted_ = true; | 160 old_buffer_is_sorted_ = true; |
153 } | 161 } |
154 | 162 |
155 | 163 |
156 #ifdef DEBUG | 164 #ifdef DEBUG |
157 void StoreBuffer::Clean() { | 165 void StoreBuffer::Clean() { |
158 if (must_scan_entire_memory_) { | 166 if (store_buffer_mode_ == kStoreBufferDisabled) { |
159 // We don't currently have a way to go back to using the store buffer. | |
160 // TODO(gc): We should rebuild the store buffer during GC. | |
161 old_top_ = old_start_; // Just clear the cache. | 167 old_top_ = old_start_; // Just clear the cache. |
162 return; | 168 return; |
163 } | 169 } |
164 ZapHashTables(); | 170 ZapHashTables(); |
165 Uniq(); // Also removes things that no longer point to new space. | 171 Uniq(); // Also removes things that no longer point to new space. |
166 CheckForFullBuffer(); | 172 CheckForFullBuffer(); |
167 } | 173 } |
168 | 174 |
169 | 175 |
170 static bool Zapped(char* start, int size) { | 176 static bool Zapped(char* start, int size) { |
(...skipping 21 matching lines...) Expand all Loading... |
192 sizeof(uintptr_t) * kHashMapLength); | 198 sizeof(uintptr_t) * kHashMapLength); |
193 memset(reinterpret_cast<void*>(hash_map_2_), | 199 memset(reinterpret_cast<void*>(hash_map_2_), |
194 0, | 200 0, |
195 sizeof(uintptr_t) * kHashMapLength); | 201 sizeof(uintptr_t) * kHashMapLength); |
196 } | 202 } |
197 | 203 |
198 | 204 |
199 void StoreBuffer::GCPrologue(GCType type, GCCallbackFlags flags) { | 205 void StoreBuffer::GCPrologue(GCType type, GCCallbackFlags flags) { |
200 ZapHashTables(); | 206 ZapHashTables(); |
201 during_gc_ = true; | 207 during_gc_ = true; |
202 if (type != kGCTypeScavenge) { | |
203 old_top_ = old_start_; | |
204 Heap::public_set_store_buffer_top(start_); | |
205 } | |
206 } | 208 } |
207 | 209 |
208 | 210 |
209 void StoreBuffer::Verify() { | 211 void StoreBuffer::Verify() { |
210 #ifdef DEBUG | 212 #ifdef DEBUG |
211 if (FLAG_verify_heap && !StoreBuffer::must_scan_entire_memory()) { | 213 if (FLAG_verify_heap && |
| 214 StoreBuffer::store_buffer_mode_ == kStoreBufferFunctional) { |
212 Heap::OldPointerSpaceCheckStoreBuffer(Heap::WATERMARK_SHOULD_BE_VALID); | 215 Heap::OldPointerSpaceCheckStoreBuffer(Heap::WATERMARK_SHOULD_BE_VALID); |
213 Heap::MapSpaceCheckStoreBuffer(Heap::WATERMARK_SHOULD_BE_VALID); | 216 Heap::MapSpaceCheckStoreBuffer(Heap::WATERMARK_SHOULD_BE_VALID); |
214 Heap::LargeObjectSpaceCheckStoreBuffer(); | 217 Heap::LargeObjectSpaceCheckStoreBuffer(); |
215 } | 218 } |
216 #endif | 219 #endif |
217 } | 220 } |
218 | 221 |
219 | 222 |
220 void StoreBuffer::GCEpilogue(GCType type, GCCallbackFlags flags) { | 223 void StoreBuffer::GCEpilogue(GCType type, GCCallbackFlags flags) { |
221 during_gc_ = false; | 224 during_gc_ = false; |
| 225 if (store_buffer_mode_ == kStoreBufferBeingRebuilt) { |
| 226 store_buffer_mode_ = kStoreBufferFunctional; |
| 227 } |
222 Verify(); | 228 Verify(); |
223 } | 229 } |
224 | 230 |
225 | 231 |
| 232 void StoreBuffer::IteratePointersToNewSpace(ObjectSlotCallback callback) { |
| 233 if (store_buffer_mode_ != kStoreBufferFunctional) { |
| 234 old_top_ = old_start_; |
| 235 ZapHashTables(); |
| 236 Heap::public_set_store_buffer_top(start_); |
| 237 store_buffer_mode_ = kStoreBufferBeingRebuilt; |
| 238 Heap::IteratePointers(Heap::old_pointer_space(), |
| 239 &Heap::IteratePointersToNewSpace, |
| 240 callback, |
| 241 Heap::WATERMARK_SHOULD_BE_VALID); |
| 242 |
| 243 Heap::IteratePointers(Heap::map_space(), |
| 244 &Heap::IteratePointersFromMapsToNewSpace, |
| 245 callback, |
| 246 Heap::WATERMARK_SHOULD_BE_VALID); |
| 247 |
| 248 Heap::lo_space()->IteratePointersToNewSpace(callback); |
| 249 } else { |
| 250 SortUniq(); |
| 251 Address* limit = old_top_; |
| 252 old_top_ = old_start_; |
| 253 { |
| 254 DontMoveStoreBufferEntriesScope scope; |
| 255 for (Address* current = old_start_; current < limit; current++) { |
| 256 #ifdef DEBUG |
| 257 Address* saved_top = old_top_; |
| 258 #endif |
| 259 Object** cell = reinterpret_cast<Object**>(*current); |
| 260 Object* object = *cell; |
| 261 // May be invalid if object is not in new space. |
| 262 HeapObject* heap_object = reinterpret_cast<HeapObject*>(object); |
| 263 if (Heap::InNewSpace(object)) { |
| 264 callback(reinterpret_cast<HeapObject**>(cell), heap_object); |
| 265 } |
| 266 ASSERT(old_top_ == saved_top + 1 || old_top_ == saved_top); |
| 267 ASSERT((old_top_ == saved_top + 1) == |
| 268 (Heap::InNewSpace(*cell) && |
| 269 !Heap::InNewSpace(reinterpret_cast<Address>(cell)) && |
| 270 Memory::Address_at(heap_object->address()) != NULL)); |
| 271 } |
| 272 } |
| 273 } |
| 274 } |
| 275 |
| 276 |
226 void StoreBuffer::Compact() { | 277 void StoreBuffer::Compact() { |
227 Address* top = reinterpret_cast<Address*>(Heap::store_buffer_top()); | 278 Address* top = reinterpret_cast<Address*>(Heap::store_buffer_top()); |
| 279 |
228 if (top == start_) return; | 280 if (top == start_) return; |
| 281 |
| 282 // There's no check of the limit in the loop below so we check here for |
| 283 // the worst case (compaction doesn't eliminate any pointers). |
229 ASSERT(top <= limit_); | 284 ASSERT(top <= limit_); |
230 Heap::public_set_store_buffer_top(start_); | 285 Heap::public_set_store_buffer_top(start_); |
231 if (must_scan_entire_memory_) return; | 286 if (top - start_ > old_limit_ - old_top_) { |
| 287 CheckForFullBuffer(); |
| 288 } |
| 289 if (store_buffer_mode_ == kStoreBufferDisabled) return; |
| 290 ASSERT(may_move_store_buffer_entries_); |
232 // Goes through the addresses in the store buffer attempting to remove | 291 // Goes through the addresses in the store buffer attempting to remove |
233 // duplicates. In the interest of speed this is a lossy operation. Some | 292 // duplicates. In the interest of speed this is a lossy operation. Some |
234 // duplicates will remain. We have two hash tables with different hash | 293 // duplicates will remain. We have two hash tables with different hash |
235 // functions to reduce the number of unnecessary clashes. | 294 // functions to reduce the number of unnecessary clashes. |
236 for (Address* current = start_; current < top; current++) { | 295 for (Address* current = start_; current < top; current++) { |
237 uintptr_t int_addr = reinterpret_cast<uintptr_t>(*current); | 296 uintptr_t int_addr = reinterpret_cast<uintptr_t>(*current); |
238 // Shift out the last bits including any tags. | 297 // Shift out the last bits including any tags. |
239 int_addr >>= kPointerSizeLog2; | 298 int_addr >>= kPointerSizeLog2; |
240 int hash1 = | 299 int hash1 = |
241 ((int_addr ^ (int_addr >> kHashMapLengthLog2)) & (kHashMapLength - 1)); | 300 ((int_addr ^ (int_addr >> kHashMapLengthLog2)) & (kHashMapLength - 1)); |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
274 return; | 333 return; |
275 } | 334 } |
276 // TODO(gc): Set an interrupt to do a GC on the next back edge. | 335 // TODO(gc): Set an interrupt to do a GC on the next back edge. |
277 // TODO(gc): Allocate the rest of new space to force a GC on the next | 336 // TODO(gc): Allocate the rest of new space to force a GC on the next |
278 // allocation. | 337 // allocation. |
279 if (old_limit_ - old_top_ < kStoreBufferSize) { | 338 if (old_limit_ - old_top_ < kStoreBufferSize) { |
280 // After compression we don't even have enough space for the next | 339 // After compression we don't even have enough space for the next |
281 // compression to be guaranteed to succeed. | 340 // compression to be guaranteed to succeed. |
282 // TODO(gc): Set a flag to scan all of memory. | 341 // TODO(gc): Set a flag to scan all of memory. |
283 Counters::store_buffer_overflows.Increment(); | 342 Counters::store_buffer_overflows.Increment(); |
284 must_scan_entire_memory_ = true; | 343 store_buffer_mode_ = kStoreBufferDisabled; |
285 } | 344 } |
286 } | 345 } |
287 } | 346 } |
288 | 347 |
289 } } // namespace v8::internal | 348 } } // namespace v8::internal |
OLD | NEW |