| OLD | NEW |
| 1 // Copyright 2011 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 |
| (...skipping 2197 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2208 } else { | 2208 } else { |
| 2209 huge_list_.Free(node, size_in_bytes); | 2209 huge_list_.Free(node, size_in_bytes); |
| 2210 page->add_available_in_huge_free_list(size_in_bytes); | 2210 page->add_available_in_huge_free_list(size_in_bytes); |
| 2211 } | 2211 } |
| 2212 | 2212 |
| 2213 ASSERT(IsVeryLong() || available() == SumFreeLists()); | 2213 ASSERT(IsVeryLong() || available() == SumFreeLists()); |
| 2214 return 0; | 2214 return 0; |
| 2215 } | 2215 } |
| 2216 | 2216 |
| 2217 | 2217 |
| 2218 FreeListNode* FreeList::FindNodeFor(int size_in_bytes, int* node_size) { | 2218 FreeListNode* FreeList::FindNodeInHugeList(int size_in_bytes, int* node_size) { |
| 2219 FreeListNode* node = NULL; | 2219 FreeListNode* node = NULL; |
| 2220 Page* page = NULL; | |
| 2221 | |
| 2222 if (size_in_bytes <= kSmallAllocationMax) { | |
| 2223 node = small_list_.PickNodeFromList(node_size); | |
| 2224 if (node != NULL) { | |
| 2225 page = Page::FromAddress(node->address()); | |
| 2226 page->add_available_in_small_free_list(-(*node_size)); | |
| 2227 return node; | |
| 2228 } | |
| 2229 } | |
| 2230 | |
| 2231 if (size_in_bytes <= kMediumAllocationMax) { | |
| 2232 node = medium_list_.PickNodeFromList(node_size); | |
| 2233 if (node != NULL) { | |
| 2234 page = Page::FromAddress(node->address()); | |
| 2235 page->add_available_in_medium_free_list(-(*node_size)); | |
| 2236 return node; | |
| 2237 } | |
| 2238 } | |
| 2239 | |
| 2240 if (size_in_bytes <= kLargeAllocationMax) { | |
| 2241 node = large_list_.PickNodeFromList(node_size); | |
| 2242 if (node != NULL) { | |
| 2243 page = Page::FromAddress(node->address()); | |
| 2244 page->add_available_in_large_free_list(-(*node_size)); | |
| 2245 return node; | |
| 2246 } | |
| 2247 } | |
| 2248 | 2220 |
| 2249 int huge_list_available = huge_list_.available(); | 2221 int huge_list_available = huge_list_.available(); |
| 2250 for (FreeListNode** cur = huge_list_.GetTopAddress(); | 2222 for (FreeListNode** cur = huge_list_.GetTopAddress(); |
| 2251 *cur != NULL; | 2223 *cur != NULL; |
| 2252 cur = (*cur)->next_address()) { | 2224 cur = (*cur)->next_address()) { |
| 2253 FreeListNode* cur_node = *cur; | 2225 FreeListNode* cur_node = *cur; |
| 2254 while (cur_node != NULL && | 2226 while (cur_node != NULL && |
| 2255 Page::FromAddress(cur_node->address())->IsEvacuationCandidate()) { | 2227 Page::FromAddress(cur_node->address())->IsEvacuationCandidate()) { |
| 2256 int size = reinterpret_cast<FreeSpace*>(cur_node)->Size(); | 2228 int size = reinterpret_cast<FreeSpace*>(cur_node)->Size(); |
| 2257 huge_list_available -= size; | 2229 huge_list_available -= size; |
| 2258 page = Page::FromAddress(cur_node->address()); | 2230 Page* page = Page::FromAddress(cur_node->address()); |
| 2259 page->add_available_in_huge_free_list(-size); | 2231 page->add_available_in_huge_free_list(-size); |
| 2260 cur_node = cur_node->next(); | 2232 cur_node = cur_node->next(); |
| 2261 } | 2233 } |
| 2262 | 2234 |
| 2263 *cur = cur_node; | 2235 *cur = cur_node; |
| 2264 if (cur_node == NULL) { | 2236 if (cur_node == NULL) { |
| 2265 huge_list_.set_end(NULL); | 2237 huge_list_.set_end(NULL); |
| 2266 break; | 2238 break; |
| 2267 } | 2239 } |
| 2268 | 2240 |
| 2269 ASSERT((*cur)->map() == heap_->raw_unchecked_free_space_map()); | 2241 ASSERT((*cur)->map() == heap_->raw_unchecked_free_space_map()); |
| 2270 FreeSpace* cur_as_free_space = reinterpret_cast<FreeSpace*>(*cur); | 2242 FreeSpace* cur_as_free_space = reinterpret_cast<FreeSpace*>(*cur); |
| 2271 int size = cur_as_free_space->Size(); | 2243 int size = cur_as_free_space->Size(); |
| 2272 if (size >= size_in_bytes) { | 2244 if (size >= size_in_bytes) { |
| 2273 // Large enough node found. Unlink it from the list. | 2245 // Large enough node found. Unlink it from the list. |
| 2274 node = *cur; | 2246 node = *cur; |
| 2275 *cur = node->next(); | 2247 *cur = node->next(); |
| 2276 *node_size = size; | 2248 *node_size = size; |
| 2277 huge_list_available -= size; | 2249 huge_list_available -= size; |
| 2278 page = Page::FromAddress(node->address()); | 2250 Page* page = Page::FromAddress(node->address()); |
| 2279 page->add_available_in_huge_free_list(-size); | 2251 page->add_available_in_huge_free_list(-size); |
| 2280 break; | 2252 break; |
| 2281 } | 2253 } |
| 2282 } | 2254 } |
| 2283 | 2255 |
| 2284 if (huge_list_.top() == NULL) { | 2256 if (huge_list_.top() == NULL) { |
| 2285 huge_list_.set_end(NULL); | 2257 huge_list_.set_end(NULL); |
| 2286 } | 2258 } |
| 2287 | 2259 |
| 2288 huge_list_.set_available(huge_list_available); | 2260 huge_list_.set_available(huge_list_available); |
| 2289 ASSERT(IsVeryLong() || available() == SumFreeLists()); | 2261 ASSERT(IsVeryLong() || available() == SumFreeLists()); |
| 2290 | 2262 |
| 2291 return node; | 2263 return node; |
| 2292 } | 2264 } |
| 2293 | 2265 |
| 2294 | 2266 |
| 2267 FreeListNode* FreeList::FindNodeForWorstFit(int size_in_bytes, int* node_size) { |
| 2268 FreeListNode* node = FindNodeInHugeList(size_in_bytes, node_size); |
| 2269 if (node != NULL) { |
| 2270 return node; |
| 2271 } |
| 2272 |
| 2273 if (size_in_bytes <= kLargeAllocationMax) { |
| 2274 node = large_list_.PickNodeFromList(node_size); |
| 2275 if (node != NULL) { |
| 2276 Page* page = Page::FromAddress(node->address()); |
| 2277 page->add_available_in_large_free_list(-(*node_size)); |
| 2278 return node; |
| 2279 } |
| 2280 } |
| 2281 |
| 2282 if (size_in_bytes <= kMediumAllocationMax) { |
| 2283 node = medium_list_.PickNodeFromList(node_size); |
| 2284 if (node != NULL) { |
| 2285 Page* page = Page::FromAddress(node->address()); |
| 2286 page->add_available_in_medium_free_list(-(*node_size)); |
| 2287 return node; |
| 2288 } |
| 2289 } |
| 2290 |
| 2291 return node; |
| 2292 } |
| 2293 |
| 2294 |
| 2295 FreeListNode* FreeList::FindNodeForBestFit(int size_in_bytes, int* node_size) { |
| 2296 FreeListNode* node = NULL; |
| 2297 |
| 2298 if (size_in_bytes <= kSmallAllocationMax) { |
| 2299 node = small_list_.PickNodeFromList(node_size); |
| 2300 if (node != NULL) { |
| 2301 Page* page = Page::FromAddress(node->address()); |
| 2302 page->add_available_in_small_free_list(-(*node_size)); |
| 2303 return node; |
| 2304 } |
| 2305 } |
| 2306 |
| 2307 if (size_in_bytes <= kMediumAllocationMax) { |
| 2308 node = medium_list_.PickNodeFromList(node_size); |
| 2309 if (node != NULL) { |
| 2310 Page* page = Page::FromAddress(node->address()); |
| 2311 page->add_available_in_medium_free_list(-(*node_size)); |
| 2312 return node; |
| 2313 } |
| 2314 } |
| 2315 |
| 2316 if (size_in_bytes <= kLargeAllocationMax) { |
| 2317 node = large_list_.PickNodeFromList(node_size); |
| 2318 if (node != NULL) { |
| 2319 Page* page = Page::FromAddress(node->address()); |
| 2320 page->add_available_in_large_free_list(-(*node_size)); |
| 2321 return node; |
| 2322 } |
| 2323 } |
| 2324 |
| 2325 node = FindNodeInHugeList(size_in_bytes, node_size); |
| 2326 return node; |
| 2327 } |
| 2328 |
| 2329 |
| 2330 template HeapObject* FreeList::Allocate<FreeList::BEST_FIT>(int size_in_bytes); |
| 2331 |
| 2332 |
| 2333 template HeapObject* FreeList::Allocate<FreeList::WORST_FIT>(int size_in_bytes); |
| 2334 |
| 2335 |
| 2295 // Allocation on the old space free list. If it succeeds then a new linear | 2336 // Allocation on the old space free list. If it succeeds then a new linear |
| 2296 // allocation space has been set up with the top and limit of the space. If | 2337 // allocation space has been set up with the top and limit of the space. If |
| 2297 // the allocation fails then NULL is returned, and the caller can perform a GC | 2338 // the allocation fails then NULL is returned, and the caller can perform a GC |
| 2298 // or allocate a new page before retrying. | 2339 // or allocate a new page before retrying. |
| 2340 template<FreeList::AllocationStrategy strategy> |
| 2299 HeapObject* FreeList::Allocate(int size_in_bytes) { | 2341 HeapObject* FreeList::Allocate(int size_in_bytes) { |
| 2300 ASSERT(0 < size_in_bytes); | 2342 ASSERT(0 < size_in_bytes); |
| 2301 ASSERT(size_in_bytes <= kMaxBlockSize); | 2343 ASSERT(size_in_bytes <= kMaxBlockSize); |
| 2302 ASSERT(IsAligned(size_in_bytes, kPointerSize)); | 2344 ASSERT(IsAligned(size_in_bytes, kPointerSize)); |
| 2303 // Don't free list allocate if there is linear space available. | 2345 // Don't free list allocate if there is linear space available. |
| 2304 ASSERT(owner_->limit() - owner_->top() < size_in_bytes); | 2346 ASSERT(owner_->limit() - owner_->top() < size_in_bytes); |
| 2305 | 2347 |
| 2306 int new_node_size = 0; | 2348 int new_node_size = 0; |
| 2307 FreeListNode* new_node = FindNodeFor(size_in_bytes, &new_node_size); | 2349 FreeListNode* new_node; |
| 2350 if (FreeList::BEST_FIT == strategy) { |
| 2351 new_node = FindNodeForBestFit(size_in_bytes, &new_node_size); |
| 2352 } else { |
| 2353 new_node = FindNodeForWorstFit(size_in_bytes, &new_node_size); |
| 2354 } |
| 2308 if (new_node == NULL) return NULL; | 2355 if (new_node == NULL) return NULL; |
| 2309 | 2356 |
| 2310 | 2357 |
| 2311 int bytes_left = new_node_size - size_in_bytes; | 2358 int bytes_left = new_node_size - size_in_bytes; |
| 2312 ASSERT(bytes_left >= 0); | 2359 ASSERT(bytes_left >= 0); |
| 2313 | 2360 |
| 2314 int old_linear_size = static_cast<int>(owner_->limit() - owner_->top()); | 2361 int old_linear_size = static_cast<int>(owner_->limit() - owner_->top()); |
| 2315 // Mark the old linear allocation area with a free space map so it can be | 2362 // Mark the old linear allocation area with a free space map so it can be |
| 2316 // skipped when scanning the heap. This also puts it back in the free list | 2363 // skipped when scanning the heap. This also puts it back in the free list |
| 2317 // if it is big enough. | 2364 // if it is big enough. |
| (...skipping 10 matching lines...) Expand all Loading... |
| 2328 #endif | 2375 #endif |
| 2329 | 2376 |
| 2330 // The old-space-step might have finished sweeping and restarted marking. | 2377 // The old-space-step might have finished sweeping and restarted marking. |
| 2331 // Verify that it did not turn the page of the new node into an evacuation | 2378 // Verify that it did not turn the page of the new node into an evacuation |
| 2332 // candidate. | 2379 // candidate. |
| 2333 ASSERT(!MarkCompactCollector::IsOnEvacuationCandidate(new_node)); | 2380 ASSERT(!MarkCompactCollector::IsOnEvacuationCandidate(new_node)); |
| 2334 | 2381 |
| 2335 const int kThreshold = IncrementalMarking::kAllocatedThreshold; | 2382 const int kThreshold = IncrementalMarking::kAllocatedThreshold; |
| 2336 | 2383 |
| 2337 // Memory in the linear allocation area is counted as allocated. We may free | 2384 // Memory in the linear allocation area is counted as allocated. We may free |
| 2338 // a little of this again immediately - see below. | 2385 // a little of this again immediately - see below. We try to create large |
| 2386 // bump pointer ranges when we use worst-fit, therefore we do not give |
| 2387 // memory back to the free-list. |
| 2339 owner_->Allocate(new_node_size); | 2388 owner_->Allocate(new_node_size); |
| 2340 | 2389 |
| 2341 if (bytes_left > kThreshold && | 2390 if (FreeList::WORST_FIT == strategy) { |
| 2391 owner_->AllocatePretenure(new_node_size); |
| 2392 } |
| 2393 |
| 2394 if (FreeList::BEST_FIT == strategy && |
| 2395 bytes_left > kThreshold && |
| 2342 owner_->heap()->incremental_marking()->IsMarkingIncomplete() && | 2396 owner_->heap()->incremental_marking()->IsMarkingIncomplete() && |
| 2343 FLAG_incremental_marking_steps) { | 2397 FLAG_incremental_marking_steps) { |
| 2344 int linear_size = owner_->RoundSizeDownToObjectAlignment(kThreshold); | 2398 int linear_size = owner_->RoundSizeDownToObjectAlignment(kThreshold); |
| 2345 // We don't want to give too large linear areas to the allocator while | 2399 // We don't want to give too large linear areas to the allocator while |
| 2346 // incremental marking is going on, because we won't check again whether | 2400 // incremental marking is going on, because we won't check again whether |
| 2347 // we want to do another increment until the linear area is used up. | 2401 // we want to do another increment until the linear area is used up. |
| 2348 owner_->Free(new_node->address() + size_in_bytes + linear_size, | 2402 owner_->Free(new_node->address() + size_in_bytes + linear_size, |
| 2349 new_node_size - size_in_bytes - linear_size); | 2403 new_node_size - size_in_bytes - linear_size); |
| 2350 owner_->SetTop(new_node->address() + size_in_bytes, | 2404 owner_->SetTop(new_node->address() + size_in_bytes, |
| 2351 new_node->address() + size_in_bytes + linear_size); | 2405 new_node->address() + size_in_bytes + linear_size); |
| (...skipping 148 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2500 } | 2554 } |
| 2501 | 2555 |
| 2502 | 2556 |
| 2503 bool PagedSpace::ReserveSpace(int size_in_bytes) { | 2557 bool PagedSpace::ReserveSpace(int size_in_bytes) { |
| 2504 ASSERT(size_in_bytes <= AreaSize()); | 2558 ASSERT(size_in_bytes <= AreaSize()); |
| 2505 ASSERT(size_in_bytes == RoundSizeDownToObjectAlignment(size_in_bytes)); | 2559 ASSERT(size_in_bytes == RoundSizeDownToObjectAlignment(size_in_bytes)); |
| 2506 Address current_top = allocation_info_.top; | 2560 Address current_top = allocation_info_.top; |
| 2507 Address new_top = current_top + size_in_bytes; | 2561 Address new_top = current_top + size_in_bytes; |
| 2508 if (new_top <= allocation_info_.limit) return true; | 2562 if (new_top <= allocation_info_.limit) return true; |
| 2509 | 2563 |
| 2510 HeapObject* new_area = free_list_.Allocate(size_in_bytes); | 2564 HeapObject* new_area = free_list_.Allocate<FreeList::BEST_FIT>(size_in_bytes); |
| 2511 if (new_area == NULL) new_area = SlowAllocateRaw(size_in_bytes); | 2565 if (new_area == NULL) { |
| 2566 new_area = SlowAllocateRaw<FreeList::BEST_FIT>(size_in_bytes); |
| 2567 } |
| 2512 if (new_area == NULL) return false; | 2568 if (new_area == NULL) return false; |
| 2513 | 2569 |
| 2514 int old_linear_size = static_cast<int>(limit() - top()); | 2570 int old_linear_size = static_cast<int>(limit() - top()); |
| 2515 // Mark the old linear allocation area with a free space so it can be | 2571 // Mark the old linear allocation area with a free space so it can be |
| 2516 // skipped when scanning the heap. This also puts it back in the free list | 2572 // skipped when scanning the heap. This also puts it back in the free list |
| 2517 // if it is big enough. | 2573 // if it is big enough. |
| 2518 Free(top(), old_linear_size); | 2574 Free(top(), old_linear_size); |
| 2519 | 2575 |
| 2520 SetTop(new_area->address(), new_area->address() + size_in_bytes); | 2576 SetTop(new_area->address(), new_area->address() + size_in_bytes); |
| 2521 return true; | 2577 return true; |
| (...skipping 84 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2606 } | 2662 } |
| 2607 return false; | 2663 return false; |
| 2608 } | 2664 } |
| 2609 return true; | 2665 return true; |
| 2610 } else { | 2666 } else { |
| 2611 return AdvanceSweeper(size_in_bytes); | 2667 return AdvanceSweeper(size_in_bytes); |
| 2612 } | 2668 } |
| 2613 } | 2669 } |
| 2614 | 2670 |
| 2615 | 2671 |
| 2672 template HeapObject* PagedSpace:: |
| 2673 SlowAllocateRaw<FreeList::BEST_FIT>(int size_in_bytes); |
| 2674 |
| 2675 |
| 2676 template HeapObject* PagedSpace:: |
| 2677 SlowAllocateRaw<FreeList::WORST_FIT>(int size_in_bytes); |
| 2678 |
| 2679 |
| 2680 template<FreeList::AllocationStrategy strategy> |
| 2616 HeapObject* PagedSpace::SlowAllocateRaw(int size_in_bytes) { | 2681 HeapObject* PagedSpace::SlowAllocateRaw(int size_in_bytes) { |
| 2617 // Allocation in this space has failed. | 2682 // Allocation in this space has failed. |
| 2618 | 2683 |
| 2619 // If there are unswept pages advance lazy sweeper a bounded number of times | 2684 // If there are unswept pages advance lazy sweeper a bounded number of times |
| 2620 // until we find a size_in_bytes contiguous piece of memory | 2685 // until we find a size_in_bytes contiguous piece of memory |
| 2621 const int kMaxSweepingTries = 5; | 2686 const int kMaxSweepingTries = 5; |
| 2622 bool sweeping_complete = false; | 2687 bool sweeping_complete = false; |
| 2623 | 2688 |
| 2624 for (int i = 0; i < kMaxSweepingTries && !sweeping_complete; i++) { | 2689 for (int i = 0; i < kMaxSweepingTries && !sweeping_complete; i++) { |
| 2625 sweeping_complete = EnsureSweeperProgress(size_in_bytes); | 2690 sweeping_complete = EnsureSweeperProgress(size_in_bytes); |
| 2626 | 2691 |
| 2627 // Retry the free list allocation. | 2692 // Retry the free list allocation. |
| 2628 HeapObject* object = free_list_.Allocate(size_in_bytes); | 2693 HeapObject* object = free_list_.Allocate<strategy>(size_in_bytes); |
| 2629 if (object != NULL) return object; | 2694 if (object != NULL) return object; |
| 2630 } | 2695 } |
| 2631 | 2696 |
| 2632 // Free list allocation failed and there is no next page. Fail if we have | 2697 // Free list allocation failed and there is no next page. Fail if we have |
| 2633 // hit the old generation size limit that should cause a garbage | 2698 // hit the old generation size limit that should cause a garbage |
| 2634 // collection. | 2699 // collection. |
| 2635 if (!heap()->always_allocate() && | 2700 if (!heap()->always_allocate() && |
| 2701 !heap()->AggressivePromotionMode() && |
| 2636 heap()->OldGenerationAllocationLimitReached()) { | 2702 heap()->OldGenerationAllocationLimitReached()) { |
| 2637 return NULL; | 2703 return NULL; |
| 2638 } | 2704 } |
| 2639 | 2705 |
| 2640 // Try to expand the space and allocate in the new next page. | 2706 // Try to expand the space and allocate in the new next page. |
| 2641 if (Expand()) { | 2707 if (Expand()) { |
| 2642 return free_list_.Allocate(size_in_bytes); | 2708 return free_list_.Allocate<strategy>(size_in_bytes); |
| 2643 } | 2709 } |
| 2644 | 2710 |
| 2645 // Last ditch, sweep all the remaining pages to try to find space. This may | 2711 // Last ditch, sweep all the remaining pages to try to find space. This may |
| 2646 // cause a pause. | 2712 // cause a pause. |
| 2647 if (!IsLazySweepingComplete()) { | 2713 if (!IsLazySweepingComplete()) { |
| 2648 EnsureSweeperProgress(kMaxInt); | 2714 EnsureSweeperProgress(kMaxInt); |
| 2649 | 2715 |
| 2650 // Retry the free list allocation. | 2716 // Retry the free list allocation. |
| 2651 HeapObject* object = free_list_.Allocate(size_in_bytes); | 2717 HeapObject* object = free_list_.Allocate<strategy>(size_in_bytes); |
| 2652 if (object != NULL) return object; | 2718 if (object != NULL) return object; |
| 2653 } | 2719 } |
| 2654 | 2720 |
| 2655 // Finally, fail. | 2721 // Finally, fail. |
| 2656 return NULL; | 2722 return NULL; |
| 2657 } | 2723 } |
| 2658 | 2724 |
| 2659 | 2725 |
| 2660 #ifdef DEBUG | 2726 #ifdef DEBUG |
| 2661 void PagedSpace::ReportCodeStatistics() { | 2727 void PagedSpace::ReportCodeStatistics() { |
| (...skipping 513 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3175 object->ShortPrint(); | 3241 object->ShortPrint(); |
| 3176 PrintF("\n"); | 3242 PrintF("\n"); |
| 3177 } | 3243 } |
| 3178 printf(" --------------------------------------\n"); | 3244 printf(" --------------------------------------\n"); |
| 3179 printf(" Marked: %x, LiveCount: %x\n", mark_size, LiveBytes()); | 3245 printf(" Marked: %x, LiveCount: %x\n", mark_size, LiveBytes()); |
| 3180 } | 3246 } |
| 3181 | 3247 |
| 3182 #endif // DEBUG | 3248 #endif // DEBUG |
| 3183 | 3249 |
| 3184 } } // namespace v8::internal | 3250 } } // namespace v8::internal |
| OLD | NEW |