| 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/v8.h" | 5 #include "src/v8.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.h" | 9 #include "src/full-codegen.h" |
| 10 #include "src/heap/mark-compact.h" | 10 #include "src/heap/mark-compact.h" |
| (...skipping 2195 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2206 free_bytes += huge_list_.Concatenate(free_list->huge_list()); | 2206 free_bytes += huge_list_.Concatenate(free_list->huge_list()); |
| 2207 return free_bytes; | 2207 return free_bytes; |
| 2208 } | 2208 } |
| 2209 | 2209 |
| 2210 | 2210 |
| 2211 void FreeList::Reset() { | 2211 void FreeList::Reset() { |
| 2212 small_list_.Reset(); | 2212 small_list_.Reset(); |
| 2213 medium_list_.Reset(); | 2213 medium_list_.Reset(); |
| 2214 large_list_.Reset(); | 2214 large_list_.Reset(); |
| 2215 huge_list_.Reset(); | 2215 huge_list_.Reset(); |
| 2216 unreported_allocation_ = 0; | |
| 2217 } | 2216 } |
| 2218 | 2217 |
| 2219 | 2218 |
| 2220 int FreeList::Free(Address start, int size_in_bytes) { | 2219 int FreeList::Free(Address start, int size_in_bytes) { |
| 2221 if (size_in_bytes == 0) return 0; | 2220 if (size_in_bytes == 0) return 0; |
| 2222 | 2221 |
| 2223 heap_->CreateFillerObjectAt(start, size_in_bytes); | 2222 heap_->CreateFillerObjectAt(start, size_in_bytes); |
| 2224 | 2223 |
| 2225 Page* page = Page::FromAddress(start); | 2224 Page* page = Page::FromAddress(start); |
| 2226 | 2225 |
| (...skipping 127 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2354 page = Page::FromAddress(node->address()); | 2353 page = Page::FromAddress(node->address()); |
| 2355 page->add_available_in_large_free_list(-(*node_size)); | 2354 page->add_available_in_large_free_list(-(*node_size)); |
| 2356 } | 2355 } |
| 2357 } | 2356 } |
| 2358 | 2357 |
| 2359 DCHECK(IsVeryLong() || available() == SumFreeLists()); | 2358 DCHECK(IsVeryLong() || available() == SumFreeLists()); |
| 2360 return node; | 2359 return node; |
| 2361 } | 2360 } |
| 2362 | 2361 |
| 2363 | 2362 |
| 2364 void PagedSpace::SetTopAndLimit(Address top, Address limit) { | |
| 2365 DCHECK(top == limit || | |
| 2366 Page::FromAddress(top) == Page::FromAddress(limit - 1)); | |
| 2367 MemoryChunk::UpdateHighWaterMark(allocation_info_.top()); | |
| 2368 allocation_info_.set_top(top); | |
| 2369 allocation_info_.set_limit(limit); | |
| 2370 } | |
| 2371 | |
| 2372 | |
| 2373 void PagedSpace::ReturnLinearAllocationAreaToFreeList() { | |
| 2374 int old_linear_size = static_cast<int>(limit() - top()); | |
| 2375 Free(top(), old_linear_size); | |
| 2376 SetTopAndLimit(NULL, NULL); | |
| 2377 } | |
| 2378 | |
| 2379 | |
| 2380 // Allocation on the old space free list. If it succeeds then a new linear | 2363 // Allocation on the old space free list. If it succeeds then a new linear |
| 2381 // allocation space has been set up with the top and limit of the space. If | 2364 // allocation space has been set up with the top and limit of the space. If |
| 2382 // the allocation fails then NULL is returned, and the caller can perform a GC | 2365 // the allocation fails then NULL is returned, and the caller can perform a GC |
| 2383 // or allocate a new page before retrying. | 2366 // or allocate a new page before retrying. |
| 2384 HeapObject* FreeList::Allocate(int size_in_bytes) { | 2367 HeapObject* FreeList::Allocate(int size_in_bytes) { |
| 2385 DCHECK(0 < size_in_bytes); | 2368 DCHECK(0 < size_in_bytes); |
| 2386 DCHECK(size_in_bytes <= kMaxBlockSize); | 2369 DCHECK(size_in_bytes <= kMaxBlockSize); |
| 2387 DCHECK(IsAligned(size_in_bytes, kPointerSize)); | 2370 DCHECK(IsAligned(size_in_bytes, kPointerSize)); |
| 2388 // Don't free list allocate if there is linear space available. | 2371 // Don't free list allocate if there is linear space available. |
| 2389 DCHECK(owner_->limit() - owner_->top() < size_in_bytes); | 2372 DCHECK(owner_->limit() - owner_->top() < size_in_bytes); |
| 2390 | 2373 |
| 2391 int old_linear_size = static_cast<int>(owner_->limit() - owner_->top()); | 2374 int old_linear_size = static_cast<int>(owner_->limit() - owner_->top()); |
| 2392 // Mark the old linear allocation area with a free space map so it can be | 2375 // Mark the old linear allocation area with a free space map so it can be |
| 2393 // skipped when scanning the heap. This also puts it back in the free list | 2376 // skipped when scanning the heap. This also puts it back in the free list |
| 2394 // if it is big enough. | 2377 // if it is big enough. |
| 2395 owner_->Free(owner_->top(), old_linear_size); | 2378 owner_->Free(owner_->top(), old_linear_size); |
| 2396 | 2379 |
| 2380 owner_->heap()->incremental_marking()->OldSpaceStep(size_in_bytes - |
| 2381 old_linear_size); |
| 2382 |
| 2397 int new_node_size = 0; | 2383 int new_node_size = 0; |
| 2398 FreeSpace* new_node = FindNodeFor(size_in_bytes, &new_node_size); | 2384 FreeSpace* new_node = FindNodeFor(size_in_bytes, &new_node_size); |
| 2399 if (new_node == NULL) { | 2385 if (new_node == NULL) { |
| 2400 owner_->SetTopAndLimit(NULL, NULL); | 2386 owner_->SetTopAndLimit(NULL, NULL); |
| 2401 return NULL; | 2387 return NULL; |
| 2402 } | 2388 } |
| 2403 | 2389 |
| 2404 int bytes_left = new_node_size - size_in_bytes; | 2390 int bytes_left = new_node_size - size_in_bytes; |
| 2405 DCHECK(bytes_left >= 0); | 2391 DCHECK(bytes_left >= 0); |
| 2406 | 2392 |
| 2407 #ifdef DEBUG | 2393 #ifdef DEBUG |
| 2408 for (int i = 0; i < size_in_bytes / kPointerSize; i++) { | 2394 for (int i = 0; i < size_in_bytes / kPointerSize; i++) { |
| 2409 reinterpret_cast<Object**>(new_node->address())[i] = | 2395 reinterpret_cast<Object**>(new_node->address())[i] = |
| 2410 Smi::FromInt(kCodeZapValue); | 2396 Smi::FromInt(kCodeZapValue); |
| 2411 } | 2397 } |
| 2412 #endif | 2398 #endif |
| 2413 | 2399 |
| 2414 // The old-space-step might have finished sweeping and restarted marking. | 2400 // The old-space-step might have finished sweeping and restarted marking. |
| 2415 // Verify that it did not turn the page of the new node into an evacuation | 2401 // Verify that it did not turn the page of the new node into an evacuation |
| 2416 // candidate. | 2402 // candidate. |
| 2417 DCHECK(!MarkCompactCollector::IsOnEvacuationCandidate(new_node)); | 2403 DCHECK(!MarkCompactCollector::IsOnEvacuationCandidate(new_node)); |
| 2418 | 2404 |
| 2419 // An old-space step will mark more data per byte allocated, because old space | 2405 const int kThreshold = IncrementalMarking::kAllocatedThreshold; |
| 2420 // allocation is more serious. We don't want the pause to be bigger, so we | |
| 2421 // do marking after a smaller amount of allocation. | |
| 2422 const int kThreshold = IncrementalMarking::kAllocatedThreshold * | |
| 2423 IncrementalMarking::kOldSpaceAllocationMarkingFactor; | |
| 2424 | 2406 |
| 2425 // Memory in the linear allocation area is counted as allocated. We may free | 2407 // Memory in the linear allocation area is counted as allocated. We may free |
| 2426 // a little of this again immediately - see below. | 2408 // a little of this again immediately - see below. |
| 2427 owner_->Allocate(new_node_size); | 2409 owner_->Allocate(new_node_size); |
| 2428 | 2410 |
| 2429 unreported_allocation_ += new_node_size; | |
| 2430 | |
| 2431 if (owner_->heap()->inline_allocation_disabled()) { | 2411 if (owner_->heap()->inline_allocation_disabled()) { |
| 2432 // Keep the linear allocation area empty if requested to do so, just | 2412 // Keep the linear allocation area empty if requested to do so, just |
| 2433 // return area back to the free list instead. | 2413 // return area back to the free list instead. |
| 2434 owner_->Free(new_node->address() + size_in_bytes, bytes_left); | 2414 owner_->Free(new_node->address() + size_in_bytes, bytes_left); |
| 2435 DCHECK(owner_->top() == NULL && owner_->limit() == NULL); | 2415 DCHECK(owner_->top() == NULL && owner_->limit() == NULL); |
| 2436 } else if (bytes_left > kThreshold && | 2416 } else if (bytes_left > kThreshold && |
| 2437 owner_->heap()->incremental_marking()->CanDoSteps()) { | 2417 owner_->heap()->incremental_marking()->IsMarkingIncomplete() && |
| 2418 FLAG_incremental_marking_steps) { |
| 2438 int linear_size = owner_->RoundSizeDownToObjectAlignment(kThreshold); | 2419 int linear_size = owner_->RoundSizeDownToObjectAlignment(kThreshold); |
| 2439 | |
| 2440 // We don't want to give too large linear areas to the allocator while | 2420 // We don't want to give too large linear areas to the allocator while |
| 2441 // incremental marking is going on, because we won't check again whether | 2421 // incremental marking is going on, because we won't check again whether |
| 2442 // we want to do another increment until the linear area is used up. | 2422 // we want to do another increment until the linear area is used up. |
| 2443 owner_->Free(new_node->address() + size_in_bytes + linear_size, | 2423 owner_->Free(new_node->address() + size_in_bytes + linear_size, |
| 2444 new_node_size - size_in_bytes - linear_size); | 2424 new_node_size - size_in_bytes - linear_size); |
| 2445 owner_->SetTopAndLimit(new_node->address() + size_in_bytes, | 2425 owner_->SetTopAndLimit(new_node->address() + size_in_bytes, |
| 2446 new_node->address() + size_in_bytes + linear_size); | 2426 new_node->address() + size_in_bytes + linear_size); |
| 2447 // It is important that we are done updating top and limit before we call | 2427 } else if (bytes_left > 0) { |
| 2448 // this, because it might add the free space between top and limit to the | 2428 // Normally we give the rest of the node to the allocator as its new |
| 2449 // free list, and that would be very bad if top and new_node were still | 2429 // linear allocation area. |
| 2450 // pointing to the same place. | 2430 owner_->SetTopAndLimit(new_node->address() + size_in_bytes, |
| 2451 owner_->heap()->incremental_marking()->OldSpaceStep(size_in_bytes + | 2431 new_node->address() + new_node_size); |
| 2452 linear_size); | |
| 2453 unreported_allocation_ = 0; | |
| 2454 } else { | 2432 } else { |
| 2455 if (bytes_left > 0) { | 2433 // TODO(gc) Try not freeing linear allocation region when bytes_left |
| 2456 // Normally we give the rest of the node to the allocator as its new | 2434 // are zero. |
| 2457 // linear allocation area. | 2435 owner_->SetTopAndLimit(NULL, NULL); |
| 2458 owner_->SetTopAndLimit(new_node->address() + size_in_bytes, | |
| 2459 new_node->address() + new_node_size); | |
| 2460 } else { | |
| 2461 // TODO(gc) Try not freeing linear allocation region when bytes_left | |
| 2462 // are zero. | |
| 2463 owner_->SetTopAndLimit(NULL, NULL); | |
| 2464 } | |
| 2465 if (unreported_allocation_ > kThreshold) { | |
| 2466 // This may start the incremental marker, or do a little work if it's | |
| 2467 // already started. It is important that we are finished updating top | |
| 2468 // and limit before we call this (see above). | |
| 2469 owner_->heap()->incremental_marking()->OldSpaceStep( | |
| 2470 Min(kThreshold, unreported_allocation_)); | |
| 2471 unreported_allocation_ = 0; | |
| 2472 } | |
| 2473 } | 2436 } |
| 2474 | 2437 |
| 2475 return new_node; | 2438 return new_node; |
| 2476 } | 2439 } |
| 2477 | 2440 |
| 2478 | 2441 |
| 2479 intptr_t FreeList::EvictFreeListItems(Page* p) { | 2442 intptr_t FreeList::EvictFreeListItems(Page* p) { |
| 2480 intptr_t sum = huge_list_.EvictFreeListItemsInList(p); | 2443 intptr_t sum = huge_list_.EvictFreeListItemsInList(p); |
| 2481 p->set_available_in_huge_free_list(0); | 2444 p->set_available_in_huge_free_list(0); |
| 2482 | 2445 |
| (...skipping 466 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 2949 MSAN_ALLOCATED_UNINITIALIZED_MEMORY(object->address(), object_size); | 2912 MSAN_ALLOCATED_UNINITIALIZED_MEMORY(object->address(), object_size); |
| 2950 | 2913 |
| 2951 if (Heap::ShouldZapGarbage()) { | 2914 if (Heap::ShouldZapGarbage()) { |
| 2952 // Make the object consistent so the heap can be verified in OldSpaceStep. | 2915 // Make the object consistent so the heap can be verified in OldSpaceStep. |
| 2953 // We only need to do this in debug builds or if verify_heap is on. | 2916 // We only need to do this in debug builds or if verify_heap is on. |
| 2954 reinterpret_cast<Object**>(object->address())[0] = | 2917 reinterpret_cast<Object**>(object->address())[0] = |
| 2955 heap()->fixed_array_map(); | 2918 heap()->fixed_array_map(); |
| 2956 reinterpret_cast<Object**>(object->address())[1] = Smi::FromInt(0); | 2919 reinterpret_cast<Object**>(object->address())[1] = Smi::FromInt(0); |
| 2957 } | 2920 } |
| 2958 | 2921 |
| 2959 // We would like to tell the incremental marker to do a lot of work, since | 2922 heap()->incremental_marking()->OldSpaceStep(object_size); |
| 2960 // we just made a large allocation in old space, but that might cause a huge | |
| 2961 // pause. Underreporting here may cause the marker to speed up because it | |
| 2962 // will perceive that it is not keeping up with allocation. Although this | |
| 2963 // causes some big incremental marking steps they are not as big as this one | |
| 2964 // might have been. In testing, a very large pause was divided up into about | |
| 2965 // 12 parts. | |
| 2966 const int kThreshold = IncrementalMarking::kAllocatedThreshold * | |
| 2967 IncrementalMarking::kOldSpaceAllocationMarkingFactor; | |
| 2968 heap()->incremental_marking()->OldSpaceStep(kThreshold); | |
| 2969 return object; | 2923 return object; |
| 2970 } | 2924 } |
| 2971 | 2925 |
| 2972 | 2926 |
| 2973 size_t LargeObjectSpace::CommittedPhysicalMemory() { | 2927 size_t LargeObjectSpace::CommittedPhysicalMemory() { |
| 2974 if (!base::VirtualMemory::HasLazyCommits()) return CommittedMemory(); | 2928 if (!base::VirtualMemory::HasLazyCommits()) return CommittedMemory(); |
| 2975 size_t size = 0; | 2929 size_t size = 0; |
| 2976 LargePage* current = first_page_; | 2930 LargePage* current = first_page_; |
| 2977 while (current != NULL) { | 2931 while (current != NULL) { |
| 2978 size += current->CommittedPhysicalMemory(); | 2932 size += current->CommittedPhysicalMemory(); |
| (...skipping 201 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 3180 object->ShortPrint(); | 3134 object->ShortPrint(); |
| 3181 PrintF("\n"); | 3135 PrintF("\n"); |
| 3182 } | 3136 } |
| 3183 printf(" --------------------------------------\n"); | 3137 printf(" --------------------------------------\n"); |
| 3184 printf(" Marked: %x, LiveCount: %x\n", mark_size, LiveBytes()); | 3138 printf(" Marked: %x, LiveCount: %x\n", mark_size, LiveBytes()); |
| 3185 } | 3139 } |
| 3186 | 3140 |
| 3187 #endif // DEBUG | 3141 #endif // DEBUG |
| 3188 } // namespace internal | 3142 } // namespace internal |
| 3189 } // namespace v8 | 3143 } // namespace v8 |
| OLD | NEW |