OLD | NEW |
1 // Copyright 2012 the V8 project authors. All rights reserved. | 1 // Copyright 2012 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/heap/mark-compact.h" | 5 #include "src/heap/mark-compact.h" |
6 | 6 |
7 #include "src/base/atomicops.h" | 7 #include "src/base/atomicops.h" |
8 #include "src/base/bits.h" | 8 #include "src/base/bits.h" |
9 #include "src/base/sys-info.h" | 9 #include "src/base/sys-info.h" |
10 #include "src/code-stubs.h" | 10 #include "src/code-stubs.h" |
(...skipping 3302 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3313 } | 3313 } |
3314 } | 3314 } |
3315 return object; | 3315 return object; |
3316 } | 3316 } |
3317 }; | 3317 }; |
3318 | 3318 |
3319 int MarkCompactCollector::Sweeper::RawSweep( | 3319 int MarkCompactCollector::Sweeper::RawSweep( |
3320 Page* p, FreeListRebuildingMode free_list_mode, | 3320 Page* p, FreeListRebuildingMode free_list_mode, |
3321 FreeSpaceTreatmentMode free_space_mode) { | 3321 FreeSpaceTreatmentMode free_space_mode) { |
3322 Space* space = p->owner(); | 3322 Space* space = p->owner(); |
| 3323 AllocationSpace identity = space->identity(); |
3323 DCHECK_NOT_NULL(space); | 3324 DCHECK_NOT_NULL(space); |
3324 DCHECK(free_list_mode == IGNORE_FREE_LIST || space->identity() == OLD_SPACE || | 3325 DCHECK(free_list_mode == IGNORE_FREE_LIST || identity == OLD_SPACE || |
3325 space->identity() == CODE_SPACE || space->identity() == MAP_SPACE); | 3326 identity == CODE_SPACE || identity == MAP_SPACE); |
3326 DCHECK(!p->IsEvacuationCandidate() && !p->SweepingDone()); | 3327 DCHECK(!p->IsEvacuationCandidate() && !p->SweepingDone()); |
3327 | 3328 |
3328 // Before we sweep objects on the page, we free dead array buffers which | 3329 // Before we sweep objects on the page, we free dead array buffers which |
3329 // requires valid mark bits. | 3330 // requires valid mark bits. |
3330 ArrayBufferTracker::FreeDead(p); | 3331 ArrayBufferTracker::FreeDead(p); |
3331 | 3332 |
3332 // We also release the black area markers here. | 3333 // We also release the black area markers here. |
3333 p->ReleaseBlackAreaEndMarkerMap(); | 3334 p->ReleaseBlackAreaEndMarkerMap(); |
3334 | 3335 |
3335 Address free_start = p->area_start(); | 3336 Address free_start = p->area_start(); |
3336 DCHECK(reinterpret_cast<intptr_t>(free_start) % (32 * kPointerSize) == 0); | 3337 DCHECK(reinterpret_cast<intptr_t>(free_start) % (32 * kPointerSize) == 0); |
3337 | 3338 |
3338 // If we use the skip list for code space pages, we have to lock the skip | 3339 // If we use the skip list for code space pages, we have to lock the skip |
3339 // list because it could be accessed concurrently by the runtime or the | 3340 // list because it could be accessed concurrently by the runtime or the |
3340 // deoptimizer. | 3341 // deoptimizer. |
3341 const bool rebuild_skip_list = | 3342 const bool rebuild_skip_list = |
3342 space->identity() == CODE_SPACE && p->skip_list() != nullptr; | 3343 space->identity() == CODE_SPACE && p->skip_list() != nullptr; |
3343 SkipList* skip_list = p->skip_list(); | 3344 SkipList* skip_list = p->skip_list(); |
3344 if (rebuild_skip_list) { | 3345 if (rebuild_skip_list) { |
3345 skip_list->Clear(); | 3346 skip_list->Clear(); |
3346 } | 3347 } |
3347 | 3348 |
3348 intptr_t freed_bytes = 0; | 3349 intptr_t freed_bytes = 0; |
3349 intptr_t max_freed_bytes = 0; | 3350 intptr_t max_freed_bytes = 0; |
3350 int curr_region = -1; | 3351 int curr_region = -1; |
3351 | 3352 |
3352 LiveObjectIterator<kBlackObjects> it(p); | 3353 LiveObjectIterator<kBlackObjects> it(p); |
3353 HeapObject* object = NULL; | 3354 HeapObject* object = NULL; |
| 3355 bool clear_slots = |
| 3356 p->old_to_new_slots() && (identity == OLD_SPACE || identity == MAP_SPACE); |
3354 while ((object = it.Next()) != NULL) { | 3357 while ((object = it.Next()) != NULL) { |
3355 DCHECK(Marking::IsBlack(ObjectMarking::MarkBitFrom(object))); | 3358 DCHECK(Marking::IsBlack(ObjectMarking::MarkBitFrom(object))); |
3356 Address free_end = object->address(); | 3359 Address free_end = object->address(); |
3357 if (free_end != free_start) { | 3360 if (free_end != free_start) { |
3358 CHECK_GT(free_end, free_start); | 3361 CHECK_GT(free_end, free_start); |
3359 size_t size = static_cast<size_t>(free_end - free_start); | 3362 size_t size = static_cast<size_t>(free_end - free_start); |
3360 if (free_space_mode == ZAP_FREE_SPACE) { | 3363 if (free_space_mode == ZAP_FREE_SPACE) { |
3361 memset(free_start, 0xcc, size); | 3364 memset(free_start, 0xcc, size); |
3362 } | 3365 } |
3363 if (free_list_mode == REBUILD_FREE_LIST) { | 3366 if (free_list_mode == REBUILD_FREE_LIST) { |
3364 freed_bytes = reinterpret_cast<PagedSpace*>(space)->UnaccountedFree( | 3367 freed_bytes = reinterpret_cast<PagedSpace*>(space)->UnaccountedFree( |
3365 free_start, size); | 3368 free_start, size); |
3366 max_freed_bytes = Max(freed_bytes, max_freed_bytes); | 3369 max_freed_bytes = Max(freed_bytes, max_freed_bytes); |
3367 } else { | 3370 } else { |
3368 p->heap()->CreateFillerObjectAt(free_start, static_cast<int>(size), | 3371 p->heap()->CreateFillerObjectAt(free_start, static_cast<int>(size), |
3369 ClearRecordedSlots::kNo); | 3372 ClearRecordedSlots::kNo); |
3370 } | 3373 } |
| 3374 |
| 3375 if (clear_slots) { |
| 3376 RememberedSet<OLD_TO_NEW>::RemoveRange(p, free_start, free_end, |
| 3377 SlotSet::KEEP_EMPTY_BUCKETS); |
| 3378 } |
3371 } | 3379 } |
3372 Map* map = object->synchronized_map(); | 3380 Map* map = object->synchronized_map(); |
3373 int size = object->SizeFromMap(map); | 3381 int size = object->SizeFromMap(map); |
3374 if (rebuild_skip_list) { | 3382 if (rebuild_skip_list) { |
3375 int new_region_start = SkipList::RegionNumber(free_end); | 3383 int new_region_start = SkipList::RegionNumber(free_end); |
3376 int new_region_end = | 3384 int new_region_end = |
3377 SkipList::RegionNumber(free_end + size - kPointerSize); | 3385 SkipList::RegionNumber(free_end + size - kPointerSize); |
3378 if (new_region_start != curr_region || new_region_end != curr_region) { | 3386 if (new_region_start != curr_region || new_region_end != curr_region) { |
3379 skip_list->AddObject(free_end, size); | 3387 skip_list->AddObject(free_end, size); |
3380 curr_region = new_region_end; | 3388 curr_region = new_region_end; |
3381 } | 3389 } |
3382 } | 3390 } |
3383 free_start = free_end + size; | 3391 free_start = free_end + size; |
3384 } | 3392 } |
3385 | 3393 |
3386 // Clear the mark bits of that page and reset live bytes count. | |
3387 p->ClearLiveness(); | |
3388 | |
3389 if (free_start != p->area_end()) { | 3394 if (free_start != p->area_end()) { |
3390 CHECK_GT(p->area_end(), free_start); | 3395 CHECK_GT(p->area_end(), free_start); |
3391 size_t size = static_cast<size_t>(p->area_end() - free_start); | 3396 size_t size = static_cast<size_t>(p->area_end() - free_start); |
3392 if (free_space_mode == ZAP_FREE_SPACE) { | 3397 if (free_space_mode == ZAP_FREE_SPACE) { |
3393 memset(free_start, 0xcc, size); | 3398 memset(free_start, 0xcc, size); |
3394 } | 3399 } |
3395 if (free_list_mode == REBUILD_FREE_LIST) { | 3400 if (free_list_mode == REBUILD_FREE_LIST) { |
3396 freed_bytes = reinterpret_cast<PagedSpace*>(space)->UnaccountedFree( | 3401 freed_bytes = reinterpret_cast<PagedSpace*>(space)->UnaccountedFree( |
3397 free_start, size); | 3402 free_start, size); |
3398 max_freed_bytes = Max(freed_bytes, max_freed_bytes); | 3403 max_freed_bytes = Max(freed_bytes, max_freed_bytes); |
3399 } else { | 3404 } else { |
3400 p->heap()->CreateFillerObjectAt(free_start, static_cast<int>(size), | 3405 p->heap()->CreateFillerObjectAt(free_start, static_cast<int>(size), |
3401 ClearRecordedSlots::kNo); | 3406 ClearRecordedSlots::kNo); |
3402 } | 3407 } |
| 3408 |
| 3409 if (clear_slots) { |
| 3410 RememberedSet<OLD_TO_NEW>::RemoveRange(p, free_start, p->area_end(), |
| 3411 SlotSet::KEEP_EMPTY_BUCKETS); |
| 3412 } |
3403 } | 3413 } |
| 3414 |
| 3415 // Clear the mark bits of that page and reset live bytes count. |
| 3416 p->ClearLiveness(); |
| 3417 |
3404 p->concurrent_sweeping_state().SetValue(Page::kSweepingDone); | 3418 p->concurrent_sweeping_state().SetValue(Page::kSweepingDone); |
3405 if (free_list_mode == IGNORE_FREE_LIST) return 0; | 3419 if (free_list_mode == IGNORE_FREE_LIST) return 0; |
3406 return FreeList::GuaranteedAllocatable(static_cast<int>(max_freed_bytes)); | 3420 return FreeList::GuaranteedAllocatable(static_cast<int>(max_freed_bytes)); |
3407 } | 3421 } |
3408 | 3422 |
3409 void MarkCompactCollector::InvalidateCode(Code* code) { | 3423 void MarkCompactCollector::InvalidateCode(Code* code) { |
3410 Page* page = Page::FromAddress(code->address()); | 3424 Page* page = Page::FromAddress(code->address()); |
3411 Address start = code->instruction_start(); | 3425 Address start = code->instruction_start(); |
3412 Address end = code->address() + code->Size(); | 3426 Address end = code->address() + code->Size(); |
3413 | 3427 |
(...skipping 194 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3608 isolate, type, slot, [heap](Object** slot) { | 3622 isolate, type, slot, [heap](Object** slot) { |
3609 return CheckAndUpdateOldToNewSlot( | 3623 return CheckAndUpdateOldToNewSlot( |
3610 heap, reinterpret_cast<Address>(slot)); | 3624 heap, reinterpret_cast<Address>(slot)); |
3611 }); | 3625 }); |
3612 }); | 3626 }); |
3613 } | 3627 } |
3614 } | 3628 } |
3615 | 3629 |
3616 static SlotCallbackResult CheckAndUpdateOldToNewSlot(Heap* heap, | 3630 static SlotCallbackResult CheckAndUpdateOldToNewSlot(Heap* heap, |
3617 Address slot_address) { | 3631 Address slot_address) { |
| 3632 // There may be concurrent action on slots in dead objects. Concurrent |
| 3633 // sweeper threads may overwrite the slot content with a free space object. |
| 3634 // Moreover, the pointed-to object may also get concurrently overwritten |
| 3635 // with a free space object. The sweeper always gets priority performing |
| 3636 // these writes. |
3618 base::NoBarrierAtomicValue<Object*>* slot = | 3637 base::NoBarrierAtomicValue<Object*>* slot = |
3619 base::NoBarrierAtomicValue<Object*>::FromAddress(slot_address); | 3638 base::NoBarrierAtomicValue<Object*>::FromAddress(slot_address); |
3620 Object* slot_reference = slot->Value(); | 3639 Object* slot_reference = slot->Value(); |
3621 if (heap->InFromSpace(slot_reference)) { | 3640 if (heap->InFromSpace(slot_reference)) { |
3622 HeapObject* heap_object = reinterpret_cast<HeapObject*>(slot_reference); | 3641 HeapObject* heap_object = reinterpret_cast<HeapObject*>(slot_reference); |
3623 DCHECK(heap_object->IsHeapObject()); | 3642 DCHECK(heap_object->IsHeapObject()); |
3624 MapWord map_word = heap_object->map_word(); | 3643 MapWord map_word = heap_object->map_word(); |
3625 // There could still be stale pointers in large object space, map space, | 3644 // There could still be stale pointers in large object space, map space, |
3626 // and old space for pages that have been promoted. | 3645 // and old space for pages that have been promoted. |
3627 if (map_word.IsForwardingAddress()) { | 3646 if (map_word.IsForwardingAddress()) { |
3628 // A sweeper thread may concurrently write a size value which looks like | 3647 // A sweeper thread may concurrently write a size value which looks like |
3629 // a forwarding pointer. We have to ignore these values. | 3648 // a forwarding pointer. We have to ignore these values. |
3630 if (map_word.ToRawValue() < Page::kPageSize) { | 3649 if (map_word.ToRawValue() < Page::kPageSize) { |
3631 return REMOVE_SLOT; | 3650 return REMOVE_SLOT; |
3632 } | 3651 } |
3633 // Update the corresponding slot. | 3652 // Update the corresponding slot only if the slot content did not |
3634 slot->SetValue(map_word.ToForwardingAddress()); | 3653 // change in the meantime. This may happen when a concurrent sweeper |
| 3654 // thread stored a free space object at that memory location. |
| 3655 slot->TrySetValue(slot_reference, map_word.ToForwardingAddress()); |
3635 } | 3656 } |
3636 // If the object was in from space before and is after executing the | 3657 // If the object was in from space before and is after executing the |
3637 // callback in to space, the object is still live. | 3658 // callback in to space, the object is still live. |
3638 // Unfortunately, we do not know about the slot. It could be in a | 3659 // Unfortunately, we do not know about the slot. It could be in a |
3639 // just freed free space object. | 3660 // just freed free space object. |
3640 if (heap->InToSpace(slot->Value())) { | 3661 if (heap->InToSpace(slot->Value())) { |
3641 return KEEP_SLOT; | 3662 return KEEP_SLOT; |
3642 } | 3663 } |
3643 } else if (heap->InToSpace(slot_reference)) { | 3664 } else if (heap->InToSpace(slot_reference)) { |
3644 // Slots can point to "to" space if the page has been moved, or if the | 3665 // Slots can point to "to" space if the page has been moved, or if the |
(...skipping 164 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3809 if (page->concurrent_sweeping_state().Value() != Page::kSweepingPending) { | 3830 if (page->concurrent_sweeping_state().Value() != Page::kSweepingPending) { |
3810 page->mutex()->Unlock(); | 3831 page->mutex()->Unlock(); |
3811 return 0; | 3832 return 0; |
3812 } | 3833 } |
3813 page->concurrent_sweeping_state().SetValue(Page::kSweepingInProgress); | 3834 page->concurrent_sweeping_state().SetValue(Page::kSweepingInProgress); |
3814 const Sweeper::FreeSpaceTreatmentMode free_space_mode = | 3835 const Sweeper::FreeSpaceTreatmentMode free_space_mode = |
3815 Heap::ShouldZapGarbage() ? ZAP_FREE_SPACE : IGNORE_FREE_SPACE; | 3836 Heap::ShouldZapGarbage() ? ZAP_FREE_SPACE : IGNORE_FREE_SPACE; |
3816 if (identity == NEW_SPACE) { | 3837 if (identity == NEW_SPACE) { |
3817 RawSweep(page, IGNORE_FREE_LIST, free_space_mode); | 3838 RawSweep(page, IGNORE_FREE_LIST, free_space_mode); |
3818 } else { | 3839 } else { |
3819 if (identity == OLD_SPACE || identity == MAP_SPACE) { | 3840 if (identity == CODE_SPACE) { |
3820 RememberedSet<OLD_TO_NEW>::ClearInvalidSlots(heap_, page); | |
3821 } else { | |
3822 RememberedSet<OLD_TO_NEW>::ClearInvalidTypedSlots(heap_, page); | 3841 RememberedSet<OLD_TO_NEW>::ClearInvalidTypedSlots(heap_, page); |
3823 } | 3842 } |
3824 max_freed = RawSweep(page, REBUILD_FREE_LIST, free_space_mode); | 3843 max_freed = RawSweep(page, REBUILD_FREE_LIST, free_space_mode); |
3825 } | 3844 } |
3826 | 3845 |
3827 // After finishing sweeping of a page we clean up its remembered set. | 3846 // After finishing sweeping of a page we clean up its remembered set. |
3828 if (page->typed_old_to_new_slots()) { | 3847 if (page->typed_old_to_new_slots()) { |
3829 page->typed_old_to_new_slots()->FreeToBeFreedChunks(); | 3848 page->typed_old_to_new_slots()->FreeToBeFreedChunks(); |
3830 } | 3849 } |
3831 if (page->old_to_new_slots()) { | 3850 if (page->old_to_new_slots()) { |
(...skipping 168 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
4000 // The target is always in old space, we don't have to record the slot in | 4019 // The target is always in old space, we don't have to record the slot in |
4001 // the old-to-new remembered set. | 4020 // the old-to-new remembered set. |
4002 DCHECK(!heap()->InNewSpace(target)); | 4021 DCHECK(!heap()->InNewSpace(target)); |
4003 RecordRelocSlot(host, &rinfo, target); | 4022 RecordRelocSlot(host, &rinfo, target); |
4004 } | 4023 } |
4005 } | 4024 } |
4006 } | 4025 } |
4007 | 4026 |
4008 } // namespace internal | 4027 } // namespace internal |
4009 } // namespace v8 | 4028 } // namespace v8 |
OLD | NEW |