OLD | NEW |
1 // Copyright 2011 the V8 project authors. All rights reserved. | 1 // Copyright 2011 the V8 project authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "src/heap/spaces.h" | 5 #include "src/heap/spaces.h" |
6 | 6 |
7 #include "src/base/bits.h" | 7 #include "src/base/bits.h" |
8 #include "src/base/platform/platform.h" | 8 #include "src/base/platform/platform.h" |
9 #include "src/full-codegen/full-codegen.h" | 9 #include "src/full-codegen/full-codegen.h" |
10 #include "src/heap/slot-set.h" | 10 #include "src/heap/slot-set.h" |
(...skipping 470 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
481 chunk->slots_buffer_ = nullptr; | 481 chunk->slots_buffer_ = nullptr; |
482 chunk->old_to_new_slots_ = nullptr; | 482 chunk->old_to_new_slots_ = nullptr; |
483 chunk->old_to_old_slots_ = nullptr; | 483 chunk->old_to_old_slots_ = nullptr; |
484 chunk->skip_list_ = nullptr; | 484 chunk->skip_list_ = nullptr; |
485 chunk->write_barrier_counter_ = kWriteBarrierCounterGranularity; | 485 chunk->write_barrier_counter_ = kWriteBarrierCounterGranularity; |
486 chunk->progress_bar_ = 0; | 486 chunk->progress_bar_ = 0; |
487 chunk->high_water_mark_.SetValue(static_cast<intptr_t>(area_start - base)); | 487 chunk->high_water_mark_.SetValue(static_cast<intptr_t>(area_start - base)); |
488 chunk->concurrent_sweeping_state().SetValue(kSweepingDone); | 488 chunk->concurrent_sweeping_state().SetValue(kSweepingDone); |
489 chunk->parallel_compaction_state().SetValue(kCompactingDone); | 489 chunk->parallel_compaction_state().SetValue(kCompactingDone); |
490 chunk->mutex_ = nullptr; | 490 chunk->mutex_ = nullptr; |
491 chunk->available_in_small_free_list_ = 0; | 491 chunk->available_in_free_list_ = 0; |
492 chunk->available_in_medium_free_list_ = 0; | 492 chunk->wasted_memory_ = 0; |
493 chunk->available_in_large_free_list_ = 0; | |
494 chunk->available_in_huge_free_list_ = 0; | |
495 chunk->non_available_small_blocks_ = 0; | |
496 chunk->ResetLiveBytes(); | 493 chunk->ResetLiveBytes(); |
497 Bitmap::Clear(chunk); | 494 Bitmap::Clear(chunk); |
498 chunk->set_next_chunk(nullptr); | 495 chunk->set_next_chunk(nullptr); |
499 chunk->set_prev_chunk(nullptr); | 496 chunk->set_prev_chunk(nullptr); |
500 | 497 |
501 DCHECK(OFFSET_OF(MemoryChunk, flags_) == kFlagsOffset); | 498 DCHECK(OFFSET_OF(MemoryChunk, flags_) == kFlagsOffset); |
502 DCHECK(OFFSET_OF(MemoryChunk, live_byte_count_) == kLiveBytesOffset); | 499 DCHECK(OFFSET_OF(MemoryChunk, live_byte_count_) == kLiveBytesOffset); |
503 | 500 |
504 if (executable == EXECUTABLE) { | 501 if (executable == EXECUTABLE) { |
505 chunk->SetFlag(IS_EXECUTABLE); | 502 chunk->SetFlag(IS_EXECUTABLE); |
(...skipping 203 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
709 ObjectSpace space = static_cast<ObjectSpace>(1 << owner->identity()); | 706 ObjectSpace space = static_cast<ObjectSpace>(1 << owner->identity()); |
710 PerformAllocationCallback(space, kAllocationActionAllocate, chunk_size); | 707 PerformAllocationCallback(space, kAllocationActionAllocate, chunk_size); |
711 } | 708 } |
712 | 709 |
713 return MemoryChunk::Initialize(heap, base, chunk_size, area_start, area_end, | 710 return MemoryChunk::Initialize(heap, base, chunk_size, area_start, area_end, |
714 executable, owner, &reservation); | 711 executable, owner, &reservation); |
715 } | 712 } |
716 | 713 |
717 | 714 |
718 void Page::ResetFreeListStatistics() { | 715 void Page::ResetFreeListStatistics() { |
719 non_available_small_blocks_ = 0; | 716 wasted_memory_ = 0; |
720 available_in_small_free_list_ = 0; | 717 available_in_free_list_ = 0; |
721 available_in_medium_free_list_ = 0; | |
722 available_in_large_free_list_ = 0; | |
723 available_in_huge_free_list_ = 0; | |
724 } | 718 } |
725 | 719 |
726 | 720 |
727 Page* MemoryAllocator::AllocatePage(intptr_t size, PagedSpace* owner, | 721 Page* MemoryAllocator::AllocatePage(intptr_t size, PagedSpace* owner, |
728 Executability executable) { | 722 Executability executable) { |
729 MemoryChunk* chunk = AllocateChunk(size, size, executable, owner); | 723 MemoryChunk* chunk = AllocateChunk(size, size, executable, owner); |
730 if (chunk == NULL) return NULL; | 724 if (chunk == NULL) return NULL; |
731 return Page::Initialize(isolate_->heap(), chunk, executable, owner); | 725 return Page::Initialize(isolate_->heap(), chunk, executable, owner); |
732 } | 726 } |
733 | 727 |
(...skipping 1467 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2201 if (cur_node == end()) { | 2195 if (cur_node == end()) { |
2202 set_end(prev_node); | 2196 set_end(prev_node); |
2203 } | 2197 } |
2204 if (prev_node != nullptr) { | 2198 if (prev_node != nullptr) { |
2205 prev_node->set_next(cur_node->next()); | 2199 prev_node->set_next(cur_node->next()); |
2206 } | 2200 } |
2207 continue; | 2201 continue; |
2208 } | 2202 } |
2209 prev_node = cur_node; | 2203 prev_node = cur_node; |
2210 } | 2204 } |
2211 DCHECK_EQ(p->available_in_free_list(type_), sum); | 2205 p->add_available_in_free_list(-sum); |
2212 p->add_available_in_free_list(type_, -sum); | |
2213 available_ -= sum; | 2206 available_ -= sum; |
2214 return sum; | 2207 return sum; |
2215 } | 2208 } |
2216 | 2209 |
2217 | 2210 |
2218 bool FreeListCategory::ContainsPageFreeListItemsInList(Page* p) { | 2211 bool FreeListCategory::ContainsPageFreeListItemsInList(Page* p) { |
2219 FreeSpace* node = top(); | 2212 FreeSpace* node = top(); |
2220 while (node != NULL) { | 2213 while (node != NULL) { |
2221 if (Page::FromAddress(node->address()) == p) return true; | 2214 if (Page::FromAddress(node->address()) == p) return true; |
2222 node = node->next(); | 2215 node = node->next(); |
2223 } | 2216 } |
2224 return false; | 2217 return false; |
2225 } | 2218 } |
2226 | 2219 |
2227 | 2220 |
2228 FreeSpace* FreeListCategory::PickNodeFromList(int* node_size) { | 2221 FreeSpace* FreeListCategory::PickNodeFromList(int* node_size) { |
2229 FreeSpace* node = top(); | 2222 FreeSpace* node = top(); |
2230 if (node == nullptr) return nullptr; | 2223 if (node == nullptr) return nullptr; |
2231 | 2224 |
2232 Page* page = Page::FromAddress(node->address()); | 2225 Page* page = Page::FromAddress(node->address()); |
2233 while ((node != nullptr) && !page->CanAllocate()) { | 2226 while ((node != nullptr) && !page->CanAllocate()) { |
2234 available_ -= node->size(); | 2227 available_ -= node->size(); |
2235 page->add_available_in_free_list(type_, -(node->Size())); | 2228 page->add_available_in_free_list(-(node->Size())); |
2236 node = node->next(); | 2229 node = node->next(); |
2237 } | 2230 } |
2238 | 2231 |
2239 if (node != nullptr) { | 2232 if (node != nullptr) { |
2240 set_top(node->next()); | 2233 set_top(node->next()); |
2241 *node_size = node->Size(); | 2234 *node_size = node->Size(); |
2242 available_ -= *node_size; | 2235 available_ -= *node_size; |
2243 } else { | 2236 } else { |
2244 set_top(nullptr); | 2237 set_top(nullptr); |
2245 } | 2238 } |
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2280 set_top(cur_node->next()); | 2273 set_top(cur_node->next()); |
2281 } | 2274 } |
2282 if (cur_node == end()) { | 2275 if (cur_node == end()) { |
2283 set_end(prev_non_evac_node); | 2276 set_end(prev_non_evac_node); |
2284 } | 2277 } |
2285 if (prev_non_evac_node != nullptr) { | 2278 if (prev_non_evac_node != nullptr) { |
2286 prev_non_evac_node->set_next(cur_node->next()); | 2279 prev_non_evac_node->set_next(cur_node->next()); |
2287 } | 2280 } |
2288 // For evacuation candidates we continue. | 2281 // For evacuation candidates we continue. |
2289 if (!page_for_node->CanAllocate()) { | 2282 if (!page_for_node->CanAllocate()) { |
2290 page_for_node->add_available_in_free_list(type_, -size); | 2283 page_for_node->add_available_in_free_list(-size); |
2291 continue; | 2284 continue; |
2292 } | 2285 } |
2293 // Otherwise we have a large enough node and can return. | 2286 // Otherwise we have a large enough node and can return. |
2294 *node_size = size; | 2287 *node_size = size; |
2295 return cur_node; | 2288 return cur_node; |
2296 } | 2289 } |
2297 | 2290 |
2298 prev_non_evac_node = cur_node; | 2291 prev_non_evac_node = cur_node; |
2299 } | 2292 } |
2300 return nullptr; | 2293 return nullptr; |
(...skipping 67 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2368 | 2361 |
2369 int FreeList::Free(Address start, int size_in_bytes) { | 2362 int FreeList::Free(Address start, int size_in_bytes) { |
2370 if (size_in_bytes == 0) return 0; | 2363 if (size_in_bytes == 0) return 0; |
2371 | 2364 |
2372 owner()->heap()->CreateFillerObjectAt(start, size_in_bytes); | 2365 owner()->heap()->CreateFillerObjectAt(start, size_in_bytes); |
2373 | 2366 |
2374 Page* page = Page::FromAddress(start); | 2367 Page* page = Page::FromAddress(start); |
2375 | 2368 |
2376 // Early return to drop too-small blocks on the floor. | 2369 // Early return to drop too-small blocks on the floor. |
2377 if (size_in_bytes <= kSmallListMin) { | 2370 if (size_in_bytes <= kSmallListMin) { |
2378 page->add_non_available_small_blocks(size_in_bytes); | 2371 page->add_wasted_memory(size_in_bytes); |
2379 wasted_bytes_ += size_in_bytes; | 2372 wasted_bytes_ += size_in_bytes; |
2380 return size_in_bytes; | 2373 return size_in_bytes; |
2381 } | 2374 } |
2382 | 2375 |
2383 FreeSpace* free_space = FreeSpace::cast(HeapObject::FromAddress(start)); | 2376 FreeSpace* free_space = FreeSpace::cast(HeapObject::FromAddress(start)); |
2384 // Insert other blocks at the head of a free list of the appropriate | 2377 // Insert other blocks at the head of a free list of the appropriate |
2385 // magnitude. | 2378 // magnitude. |
2386 if (size_in_bytes <= kSmallListMax) { | 2379 FreeListCategoryType type = SelectFreeListCategoryType(size_in_bytes); |
2387 category_[kSmall].Free(free_space, size_in_bytes); | 2380 category_[type].Free(free_space, size_in_bytes); |
2388 page->add_available_in_small_free_list(size_in_bytes); | 2381 page->add_available_in_free_list(size_in_bytes); |
2389 } else if (size_in_bytes <= kMediumListMax) { | |
2390 category_[kMedium].Free(free_space, size_in_bytes); | |
2391 page->add_available_in_medium_free_list(size_in_bytes); | |
2392 } else if (size_in_bytes <= kLargeListMax) { | |
2393 category_[kLarge].Free(free_space, size_in_bytes); | |
2394 page->add_available_in_large_free_list(size_in_bytes); | |
2395 } else { | |
2396 category_[kHuge].Free(free_space, size_in_bytes); | |
2397 page->add_available_in_huge_free_list(size_in_bytes); | |
2398 } | |
2399 | 2382 |
2400 DCHECK(IsVeryLong() || Available() == SumFreeLists()); | 2383 DCHECK(IsVeryLong() || Available() == SumFreeLists()); |
2401 return 0; | 2384 return 0; |
2402 } | 2385 } |
2403 | 2386 |
2404 | 2387 |
2405 FreeSpace* FreeList::FindNodeIn(FreeListCategoryType category, int* node_size) { | 2388 FreeSpace* FreeList::FindNodeIn(FreeListCategoryType category, int* node_size) { |
2406 FreeSpace* node = GetFreeListCategory(category)->PickNodeFromList(node_size); | 2389 FreeSpace* node = GetFreeListCategory(category)->PickNodeFromList(node_size); |
2407 if (node != nullptr) { | 2390 if (node != nullptr) { |
2408 Page::FromAddress(node->address()) | 2391 Page::FromAddress(node->address()) |
2409 ->add_available_in_free_list(category, -(*node_size)); | 2392 ->add_available_in_free_list(-(*node_size)); |
2410 DCHECK(IsVeryLong() || Available() == SumFreeLists()); | 2393 DCHECK(IsVeryLong() || Available() == SumFreeLists()); |
2411 } | 2394 } |
2412 return node; | 2395 return node; |
2413 } | 2396 } |
2414 | 2397 |
2415 | 2398 |
2416 FreeSpace* FreeList::FindNodeFor(int size_in_bytes, int* node_size) { | 2399 FreeSpace* FreeList::FindNodeFor(int size_in_bytes, int* node_size) { |
2417 FreeSpace* node = nullptr; | 2400 FreeSpace* node = nullptr; |
2418 Page* page = nullptr; | 2401 Page* page = nullptr; |
2419 | 2402 |
2420 if (size_in_bytes <= kSmallAllocationMax) { | 2403 // First try the allocation fast path: try to allocate the minimum element |
2421 node = FindNodeIn(kSmall, node_size); | 2404 // size of a free list category. This operation is constant time. |
| 2405 FreeListCategoryType type = |
| 2406 SelectFastAllocationFreeListCategoryType(size_in_bytes); |
| 2407 for (int i = type; i < kHuge; i++) { |
| 2408 node = FindNodeIn(static_cast<FreeListCategoryType>(i), node_size); |
2422 if (node != nullptr) return node; | 2409 if (node != nullptr) return node; |
2423 } | 2410 } |
2424 | 2411 |
2425 if (size_in_bytes <= kMediumAllocationMax) { | 2412 // Next search the huge list for free list nodes. This takes linear time in |
2426 node = FindNodeIn(kMedium, node_size); | 2413 // the number of huge elements. |
2427 if (node != nullptr) return node; | |
2428 } | |
2429 | |
2430 if (size_in_bytes <= kLargeAllocationMax) { | |
2431 node = FindNodeIn(kLarge, node_size); | |
2432 if (node != nullptr) return node; | |
2433 } | |
2434 | |
2435 node = category_[kHuge].SearchForNodeInList(size_in_bytes, node_size); | 2414 node = category_[kHuge].SearchForNodeInList(size_in_bytes, node_size); |
2436 if (node != nullptr) { | 2415 if (node != nullptr) { |
2437 page = Page::FromAddress(node->address()); | 2416 page = Page::FromAddress(node->address()); |
2438 page->add_available_in_large_free_list(-(*node_size)); | 2417 page->add_available_in_free_list(-(*node_size)); |
2439 DCHECK(IsVeryLong() || Available() == SumFreeLists()); | 2418 DCHECK(IsVeryLong() || Available() == SumFreeLists()); |
2440 return node; | 2419 return node; |
2441 } | 2420 } |
2442 | 2421 |
2443 if (size_in_bytes <= kSmallListMax) { | 2422 // We need a huge block of memory, but we didn't find anything in the huge |
2444 node = category_[kSmall].PickNodeFromList(size_in_bytes, node_size); | 2423 // list. |
2445 if (node != NULL) { | 2424 if (type == kHuge) return nullptr; |
2446 DCHECK(size_in_bytes <= *node_size); | 2425 |
2447 page = Page::FromAddress(node->address()); | 2426 // Now search the best fitting free list for a node that has at least the |
2448 page->add_available_in_small_free_list(-(*node_size)); | 2427 // requested size. This takes linear time in the number of elements. |
2449 } | 2428 type = SelectFreeListCategoryType(size_in_bytes); |
2450 } else if (size_in_bytes <= kMediumListMax) { | 2429 node = category_[type].PickNodeFromList(size_in_bytes, node_size); |
2451 node = category_[kMedium].PickNodeFromList(size_in_bytes, node_size); | 2430 if (node != nullptr) { |
2452 if (node != NULL) { | 2431 DCHECK(size_in_bytes <= *node_size); |
2453 DCHECK(size_in_bytes <= *node_size); | 2432 page = Page::FromAddress(node->address()); |
2454 page = Page::FromAddress(node->address()); | 2433 page->add_available_in_free_list(-(*node_size)); |
2455 page->add_available_in_medium_free_list(-(*node_size)); | |
2456 } | |
2457 } else if (size_in_bytes <= kLargeListMax) { | |
2458 node = category_[kLarge].PickNodeFromList(size_in_bytes, node_size); | |
2459 if (node != NULL) { | |
2460 DCHECK(size_in_bytes <= *node_size); | |
2461 page = Page::FromAddress(node->address()); | |
2462 page->add_available_in_large_free_list(-(*node_size)); | |
2463 } | |
2464 } | 2434 } |
2465 | 2435 |
2466 DCHECK(IsVeryLong() || Available() == SumFreeLists()); | 2436 DCHECK(IsVeryLong() || Available() == SumFreeLists()); |
2467 return node; | 2437 return node; |
2468 } | 2438 } |
2469 | 2439 |
2470 | 2440 |
2471 FreeSpace* FreeList::TryRemoveMemory(intptr_t hint_size_in_bytes) { | 2441 FreeSpace* FreeList::TryRemoveMemory(intptr_t hint_size_in_bytes) { |
2472 hint_size_in_bytes = RoundDown(hint_size_in_bytes, kPointerSize); | 2442 hint_size_in_bytes = RoundDown(hint_size_in_bytes, kPointerSize); |
2473 base::LockGuard<base::Mutex> guard(&mutex_); | 2443 base::LockGuard<base::Mutex> guard(&mutex_); |
(...skipping 206 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
2680 // on the heap. If there was already a free list then the elements on it | 2650 // on the heap. If there was already a free list then the elements on it |
2681 // were created with the wrong FreeSpaceMap (normally NULL), so we need to | 2651 // were created with the wrong FreeSpaceMap (normally NULL), so we need to |
2682 // fix them. | 2652 // fix them. |
2683 void PagedSpace::RepairFreeListsAfterDeserialization() { | 2653 void PagedSpace::RepairFreeListsAfterDeserialization() { |
2684 free_list_.RepairLists(heap()); | 2654 free_list_.RepairLists(heap()); |
2685 // Each page may have a small free space that is not tracked by a free list. | 2655 // Each page may have a small free space that is not tracked by a free list. |
2686 // Update the maps for those free space objects. | 2656 // Update the maps for those free space objects. |
2687 PageIterator iterator(this); | 2657 PageIterator iterator(this); |
2688 while (iterator.has_next()) { | 2658 while (iterator.has_next()) { |
2689 Page* page = iterator.next(); | 2659 Page* page = iterator.next(); |
2690 int size = static_cast<int>(page->non_available_small_blocks()); | 2660 int size = static_cast<int>(page->wasted_memory()); |
2691 if (size == 0) continue; | 2661 if (size == 0) continue; |
2692 Address address = page->OffsetToAddress(Page::kPageSize - size); | 2662 Address address = page->OffsetToAddress(Page::kPageSize - size); |
2693 heap()->CreateFillerObjectAt(address, size); | 2663 heap()->CreateFillerObjectAt(address, size); |
2694 } | 2664 } |
2695 } | 2665 } |
2696 | 2666 |
2697 | 2667 |
2698 void PagedSpace::EvictEvacuationCandidatesFromLinearAllocationArea() { | 2668 void PagedSpace::EvictEvacuationCandidatesFromLinearAllocationArea() { |
2699 if (allocation_info_.top() >= allocation_info_.limit()) return; | 2669 if (allocation_info_.top() >= allocation_info_.limit()) return; |
2700 | 2670 |
(...skipping 559 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
3260 object->ShortPrint(); | 3230 object->ShortPrint(); |
3261 PrintF("\n"); | 3231 PrintF("\n"); |
3262 } | 3232 } |
3263 printf(" --------------------------------------\n"); | 3233 printf(" --------------------------------------\n"); |
3264 printf(" Marked: %x, LiveCount: %x\n", mark_size, LiveBytes()); | 3234 printf(" Marked: %x, LiveCount: %x\n", mark_size, LiveBytes()); |
3265 } | 3235 } |
3266 | 3236 |
3267 #endif // DEBUG | 3237 #endif // DEBUG |
3268 } // namespace internal | 3238 } // namespace internal |
3269 } // namespace v8 | 3239 } // namespace v8 |
OLD | NEW |