| 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 |