| Index: src/heap/spaces.cc
|
| diff --git a/src/heap/spaces.cc b/src/heap/spaces.cc
|
| index 81199e72a464b3ed8954aa7ac4abcea742871bda..1a2ff27c2b6826434fbdbc0d6ca0aee9cc5adac7 100644
|
| --- a/src/heap/spaces.cc
|
| +++ b/src/heap/spaces.cc
|
| @@ -1028,6 +1028,10 @@
|
|
|
| intptr_t size = AreaSize();
|
|
|
| + if (anchor_.next_page() == &anchor_) {
|
| + size = SizeOfFirstPage();
|
| + }
|
| +
|
| Page* p = heap()->isolate()->memory_allocator()->AllocatePage(size, this,
|
| executable());
|
| if (p == NULL) return false;
|
| @@ -1037,6 +1041,50 @@
|
| p->InsertAfter(anchor_.prev_page());
|
|
|
| return true;
|
| +}
|
| +
|
| +
|
| +intptr_t PagedSpace::SizeOfFirstPage() {
|
| + // If the snapshot contains a custom script, all size guarantees are off.
|
| + if (Snapshot::EmbedsScript()) return AreaSize();
|
| + // If using an ool constant pool then transfer the constant pool allowance
|
| + // from the code space to the old pointer space.
|
| + static const int constant_pool_delta = FLAG_enable_ool_constant_pool ? 48 : 0;
|
| + int size = 0;
|
| + switch (identity()) {
|
| + case OLD_POINTER_SPACE:
|
| + size = (128 + constant_pool_delta) * kPointerSize * KB;
|
| + break;
|
| + case OLD_DATA_SPACE:
|
| + size = 192 * KB;
|
| + break;
|
| + case MAP_SPACE:
|
| + size = 16 * kPointerSize * KB;
|
| + break;
|
| + case CELL_SPACE:
|
| + size = 16 * kPointerSize * KB;
|
| + break;
|
| + case PROPERTY_CELL_SPACE:
|
| + size = 8 * kPointerSize * KB;
|
| + break;
|
| + case CODE_SPACE: {
|
| + CodeRange* code_range = heap()->isolate()->code_range();
|
| + if (code_range != NULL && code_range->valid()) {
|
| + // When code range exists, code pages are allocated in a special way
|
| + // (from the reserved code range). That part of the code is not yet
|
| + // upgraded to handle small pages.
|
| + size = AreaSize();
|
| + } else {
|
| + size = RoundUp((480 - constant_pool_delta) * KB *
|
| + FullCodeGenerator::kBootCodeSizeMultiplier / 100,
|
| + kPointerSize);
|
| + }
|
| + break;
|
| + }
|
| + default:
|
| + UNREACHABLE();
|
| + }
|
| + return Min(size, AreaSize());
|
| }
|
|
|
|
|
| @@ -2034,6 +2082,79 @@
|
| // -----------------------------------------------------------------------------
|
| // Free lists for old object spaces implementation
|
|
|
| +void FreeListNode::set_size(Heap* heap, int size_in_bytes) {
|
| + DCHECK(size_in_bytes > 0);
|
| + DCHECK(IsAligned(size_in_bytes, kPointerSize));
|
| +
|
| + // We write a map and possibly size information to the block. If the block
|
| + // is big enough to be a FreeSpace with at least one extra word (the next
|
| + // pointer), we set its map to be the free space map and its size to an
|
| + // appropriate array length for the desired size from HeapObject::Size().
|
| + // If the block is too small (eg, one or two words), to hold both a size
|
| + // field and a next pointer, we give it a filler map that gives it the
|
| + // correct size.
|
| + if (size_in_bytes > FreeSpace::kHeaderSize) {
|
| + // Can't use FreeSpace::cast because it fails during deserialization.
|
| + // We have to set the size first with a release store before we store
|
| + // the map because a concurrent store buffer scan on scavenge must not
|
| + // observe a map with an invalid size.
|
| + FreeSpace* this_as_free_space = reinterpret_cast<FreeSpace*>(this);
|
| + this_as_free_space->nobarrier_set_size(size_in_bytes);
|
| + synchronized_set_map_no_write_barrier(heap->raw_unchecked_free_space_map());
|
| + } else if (size_in_bytes == kPointerSize) {
|
| + set_map_no_write_barrier(heap->raw_unchecked_one_pointer_filler_map());
|
| + } else if (size_in_bytes == 2 * kPointerSize) {
|
| + set_map_no_write_barrier(heap->raw_unchecked_two_pointer_filler_map());
|
| + } else {
|
| + UNREACHABLE();
|
| + }
|
| + // We would like to DCHECK(Size() == size_in_bytes) but this would fail during
|
| + // deserialization because the free space map is not done yet.
|
| +}
|
| +
|
| +
|
| +FreeListNode* FreeListNode::next() {
|
| + DCHECK(IsFreeListNode(this));
|
| + if (map() == GetHeap()->raw_unchecked_free_space_map()) {
|
| + DCHECK(map() == NULL || Size() >= kNextOffset + kPointerSize);
|
| + return reinterpret_cast<FreeListNode*>(
|
| + Memory::Address_at(address() + kNextOffset));
|
| + } else {
|
| + return reinterpret_cast<FreeListNode*>(
|
| + Memory::Address_at(address() + kPointerSize));
|
| + }
|
| +}
|
| +
|
| +
|
| +FreeListNode** FreeListNode::next_address() {
|
| + DCHECK(IsFreeListNode(this));
|
| + if (map() == GetHeap()->raw_unchecked_free_space_map()) {
|
| + DCHECK(Size() >= kNextOffset + kPointerSize);
|
| + return reinterpret_cast<FreeListNode**>(address() + kNextOffset);
|
| + } else {
|
| + return reinterpret_cast<FreeListNode**>(address() + kPointerSize);
|
| + }
|
| +}
|
| +
|
| +
|
| +void FreeListNode::set_next(FreeListNode* next) {
|
| + DCHECK(IsFreeListNode(this));
|
| + // While we are booting the VM the free space map will actually be null. So
|
| + // we have to make sure that we don't try to use it for anything at that
|
| + // stage.
|
| + if (map() == GetHeap()->raw_unchecked_free_space_map()) {
|
| + DCHECK(map() == NULL || Size() >= kNextOffset + kPointerSize);
|
| + base::NoBarrier_Store(
|
| + reinterpret_cast<base::AtomicWord*>(address() + kNextOffset),
|
| + reinterpret_cast<base::AtomicWord>(next));
|
| + } else {
|
| + base::NoBarrier_Store(
|
| + reinterpret_cast<base::AtomicWord*>(address() + kPointerSize),
|
| + reinterpret_cast<base::AtomicWord>(next));
|
| + }
|
| +}
|
| +
|
| +
|
| intptr_t FreeListCategory::Concatenate(FreeListCategory* category) {
|
| intptr_t free_bytes = 0;
|
| if (category->top() != NULL) {
|
| @@ -2067,11 +2188,11 @@
|
|
|
| intptr_t FreeListCategory::EvictFreeListItemsInList(Page* p) {
|
| int sum = 0;
|
| - FreeSpace* t = top();
|
| - FreeSpace** n = &t;
|
| + FreeListNode* t = top();
|
| + FreeListNode** n = &t;
|
| while (*n != NULL) {
|
| if (Page::FromAddress((*n)->address()) == p) {
|
| - FreeSpace* free_space = *n;
|
| + FreeSpace* free_space = reinterpret_cast<FreeSpace*>(*n);
|
| sum += free_space->Size();
|
| *n = (*n)->next();
|
| } else {
|
| @@ -2088,7 +2209,7 @@
|
|
|
|
|
| bool FreeListCategory::ContainsPageFreeListItemsInList(Page* p) {
|
| - FreeSpace* node = top();
|
| + FreeListNode* node = top();
|
| while (node != NULL) {
|
| if (Page::FromAddress(node->address()) == p) return true;
|
| node = node->next();
|
| @@ -2097,20 +2218,20 @@
|
| }
|
|
|
|
|
| -FreeSpace* FreeListCategory::PickNodeFromList(int* node_size) {
|
| - FreeSpace* node = top();
|
| +FreeListNode* FreeListCategory::PickNodeFromList(int* node_size) {
|
| + FreeListNode* node = top();
|
|
|
| if (node == NULL) return NULL;
|
|
|
| while (node != NULL &&
|
| Page::FromAddress(node->address())->IsEvacuationCandidate()) {
|
| - available_ -= node->Size();
|
| + available_ -= reinterpret_cast<FreeSpace*>(node)->Size();
|
| node = node->next();
|
| }
|
|
|
| if (node != NULL) {
|
| set_top(node->next());
|
| - *node_size = node->Size();
|
| + *node_size = reinterpret_cast<FreeSpace*>(node)->Size();
|
| available_ -= *node_size;
|
| } else {
|
| set_top(NULL);
|
| @@ -2124,9 +2245,9 @@
|
| }
|
|
|
|
|
| -FreeSpace* FreeListCategory::PickNodeFromList(int size_in_bytes,
|
| - int* node_size) {
|
| - FreeSpace* node = PickNodeFromList(node_size);
|
| +FreeListNode* FreeListCategory::PickNodeFromList(int size_in_bytes,
|
| + int* node_size) {
|
| + FreeListNode* node = PickNodeFromList(node_size);
|
| if (node != NULL && *node_size < size_in_bytes) {
|
| Free(node, *node_size);
|
| *node_size = 0;
|
| @@ -2136,19 +2257,18 @@
|
| }
|
|
|
|
|
| -void FreeListCategory::Free(FreeSpace* free_space, int size_in_bytes) {
|
| - DCHECK_LE(FreeList::kSmallListMin, size_in_bytes);
|
| - free_space->set_next(top());
|
| - set_top(free_space);
|
| +void FreeListCategory::Free(FreeListNode* node, int size_in_bytes) {
|
| + node->set_next(top());
|
| + set_top(node);
|
| if (end_ == NULL) {
|
| - end_ = free_space;
|
| + end_ = node;
|
| }
|
| available_ += size_in_bytes;
|
| }
|
|
|
|
|
| void FreeListCategory::RepairFreeList(Heap* heap) {
|
| - FreeSpace* n = top();
|
| + FreeListNode* n = top();
|
| while (n != NULL) {
|
| Map** map_location = reinterpret_cast<Map**>(n->address());
|
| if (*map_location == NULL) {
|
| @@ -2187,8 +2307,8 @@
|
| int FreeList::Free(Address start, int size_in_bytes) {
|
| if (size_in_bytes == 0) return 0;
|
|
|
| - heap_->CreateFillerObjectAt(start, size_in_bytes);
|
| -
|
| + FreeListNode* node = FreeListNode::FromAddress(start);
|
| + node->set_size(heap_, size_in_bytes);
|
| Page* page = Page::FromAddress(start);
|
|
|
| // Early return to drop too-small blocks on the floor.
|
| @@ -2197,20 +2317,19 @@
|
| return size_in_bytes;
|
| }
|
|
|
| - FreeSpace* free_space = FreeSpace::cast(HeapObject::FromAddress(start));
|
| // Insert other blocks at the head of a free list of the appropriate
|
| // magnitude.
|
| if (size_in_bytes <= kSmallListMax) {
|
| - small_list_.Free(free_space, size_in_bytes);
|
| + small_list_.Free(node, size_in_bytes);
|
| page->add_available_in_small_free_list(size_in_bytes);
|
| } else if (size_in_bytes <= kMediumListMax) {
|
| - medium_list_.Free(free_space, size_in_bytes);
|
| + medium_list_.Free(node, size_in_bytes);
|
| page->add_available_in_medium_free_list(size_in_bytes);
|
| } else if (size_in_bytes <= kLargeListMax) {
|
| - large_list_.Free(free_space, size_in_bytes);
|
| + large_list_.Free(node, size_in_bytes);
|
| page->add_available_in_large_free_list(size_in_bytes);
|
| } else {
|
| - huge_list_.Free(free_space, size_in_bytes);
|
| + huge_list_.Free(node, size_in_bytes);
|
| page->add_available_in_huge_free_list(size_in_bytes);
|
| }
|
|
|
| @@ -2219,8 +2338,8 @@
|
| }
|
|
|
|
|
| -FreeSpace* FreeList::FindNodeFor(int size_in_bytes, int* node_size) {
|
| - FreeSpace* node = NULL;
|
| +FreeListNode* FreeList::FindNodeFor(int size_in_bytes, int* node_size) {
|
| + FreeListNode* node = NULL;
|
| Page* page = NULL;
|
|
|
| if (size_in_bytes <= kSmallAllocationMax) {
|
| @@ -2257,13 +2376,13 @@
|
| }
|
|
|
| int huge_list_available = huge_list_.available();
|
| - FreeSpace* top_node = huge_list_.top();
|
| - for (FreeSpace** cur = &top_node; *cur != NULL;
|
| + FreeListNode* top_node = huge_list_.top();
|
| + for (FreeListNode** cur = &top_node; *cur != NULL;
|
| cur = (*cur)->next_address()) {
|
| - FreeSpace* cur_node = *cur;
|
| + FreeListNode* cur_node = *cur;
|
| while (cur_node != NULL &&
|
| Page::FromAddress(cur_node->address())->IsEvacuationCandidate()) {
|
| - int size = cur_node->Size();
|
| + int size = reinterpret_cast<FreeSpace*>(cur_node)->Size();
|
| huge_list_available -= size;
|
| page = Page::FromAddress(cur_node->address());
|
| page->add_available_in_huge_free_list(-size);
|
| @@ -2276,7 +2395,9 @@
|
| break;
|
| }
|
|
|
| - int size = cur_node->Size();
|
| + DCHECK((*cur)->map() == heap_->raw_unchecked_free_space_map());
|
| + FreeSpace* cur_as_free_space = reinterpret_cast<FreeSpace*>(*cur);
|
| + int size = cur_as_free_space->Size();
|
| if (size >= size_in_bytes) {
|
| // Large enough node found. Unlink it from the list.
|
| node = *cur;
|
| @@ -2349,7 +2470,7 @@
|
| old_linear_size);
|
|
|
| int new_node_size = 0;
|
| - FreeSpace* new_node = FindNodeFor(size_in_bytes, &new_node_size);
|
| + FreeListNode* new_node = FindNodeFor(size_in_bytes, &new_node_size);
|
| if (new_node == NULL) {
|
| owner_->SetTopAndLimit(NULL, NULL);
|
| return NULL;
|
| @@ -2443,10 +2564,11 @@
|
| #ifdef DEBUG
|
| intptr_t FreeListCategory::SumFreeList() {
|
| intptr_t sum = 0;
|
| - FreeSpace* cur = top();
|
| + FreeListNode* cur = top();
|
| while (cur != NULL) {
|
| DCHECK(cur->map() == cur->GetHeap()->raw_unchecked_free_space_map());
|
| - sum += cur->nobarrier_size();
|
| + FreeSpace* cur_as_free_space = reinterpret_cast<FreeSpace*>(cur);
|
| + sum += cur_as_free_space->nobarrier_size();
|
| cur = cur->next();
|
| }
|
| return sum;
|
| @@ -2458,7 +2580,7 @@
|
|
|
| int FreeListCategory::FreeListLength() {
|
| int length = 0;
|
| - FreeSpace* cur = top();
|
| + FreeListNode* cur = top();
|
| while (cur != NULL) {
|
| length++;
|
| cur = cur->next();
|
| @@ -2519,9 +2641,7 @@
|
| // on the heap. If there was already a free list then the elements on it
|
| // were created with the wrong FreeSpaceMap (normally NULL), so we need to
|
| // fix them.
|
| -void PagedSpace::RepairFreeListsAfterDeserialization() {
|
| - free_list_.RepairLists(heap());
|
| -}
|
| +void PagedSpace::RepairFreeListsAfterBoot() { free_list_.RepairLists(heap()); }
|
|
|
|
|
| void PagedSpace::EvictEvacuationCandidatesFromFreeLists() {
|
|
|