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