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

Side by Side Diff: src/spaces.cc

Issue 6639024: Get rid of distinction between below- and above-watermark in page allocation.... (Closed) Base URL: http://v8.googlecode.com/svn/branches/experimental/gc/
Patch Set: Created 9 years, 9 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 | Annotate | Revision Log
OLDNEW
1 // Copyright 2006-2010 the V8 project authors. All rights reserved. 1 // Copyright 2011 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
11 // with the distribution. 11 // with the distribution.
(...skipping 23 matching lines...) Expand all
35 namespace v8 { 35 namespace v8 {
36 namespace internal { 36 namespace internal {
37 37
38 // For contiguous spaces, top should be in the space (or at the end) and limit 38 // For contiguous spaces, top should be in the space (or at the end) and limit
39 // should be the end of the space. 39 // should be the end of the space.
40 #define ASSERT_SEMISPACE_ALLOCATION_INFO(info, space) \ 40 #define ASSERT_SEMISPACE_ALLOCATION_INFO(info, space) \
41 ASSERT((space).low() <= (info).top \ 41 ASSERT((space).low() <= (info).top \
42 && (info).top <= (space).high() \ 42 && (info).top <= (space).high() \
43 && (info).limit == (space).high()) 43 && (info).limit == (space).high())
44 44
45 intptr_t Page::watermark_invalidated_mark_ = 1 << Page::WATERMARK_INVALIDATED;
46
47 // ---------------------------------------------------------------------------- 45 // ----------------------------------------------------------------------------
48 // HeapObjectIterator 46 // HeapObjectIterator
49 47
50 HeapObjectIterator::HeapObjectIterator(PagedSpace* space) { 48 HeapObjectIterator::HeapObjectIterator(PagedSpace* space) {
51 Initialize(space->bottom(), space->top(), NULL); 49 // You can't actually iterate over the anchor page. It is not a real page,
50 // just an anchor for the double linked page list. Initialize as if we have
51 // reached the end of the anchor page, then the first iteration will move on
52 // to the first page.
53 Initialize(space,
54 NULL,
55 NULL,
56 kAllPagesInSpace,
57 NULL);
52 } 58 }
53 59
54 60
55 HeapObjectIterator::HeapObjectIterator(PagedSpace* space, 61 HeapObjectIterator::HeapObjectIterator(PagedSpace* space,
56 HeapObjectCallback size_func) { 62 HeapObjectCallback size_func) {
57 Initialize(space->bottom(), space->top(), size_func); 63 // You can't actually iterate over the anchor page. It is not a real page,
64 // just an anchor for the double linked page list. Initialize the current
65 // address and end as NULL, then the first iteration will move on
66 // to the first page.
67 Initialize(space,
68 NULL,
69 NULL,
70 kAllPagesInSpace,
71 size_func);
58 } 72 }
59 73
60 74
61 HeapObjectIterator::HeapObjectIterator(Page* page, 75 HeapObjectIterator::HeapObjectIterator(Page* page,
62 HeapObjectCallback size_func) { 76 HeapObjectCallback size_func) {
63 Initialize(page->ObjectAreaStart(), page->AllocationTop(), size_func); 77 Initialize(page->owner(),
78 page->ObjectAreaStart(),
79 page->ObjectAreaEnd(),
80 kOnePageOnly,
81 size_func);
82 ASSERT(!page->IsFlagSet(Page::WAS_SWEPT_CONSERVATIVELY));
64 } 83 }
65 84
66 85
67 void HeapObjectIterator::Initialize(Address cur, Address end, 86 void HeapObjectIterator::Initialize(PagedSpace* space,
87 Address cur, Address end,
88 HeapObjectIterator::PageMode mode,
68 HeapObjectCallback size_f) { 89 HeapObjectCallback size_f) {
90 space_ = space;
69 cur_addr_ = cur; 91 cur_addr_ = cur;
70 end_addr_ = end; 92 cur_end_ = end;
71 end_page_ = Page::FromAllocationTop(end); 93 page_mode_ = mode;
72 size_func_ = size_f; 94 size_func_ = size_f;
73 Page* p = Page::FromAllocationTop(cur_addr_);
74 cur_limit_ = (p == end_page_) ? end_addr_ : p->AllocationTop();
75 95
76 if (!p->IsFlagSet(Page::IS_CONTINUOUS)) { 96 // You must call Heap::EnsureHeapIsIterable before creating a heap object
77 ASSERT(IncrementalMarking::state() == IncrementalMarking::STOPPED); 97 // iterator.
78 cur_addr_ = Marking::FirstLiveObject(cur_addr_, cur_limit_); 98 ASSERT(IncrementalMarking::state() == IncrementalMarking::STOPPED);
79 if (cur_addr_ > cur_limit_) cur_addr_ = cur_limit_;
80 }
81 99
82 #ifdef DEBUG 100 #ifdef DEBUG
83 Verify(); 101 Verify();
84 #endif 102 #endif
85 } 103 }
86 104
87 105
88 HeapObject* HeapObjectIterator::FromNextPage() { 106 // We have hit the end of the page and should advance to the next block of
89 if (cur_addr_ == end_addr_) return NULL; 107 // objects. This happens at the end of the page.
90 108 bool HeapObjectIterator::AdvanceToNextPage() {
91 Page* cur_page = Page::FromAllocationTop(cur_addr_); 109 ASSERT(cur_addr_ == cur_end_);
110 if (page_mode_ == kOnePageOnly) return false;
111 Page* cur_page;
112 if (cur_addr_ == NULL) {
113 cur_page = space_->anchor();
114 } else {
115 cur_page = Page::FromAddress(cur_addr_ - 1);
116 ASSERT(cur_addr_ == cur_page->ObjectAreaEnd());
117 }
92 cur_page = cur_page->next_page(); 118 cur_page = cur_page->next_page();
93 ASSERT(cur_page->is_valid()); 119 if (cur_page == space_->anchor()) return false;
94
95 cur_addr_ = cur_page->ObjectAreaStart(); 120 cur_addr_ = cur_page->ObjectAreaStart();
96 cur_limit_ = (cur_page == end_page_) ? end_addr_ : cur_page->AllocationTop(); 121 cur_end_ = cur_page->ObjectAreaEnd();
97 122 ASSERT(!cur_page->IsFlagSet(Page::WAS_SWEPT_CONSERVATIVELY));
98 if (!cur_page->IsFlagSet(Page::IS_CONTINUOUS)) {
99 ASSERT(IncrementalMarking::state() == IncrementalMarking::STOPPED);
100 cur_addr_ = Marking::FirstLiveObject(cur_addr_, cur_limit_);
101 if (cur_addr_ > cur_limit_) cur_addr_ = cur_limit_;
102 }
103
104 if (cur_addr_ == end_addr_) return NULL;
105 ASSERT(cur_addr_ < cur_limit_);
106 #ifdef DEBUG
107 Verify();
108 #endif
109 return FromCurrentPage();
110 }
111
112
113 void HeapObjectIterator::AdvanceUsingMarkbits() {
114 ASSERT(IncrementalMarking::state() == IncrementalMarking::STOPPED); 123 ASSERT(IncrementalMarking::state() == IncrementalMarking::STOPPED);
115 HeapObject* obj = HeapObject::FromAddress(cur_addr_); 124 return true;
116 int obj_size = (size_func_ == NULL) ? obj->Size() : size_func_(obj);
117 ASSERT_OBJECT_SIZE(obj_size);
118 cur_addr_ = Marking::NextLiveObject(obj,
119 obj_size,
120 cur_limit_);
121 if (cur_addr_ > cur_limit_) cur_addr_ = cur_limit_;
122 } 125 }
123 126
124 127
125 #ifdef DEBUG 128 #ifdef DEBUG
126 void HeapObjectIterator::Verify() { 129 void HeapObjectIterator::Verify() {
127 Page* p = Page::FromAllocationTop(cur_addr_); 130 // TODO(gc): We should do something here.
128 ASSERT(p == Page::FromAllocationTop(cur_limit_));
129 ASSERT(p->Offset(cur_addr_) <= p->Offset(cur_limit_));
130 } 131 }
131 #endif 132 #endif
132 133
133 134
134 // ----------------------------------------------------------------------------- 135 // -----------------------------------------------------------------------------
135 // PageIterator
136
137 PageIterator::PageIterator(PagedSpace* space, Mode mode) : space_(space) {
138 prev_page_ = NULL;
139 switch (mode) {
140 case PAGES_IN_USE:
141 stop_page_ = space->AllocationTopPage();
142 break;
143 case ALL_PAGES:
144 #ifdef DEBUG
145 // Verify that the cached last page in the space is actually the
146 // last page.
147 for (Page* p = space->first_page_; p->is_valid(); p = p->next_page()) {
148 if (!p->next_page()->is_valid()) {
149 ASSERT(space->last_page_ == p);
150 }
151 }
152 #endif
153 stop_page_ = space->last_page_;
154 break;
155 }
156 }
157
158
159 // -----------------------------------------------------------------------------
160 // CodeRange 136 // CodeRange
161 137
162 List<CodeRange::FreeBlock> CodeRange::free_list_(0); 138 List<CodeRange::FreeBlock> CodeRange::free_list_(0);
163 List<CodeRange::FreeBlock> CodeRange::allocation_list_(0); 139 List<CodeRange::FreeBlock> CodeRange::allocation_list_(0);
164 int CodeRange::current_allocation_block_index_ = 0; 140 int CodeRange::current_allocation_block_index_ = 0;
165 VirtualMemory* CodeRange::code_range_ = NULL; 141 VirtualMemory* CodeRange::code_range_ = NULL;
166 142
167 143
168 bool CodeRange::Setup(const size_t requested) { 144 bool CodeRange::Setup(const size_t requested) {
169 ASSERT(code_range_ == NULL); 145 ASSERT(code_range_ == NULL);
(...skipping 236 matching lines...) Expand 10 before | Expand all | Expand 10 after
406 executable == EXECUTABLE)) { 382 executable == EXECUTABLE)) {
407 VirtualMemory::ReleaseRegion(base, *allocated_size); 383 VirtualMemory::ReleaseRegion(base, *allocated_size);
408 size_ -= *allocated_size; 384 size_ -= *allocated_size;
409 return NULL; 385 return NULL;
410 } 386 }
411 387
412 return base; 388 return base;
413 } 389 }
414 390
415 391
392 void Page::InitializeAsAnchor(PagedSpace* owner) {
393 owner_ = owner;
394 set_prev_page(this);
395 set_next_page(this);
396 }
397
398
399 void MemoryChunk::InsertAfter(MemoryChunk* other) {
400 next_chunk_ = other->next_chunk_;
401 prev_chunk_ = other;
402 other->next_chunk_->prev_chunk_ = this;
403 other->next_chunk_ = this;
404 }
405
406
407 void MemoryChunk::Unlink() {
408 next_chunk_->prev_chunk_ = prev_chunk_;
409 prev_chunk_->next_chunk_ = next_chunk_;
410 prev_chunk_ = NULL;
411 next_chunk_ = NULL;
412 }
413
414
416 MemoryChunk* MemoryAllocator::AllocateChunk(intptr_t body_size, 415 MemoryChunk* MemoryAllocator::AllocateChunk(intptr_t body_size,
417 Executability executable, 416 Executability executable,
418 Space* owner) { 417 Space* owner) {
419 size_t chunk_size = MemoryChunk::kBodyOffset + body_size; 418 size_t chunk_size = MemoryChunk::kObjectStartOffset + body_size;
420 Address base = NULL; 419 Address base = NULL;
421 if (executable == EXECUTABLE) { 420 if (executable == EXECUTABLE) {
422 // Check executable memory limit. 421 // Check executable memory limit.
423 if (size_executable_ + chunk_size > capacity_executable_) { 422 if (size_executable_ + chunk_size > capacity_executable_) {
424 LOG(StringEvent("MemoryAllocator::AllocateRawMemory", 423 LOG(StringEvent("MemoryAllocator::AllocateRawMemory",
425 "V8 Executable Allocation capacity exceeded")); 424 "V8 Executable Allocation capacity exceeded"));
426 return NULL; 425 return NULL;
427 } 426 }
428 427
429 // Allocate executable memory either from code range or from the 428 // Allocate executable memory either from code range or from the
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after
467 return MemoryChunk::Initialize(base, chunk_size, executable, owner); 466 return MemoryChunk::Initialize(base, chunk_size, executable, owner);
468 } 467 }
469 468
470 469
471 Page* MemoryAllocator::AllocatePage(PagedSpace* owner, 470 Page* MemoryAllocator::AllocatePage(PagedSpace* owner,
472 Executability executable) { 471 Executability executable) {
473 MemoryChunk* chunk = AllocateChunk(Page::kObjectAreaSize, executable, owner); 472 MemoryChunk* chunk = AllocateChunk(Page::kObjectAreaSize, executable, owner);
474 473
475 if (chunk == NULL) return NULL; 474 if (chunk == NULL) return NULL;
476 475
477 return Page::Initialize(chunk); 476 return Page::Initialize(chunk, executable, owner);
478 } 477 }
479 478
480 479
481 LargePage* MemoryAllocator::AllocateLargePage(intptr_t object_size, 480 LargePage* MemoryAllocator::AllocateLargePage(intptr_t object_size,
482 Executability executable, 481 Executability executable,
483 Space* owner) { 482 Space* owner) {
484 MemoryChunk* chunk = AllocateChunk(object_size, executable, owner); 483 MemoryChunk* chunk = AllocateChunk(object_size, executable, owner);
485 if (chunk == NULL) return NULL; 484 if (chunk == NULL) return NULL;
486 return LargePage::Initialize(chunk); 485 return LargePage::Initialize(chunk);
487 } 486 }
(...skipping 94 matching lines...) Expand 10 before | Expand all | Expand 10 after
582 capacity_, size_, static_cast<int>(pct*100)); 581 capacity_, size_, static_cast<int>(pct*100));
583 } 582 }
584 #endif 583 #endif
585 584
586 // ----------------------------------------------------------------------------- 585 // -----------------------------------------------------------------------------
587 // PagedSpace implementation 586 // PagedSpace implementation
588 587
589 PagedSpace::PagedSpace(intptr_t max_capacity, 588 PagedSpace::PagedSpace(intptr_t max_capacity,
590 AllocationSpace id, 589 AllocationSpace id,
591 Executability executable) 590 Executability executable)
592 : Space(id, executable) { 591 : Space(id, executable),
592 free_list_(this),
593 was_swept_conservatively_(false) {
593 max_capacity_ = (RoundDown(max_capacity, Page::kPageSize) / Page::kPageSize) 594 max_capacity_ = (RoundDown(max_capacity, Page::kPageSize) / Page::kPageSize)
594 * Page::kObjectAreaSize; 595 * Page::kObjectAreaSize;
595 accounting_stats_.Clear(); 596 accounting_stats_.Clear();
596 597
597 allocation_info_.top = NULL; 598 allocation_info_.top = NULL;
598 allocation_info_.limit = NULL; 599 allocation_info_.limit = NULL;
600
601 anchor_.InitializeAsAnchor(this);
599 } 602 }
600 603
601 604
602 bool PagedSpace::Setup() { 605 bool PagedSpace::Setup() {
603 if (HasBeenSetup()) return false;
604
605 // Maximum space capacity can not be less than single page size.
606 if (max_capacity_ < Page::kPageSize) return false;
607
608 first_page_ = MemoryAllocator::AllocatePage(this, executable());
609 if (!first_page_->is_valid()) return false;
610
611 // We are sure that the first page is valid and that we have at least one
612 // page.
613 accounting_stats_.ExpandSpace(Page::kObjectAreaSize);
614 ASSERT(Capacity() <= max_capacity_);
615
616 last_page_ = first_page_;
617 ASSERT(!last_page_->next_page()->is_valid());
618
619 // Use first_page_ for allocation.
620 SetAllocationInfo(&allocation_info_, first_page_);
621
622 return true; 606 return true;
623 } 607 }
624 608
625 609
626 bool PagedSpace::HasBeenSetup() { 610 bool PagedSpace::HasBeenSetup() {
627 return (Capacity() > 0); 611 return true;
628 } 612 }
629 613
630 614
631 void PagedSpace::TearDown() { 615 void PagedSpace::TearDown() {
632 Page* next = NULL; 616 PageIterator iterator(this);
633 for (Page* p = first_page_; p->is_valid(); p = next) { 617 while (iterator.has_next()) {
634 next = p->next_page(); 618 MemoryAllocator::Free(iterator.next());
635 MemoryAllocator::Free(p);
636 } 619 }
637 first_page_ = NULL; 620 anchor_.set_next_page(&anchor_);
638 last_page_ = NULL; 621 anchor_.set_prev_page(&anchor_);
639 accounting_stats_.Clear(); 622 accounting_stats_.Clear();
640 } 623 }
641 624
642 625
643 #ifdef ENABLE_HEAP_PROTECTION 626 #ifdef ENABLE_HEAP_PROTECTION
644 627
645 void PagedSpace::Protect() { 628 void PagedSpace::Protect() {
646 Page* page = first_page_; 629 Page* page = first_page_;
647 while (page->is_valid()) { 630 while (page->is_valid()) {
648 MemoryAllocator::ProtectChunkFromPage(page); 631 MemoryAllocator::ProtectChunkFromPage(page);
649 page = MemoryAllocator::FindLastPageInSameChunk(page)->next_page(); 632 page = MemoryAllocator::FindLastPageInSameChunk(page)->next_page();
650 } 633 }
651 } 634 }
652 635
653 636
654 void PagedSpace::Unprotect() { 637 void PagedSpace::Unprotect() {
655 Page* page = first_page_; 638 Page* page = first_page_;
656 while (page->is_valid()) { 639 while (page->is_valid()) {
657 MemoryAllocator::UnprotectChunkFromPage(page); 640 MemoryAllocator::UnprotectChunkFromPage(page);
658 page = MemoryAllocator::FindLastPageInSameChunk(page)->next_page(); 641 page = MemoryAllocator::FindLastPageInSameChunk(page)->next_page();
659 } 642 }
660 } 643 }
661 644
662 #endif 645 #endif
663 646
664 647
665 MaybeObject* PagedSpace::FindObject(Address addr) { 648 MaybeObject* PagedSpace::FindObject(Address addr) {
666 // Note: this function can only be called before or after mark-compact GC 649 // Note: this function can only be called on precisely swept spaces.
667 // because it accesses map pointers.
668 ASSERT(!MarkCompactCollector::in_use()); 650 ASSERT(!MarkCompactCollector::in_use());
669 651
670 if (!Contains(addr)) return Failure::Exception(); 652 if (!Contains(addr)) return Failure::Exception();
671 653
672 Page* p = Page::FromAddress(addr); 654 Page* p = Page::FromAddress(addr);
673 ASSERT(IsUsed(p)); 655 HeapObjectIterator it(p, NULL);
674 Address cur = p->ObjectAreaStart(); 656 for (HeapObject* obj = it.Next(); obj != NULL; obj = it.Next()) {
675 Address end = p->AllocationTop(); 657 Address cur = obj->address();
676 while (cur < end) {
677 HeapObject* obj = HeapObject::FromAddress(cur);
678 Address next = cur + obj->Size(); 658 Address next = cur + obj->Size();
679 if ((cur <= addr) && (addr < next)) return obj; 659 if ((cur <= addr) && (addr < next)) return obj;
680 cur = next;
681 } 660 }
682 661
683 UNREACHABLE(); 662 UNREACHABLE();
684 return Failure::Exception(); 663 return Failure::Exception();
685 } 664 }
686 665
687 666
688 bool PagedSpace::IsUsed(Page* page) { 667 void PagedSpace::SetAllocationInfo(Address top, Address limit) {
689 PageIterator it(this, PageIterator::PAGES_IN_USE); 668 Free(allocation_info_.top, allocation_info_.limit - allocation_info_.top);
690 while (it.has_next()) { 669 allocation_info_.top = top;
691 if (page == it.next()) return true; 670 allocation_info_.limit = limit;
692 } 671 ASSERT(allocation_info_.VerifyPagedAllocation());
693 return false;
694 }
695
696
697 void PagedSpace::SetAllocationInfo(AllocationInfo* alloc_info, Page* p) {
698 alloc_info->top = p->ObjectAreaStart();
699 alloc_info->limit = p->ObjectAreaEnd();
700 ASSERT(alloc_info->VerifyPagedAllocation());
701 } 672 }
702 673
703 674
704 bool PagedSpace::Expand() { 675 bool PagedSpace::Expand() {
705 ASSERT(max_capacity_ % Page::kObjectAreaSize == 0); 676 ASSERT(max_capacity_ % Page::kObjectAreaSize == 0);
706 ASSERT(Capacity() % Page::kObjectAreaSize == 0); 677 ASSERT(Capacity() % Page::kObjectAreaSize == 0);
707 678
708 if (Capacity() == max_capacity_) return false; 679 if (Capacity() == max_capacity_) return false;
709 680
710 ASSERT(Capacity() < max_capacity_); 681 ASSERT(Capacity() < max_capacity_);
711 // Last page must be valid and its next page is invalid.
712 ASSERT(last_page_->is_valid() && !last_page_->next_page()->is_valid());
713 682
714 // We are going to exceed capacity for this space. 683 // Are we going to exceed capacity for this space?
715 if ((Capacity() + Page::kPageSize) > max_capacity_) return false; 684 if ((Capacity() + Page::kPageSize) > max_capacity_) return false;
716 685
717 Page* p = MemoryAllocator::AllocatePage(this, executable()); 686 Page* p = MemoryAllocator::AllocatePage(this, executable());
718 if (!p->is_valid()) return false; 687 if (p == NULL) return false;
719 688
720 accounting_stats_.ExpandSpace(Page::kObjectAreaSize);
721 ASSERT(Capacity() <= max_capacity_); 689 ASSERT(Capacity() <= max_capacity_);
722 690
723 last_page_->set_next_page(p); 691 p->InsertAfter(anchor_.prev_page());
724 last_page_ = p;
725
726 ASSERT(!last_page_->next_page()->is_valid());
727 692
728 return true; 693 return true;
729 } 694 }
730 695
731 696
732 #ifdef DEBUG 697 #ifdef DEBUG
733 int PagedSpace::CountTotalPages() { 698 int PagedSpace::CountTotalPages() {
699 PageIterator it(this);
734 int count = 0; 700 int count = 0;
735 for (Page* p = first_page_; p->is_valid(); p = p->next_page()) { 701 while (it.has_next()) {
702 it.next();
736 count++; 703 count++;
737 } 704 }
738 return count; 705 return count;
739 } 706 }
740 #endif 707 #endif
741 708
742 709
743 void PagedSpace::Shrink() { 710 void PagedSpace::Shrink() {
744 Page* top_page = AllocationTopPage();
745 ASSERT(top_page->is_valid());
746
747 // TODO(gc) release half of pages? 711 // TODO(gc) release half of pages?
748 if (top_page->next_page()->is_valid()) {
749 int pages_freed = 0;
750 Page* page = top_page->next_page();
751 Page* next_page;
752 while (page->is_valid()) {
753 next_page = page->next_page();
754 MemoryAllocator::Free(page);
755 pages_freed++;
756 page = next_page;
757 }
758 top_page->set_next_page(Page::FromAddress(NULL));
759 last_page_ = top_page;
760
761 accounting_stats_.ShrinkSpace(pages_freed * Page::kObjectAreaSize);
762 ASSERT(Capacity() == CountTotalPages() * Page::kObjectAreaSize);
763 }
764 } 712 }
765 713
766 714
767 bool PagedSpace::EnsureCapacity(int capacity) { 715 bool PagedSpace::EnsureCapacity(int capacity) {
768 while (Capacity() < capacity) { 716 while (Capacity() < capacity) {
769 // Expand the space until it has the required capacity or expansion fails. 717 // Expand the space until it has the required capacity or expansion fails.
770 if (!Expand()) return false; 718 if (!Expand()) return false;
771 } 719 }
772 return true; 720 return true;
773 } 721 }
774 722
775 723
776 #ifdef DEBUG 724 #ifdef DEBUG
777 void PagedSpace::Print() { } 725 void PagedSpace::Print() { }
778 #endif 726 #endif
779 727
780 728
781 #ifdef DEBUG 729 #ifdef DEBUG
782 // We do not assume that the PageIterator works, because it depends on the
783 // invariants we are checking during verification.
784 void PagedSpace::Verify(ObjectVisitor* visitor) { 730 void PagedSpace::Verify(ObjectVisitor* visitor) {
785 // The allocation pointer should be valid, and it should be in a page in the 731 // We can only iterate over the pages if they were swept precisely.
786 // space. 732 if (was_swept_conservatively_) return;
787 ASSERT(allocation_info_.VerifyPagedAllocation());
788 Page* top_page = Page::FromAllocationTop(allocation_info_.top);
789 733
790 // Loop over all the pages. 734 bool allocation_pointer_found_in_space =
791 bool above_allocation_top = false; 735 (allocation_info_.top != allocation_info_.limit);
792 Page* current_page = first_page_; 736 PageIterator page_iterator(this);
793 while (current_page->is_valid()) { 737 while (page_iterator.has_next()) {
794 if (above_allocation_top) { 738 Page* page = page_iterator.next();
795 // We don't care what's above the allocation top. 739 ASSERT(page->owner() == this);
796 } else { 740 if (page == Page::FromAllocationTop(allocation_info_.top)) {
797 Address top = current_page->AllocationTop(); 741 allocation_pointer_found_in_space = true;
798 if (current_page == top_page) { 742 }
799 ASSERT(top == allocation_info_.top); 743 ASSERT(!page->IsFlagSet(MemoryChunk::WAS_SWEPT_CONSERVATIVELY));
800 // The next page will be above the allocation top. 744 HeapObjectIterator it(page, NULL);
801 above_allocation_top = true; 745 Address end_of_previous_object = page->ObjectAreaStart();
802 } 746 Address top = page->ObjectAreaEnd();
747 for (HeapObject* object = it.Next(); object != NULL; object = it.Next()) {
748 ASSERT(end_of_previous_object <= object->address());
803 749
804 HeapObjectIterator it(current_page, NULL); 750 // The first word should be a map, and we expect all map pointers to
805 Address end_of_previous_object = current_page->ObjectAreaStart(); 751 // be in map space.
806 for (HeapObject* object = it.next(); object != NULL; object = it.next()) { 752 Map* map = object->map();
807 ASSERT(end_of_previous_object <= object->address()); 753 ASSERT(map->IsMap());
754 ASSERT(Heap::map_space()->Contains(map));
808 755
809 // The first word should be a map, and we expect all map pointers to 756 // Perform space-specific object verification.
810 // be in map space. 757 VerifyObject(object);
811 Map* map = object->map();
812 ASSERT(map->IsMap());
813 ASSERT(Heap::map_space()->Contains(map));
814 758
815 // Perform space-specific object verification. 759 // The object itself should look OK.
816 VerifyObject(object); 760 object->Verify();
817 761
818 // The object itself should look OK. 762 // All the interior pointers should be contained in the heap.
819 object->Verify(); 763 int size = object->Size();
764 object->IterateBody(map->instance_type(), size, visitor);
820 765
821 // All the interior pointers should be contained in the heap and 766 ASSERT(object->address() + size <= top);
822 // have page regions covering intergenerational references should be 767 end_of_previous_object = object->address() + size;
823 // marked dirty.
824 int size = object->Size();
825 object->IterateBody(map->instance_type(), size, visitor);
826
827 ASSERT(object->address() + size <= top);
828 end_of_previous_object = object->address() + size;
829 }
830 } 768 }
831
832 current_page = current_page->next_page();
833 } 769 }
834 } 770 }
835 #endif 771 #endif
836 772
837 773
838 // ----------------------------------------------------------------------------- 774 // -----------------------------------------------------------------------------
839 // NewSpace implementation 775 // NewSpace implementation
840 776
841 777
842 bool NewSpace::Setup(int maximum_semispace_capacity) { 778 bool NewSpace::Setup(int maximum_semispace_capacity) {
(...skipping 563 matching lines...) Expand 10 before | Expand all | Expand 10 after
1406 } else if (size_in_bytes == 2 * kPointerSize) { 1342 } else if (size_in_bytes == 2 * kPointerSize) {
1407 set_map(Heap::raw_unchecked_two_pointer_filler_map()); 1343 set_map(Heap::raw_unchecked_two_pointer_filler_map());
1408 } else { 1344 } else {
1409 UNREACHABLE(); 1345 UNREACHABLE();
1410 } 1346 }
1411 // We would like to ASSERT(Size() == size_in_bytes) but this would fail during 1347 // We would like to ASSERT(Size() == size_in_bytes) but this would fail during
1412 // deserialization because the byte array map is not done yet. 1348 // deserialization because the byte array map is not done yet.
1413 } 1349 }
1414 1350
1415 1351
1416 Address FreeListNode::next() { 1352 FreeListNode* FreeListNode::next() {
1417 ASSERT(IsFreeListNode(this)); 1353 ASSERT(IsFreeListNode(this));
1418 if (map() == Heap::raw_unchecked_byte_array_map()) { 1354 if (map() == Heap::raw_unchecked_byte_array_map()) {
1419 ASSERT(Size() >= kNextOffset + kPointerSize); 1355 ASSERT(map() == NULL || Size() >= kNextOffset + kPointerSize);
1420 return Memory::Address_at(address() + kNextOffset); 1356 return reinterpret_cast<FreeListNode*>(
1357 Memory::Address_at(address() + kNextOffset));
1421 } else { 1358 } else {
1422 return Memory::Address_at(address() + kPointerSize); 1359 return reinterpret_cast<FreeListNode*>(
1360 Memory::Address_at(address() + kPointerSize));
1423 } 1361 }
1424 } 1362 }
1425 1363
1426 1364
1427 void FreeListNode::set_next(Address next) { 1365 FreeListNode** FreeListNode::next_address() {
1428 ASSERT(IsFreeListNode(this)); 1366 ASSERT(IsFreeListNode(this));
1429 if (map() == Heap::raw_unchecked_byte_array_map()) { 1367 if (map() == Heap::raw_unchecked_byte_array_map()) {
1430 ASSERT(Size() >= kNextOffset + kPointerSize); 1368 ASSERT(Size() >= kNextOffset + kPointerSize);
1431 Memory::Address_at(address() + kNextOffset) = next; 1369 return reinterpret_cast<FreeListNode**>(address() + kNextOffset);
1432 } else { 1370 } else {
1433 Memory::Address_at(address() + kPointerSize) = next; 1371 return reinterpret_cast<FreeListNode**>(address() + kPointerSize);
1434 } 1372 }
1435 } 1373 }
1436 1374
1437 1375
1438 OldSpaceFreeList::OldSpaceFreeList(AllocationSpace owner) : owner_(owner) { 1376 void FreeListNode::set_next(FreeListNode* next) {
1377 ASSERT(IsFreeListNode(this));
1378 // While we are booting the VM the byte array map will actually be null. So
1379 // we have to make sure that we don't try to use it for anything at that
1380 // stage.
1381 if (map() == Heap::raw_unchecked_byte_array_map()) {
1382 ASSERT(map() == NULL || Size() >= kNextOffset + kPointerSize);
1383 Memory::Address_at(address() + kNextOffset) =
1384 reinterpret_cast<Address>(next);
1385 } else {
1386 Memory::Address_at(address() + kPointerSize) =
1387 reinterpret_cast<Address>(next);
1388 }
1389 }
1390
1391
1392 OldSpaceFreeList::OldSpaceFreeList(PagedSpace* owner) : owner_(owner) {
1439 Reset(); 1393 Reset();
1440 } 1394 }
1441 1395
1442 1396
1443 void OldSpaceFreeList::Reset() { 1397 void OldSpaceFreeList::Reset() {
1444 available_ = 0; 1398 available_ = 0;
1445 for (int i = 0; i < kFreeListsLength; i++) { 1399 small_list_ = NULL;
1446 free_[i].head_node_ = NULL; 1400 medium_list_ = NULL;
1447 } 1401 large_list_ = NULL;
1448 needs_rebuild_ = false; 1402 huge_list_ = NULL;
1449 finger_ = kHead;
1450 free_[kHead].next_size_ = kEnd;
1451 }
1452
1453
1454 void OldSpaceFreeList::RebuildSizeList() {
1455 ASSERT(needs_rebuild_);
1456 int cur = kHead;
1457 for (int i = cur + 1; i < kFreeListsLength; i++) {
1458 if (free_[i].head_node_ != NULL) {
1459 free_[cur].next_size_ = i;
1460 cur = i;
1461 }
1462 }
1463 free_[cur].next_size_ = kEnd;
1464 needs_rebuild_ = false;
1465 } 1403 }
1466 1404
1467 1405
1468 int OldSpaceFreeList::Free(Address start, int size_in_bytes) { 1406 int OldSpaceFreeList::Free(Address start, int size_in_bytes) {
1469 #ifdef DEBUG 1407 #ifdef DEBUG
1470 MemoryAllocator::ZapBlock(start, size_in_bytes); 1408 MemoryAllocator::ZapBlock(start, size_in_bytes);
1471 #endif 1409 #endif
1410 if (size_in_bytes == 0) return 0;
1472 FreeListNode* node = FreeListNode::FromAddress(start); 1411 FreeListNode* node = FreeListNode::FromAddress(start);
1473 node->set_size(size_in_bytes); 1412 node->set_size(size_in_bytes);
1474 1413
1475 // We don't use the freelists in compacting mode. This makes it more like a 1414 // Early return to drop too-small blocks on the floor.
1476 // GC that only has mark-sweep-compact and doesn't have a mark-sweep 1415 if (size_in_bytes < kSmallListMin) return size_in_bytes;
1477 // collector. 1416
1478 if (FLAG_always_compact) { 1417 // Insert other blocks at the head of a free list of the appropriate
1479 return size_in_bytes; 1418 // magnitude.
1419 if (size_in_bytes <= kSmallListMax) {
1420 node->set_next(small_list_);
1421 small_list_ = node;
1422 } else if (size_in_bytes <= kMediumListMax) {
1423 node->set_next(medium_list_);
1424 medium_list_ = node;
1425 } else if (size_in_bytes <= kLargeListMax) {
1426 node->set_next(large_list_);
1427 large_list_ = node;
1428 } else {
1429 node->set_next(huge_list_);
1430 huge_list_ = node;
1480 } 1431 }
1481
1482 // Early return to drop too-small blocks on the floor (one or two word
1483 // blocks cannot hold a map pointer, a size field, and a pointer to the
1484 // next block in the free list).
1485 if (size_in_bytes < kMinBlockSize) {
1486 return size_in_bytes;
1487 }
1488
1489 // Insert other blocks at the head of an exact free list.
1490 int index = size_in_bytes >> kPointerSizeLog2;
1491 node->set_next(free_[index].head_node_);
1492 free_[index].head_node_ = node->address();
1493 available_ += size_in_bytes; 1432 available_ += size_in_bytes;
1494 needs_rebuild_ = true; 1433 ASSERT(available_ == SumFreeLists());
1495 return 0; 1434 return 0;
1496 } 1435 }
1497 1436
1498 1437
1499 MaybeObject* OldSpaceFreeList::Allocate(int size_in_bytes, int* wasted_bytes) { 1438 // Allocation on the old space free list. If it succeeds then a new linear
1439 // allocation space has been set up with the top and limit of the space. If
1440 // the allocation fails then NULL is returned, and the caller can perform a GC
1441 // or allocate a new page before retrying.
1442 HeapObject* OldSpaceFreeList::Allocate(int size_in_bytes) {
1500 ASSERT(0 < size_in_bytes); 1443 ASSERT(0 < size_in_bytes);
1501 ASSERT(size_in_bytes <= kMaxBlockSize); 1444 ASSERT(size_in_bytes <= kMaxBlockSize);
1502 ASSERT(IsAligned(size_in_bytes, kPointerSize)); 1445 ASSERT(IsAligned(size_in_bytes, kPointerSize));
1446 // Don't free list allocate if there is linear space available.
1447 ASSERT(owner_->limit() - owner_->top() < size_in_bytes);
1503 1448
1504 if (needs_rebuild_) RebuildSizeList(); 1449 FreeListNode* new_node = NULL;
1505 int index = size_in_bytes >> kPointerSizeLog2; 1450 int new_node_size = 0;
1506 // Check for a perfect fit. 1451
1507 if (free_[index].head_node_ != NULL) { 1452 if (size_in_bytes <= kSmallAllocationMax && small_list_ != NULL) {
1508 FreeListNode* node = FreeListNode::FromAddress(free_[index].head_node_); 1453 new_node = small_list_;
1509 // If this was the last block of its size, remove the size. 1454 new_node_size = new_node->Size();
1510 if ((free_[index].head_node_ = node->next()) == NULL) RemoveSize(index); 1455 small_list_ = new_node->next();
1511 available_ -= size_in_bytes; 1456 } else if (size_in_bytes <= kMediumAllocationMax && medium_list_ != NULL) {
1512 *wasted_bytes = 0; 1457 new_node = medium_list_;
1513 ASSERT(!FLAG_always_compact); // We only use the freelists with mark-sweep. 1458 new_node_size = new_node->Size();
1514 return node; 1459 medium_list_ = new_node->next();
1460 } else if (size_in_bytes <= kLargeAllocationMax && large_list_ != NULL) {
1461 new_node = large_list_;
1462 new_node_size = new_node->Size();
1463 large_list_ = new_node->next();
1464 } else {
1465 for (FreeListNode** cur = &huge_list_;
1466 *cur != NULL;
1467 cur = (*cur)->next_address()) {
1468 ASSERT((*cur)->map() == Heap::raw_unchecked_byte_array_map());
1469 ByteArray* cur_as_byte_array = reinterpret_cast<ByteArray*>(*cur);
1470 int size = cur_as_byte_array->Size();
1471 if (size >= size_in_bytes) {
1472 // Large enough node found. Unlink it from the list.
1473 new_node = *cur;
1474 new_node_size = size;
1475 *cur = new_node->next();
1476 break;
1477 }
1478 }
1479 if (new_node == NULL) return NULL;
1515 } 1480 }
1516 // Search the size list for the best fit. 1481
1517 int prev = finger_ < index ? finger_ : kHead; 1482 available_ -= new_node_size;
1518 int cur = FindSize(index, &prev); 1483 ASSERT(available_ == SumFreeLists());
1519 ASSERT(index < cur); 1484
1520 if (cur == kEnd) { 1485 int old_linear_size = owner_->limit() - owner_->top();
1521 // No large enough size in list. 1486 // Mark the old linear allocation area with a byte array so it can be
1522 *wasted_bytes = 0; 1487 // skipped when scanning the heap. This also puts it back in the free list
1523 return Failure::RetryAfterGC(owner_); 1488 // if it is big enough.
1489 owner_->Free(owner_->top(), old_linear_size);
1490 IncrementalMarking::Step(size_in_bytes - old_linear_size);
1491
1492 ASSERT(new_node_size - size_in_bytes >= 0); // New linear size.
1493
1494 const int kThreshold = IncrementalMarking::kAllocatedThreshold;
1495
1496 if (new_node_size - size_in_bytes > kThreshold &&
1497 IncrementalMarking::state() == IncrementalMarking::MARKING) {
1498 // We don't want to give too large linear areas to the allocator while
1499 // incremental marking is going on, because we won't check again whether
1500 // we want to do another increment until the linear area is used up.
1501 owner_->Free(new_node->address() + size_in_bytes + kThreshold,
1502 new_node_size - size_in_bytes - kThreshold);
1503 owner_->SetTop(new_node->address() + size_in_bytes,
1504 new_node->address() + size_in_bytes + kThreshold);
1505 } else {
1506 // Normally we give the rest of the node to the allocator as its new
1507 // linear allocation area.
1508 owner_->SetTop(new_node->address() + size_in_bytes,
1509 new_node->address() + new_node_size);
1524 } 1510 }
1525 ASSERT(!FLAG_always_compact); // We only use the freelists with mark-sweep.
1526 int rem = cur - index;
1527 int rem_bytes = rem << kPointerSizeLog2;
1528 FreeListNode* cur_node = FreeListNode::FromAddress(free_[cur].head_node_);
1529 ASSERT(cur_node->Size() == (cur << kPointerSizeLog2));
1530 FreeListNode* rem_node = FreeListNode::FromAddress(free_[cur].head_node_ +
1531 size_in_bytes);
1532 // Distinguish the cases prev < rem < cur and rem <= prev < cur
1533 // to avoid many redundant tests and calls to Insert/RemoveSize.
1534 if (prev < rem) {
1535 // Simple case: insert rem between prev and cur.
1536 finger_ = prev;
1537 free_[prev].next_size_ = rem;
1538 // If this was the last block of size cur, remove the size.
1539 if ((free_[cur].head_node_ = cur_node->next()) == NULL) {
1540 free_[rem].next_size_ = free_[cur].next_size_;
1541 } else {
1542 free_[rem].next_size_ = cur;
1543 }
1544 // Add the remainder block.
1545 rem_node->set_size(rem_bytes);
1546 rem_node->set_next(free_[rem].head_node_);
1547 free_[rem].head_node_ = rem_node->address();
1548 } else {
1549 // If this was the last block of size cur, remove the size.
1550 if ((free_[cur].head_node_ = cur_node->next()) == NULL) {
1551 finger_ = prev;
1552 free_[prev].next_size_ = free_[cur].next_size_;
1553 }
1554 if (rem_bytes < kMinBlockSize) {
1555 // Too-small remainder is wasted.
1556 rem_node->set_size(rem_bytes);
1557 available_ -= size_in_bytes + rem_bytes;
1558 *wasted_bytes = rem_bytes;
1559 return cur_node;
1560 }
1561 // Add the remainder block and, if needed, insert its size.
1562 rem_node->set_size(rem_bytes);
1563 rem_node->set_next(free_[rem].head_node_);
1564 free_[rem].head_node_ = rem_node->address();
1565 if (rem_node->next() == NULL) InsertSize(rem);
1566 }
1567 available_ -= size_in_bytes;
1568 *wasted_bytes = 0;
1569 return cur_node;
1570 }
1571 1511
1572 1512 return new_node;
1573 void OldSpaceFreeList::MarkNodes() {
1574 for (int i = 0; i < kFreeListsLength; i++) {
1575 Address cur_addr = free_[i].head_node_;
1576 while (cur_addr != NULL) {
1577 FreeListNode* cur_node = FreeListNode::FromAddress(cur_addr);
1578 cur_addr = cur_node->next();
1579 IntrusiveMarking::SetMark(cur_node);
1580 }
1581 }
1582 } 1513 }
1583 1514
1584 1515
1585 #ifdef DEBUG 1516 #ifdef DEBUG
1586 bool OldSpaceFreeList::Contains(FreeListNode* node) { 1517 intptr_t OldSpaceFreeList::SumFreeList(FreeListNode* cur) {
1587 for (int i = 0; i < kFreeListsLength; i++) { 1518 intptr_t sum = 0;
1588 Address cur_addr = free_[i].head_node_; 1519 while (cur != NULL) {
1589 while (cur_addr != NULL) { 1520 ASSERT(cur->map() == Heap::raw_unchecked_byte_array_map());
1590 FreeListNode* cur_node = FreeListNode::FromAddress(cur_addr); 1521 ByteArray* cur_as_byte_array = reinterpret_cast<ByteArray*>(cur);
1591 if (cur_node == node) return true; 1522 sum += cur_as_byte_array->Size();
1592 cur_addr = cur_node->next(); 1523 cur = cur->next();
1593 }
1594 } 1524 }
1595 return false; 1525 return sum;
1596 } 1526 }
1597 1527
1598 1528
1599 void FreeListNode::Zap() { 1529 intptr_t OldSpaceFreeList::SumFreeLists() {
1600 if (IsByteArray()) { 1530 intptr_t sum = SumFreeList(small_list_);
1601 ByteArray* ba = ByteArray::cast(this); 1531 sum += SumFreeList(medium_list_);
1602 // Skip map, length and next pointer. 1532 sum += SumFreeList(large_list_);
1603 Address payload_start = ba->GetDataStartAddress() + kPointerSize; 1533 sum += SumFreeList(huge_list_);
1604 Address payload_end = ba->address() + ba->Size(); 1534 return sum;
1605 for (Address cur = payload_start;
1606 cur < payload_end;
1607 cur += kPointerSize) {
1608 *reinterpret_cast<uintptr_t*>(cur) = kFreeListZapValue;
1609 }
1610 }
1611 }
1612
1613
1614 void OldSpaceFreeList::Zap() {
1615 for (int i = 0; i < kFreeListsLength; i++) {
1616 Address cur_addr = free_[i].head_node_;
1617 while (cur_addr != NULL) {
1618 FreeListNode* cur_node = FreeListNode::FromAddress(cur_addr);
1619 cur_node->Zap();
1620 cur_addr = cur_node->next();
1621 }
1622 }
1623 }
1624
1625
1626 void FixedSizeFreeList::Zap() {
1627 Address cur_addr = head_;
1628 while (cur_addr != NULL && cur_addr != tail_) {
1629 FreeListNode* cur_node = FreeListNode::FromAddress(cur_addr);
1630 cur_node->Zap();
1631 cur_addr = cur_node->next();
1632 }
1633 } 1535 }
1634 #endif 1536 #endif
1635 1537
1636 1538
1637 FixedSizeFreeList::FixedSizeFreeList(AllocationSpace owner, int object_size)
1638 : owner_(owner), object_size_(object_size) {
1639 Reset();
1640 }
1641
1642
1643 void FixedSizeFreeList::Reset() {
1644 available_ = 0;
1645 head_ = tail_ = NULL;
1646 }
1647
1648
1649 void FixedSizeFreeList::Free(Address start) {
1650 #ifdef DEBUG
1651 MemoryAllocator::ZapBlock(start, object_size_);
1652 #endif
1653 // We only use the freelists with mark-sweep.
1654 ASSERT(!MarkCompactCollector::IsCompacting());
1655 FreeListNode* node = FreeListNode::FromAddress(start);
1656 node->set_size(object_size_);
1657 node->set_next(NULL);
1658 if (head_ == NULL) {
1659 tail_ = head_ = node->address();
1660 } else {
1661 FreeListNode::FromAddress(tail_)->set_next(node->address());
1662 tail_ = node->address();
1663 }
1664 available_ += object_size_;
1665 }
1666
1667
1668 MaybeObject* FixedSizeFreeList::Allocate() {
1669 if (head_ == NULL) {
1670 return Failure::RetryAfterGC(owner_);
1671 }
1672
1673 ASSERT(!FLAG_always_compact); // We only use the freelists with mark-sweep.
1674 FreeListNode* node = FreeListNode::FromAddress(head_);
1675 head_ = node->next();
1676 available_ -= object_size_;
1677 return node;
1678 }
1679
1680
1681 void FixedSizeFreeList::MarkNodes() {
1682 Address cur_addr = head_;
1683 while (cur_addr != NULL && cur_addr != tail_) {
1684 FreeListNode* cur_node = FreeListNode::FromAddress(cur_addr);
1685 cur_addr = cur_node->next();
1686 IntrusiveMarking::SetMark(cur_node);
1687 }
1688 }
1689
1690
1691 // ----------------------------------------------------------------------------- 1539 // -----------------------------------------------------------------------------
1692 // OldSpace implementation 1540 // OldSpace implementation
1693 1541
1694 void OldSpace::PrepareForMarkCompact(bool will_compact) { 1542 void OldSpace::PrepareForMarkCompact(bool will_compact) {
1695 ASSERT(!will_compact); 1543 ASSERT(!will_compact);
1696 // Call prepare of the super class. 1544 // Call prepare of the super class.
1697 PagedSpace::PrepareForMarkCompact(will_compact); 1545 PagedSpace::PrepareForMarkCompact(will_compact);
1698 1546
1699 // During a non-compacting collection, everything below the linear
1700 // allocation pointer is considered allocated (everything above is
1701 // available) and we will rediscover available and wasted bytes during
1702 // the collection.
1703 accounting_stats_.AllocateBytes(free_list_.available());
1704 accounting_stats_.FillWastedBytes(Waste());
1705
1706 // Clear the free list before a full GC---it will be rebuilt afterward. 1547 // Clear the free list before a full GC---it will be rebuilt afterward.
1707 free_list_.Reset(); 1548 free_list_.Reset();
1708 } 1549 }
1709 1550
1710 1551
1711 bool NewSpace::ReserveSpace(int bytes) { 1552 bool NewSpace::ReserveSpace(int bytes) {
1712 // We can't reliably unpack a partial snapshot that needs more new space 1553 // We can't reliably unpack a partial snapshot that needs more new space
1713 // space than the minimum NewSpace size. 1554 // space than the minimum NewSpace size.
1714 ASSERT(bytes <= InitialCapacity()); 1555 ASSERT(bytes <= InitialCapacity());
1715 Address limit = allocation_info_.limit; 1556 Address limit = allocation_info_.limit;
1716 Address top = allocation_info_.top; 1557 Address top = allocation_info_.top;
1717 return limit - top >= bytes; 1558 return limit - top >= bytes;
1718 } 1559 }
1719 1560
1720 1561
1721 void PagedSpace::FreePages(Page* prev, Page* last) {
1722 if (last == AllocationTopPage()) {
1723 // Pages are already at the end of used pages.
1724 // Just mark them as continuous.
1725 Page* p = prev == NULL ? first_page_ : prev->next_page();
1726 Page* end_page = last->next_page();
1727 do {
1728 p->SetFlag(Page::IS_CONTINUOUS);
1729 p = p->next_page();
1730 } while (p != end_page);
1731 return;
1732 }
1733
1734 Page* first = NULL;
1735
1736 // Remove pages from the list.
1737 if (prev == NULL) {
1738 first = first_page_;
1739 first_page_ = last->next_page();
1740 } else {
1741 first = prev->next_page();
1742 prev->set_next_page(last->next_page());
1743 }
1744
1745 // Attach it after the last page.
1746 last_page_->set_next_page(first);
1747 last_page_ = last;
1748 last->set_next_page(NULL);
1749
1750 // Clean them up.
1751 do {
1752 first->InvalidateWatermark(true);
1753 first->SetAllocationWatermark(first->ObjectAreaStart());
1754 first->SetCachedAllocationWatermark(first->ObjectAreaStart());
1755 first->SetFlag(Page::IS_CONTINUOUS);
1756 first->markbits()->Clear();
1757 first = first->next_page();
1758 } while (first->is_valid());
1759 }
1760
1761
1762 void PagedSpace::PrepareForMarkCompact(bool will_compact) { 1562 void PagedSpace::PrepareForMarkCompact(bool will_compact) {
1763 ASSERT(!will_compact); 1563 ASSERT(!will_compact);
1764 } 1564 }
1765 1565
1766 1566
1767 bool PagedSpace::ReserveSpace(int bytes) { 1567 bool PagedSpace::ReserveSpace(int size_in_bytes) {
1768 Address limit = allocation_info_.limit; 1568 ASSERT(size_in_bytes <= Page::kMaxHeapObjectSize);
1769 Address top = allocation_info_.top; 1569 ASSERT(size_in_bytes == RoundUp(size_in_bytes, kPointerSize));
1770 if (limit - top >= bytes) return true; 1570 Address current_top = allocation_info_.top;
1571 Address new_top = current_top + size_in_bytes;
1572 if (new_top <= allocation_info_.limit) return true;
1771 1573
1772 // There wasn't enough space in the current page. Lets put the rest 1574 HeapObject* new_area = free_list_.Allocate(size_in_bytes);
1773 // of the page on the free list and start a fresh page. 1575 if (new_area == NULL) new_area = SlowAllocateRaw(size_in_bytes);
1774 PutRestOfCurrentPageOnFreeList(TopPageOf(allocation_info_)); 1576 if (new_area == NULL) return false;
1775 1577
1776 Page* reserved_page = TopPageOf(allocation_info_); 1578 int old_linear_size = limit() - top();
1777 int bytes_left_to_reserve = bytes; 1579 // Mark the old linear allocation area with a byte array so it can be
1778 while (bytes_left_to_reserve > 0) { 1580 // skipped when scanning the heap. This also puts it back in the free list
1779 if (!reserved_page->next_page()->is_valid()) { 1581 // if it is big enough.
1780 if (Heap::OldGenerationAllocationLimitReached()) return false; 1582 Free(top(), old_linear_size);
1781 Expand(); 1583
1782 } 1584 SetTop(new_area->address(), new_area->address() + size_in_bytes);
1783 bytes_left_to_reserve -= Page::kPageSize;
1784 reserved_page = reserved_page->next_page();
1785 if (!reserved_page->is_valid()) return false;
1786 }
1787 ASSERT(TopPageOf(allocation_info_)->next_page()->is_valid());
1788 TopPageOf(allocation_info_)->next_page()->InvalidateWatermark(true);
1789 SetAllocationInfo(&allocation_info_,
1790 TopPageOf(allocation_info_)->next_page());
1791 return true; 1585 return true;
1792 } 1586 }
1793 1587
1794 1588
1795 // You have to call this last, since the implementation from PagedSpace 1589 // You have to call this last, since the implementation from PagedSpace
1796 // doesn't know that memory was 'promised' to large object space. 1590 // doesn't know that memory was 'promised' to large object space.
1797 bool LargeObjectSpace::ReserveSpace(int bytes) { 1591 bool LargeObjectSpace::ReserveSpace(int bytes) {
1798 return Heap::OldGenerationSpaceAvailable() >= bytes; 1592 return Heap::OldGenerationSpaceAvailable() >= bytes;
1799 } 1593 }
1800 1594
1801 1595
1802 // Slow case for normal allocation. Try in order: (1) allocate in the next 1596 HeapObject* PagedSpace::SlowAllocateRaw(int size_in_bytes) {
1803 // page in the space, (2) allocate off the space's free list, (3) expand the 1597 // Allocation in this space has failed.
1804 // space, (4) fail.
1805 HeapObject* OldSpace::SlowAllocateRaw(int size_in_bytes) {
1806 // Linear allocation in this space has failed. If there is another page
1807 // in the space, move to that page and allocate there. This allocation
1808 // should succeed (size_in_bytes should not be greater than a page's
1809 // object area size).
1810 Page* current_page = TopPageOf(allocation_info_);
1811 if (current_page->next_page()->is_valid()) {
1812 return AllocateInNextPage(current_page, size_in_bytes);
1813 }
1814
1815 // There is no next page in this space. Try free list allocation unless that
1816 // is currently forbidden.
1817 if (!Heap::linear_allocation()) {
1818 int wasted_bytes;
1819 Object* result;
1820 MaybeObject* maybe = free_list_.Allocate(size_in_bytes, &wasted_bytes);
1821 accounting_stats_.WasteBytes(wasted_bytes);
1822 if (maybe->ToObject(&result)) {
1823 accounting_stats_.AllocateBytes(size_in_bytes);
1824
1825 HeapObject* obj = HeapObject::cast(result);
1826 Page* p = Page::FromAddress(obj->address());
1827
1828 if (obj->address() >= p->AllocationWatermark()) {
1829 // There should be no hole between the allocation watermark
1830 // and allocated object address.
1831 // Memory above the allocation watermark was not swept and
1832 // might contain garbage pointers to new space.
1833 ASSERT(obj->address() == p->AllocationWatermark());
1834 p->SetAllocationWatermark(obj->address() + size_in_bytes);
1835 }
1836
1837 if (!p->IsFlagSet(Page::IS_CONTINUOUS)) {
1838 // This page is not continuous so we have to mark objects
1839 // that should be visited by HeapObjectIterator.
1840 ASSERT(!Marking::IsMarked(obj));
1841 Marking::SetMark(obj);
1842 }
1843
1844 return obj;
1845 }
1846 }
1847 1598
1848 // Free list allocation failed and there is no next page. Fail if we have 1599 // Free list allocation failed and there is no next page. Fail if we have
1849 // hit the old generation size limit that should cause a garbage 1600 // hit the old generation size limit that should cause a garbage
1850 // collection. 1601 // collection.
1851 if (!Heap::always_allocate() && Heap::OldGenerationAllocationLimitReached()) { 1602 if (!Heap::always_allocate() && Heap::OldGenerationAllocationLimitReached()) {
1852 return NULL; 1603 return NULL;
1853 } 1604 }
1854 1605
1855 // Try to expand the space and allocate in the new next page. 1606 // Try to expand the space and allocate in the new next page.
1856 ASSERT(!current_page->next_page()->is_valid());
1857 if (Expand()) { 1607 if (Expand()) {
1858 return AllocateInNextPage(current_page, size_in_bytes); 1608 return free_list_.Allocate(size_in_bytes);
1859 } 1609 }
1860 1610
1861 // Finally, fail. 1611 // Finally, fail.
1862 return NULL; 1612 return NULL;
1863 } 1613 }
1864 1614
1865 1615
1866 void OldSpace::PutRestOfCurrentPageOnFreeList(Page* current_page) {
1867 current_page->SetAllocationWatermark(allocation_info_.top);
1868 int free_size =
1869 static_cast<int>(current_page->ObjectAreaEnd() - allocation_info_.top);
1870 if (free_size > 0) {
1871 int wasted_bytes = free_list_.Free(allocation_info_.top, free_size);
1872 accounting_stats_.WasteBytes(wasted_bytes);
1873 }
1874 }
1875
1876
1877 void FixedSpace::PutRestOfCurrentPageOnFreeList(Page* current_page) {
1878 current_page->SetAllocationWatermark(allocation_info_.top);
1879 int free_size =
1880 static_cast<int>(current_page->ObjectAreaEnd() - allocation_info_.top);
1881 // In the fixed space free list all the free list items have the right size.
1882 // We use up the rest of the page while preserving this invariant.
1883 while (free_size >= object_size_in_bytes_) {
1884 free_list_.Free(allocation_info_.top);
1885 allocation_info_.top += object_size_in_bytes_;
1886 free_size -= object_size_in_bytes_;
1887 accounting_stats_.WasteBytes(object_size_in_bytes_);
1888 }
1889 }
1890
1891
1892 // Add the block at the top of the page to the space's free list, set the
1893 // allocation info to the next page (assumed to be one), and allocate
1894 // linearly there.
1895 HeapObject* OldSpace::AllocateInNextPage(Page* current_page,
1896 int size_in_bytes) {
1897 ASSERT(current_page->next_page()->is_valid());
1898 Page* next_page = current_page->next_page();
1899 next_page->ClearGCFields();
1900 PutRestOfCurrentPageOnFreeList(current_page);
1901 SetAllocationInfo(&allocation_info_, next_page);
1902 return AllocateLinearly(&allocation_info_, size_in_bytes);
1903 }
1904
1905
1906 void OldSpace::DeallocateBlock(Address start,
1907 int size_in_bytes,
1908 bool add_to_freelist) {
1909 Free(start, size_in_bytes, add_to_freelist);
1910 }
1911
1912
1913 #ifdef DEBUG 1616 #ifdef DEBUG
1914 struct CommentStatistic { 1617 struct CommentStatistic {
1915 const char* comment; 1618 const char* comment;
1916 int size; 1619 int size;
1917 int count; 1620 int count;
1918 void Clear() { 1621 void Clear() {
1919 comment = NULL; 1622 comment = NULL;
1920 size = 0; 1623 size = 0;
1921 count = 0; 1624 count = 0;
1922 } 1625 }
(...skipping 88 matching lines...) Expand 10 before | Expand all | Expand 10 after
2011 } 1714 }
2012 EnterComment(comment_txt, flat_delta); 1715 EnterComment(comment_txt, flat_delta);
2013 } 1716 }
2014 1717
2015 1718
2016 // Collects code size statistics: 1719 // Collects code size statistics:
2017 // - by code kind 1720 // - by code kind
2018 // - by code comment 1721 // - by code comment
2019 void PagedSpace::CollectCodeStatistics() { 1722 void PagedSpace::CollectCodeStatistics() {
2020 HeapObjectIterator obj_it(this); 1723 HeapObjectIterator obj_it(this);
2021 for (HeapObject* obj = obj_it.next(); obj != NULL; obj = obj_it.next()) { 1724 for (HeapObject* obj = obj_it.Next(); obj != NULL; obj = obj_it.Next()) {
2022 if (obj->IsCode()) { 1725 if (obj->IsCode()) {
2023 Code* code = Code::cast(obj); 1726 Code* code = Code::cast(obj);
2024 code_kind_statistics[code->kind()] += code->Size(); 1727 code_kind_statistics[code->kind()] += code->Size();
2025 RelocIterator it(code); 1728 RelocIterator it(code);
2026 int delta = 0; 1729 int delta = 0;
2027 const byte* prev_pc = code->instruction_start(); 1730 const byte* prev_pc = code->instruction_start();
2028 while (!it.done()) { 1731 while (!it.done()) {
2029 if (it.rinfo()->rmode() == RelocInfo::COMMENT) { 1732 if (it.rinfo()->rmode() == RelocInfo::COMMENT) {
2030 delta += static_cast<int>(it.rinfo()->pc() - prev_pc); 1733 delta += static_cast<int>(it.rinfo()->pc() - prev_pc);
2031 CollectCommentStatistics(&it); 1734 CollectCommentStatistics(&it);
2032 prev_pc = it.rinfo()->pc(); 1735 prev_pc = it.rinfo()->pc();
2033 } 1736 }
2034 it.next(); 1737 it.next();
2035 } 1738 }
2036 1739
2037 ASSERT(code->instruction_start() <= prev_pc && 1740 ASSERT(code->instruction_start() <= prev_pc &&
2038 prev_pc <= code->instruction_end()); 1741 prev_pc <= code->instruction_end());
2039 delta += static_cast<int>(code->instruction_end() - prev_pc); 1742 delta += static_cast<int>(code->instruction_end() - prev_pc);
2040 EnterComment("NoComment", delta); 1743 EnterComment("NoComment", delta);
2041 } 1744 }
2042 } 1745 }
2043 } 1746 }
2044 1747
2045 1748
2046 void OldSpace::ReportStatistics() { 1749 void PagedSpace::ReportStatistics() {
2047 int pct = static_cast<int>(Available() * 100 / Capacity()); 1750 int pct = static_cast<int>(Available() * 100 / Capacity());
2048 PrintF(" capacity: %" V8_PTR_PREFIX "d" 1751 PrintF(" capacity: %" V8_PTR_PREFIX "d"
2049 ", waste: %" V8_PTR_PREFIX "d" 1752 ", waste: %" V8_PTR_PREFIX "d"
2050 ", available: %" V8_PTR_PREFIX "d, %%%d\n", 1753 ", available: %" V8_PTR_PREFIX "d, %%%d\n",
2051 Capacity(), Waste(), Available(), pct); 1754 Capacity(), Waste(), Available(), pct);
2052 1755
2053 ClearHistograms(); 1756 ClearHistograms();
2054 HeapObjectIterator obj_it(this); 1757 HeapObjectIterator obj_it(this);
2055 for (HeapObject* obj = obj_it.next(); obj != NULL; obj = obj_it.next()) 1758 for (HeapObject* obj = obj_it.Next(); obj != NULL; obj = obj_it.Next())
2056 CollectHistogramInfo(obj); 1759 CollectHistogramInfo(obj);
2057 ReportHistogram(true); 1760 ReportHistogram(true);
2058 } 1761 }
2059 #endif 1762 #endif
2060 1763
2061 // ----------------------------------------------------------------------------- 1764 // -----------------------------------------------------------------------------
2062 // FixedSpace implementation 1765 // FixedSpace implementation
2063 1766
2064 void FixedSpace::PrepareForMarkCompact(bool will_compact) { 1767 void FixedSpace::PrepareForMarkCompact(bool will_compact) {
2065 // Call prepare of the super class. 1768 // Call prepare of the super class.
2066 PagedSpace::PrepareForMarkCompact(will_compact); 1769 PagedSpace::PrepareForMarkCompact(will_compact);
2067 1770
2068 ASSERT(!will_compact); 1771 ASSERT(!will_compact);
2069 1772
2070 // During a non-compacting collection, everything below the linear 1773 // During a non-compacting collection, everything below the linear
2071 // allocation pointer except wasted top-of-page blocks is considered 1774 // allocation pointer except wasted top-of-page blocks is considered
2072 // allocated and we will rediscover available bytes during the 1775 // allocated and we will rediscover available bytes during the
2073 // collection. 1776 // collection.
2074 accounting_stats_.AllocateBytes(free_list_.available()); 1777 accounting_stats_.AllocateBytes(free_list_.available());
2075 1778
2076 // Clear the free list before a full GC---it will be rebuilt afterward. 1779 // Clear the free list before a full GC---it will be rebuilt afterward.
2077 free_list_.Reset(); 1780 free_list_.Reset();
2078 } 1781 }
2079 1782
2080 1783
2081 // Slow case for normal allocation. Try in order: (1) allocate in the next
2082 // page in the space, (2) allocate off the space's free list, (3) expand the
2083 // space, (4) fail.
2084 HeapObject* FixedSpace::SlowAllocateRaw(int size_in_bytes) {
2085 ASSERT_EQ(object_size_in_bytes_, size_in_bytes);
2086 // Linear allocation in this space has failed. If there is another page
2087 // in the space, move to that page and allocate there. This allocation
2088 // should succeed.
2089 Page* current_page = TopPageOf(allocation_info_);
2090 if (current_page->next_page()->is_valid()) {
2091 return AllocateInNextPage(current_page, size_in_bytes);
2092 }
2093
2094 // There is no next page in this space. Try free list allocation unless
2095 // that is currently forbidden. The fixed space free list implicitly assumes
2096 // that all free blocks are of the fixed size.
2097 if (!Heap::linear_allocation()) {
2098 Object* result;
2099 MaybeObject* maybe = free_list_.Allocate();
2100 if (maybe->ToObject(&result)) {
2101 accounting_stats_.AllocateBytes(size_in_bytes);
2102 HeapObject* obj = HeapObject::cast(result);
2103 Page* p = Page::FromAddress(obj->address());
2104
2105 if (obj->address() >= p->AllocationWatermark()) {
2106 // There should be no hole between the allocation watermark
2107 // and allocated object address.
2108 // Memory above the allocation watermark was not swept and
2109 // might contain garbage pointers to new space.
2110 ASSERT(obj->address() == p->AllocationWatermark());
2111 p->SetAllocationWatermark(obj->address() + size_in_bytes);
2112 }
2113
2114 return obj;
2115 }
2116 }
2117
2118 // Free list allocation failed and there is no next page. Fail if we have
2119 // hit the old generation size limit that should cause a garbage
2120 // collection.
2121 if (!Heap::always_allocate() && Heap::OldGenerationAllocationLimitReached()) {
2122 return NULL;
2123 }
2124
2125 // Try to expand the space and allocate in the new next page.
2126 ASSERT(!current_page->next_page()->is_valid());
2127 if (Expand()) {
2128 return AllocateInNextPage(current_page, size_in_bytes);
2129 }
2130
2131 // Finally, fail.
2132 return NULL;
2133 }
2134
2135
2136 // Move to the next page (there is assumed to be one) and allocate there.
2137 // The top of page block is always wasted, because it is too small to hold a
2138 // map.
2139 HeapObject* FixedSpace::AllocateInNextPage(Page* current_page,
2140 int size_in_bytes) {
2141 ASSERT(current_page->next_page()->is_valid());
2142 ASSERT(allocation_info_.top == PageAllocationLimit(current_page));
2143 ASSERT_EQ(object_size_in_bytes_, size_in_bytes);
2144 Page* next_page = current_page->next_page();
2145 next_page->ClearGCFields();
2146 current_page->SetAllocationWatermark(allocation_info_.top);
2147 accounting_stats_.WasteBytes(page_extra_);
2148 SetAllocationInfo(&allocation_info_, next_page);
2149 return AllocateLinearly(&allocation_info_, size_in_bytes);
2150 }
2151
2152
2153 void FixedSpace::DeallocateBlock(Address start,
2154 int size_in_bytes,
2155 bool add_to_freelist) {
2156 // Free-list elements in fixed space are assumed to have a fixed size.
2157 // We break the free block into chunks and add them to the free list
2158 // individually.
2159 int size = object_size_in_bytes();
2160 ASSERT(size_in_bytes % size == 0);
2161 Address end = start + size_in_bytes;
2162 for (Address a = start; a < end; a += size) {
2163 Free(a, add_to_freelist);
2164 }
2165 }
2166
2167
2168 #ifdef DEBUG
2169 void FixedSpace::ReportStatistics() {
2170 int pct = static_cast<int>(Available() * 100 / Capacity());
2171 PrintF(" capacity: %" V8_PTR_PREFIX "d"
2172 ", waste: %" V8_PTR_PREFIX "d"
2173 ", available: %" V8_PTR_PREFIX "d, %%%d\n",
2174 Capacity(), Waste(), Available(), pct);
2175
2176 ClearHistograms();
2177 HeapObjectIterator obj_it(this);
2178 for (HeapObject* obj = obj_it.next(); obj != NULL; obj = obj_it.next())
2179 CollectHistogramInfo(obj);
2180 ReportHistogram(false);
2181 }
2182 #endif
2183
2184
2185 // ----------------------------------------------------------------------------- 1784 // -----------------------------------------------------------------------------
2186 // MapSpace implementation 1785 // MapSpace implementation
2187 1786
2188 void MapSpace::PrepareForMarkCompact(bool will_compact) { 1787 void MapSpace::PrepareForMarkCompact(bool will_compact) {
2189 // Call prepare of the super class. 1788 // Call prepare of the super class.
2190 FixedSpace::PrepareForMarkCompact(will_compact); 1789 FixedSpace::PrepareForMarkCompact(will_compact);
2191 } 1790 }
2192 1791
2193 1792
2194 #ifdef DEBUG 1793 #ifdef DEBUG
(...skipping 317 matching lines...) Expand 10 before | Expand all | Expand 10 after
2512 for (HeapObject* obj = obj_it.next(); obj != NULL; obj = obj_it.next()) { 2111 for (HeapObject* obj = obj_it.next(); obj != NULL; obj = obj_it.next()) {
2513 if (obj->IsCode()) { 2112 if (obj->IsCode()) {
2514 Code* code = Code::cast(obj); 2113 Code* code = Code::cast(obj);
2515 code_kind_statistics[code->kind()] += code->Size(); 2114 code_kind_statistics[code->kind()] += code->Size();
2516 } 2115 }
2517 } 2116 }
2518 } 2117 }
2519 #endif // DEBUG 2118 #endif // DEBUG
2520 2119
2521 } } // namespace v8::internal 2120 } } // namespace v8::internal
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698