Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(100)

Side by Side Diff: src/heap/mark-compact.cc

Issue 2428493003: [heap] Reland move slot filtering logic into sweeper. (Closed)
Patch Set: comments Created 4 years, 2 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « src/base/atomic-utils.h ('k') | src/heap/remembered-set.h » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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
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
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
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
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
OLDNEW
« no previous file with comments | « src/base/atomic-utils.h ('k') | src/heap/remembered-set.h » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698