OLD | NEW |
1 // Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file | 1 // Copyright (c) 2011, the Dart project authors. Please see the AUTHORS file |
2 // for details. All rights reserved. Use of this source code is governed by a | 2 // for details. All rights reserved. Use of this source code is governed by a |
3 // BSD-style license that can be found in the LICENSE file. | 3 // BSD-style license that can be found in the LICENSE file. |
4 | 4 |
5 #include "vm/scavenger.h" | 5 #include "vm/scavenger.h" |
6 | 6 |
7 #include "vm/dart.h" | 7 #include "vm/dart.h" |
8 #include "vm/dart_api_state.h" | 8 #include "vm/dart_api_state.h" |
9 #include "vm/isolate.h" | 9 #include "vm/isolate.h" |
10 #include "vm/lockers.h" | 10 #include "vm/lockers.h" |
11 #include "vm/object.h" | 11 #include "vm/object.h" |
| 12 #include "vm/object_id_ring.h" |
12 #include "vm/object_set.h" | 13 #include "vm/object_set.h" |
13 #include "vm/object_id_ring.h" | |
14 #include "vm/safepoint.h" | 14 #include "vm/safepoint.h" |
15 #include "vm/stack_frame.h" | 15 #include "vm/stack_frame.h" |
16 #include "vm/store_buffer.h" | 16 #include "vm/store_buffer.h" |
17 #include "vm/thread_registry.h" | 17 #include "vm/thread_registry.h" |
18 #include "vm/timeline.h" | 18 #include "vm/timeline.h" |
19 #include "vm/verifier.h" | 19 #include "vm/verifier.h" |
20 #include "vm/visitor.h" | 20 #include "vm/visitor.h" |
21 #include "vm/weak_table.h" | 21 #include "vm/weak_table.h" |
22 | 22 |
23 namespace dart { | 23 namespace dart { |
(...skipping 11 matching lines...) Expand all Loading... |
35 | 35 |
36 // Scavenger uses RawObject::kMarkBit to distinguish forwarded and non-forwarded | 36 // Scavenger uses RawObject::kMarkBit to distinguish forwarded and non-forwarded |
37 // objects. The kMarkBit does not intersect with the target address because of | 37 // objects. The kMarkBit does not intersect with the target address because of |
38 // object alignment. | 38 // object alignment. |
39 enum { | 39 enum { |
40 kForwardingMask = 1 << RawObject::kMarkBit, | 40 kForwardingMask = 1 << RawObject::kMarkBit, |
41 kNotForwarded = 0, | 41 kNotForwarded = 0, |
42 kForwarded = kForwardingMask, | 42 kForwarded = kForwardingMask, |
43 }; | 43 }; |
44 | 44 |
45 | |
46 static inline bool IsForwarding(uword header) { | 45 static inline bool IsForwarding(uword header) { |
47 uword bits = header & kForwardingMask; | 46 uword bits = header & kForwardingMask; |
48 ASSERT((bits == kNotForwarded) || (bits == kForwarded)); | 47 ASSERT((bits == kNotForwarded) || (bits == kForwarded)); |
49 return bits == kForwarded; | 48 return bits == kForwarded; |
50 } | 49 } |
51 | 50 |
52 | |
53 static inline uword ForwardedAddr(uword header) { | 51 static inline uword ForwardedAddr(uword header) { |
54 ASSERT(IsForwarding(header)); | 52 ASSERT(IsForwarding(header)); |
55 return header & ~kForwardingMask; | 53 return header & ~kForwardingMask; |
56 } | 54 } |
57 | 55 |
58 | |
59 static inline void ForwardTo(uword original, uword target) { | 56 static inline void ForwardTo(uword original, uword target) { |
60 // Make sure forwarding can be encoded. | 57 // Make sure forwarding can be encoded. |
61 ASSERT((target & kForwardingMask) == 0); | 58 ASSERT((target & kForwardingMask) == 0); |
62 *reinterpret_cast<uword*>(original) = target | kForwarded; | 59 *reinterpret_cast<uword*>(original) = target | kForwarded; |
63 } | 60 } |
64 | 61 |
65 | |
66 class ScavengerVisitor : public ObjectPointerVisitor { | 62 class ScavengerVisitor : public ObjectPointerVisitor { |
67 public: | 63 public: |
68 explicit ScavengerVisitor(Isolate* isolate, | 64 explicit ScavengerVisitor(Isolate* isolate, |
69 Scavenger* scavenger, | 65 Scavenger* scavenger, |
70 SemiSpace* from) | 66 SemiSpace* from) |
71 : ObjectPointerVisitor(isolate), | 67 : ObjectPointerVisitor(isolate), |
72 thread_(Thread::Current()), | 68 thread_(Thread::Current()), |
73 scavenger_(scavenger), | 69 scavenger_(scavenger), |
74 from_(from), | 70 from_(from), |
75 heap_(scavenger->heap_), | 71 heap_(scavenger->heap_), |
(...skipping 110 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
186 PageSpace* page_space_; | 182 PageSpace* page_space_; |
187 RawWeakProperty* delayed_weak_properties_; | 183 RawWeakProperty* delayed_weak_properties_; |
188 intptr_t bytes_promoted_; | 184 intptr_t bytes_promoted_; |
189 RawObject* visiting_old_object_; | 185 RawObject* visiting_old_object_; |
190 | 186 |
191 friend class Scavenger; | 187 friend class Scavenger; |
192 | 188 |
193 DISALLOW_COPY_AND_ASSIGN(ScavengerVisitor); | 189 DISALLOW_COPY_AND_ASSIGN(ScavengerVisitor); |
194 }; | 190 }; |
195 | 191 |
196 | |
197 class ScavengerWeakVisitor : public HandleVisitor { | 192 class ScavengerWeakVisitor : public HandleVisitor { |
198 public: | 193 public: |
199 ScavengerWeakVisitor(Thread* thread, Scavenger* scavenger) | 194 ScavengerWeakVisitor(Thread* thread, Scavenger* scavenger) |
200 : HandleVisitor(thread), scavenger_(scavenger) { | 195 : HandleVisitor(thread), scavenger_(scavenger) { |
201 ASSERT(scavenger->heap_->isolate() == thread->isolate()); | 196 ASSERT(scavenger->heap_->isolate() == thread->isolate()); |
202 } | 197 } |
203 | 198 |
204 void VisitHandle(uword addr) { | 199 void VisitHandle(uword addr) { |
205 FinalizablePersistentHandle* handle = | 200 FinalizablePersistentHandle* handle = |
206 reinterpret_cast<FinalizablePersistentHandle*>(addr); | 201 reinterpret_cast<FinalizablePersistentHandle*>(addr); |
207 RawObject** p = handle->raw_addr(); | 202 RawObject** p = handle->raw_addr(); |
208 if (scavenger_->IsUnreachable(p)) { | 203 if (scavenger_->IsUnreachable(p)) { |
209 handle->UpdateUnreachable(thread()->isolate()); | 204 handle->UpdateUnreachable(thread()->isolate()); |
210 } else { | 205 } else { |
211 handle->UpdateRelocated(thread()->isolate()); | 206 handle->UpdateRelocated(thread()->isolate()); |
212 } | 207 } |
213 } | 208 } |
214 | 209 |
215 private: | 210 private: |
216 Scavenger* scavenger_; | 211 Scavenger* scavenger_; |
217 | 212 |
218 DISALLOW_COPY_AND_ASSIGN(ScavengerWeakVisitor); | 213 DISALLOW_COPY_AND_ASSIGN(ScavengerWeakVisitor); |
219 }; | 214 }; |
220 | 215 |
221 | |
222 // Visitor used to verify that all old->new references have been added to the | 216 // Visitor used to verify that all old->new references have been added to the |
223 // StoreBuffers. | 217 // StoreBuffers. |
224 class VerifyStoreBufferPointerVisitor : public ObjectPointerVisitor { | 218 class VerifyStoreBufferPointerVisitor : public ObjectPointerVisitor { |
225 public: | 219 public: |
226 VerifyStoreBufferPointerVisitor(Isolate* isolate, const SemiSpace* to) | 220 VerifyStoreBufferPointerVisitor(Isolate* isolate, const SemiSpace* to) |
227 : ObjectPointerVisitor(isolate), to_(to) {} | 221 : ObjectPointerVisitor(isolate), to_(to) {} |
228 | 222 |
229 void VisitPointers(RawObject** first, RawObject** last) { | 223 void VisitPointers(RawObject** first, RawObject** last) { |
230 for (RawObject** current = first; current <= last; current++) { | 224 for (RawObject** current = first; current <= last; current++) { |
231 RawObject* obj = *current; | 225 RawObject* obj = *current; |
232 if (obj->IsHeapObject() && obj->IsNewObject()) { | 226 if (obj->IsHeapObject() && obj->IsNewObject()) { |
233 ASSERT(to_->Contains(RawObject::ToAddr(obj))); | 227 ASSERT(to_->Contains(RawObject::ToAddr(obj))); |
234 } | 228 } |
235 } | 229 } |
236 } | 230 } |
237 | 231 |
238 private: | 232 private: |
239 const SemiSpace* to_; | 233 const SemiSpace* to_; |
240 | 234 |
241 DISALLOW_COPY_AND_ASSIGN(VerifyStoreBufferPointerVisitor); | 235 DISALLOW_COPY_AND_ASSIGN(VerifyStoreBufferPointerVisitor); |
242 }; | 236 }; |
243 | 237 |
244 | |
245 SemiSpace::SemiSpace(VirtualMemory* reserved) | 238 SemiSpace::SemiSpace(VirtualMemory* reserved) |
246 : reserved_(reserved), region_(NULL, 0) { | 239 : reserved_(reserved), region_(NULL, 0) { |
247 if (reserved != NULL) { | 240 if (reserved != NULL) { |
248 region_ = MemoryRegion(reserved_->address(), reserved_->size()); | 241 region_ = MemoryRegion(reserved_->address(), reserved_->size()); |
249 } | 242 } |
250 } | 243 } |
251 | 244 |
252 | |
253 SemiSpace::~SemiSpace() { | 245 SemiSpace::~SemiSpace() { |
254 if (reserved_ != NULL) { | 246 if (reserved_ != NULL) { |
255 #if defined(DEBUG) | 247 #if defined(DEBUG) |
256 memset(reserved_->address(), Heap::kZapByte, size_in_words() | 248 memset(reserved_->address(), Heap::kZapByte, |
257 << kWordSizeLog2); | 249 size_in_words() << kWordSizeLog2); |
258 #endif // defined(DEBUG) | 250 #endif // defined(DEBUG) |
259 delete reserved_; | 251 delete reserved_; |
260 } | 252 } |
261 } | 253 } |
262 | 254 |
263 | |
264 Mutex* SemiSpace::mutex_ = NULL; | 255 Mutex* SemiSpace::mutex_ = NULL; |
265 SemiSpace* SemiSpace::cache_ = NULL; | 256 SemiSpace* SemiSpace::cache_ = NULL; |
266 | 257 |
267 | |
268 void SemiSpace::InitOnce() { | 258 void SemiSpace::InitOnce() { |
269 ASSERT(mutex_ == NULL); | 259 ASSERT(mutex_ == NULL); |
270 mutex_ = new Mutex(); | 260 mutex_ = new Mutex(); |
271 ASSERT(mutex_ != NULL); | 261 ASSERT(mutex_ != NULL); |
272 } | 262 } |
273 | 263 |
274 | |
275 SemiSpace* SemiSpace::New(intptr_t size_in_words, const char* name) { | 264 SemiSpace* SemiSpace::New(intptr_t size_in_words, const char* name) { |
276 { | 265 { |
277 MutexLocker locker(mutex_); | 266 MutexLocker locker(mutex_); |
278 // TODO(koda): Cache one entry per size. | 267 // TODO(koda): Cache one entry per size. |
279 if (cache_ != NULL && cache_->size_in_words() == size_in_words) { | 268 if (cache_ != NULL && cache_->size_in_words() == size_in_words) { |
280 SemiSpace* result = cache_; | 269 SemiSpace* result = cache_; |
281 cache_ = NULL; | 270 cache_ = NULL; |
282 return result; | 271 return result; |
283 } | 272 } |
284 } | 273 } |
285 if (size_in_words == 0) { | 274 if (size_in_words == 0) { |
286 return new SemiSpace(NULL); | 275 return new SemiSpace(NULL); |
287 } else { | 276 } else { |
288 intptr_t size_in_bytes = size_in_words << kWordSizeLog2; | 277 intptr_t size_in_bytes = size_in_words << kWordSizeLog2; |
289 VirtualMemory* reserved = VirtualMemory::Reserve(size_in_bytes); | 278 VirtualMemory* reserved = VirtualMemory::Reserve(size_in_bytes); |
290 const bool kExecutable = false; | 279 const bool kExecutable = false; |
291 if ((reserved == NULL) || !reserved->Commit(kExecutable, name)) { | 280 if ((reserved == NULL) || !reserved->Commit(kExecutable, name)) { |
292 // TODO(koda): If cache_ is not empty, we could try to delete it. | 281 // TODO(koda): If cache_ is not empty, we could try to delete it. |
293 delete reserved; | 282 delete reserved; |
294 return NULL; | 283 return NULL; |
295 } | 284 } |
296 #if defined(DEBUG) | 285 #if defined(DEBUG) |
297 memset(reserved->address(), Heap::kZapByte, size_in_bytes); | 286 memset(reserved->address(), Heap::kZapByte, size_in_bytes); |
298 #endif // defined(DEBUG) | 287 #endif // defined(DEBUG) |
299 return new SemiSpace(reserved); | 288 return new SemiSpace(reserved); |
300 } | 289 } |
301 } | 290 } |
302 | 291 |
303 | |
304 void SemiSpace::Delete() { | 292 void SemiSpace::Delete() { |
305 #ifdef DEBUG | 293 #ifdef DEBUG |
306 if (reserved_ != NULL) { | 294 if (reserved_ != NULL) { |
307 const intptr_t size_in_bytes = size_in_words() << kWordSizeLog2; | 295 const intptr_t size_in_bytes = size_in_words() << kWordSizeLog2; |
308 memset(reserved_->address(), Heap::kZapByte, size_in_bytes); | 296 memset(reserved_->address(), Heap::kZapByte, size_in_bytes); |
309 } | 297 } |
310 #endif | 298 #endif |
311 SemiSpace* old_cache = NULL; | 299 SemiSpace* old_cache = NULL; |
312 { | 300 { |
313 MutexLocker locker(mutex_); | 301 MutexLocker locker(mutex_); |
314 old_cache = cache_; | 302 old_cache = cache_; |
315 cache_ = this; | 303 cache_ = this; |
316 } | 304 } |
317 delete old_cache; | 305 delete old_cache; |
318 } | 306 } |
319 | 307 |
320 | |
321 void SemiSpace::WriteProtect(bool read_only) { | 308 void SemiSpace::WriteProtect(bool read_only) { |
322 if (reserved_ != NULL) { | 309 if (reserved_ != NULL) { |
323 bool success = reserved_->Protect(read_only ? VirtualMemory::kReadOnly | 310 bool success = reserved_->Protect(read_only ? VirtualMemory::kReadOnly |
324 : VirtualMemory::kReadWrite); | 311 : VirtualMemory::kReadWrite); |
325 ASSERT(success); | 312 ASSERT(success); |
326 } | 313 } |
327 } | 314 } |
328 | 315 |
329 | |
330 Scavenger::Scavenger(Heap* heap, | 316 Scavenger::Scavenger(Heap* heap, |
331 intptr_t max_semi_capacity_in_words, | 317 intptr_t max_semi_capacity_in_words, |
332 uword object_alignment) | 318 uword object_alignment) |
333 : heap_(heap), | 319 : heap_(heap), |
334 max_semi_capacity_in_words_(max_semi_capacity_in_words), | 320 max_semi_capacity_in_words_(max_semi_capacity_in_words), |
335 object_alignment_(object_alignment), | 321 object_alignment_(object_alignment), |
336 scavenging_(false), | 322 scavenging_(false), |
337 delayed_weak_properties_(NULL), | 323 delayed_weak_properties_(NULL), |
338 gc_time_micros_(0), | 324 gc_time_micros_(0), |
339 collections_(0), | 325 collections_(0), |
(...skipping 19 matching lines...) Expand all Loading... |
359 top_ = FirstObjectStart(); | 345 top_ = FirstObjectStart(); |
360 resolved_top_ = top_; | 346 resolved_top_ = top_; |
361 end_ = to_->end(); | 347 end_ = to_->end(); |
362 | 348 |
363 survivor_end_ = FirstObjectStart(); | 349 survivor_end_ = FirstObjectStart(); |
364 | 350 |
365 UpdateMaxHeapCapacity(); | 351 UpdateMaxHeapCapacity(); |
366 UpdateMaxHeapUsage(); | 352 UpdateMaxHeapUsage(); |
367 } | 353 } |
368 | 354 |
369 | |
370 Scavenger::~Scavenger() { | 355 Scavenger::~Scavenger() { |
371 ASSERT(!scavenging_); | 356 ASSERT(!scavenging_); |
372 to_->Delete(); | 357 to_->Delete(); |
373 } | 358 } |
374 | 359 |
375 | |
376 intptr_t Scavenger::NewSizeInWords(intptr_t old_size_in_words) const { | 360 intptr_t Scavenger::NewSizeInWords(intptr_t old_size_in_words) const { |
377 if (stats_history_.Size() == 0) { | 361 if (stats_history_.Size() == 0) { |
378 return old_size_in_words; | 362 return old_size_in_words; |
379 } | 363 } |
380 double garbage = stats_history_.Get(0).GarbageFraction(); | 364 double garbage = stats_history_.Get(0).GarbageFraction(); |
381 if (garbage < (FLAG_new_gen_garbage_threshold / 100.0)) { | 365 if (garbage < (FLAG_new_gen_garbage_threshold / 100.0)) { |
382 return Utils::Minimum(max_semi_capacity_in_words_, | 366 return Utils::Minimum(max_semi_capacity_in_words_, |
383 old_size_in_words * FLAG_new_gen_growth_factor); | 367 old_size_in_words * FLAG_new_gen_growth_factor); |
384 } else { | 368 } else { |
385 return old_size_in_words; | 369 return old_size_in_words; |
386 } | 370 } |
387 } | 371 } |
388 | 372 |
389 | |
390 SemiSpace* Scavenger::Prologue(Isolate* isolate, bool invoke_api_callbacks) { | 373 SemiSpace* Scavenger::Prologue(Isolate* isolate, bool invoke_api_callbacks) { |
391 if (invoke_api_callbacks && (isolate->gc_prologue_callback() != NULL)) { | 374 if (invoke_api_callbacks && (isolate->gc_prologue_callback() != NULL)) { |
392 (isolate->gc_prologue_callback())(); | 375 (isolate->gc_prologue_callback())(); |
393 } | 376 } |
394 isolate->PrepareForGC(); | 377 isolate->PrepareForGC(); |
395 // Flip the two semi-spaces so that to_ is always the space for allocating | 378 // Flip the two semi-spaces so that to_ is always the space for allocating |
396 // objects. | 379 // objects. |
397 SemiSpace* from = to_; | 380 SemiSpace* from = to_; |
398 | 381 |
399 const intptr_t kVmNameSize = 128; | 382 const intptr_t kVmNameSize = 128; |
400 char vm_name[kVmNameSize]; | 383 char vm_name[kVmNameSize]; |
401 Heap::RegionName(heap_, Heap::kNew, vm_name, kVmNameSize); | 384 Heap::RegionName(heap_, Heap::kNew, vm_name, kVmNameSize); |
402 to_ = SemiSpace::New(NewSizeInWords(from->size_in_words()), vm_name); | 385 to_ = SemiSpace::New(NewSizeInWords(from->size_in_words()), vm_name); |
403 if (to_ == NULL) { | 386 if (to_ == NULL) { |
404 // TODO(koda): We could try to recover (collect old space, wait for another | 387 // TODO(koda): We could try to recover (collect old space, wait for another |
405 // isolate to finish scavenge, etc.). | 388 // isolate to finish scavenge, etc.). |
406 OUT_OF_MEMORY(); | 389 OUT_OF_MEMORY(); |
407 } | 390 } |
408 UpdateMaxHeapCapacity(); | 391 UpdateMaxHeapCapacity(); |
409 top_ = FirstObjectStart(); | 392 top_ = FirstObjectStart(); |
410 resolved_top_ = top_; | 393 resolved_top_ = top_; |
411 end_ = to_->end(); | 394 end_ = to_->end(); |
412 return from; | 395 return from; |
413 } | 396 } |
414 | 397 |
415 | |
416 void Scavenger::Epilogue(Isolate* isolate, | 398 void Scavenger::Epilogue(Isolate* isolate, |
417 SemiSpace* from, | 399 SemiSpace* from, |
418 bool invoke_api_callbacks) { | 400 bool invoke_api_callbacks) { |
419 // All objects in the to space have been copied from the from space at this | 401 // All objects in the to space have been copied from the from space at this |
420 // moment. | 402 // moment. |
421 double avg_frac = stats_history_.Get(0).PromoCandidatesSuccessFraction(); | 403 double avg_frac = stats_history_.Get(0).PromoCandidatesSuccessFraction(); |
422 if (stats_history_.Size() >= 2) { | 404 if (stats_history_.Size() >= 2) { |
423 // Previous scavenge is only given half as much weight. | 405 // Previous scavenge is only given half as much weight. |
424 avg_frac += 0.5 * stats_history_.Get(1).PromoCandidatesSuccessFraction(); | 406 avg_frac += 0.5 * stats_history_.Get(1).PromoCandidatesSuccessFraction(); |
425 avg_frac /= 1.0 + 0.5; // Normalize. | 407 avg_frac /= 1.0 + 0.5; // Normalize. |
(...skipping 22 matching lines...) Expand all Loading... |
448 from->Delete(); | 430 from->Delete(); |
449 UpdateMaxHeapUsage(); | 431 UpdateMaxHeapUsage(); |
450 if (heap_ != NULL) { | 432 if (heap_ != NULL) { |
451 heap_->UpdateGlobalMaxUsed(); | 433 heap_->UpdateGlobalMaxUsed(); |
452 } | 434 } |
453 if (invoke_api_callbacks && (isolate->gc_epilogue_callback() != NULL)) { | 435 if (invoke_api_callbacks && (isolate->gc_epilogue_callback() != NULL)) { |
454 (isolate->gc_epilogue_callback())(); | 436 (isolate->gc_epilogue_callback())(); |
455 } | 437 } |
456 } | 438 } |
457 | 439 |
458 | |
459 void Scavenger::IterateStoreBuffers(Isolate* isolate, | 440 void Scavenger::IterateStoreBuffers(Isolate* isolate, |
460 ScavengerVisitor* visitor) { | 441 ScavengerVisitor* visitor) { |
461 // Iterating through the store buffers. | 442 // Iterating through the store buffers. |
462 // Grab the deduplication sets out of the isolate's consolidated store buffer. | 443 // Grab the deduplication sets out of the isolate's consolidated store buffer. |
463 StoreBufferBlock* pending = isolate->store_buffer()->Blocks(); | 444 StoreBufferBlock* pending = isolate->store_buffer()->Blocks(); |
464 intptr_t total_count = 0; | 445 intptr_t total_count = 0; |
465 while (pending != NULL) { | 446 while (pending != NULL) { |
466 StoreBufferBlock* next = pending->next(); | 447 StoreBufferBlock* next = pending->next(); |
467 // Generated code appends to store buffers; tell MemorySanitizer. | 448 // Generated code appends to store buffers; tell MemorySanitizer. |
468 MSAN_UNPOISON(pending, sizeof(*pending)); | 449 MSAN_UNPOISON(pending, sizeof(*pending)); |
(...skipping 16 matching lines...) Expand all Loading... |
485 isolate->store_buffer()->PushBlock(pending, StoreBuffer::kIgnoreThreshold); | 466 isolate->store_buffer()->PushBlock(pending, StoreBuffer::kIgnoreThreshold); |
486 pending = next; | 467 pending = next; |
487 } | 468 } |
488 heap_->RecordData(kStoreBufferEntries, total_count); | 469 heap_->RecordData(kStoreBufferEntries, total_count); |
489 heap_->RecordData(kDataUnused1, 0); | 470 heap_->RecordData(kDataUnused1, 0); |
490 heap_->RecordData(kDataUnused2, 0); | 471 heap_->RecordData(kDataUnused2, 0); |
491 // Done iterating through old objects remembered in the store buffers. | 472 // Done iterating through old objects remembered in the store buffers. |
492 visitor->VisitingOldObject(NULL); | 473 visitor->VisitingOldObject(NULL); |
493 } | 474 } |
494 | 475 |
495 | |
496 void Scavenger::IterateObjectIdTable(Isolate* isolate, | 476 void Scavenger::IterateObjectIdTable(Isolate* isolate, |
497 ScavengerVisitor* visitor) { | 477 ScavengerVisitor* visitor) { |
498 #ifndef PRODUCT | 478 #ifndef PRODUCT |
499 if (!FLAG_support_service) { | 479 if (!FLAG_support_service) { |
500 return; | 480 return; |
501 } | 481 } |
502 ObjectIdRing* ring = isolate->object_id_ring(); | 482 ObjectIdRing* ring = isolate->object_id_ring(); |
503 if (ring == NULL) { | 483 if (ring == NULL) { |
504 // --gc_at_alloc can get us here before the ring has been initialized. | 484 // --gc_at_alloc can get us here before the ring has been initialized. |
505 ASSERT(FLAG_gc_at_alloc); | 485 ASSERT(FLAG_gc_at_alloc); |
506 return; | 486 return; |
507 } | 487 } |
508 ring->VisitPointers(visitor); | 488 ring->VisitPointers(visitor); |
509 #endif // !PRODUCT | 489 #endif // !PRODUCT |
510 } | 490 } |
511 | 491 |
512 | |
513 void Scavenger::IterateRoots(Isolate* isolate, ScavengerVisitor* visitor) { | 492 void Scavenger::IterateRoots(Isolate* isolate, ScavengerVisitor* visitor) { |
514 int64_t start = OS::GetCurrentMonotonicMicros(); | 493 int64_t start = OS::GetCurrentMonotonicMicros(); |
515 isolate->VisitObjectPointers(visitor, | 494 isolate->VisitObjectPointers(visitor, |
516 StackFrameIterator::kDontValidateFrames); | 495 StackFrameIterator::kDontValidateFrames); |
517 int64_t middle = OS::GetCurrentMonotonicMicros(); | 496 int64_t middle = OS::GetCurrentMonotonicMicros(); |
518 IterateStoreBuffers(isolate, visitor); | 497 IterateStoreBuffers(isolate, visitor); |
519 IterateObjectIdTable(isolate, visitor); | 498 IterateObjectIdTable(isolate, visitor); |
520 int64_t end = OS::GetCurrentMonotonicMicros(); | 499 int64_t end = OS::GetCurrentMonotonicMicros(); |
521 heap_->RecordData(kToKBAfterStoreBuffer, RoundWordsToKB(UsedInWords())); | 500 heap_->RecordData(kToKBAfterStoreBuffer, RoundWordsToKB(UsedInWords())); |
522 heap_->RecordTime(kVisitIsolateRoots, middle - start); | 501 heap_->RecordTime(kVisitIsolateRoots, middle - start); |
523 heap_->RecordTime(kIterateStoreBuffers, end - middle); | 502 heap_->RecordTime(kIterateStoreBuffers, end - middle); |
524 heap_->RecordTime(kDummyScavengeTime, 0); | 503 heap_->RecordTime(kDummyScavengeTime, 0); |
525 } | 504 } |
526 | 505 |
527 | |
528 bool Scavenger::IsUnreachable(RawObject** p) { | 506 bool Scavenger::IsUnreachable(RawObject** p) { |
529 RawObject* raw_obj = *p; | 507 RawObject* raw_obj = *p; |
530 if (!raw_obj->IsHeapObject()) { | 508 if (!raw_obj->IsHeapObject()) { |
531 return false; | 509 return false; |
532 } | 510 } |
533 if (!raw_obj->IsNewObject()) { | 511 if (!raw_obj->IsNewObject()) { |
534 return false; | 512 return false; |
535 } | 513 } |
536 uword raw_addr = RawObject::ToAddr(raw_obj); | 514 uword raw_addr = RawObject::ToAddr(raw_obj); |
537 if (to_->Contains(raw_addr)) { | 515 if (to_->Contains(raw_addr)) { |
538 return false; | 516 return false; |
539 } | 517 } |
540 uword header = *reinterpret_cast<uword*>(raw_addr); | 518 uword header = *reinterpret_cast<uword*>(raw_addr); |
541 if (IsForwarding(header)) { | 519 if (IsForwarding(header)) { |
542 uword new_addr = ForwardedAddr(header); | 520 uword new_addr = ForwardedAddr(header); |
543 *p = RawObject::FromAddr(new_addr); | 521 *p = RawObject::FromAddr(new_addr); |
544 return false; | 522 return false; |
545 } | 523 } |
546 return true; | 524 return true; |
547 } | 525 } |
548 | 526 |
549 | |
550 void Scavenger::IterateWeakRoots(Isolate* isolate, HandleVisitor* visitor) { | 527 void Scavenger::IterateWeakRoots(Isolate* isolate, HandleVisitor* visitor) { |
551 isolate->VisitWeakPersistentHandles(visitor); | 528 isolate->VisitWeakPersistentHandles(visitor); |
552 } | 529 } |
553 | 530 |
554 | |
555 void Scavenger::ProcessToSpace(ScavengerVisitor* visitor) { | 531 void Scavenger::ProcessToSpace(ScavengerVisitor* visitor) { |
556 // Iterate until all work has been drained. | 532 // Iterate until all work has been drained. |
557 while ((resolved_top_ < top_) || PromotedStackHasMore()) { | 533 while ((resolved_top_ < top_) || PromotedStackHasMore()) { |
558 while (resolved_top_ < top_) { | 534 while (resolved_top_ < top_) { |
559 RawObject* raw_obj = RawObject::FromAddr(resolved_top_); | 535 RawObject* raw_obj = RawObject::FromAddr(resolved_top_); |
560 intptr_t class_id = raw_obj->GetClassId(); | 536 intptr_t class_id = raw_obj->GetClassId(); |
561 if (class_id != kWeakPropertyCid) { | 537 if (class_id != kWeakPropertyCid) { |
562 resolved_top_ += raw_obj->VisitPointersNonvirtual(visitor); | 538 resolved_top_ += raw_obj->VisitPointersNonvirtual(visitor); |
563 } else { | 539 } else { |
564 RawWeakProperty* raw_weak = reinterpret_cast<RawWeakProperty*>(raw_obj); | 540 RawWeakProperty* raw_weak = reinterpret_cast<RawWeakProperty*>(raw_obj); |
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
606 } else { | 582 } else { |
607 EnqueueWeakProperty(cur_weak); | 583 EnqueueWeakProperty(cur_weak); |
608 } | 584 } |
609 // Advance to next weak property in the queue. | 585 // Advance to next weak property in the queue. |
610 cur_weak = reinterpret_cast<RawWeakProperty*>(next_weak); | 586 cur_weak = reinterpret_cast<RawWeakProperty*>(next_weak); |
611 } | 587 } |
612 } | 588 } |
613 } | 589 } |
614 } | 590 } |
615 | 591 |
616 | |
617 void Scavenger::UpdateMaxHeapCapacity() { | 592 void Scavenger::UpdateMaxHeapCapacity() { |
618 if (heap_ == NULL) { | 593 if (heap_ == NULL) { |
619 // Some unit tests. | 594 // Some unit tests. |
620 return; | 595 return; |
621 } | 596 } |
622 ASSERT(to_ != NULL); | 597 ASSERT(to_ != NULL); |
623 ASSERT(heap_ != NULL); | 598 ASSERT(heap_ != NULL); |
624 Isolate* isolate = heap_->isolate(); | 599 Isolate* isolate = heap_->isolate(); |
625 ASSERT(isolate != NULL); | 600 ASSERT(isolate != NULL); |
626 isolate->GetHeapNewCapacityMaxMetric()->SetValue(to_->size_in_words() * | 601 isolate->GetHeapNewCapacityMaxMetric()->SetValue(to_->size_in_words() * |
627 kWordSize); | 602 kWordSize); |
628 } | 603 } |
629 | 604 |
630 | |
631 void Scavenger::UpdateMaxHeapUsage() { | 605 void Scavenger::UpdateMaxHeapUsage() { |
632 if (heap_ == NULL) { | 606 if (heap_ == NULL) { |
633 // Some unit tests. | 607 // Some unit tests. |
634 return; | 608 return; |
635 } | 609 } |
636 ASSERT(to_ != NULL); | 610 ASSERT(to_ != NULL); |
637 ASSERT(heap_ != NULL); | 611 ASSERT(heap_ != NULL); |
638 Isolate* isolate = heap_->isolate(); | 612 Isolate* isolate = heap_->isolate(); |
639 ASSERT(isolate != NULL); | 613 ASSERT(isolate != NULL); |
640 isolate->GetHeapNewUsedMaxMetric()->SetValue(UsedInWords() * kWordSize); | 614 isolate->GetHeapNewUsedMaxMetric()->SetValue(UsedInWords() * kWordSize); |
641 } | 615 } |
642 | 616 |
643 | |
644 void Scavenger::EnqueueWeakProperty(RawWeakProperty* raw_weak) { | 617 void Scavenger::EnqueueWeakProperty(RawWeakProperty* raw_weak) { |
645 ASSERT(raw_weak->IsHeapObject()); | 618 ASSERT(raw_weak->IsHeapObject()); |
646 ASSERT(raw_weak->IsNewObject()); | 619 ASSERT(raw_weak->IsNewObject()); |
647 ASSERT(raw_weak->IsWeakProperty()); | 620 ASSERT(raw_weak->IsWeakProperty()); |
648 #if defined(DEBUG) | 621 #if defined(DEBUG) |
649 uword raw_addr = RawObject::ToAddr(raw_weak); | 622 uword raw_addr = RawObject::ToAddr(raw_weak); |
650 uword header = *reinterpret_cast<uword*>(raw_addr); | 623 uword header = *reinterpret_cast<uword*>(raw_addr); |
651 ASSERT(!IsForwarding(header)); | 624 ASSERT(!IsForwarding(header)); |
652 #endif // defined(DEBUG) | 625 #endif // defined(DEBUG) |
653 ASSERT(raw_weak->ptr()->next_ == 0); | 626 ASSERT(raw_weak->ptr()->next_ == 0); |
654 raw_weak->ptr()->next_ = reinterpret_cast<uword>(delayed_weak_properties_); | 627 raw_weak->ptr()->next_ = reinterpret_cast<uword>(delayed_weak_properties_); |
655 delayed_weak_properties_ = raw_weak; | 628 delayed_weak_properties_ = raw_weak; |
656 } | 629 } |
657 | 630 |
658 | |
659 uword Scavenger::ProcessWeakProperty(RawWeakProperty* raw_weak, | 631 uword Scavenger::ProcessWeakProperty(RawWeakProperty* raw_weak, |
660 ScavengerVisitor* visitor) { | 632 ScavengerVisitor* visitor) { |
661 // The fate of the weak property is determined by its key. | 633 // The fate of the weak property is determined by its key. |
662 RawObject* raw_key = raw_weak->ptr()->key_; | 634 RawObject* raw_key = raw_weak->ptr()->key_; |
663 if (raw_key->IsHeapObject() && raw_key->IsNewObject()) { | 635 if (raw_key->IsHeapObject() && raw_key->IsNewObject()) { |
664 uword raw_addr = RawObject::ToAddr(raw_key); | 636 uword raw_addr = RawObject::ToAddr(raw_key); |
665 uword header = *reinterpret_cast<uword*>(raw_addr); | 637 uword header = *reinterpret_cast<uword*>(raw_addr); |
666 if (!IsForwarding(header)) { | 638 if (!IsForwarding(header)) { |
667 // Key is white. Enqueue the weak property. | 639 // Key is white. Enqueue the weak property. |
668 EnqueueWeakProperty(raw_weak); | 640 EnqueueWeakProperty(raw_weak); |
669 return raw_weak->Size(); | 641 return raw_weak->Size(); |
670 } | 642 } |
671 } | 643 } |
672 // Key is gray or black. Make the weak property black. | 644 // Key is gray or black. Make the weak property black. |
673 return raw_weak->VisitPointersNonvirtual(visitor); | 645 return raw_weak->VisitPointersNonvirtual(visitor); |
674 } | 646 } |
675 | 647 |
676 | |
677 void Scavenger::ProcessWeakReferences() { | 648 void Scavenger::ProcessWeakReferences() { |
678 // Rehash the weak tables now that we know which objects survive this cycle. | 649 // Rehash the weak tables now that we know which objects survive this cycle. |
679 for (int sel = 0; sel < Heap::kNumWeakSelectors; sel++) { | 650 for (int sel = 0; sel < Heap::kNumWeakSelectors; sel++) { |
680 WeakTable* table = | 651 WeakTable* table = |
681 heap_->GetWeakTable(Heap::kNew, static_cast<Heap::WeakSelector>(sel)); | 652 heap_->GetWeakTable(Heap::kNew, static_cast<Heap::WeakSelector>(sel)); |
682 heap_->SetWeakTable(Heap::kNew, static_cast<Heap::WeakSelector>(sel), | 653 heap_->SetWeakTable(Heap::kNew, static_cast<Heap::WeakSelector>(sel), |
683 WeakTable::NewFrom(table)); | 654 WeakTable::NewFrom(table)); |
684 intptr_t size = table->size(); | 655 intptr_t size = table->size(); |
685 for (intptr_t i = 0; i < size; i++) { | 656 for (intptr_t i = 0; i < size; i++) { |
686 if (table->IsValidEntryAt(i)) { | 657 if (table->IsValidEntryAt(i)) { |
(...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
722 #endif // defined(DEBUG) | 693 #endif // defined(DEBUG) |
723 | 694 |
724 WeakProperty::Clear(cur_weak); | 695 WeakProperty::Clear(cur_weak); |
725 | 696 |
726 // Advance to next weak property in the queue. | 697 // Advance to next weak property in the queue. |
727 cur_weak = reinterpret_cast<RawWeakProperty*>(next_weak); | 698 cur_weak = reinterpret_cast<RawWeakProperty*>(next_weak); |
728 } | 699 } |
729 } | 700 } |
730 } | 701 } |
731 | 702 |
732 | |
733 void Scavenger::VisitObjectPointers(ObjectPointerVisitor* visitor) const { | 703 void Scavenger::VisitObjectPointers(ObjectPointerVisitor* visitor) const { |
734 uword cur = FirstObjectStart(); | 704 uword cur = FirstObjectStart(); |
735 while (cur < top_) { | 705 while (cur < top_) { |
736 RawObject* raw_obj = RawObject::FromAddr(cur); | 706 RawObject* raw_obj = RawObject::FromAddr(cur); |
737 cur += raw_obj->VisitPointers(visitor); | 707 cur += raw_obj->VisitPointers(visitor); |
738 } | 708 } |
739 } | 709 } |
740 | 710 |
741 | |
742 void Scavenger::VisitObjects(ObjectVisitor* visitor) const { | 711 void Scavenger::VisitObjects(ObjectVisitor* visitor) const { |
743 uword cur = FirstObjectStart(); | 712 uword cur = FirstObjectStart(); |
744 while (cur < top_) { | 713 while (cur < top_) { |
745 RawObject* raw_obj = RawObject::FromAddr(cur); | 714 RawObject* raw_obj = RawObject::FromAddr(cur); |
746 visitor->VisitObject(raw_obj); | 715 visitor->VisitObject(raw_obj); |
747 cur += raw_obj->Size(); | 716 cur += raw_obj->Size(); |
748 } | 717 } |
749 } | 718 } |
750 | 719 |
751 | |
752 void Scavenger::AddRegionsToObjectSet(ObjectSet* set) const { | 720 void Scavenger::AddRegionsToObjectSet(ObjectSet* set) const { |
753 set->AddRegion(to_->start(), to_->end()); | 721 set->AddRegion(to_->start(), to_->end()); |
754 } | 722 } |
755 | 723 |
756 | |
757 RawObject* Scavenger::FindObject(FindObjectVisitor* visitor) const { | 724 RawObject* Scavenger::FindObject(FindObjectVisitor* visitor) const { |
758 ASSERT(!scavenging_); | 725 ASSERT(!scavenging_); |
759 uword cur = FirstObjectStart(); | 726 uword cur = FirstObjectStart(); |
760 if (visitor->VisitRange(cur, top_)) { | 727 if (visitor->VisitRange(cur, top_)) { |
761 while (cur < top_) { | 728 while (cur < top_) { |
762 RawObject* raw_obj = RawObject::FromAddr(cur); | 729 RawObject* raw_obj = RawObject::FromAddr(cur); |
763 uword next = cur + raw_obj->Size(); | 730 uword next = cur + raw_obj->Size(); |
764 if (visitor->VisitRange(cur, next) && raw_obj->FindObject(visitor)) { | 731 if (visitor->VisitRange(cur, next) && raw_obj->FindObject(visitor)) { |
765 return raw_obj; // Found object, return it. | 732 return raw_obj; // Found object, return it. |
766 } | 733 } |
767 cur = next; | 734 cur = next; |
768 } | 735 } |
769 ASSERT(cur == top_); | 736 ASSERT(cur == top_); |
770 } | 737 } |
771 return Object::null(); | 738 return Object::null(); |
772 } | 739 } |
773 | 740 |
774 | |
775 void Scavenger::Scavenge() { | 741 void Scavenger::Scavenge() { |
776 // TODO(cshapiro): Add a decision procedure for determining when the | 742 // TODO(cshapiro): Add a decision procedure for determining when the |
777 // the API callbacks should be invoked. | 743 // the API callbacks should be invoked. |
778 Scavenge(false); | 744 Scavenge(false); |
779 } | 745 } |
780 | 746 |
781 | |
782 void Scavenger::Scavenge(bool invoke_api_callbacks) { | 747 void Scavenger::Scavenge(bool invoke_api_callbacks) { |
783 Isolate* isolate = heap_->isolate(); | 748 Isolate* isolate = heap_->isolate(); |
784 // Ensure that all threads for this isolate are at a safepoint (either stopped | 749 // Ensure that all threads for this isolate are at a safepoint (either stopped |
785 // or in native code). If two threads are racing at this point, the loser | 750 // or in native code). If two threads are racing at this point, the loser |
786 // will continue with its scavenge after waiting for the winner to complete. | 751 // will continue with its scavenge after waiting for the winner to complete. |
787 // TODO(koda): Consider moving SafepointThreads into allocation failure/retry | 752 // TODO(koda): Consider moving SafepointThreads into allocation failure/retry |
788 // logic to avoid needless collections. | 753 // logic to avoid needless collections. |
789 | 754 |
790 int64_t pre_safe_point = OS::GetCurrentMonotonicMicros(); | 755 int64_t pre_safe_point = OS::GetCurrentMonotonicMicros(); |
791 | 756 |
(...skipping 58 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
850 OS::PrintErr("Verifying after Scavenge..."); | 815 OS::PrintErr("Verifying after Scavenge..."); |
851 heap_->Verify(kForbidMarked); | 816 heap_->Verify(kForbidMarked); |
852 OS::PrintErr(" done.\n"); | 817 OS::PrintErr(" done.\n"); |
853 } | 818 } |
854 | 819 |
855 // Done scavenging. Reset the marker. | 820 // Done scavenging. Reset the marker. |
856 ASSERT(scavenging_); | 821 ASSERT(scavenging_); |
857 scavenging_ = false; | 822 scavenging_ = false; |
858 } | 823 } |
859 | 824 |
860 | |
861 void Scavenger::WriteProtect(bool read_only) { | 825 void Scavenger::WriteProtect(bool read_only) { |
862 ASSERT(!scavenging_); | 826 ASSERT(!scavenging_); |
863 to_->WriteProtect(read_only); | 827 to_->WriteProtect(read_only); |
864 } | 828 } |
865 | 829 |
866 | |
867 #ifndef PRODUCT | 830 #ifndef PRODUCT |
868 void Scavenger::PrintToJSONObject(JSONObject* object) const { | 831 void Scavenger::PrintToJSONObject(JSONObject* object) const { |
869 if (!FLAG_support_service) { | 832 if (!FLAG_support_service) { |
870 return; | 833 return; |
871 } | 834 } |
872 Isolate* isolate = Isolate::Current(); | 835 Isolate* isolate = Isolate::Current(); |
873 ASSERT(isolate != NULL); | 836 ASSERT(isolate != NULL); |
874 JSONObject space(object, "new"); | 837 JSONObject space(object, "new"); |
875 space.AddProperty("type", "HeapSpace"); | 838 space.AddProperty("type", "HeapSpace"); |
876 space.AddProperty("name", "new"); | 839 space.AddProperty("name", "new"); |
(...skipping 10 matching lines...) Expand all Loading... |
887 } else { | 850 } else { |
888 space.AddProperty("avgCollectionPeriodMillis", 0.0); | 851 space.AddProperty("avgCollectionPeriodMillis", 0.0); |
889 } | 852 } |
890 space.AddProperty64("used", UsedInWords() * kWordSize); | 853 space.AddProperty64("used", UsedInWords() * kWordSize); |
891 space.AddProperty64("capacity", CapacityInWords() * kWordSize); | 854 space.AddProperty64("capacity", CapacityInWords() * kWordSize); |
892 space.AddProperty64("external", ExternalInWords() * kWordSize); | 855 space.AddProperty64("external", ExternalInWords() * kWordSize); |
893 space.AddProperty("time", MicrosecondsToSeconds(gc_time_micros())); | 856 space.AddProperty("time", MicrosecondsToSeconds(gc_time_micros())); |
894 } | 857 } |
895 #endif // !PRODUCT | 858 #endif // !PRODUCT |
896 | 859 |
897 | |
898 void Scavenger::AllocateExternal(intptr_t size) { | 860 void Scavenger::AllocateExternal(intptr_t size) { |
899 ASSERT(size >= 0); | 861 ASSERT(size >= 0); |
900 external_size_ += size; | 862 external_size_ += size; |
901 } | 863 } |
902 | 864 |
903 | |
904 void Scavenger::FreeExternal(intptr_t size) { | 865 void Scavenger::FreeExternal(intptr_t size) { |
905 ASSERT(size >= 0); | 866 ASSERT(size >= 0); |
906 external_size_ -= size; | 867 external_size_ -= size; |
907 ASSERT(external_size_ >= 0); | 868 ASSERT(external_size_ >= 0); |
908 } | 869 } |
909 | 870 |
910 | |
911 void Scavenger::Evacuate() { | 871 void Scavenger::Evacuate() { |
912 // We need a safepoint here to prevent allocation right before or right after | 872 // We need a safepoint here to prevent allocation right before or right after |
913 // the scavenge. | 873 // the scavenge. |
914 // The former can introduce an object that we might fail to collect. | 874 // The former can introduce an object that we might fail to collect. |
915 // The latter means even if the scavenge promotes every object in the new | 875 // The latter means even if the scavenge promotes every object in the new |
916 // space, the new allocation means the space is not empty, | 876 // space, the new allocation means the space is not empty, |
917 // causing the assertion below to fail. | 877 // causing the assertion below to fail. |
918 SafepointOperationScope scope(Thread::Current()); | 878 SafepointOperationScope scope(Thread::Current()); |
919 | 879 |
920 // Forces the next scavenge to promote all the objects in the new space. | 880 // Forces the next scavenge to promote all the objects in the new space. |
921 survivor_end_ = top_; | 881 survivor_end_ = top_; |
922 Scavenge(); | 882 Scavenge(); |
923 | 883 |
924 // It is possible for objects to stay in the new space | 884 // It is possible for objects to stay in the new space |
925 // if the VM cannot create more pages for these objects. | 885 // if the VM cannot create more pages for these objects. |
926 ASSERT((UsedInWords() == 0) || failed_to_promote_); | 886 ASSERT((UsedInWords() == 0) || failed_to_promote_); |
927 } | 887 } |
928 | 888 |
929 } // namespace dart | 889 } // namespace dart |
OLD | NEW |