Index: src/heap/spaces.h |
diff --git a/src/heap/spaces.h b/src/heap/spaces.h |
index dd23bbc7714d4af766a6ccb9052bb96dd2d163a0..f181927ea0da82cf77c3e08d8b62f1c8dadd017f 100644 |
--- a/src/heap/spaces.h |
+++ b/src/heap/spaces.h |
@@ -27,6 +27,7 @@ class FreeList; |
class Isolate; |
class MemoryAllocator; |
class MemoryChunk; |
+class NewSpacePage; |
class Page; |
class PagedSpace; |
class SemiSpace; |
@@ -1246,6 +1247,11 @@ class SkipList { |
// |
class MemoryAllocator { |
public: |
+ enum AllocationMode { |
+ kRegular, |
+ kPooled, |
+ }; |
+ |
explicit MemoryAllocator(Isolate* isolate); |
// Initializes its internal bookkeeping structures. |
@@ -1254,8 +1260,13 @@ class MemoryAllocator { |
void TearDown(); |
- Page* AllocatePage(intptr_t size, PagedSpace* owner, |
- Executability executable); |
+ // Allocates either Page or NewSpacePage from the allocator. AllocationMode |
+ // is used to indicate whether pooled allocation, which only works for |
+ // MemoryChunk::kPageSize, should be tried first. |
+ template <typename PageType, MemoryAllocator::AllocationMode mode = kRegular, |
+ typename SpaceType> |
+ PageType* AllocatePage(intptr_t size, SpaceType* owner, |
+ Executability executable); |
LargePage* AllocateLargePage(intptr_t object_size, Space* owner, |
Executability executable); |
@@ -1267,8 +1278,9 @@ class MemoryAllocator { |
// FreeMemory can be called concurrently when PreFree was executed before. |
void PerformFreeMemory(MemoryChunk* chunk); |
- // Free is a wrapper method, which calls PreFree and PerformFreeMemory |
- // together. |
+ // Free is a wrapper method. For kRegular AllocationMode it calls PreFree and |
+ // PerformFreeMemory together. For kPooled it will dispatch to pooled free. |
+ template <MemoryAllocator::AllocationMode mode = kRegular> |
void Free(MemoryChunk* chunk); |
// Returns allocated spaces in bytes. |
@@ -1322,8 +1334,6 @@ class MemoryAllocator { |
bool CommitMemory(Address addr, size_t size, Executability executable); |
- void FreeNewSpaceMemory(Address addr, base::VirtualMemory* reservation, |
- Executability executable); |
void FreeMemory(base::VirtualMemory* reservation, Executability executable); |
void FreeMemory(Address addr, size_t size, Executability executable); |
@@ -1376,6 +1386,14 @@ class MemoryAllocator { |
size_t reserved_size); |
private: |
+ // See AllocatePage for public interface. Note that currently we only support |
+ // pools for NOT_EXECUTABLE pages of size MemoryChunk::kPageSize. |
+ template <typename SpaceType> |
+ MemoryChunk* AllocatePagePooled(SpaceType* owner); |
+ |
+ // Free that chunk into the pool. |
+ void FreePooled(MemoryChunk* chunk); |
+ |
Isolate* isolate_; |
// Maximum space size in bytes. |
@@ -1429,6 +1447,8 @@ class MemoryAllocator { |
} while ((high > ptr) && !highest_ever_allocated_.TrySetValue(ptr, high)); |
} |
+ List<MemoryChunk*> chunk_pool_; |
+ |
DISALLOW_IMPLICIT_CONSTRUCTORS(MemoryAllocator); |
}; |
@@ -2269,6 +2289,10 @@ enum SemiSpaceId { kFromSpace = 0, kToSpace = 1 }; |
class NewSpacePage : public MemoryChunk { |
public: |
+ static inline NewSpacePage* Initialize(Heap* heap, MemoryChunk* chunk, |
+ Executability executable, |
+ SemiSpace* owner); |
+ |
static bool IsAtStart(Address addr) { |
return (reinterpret_cast<intptr_t>(addr) & Page::kPageAlignmentMask) == |
kObjectStartOffset; |
@@ -2326,9 +2350,6 @@ class NewSpacePage : public MemoryChunk { |
// for the doubly-linked list of real pages. |
explicit NewSpacePage(SemiSpace* owner) { InitializeAsAnchor(owner); } |
- static NewSpacePage* Initialize(Heap* heap, Address start, |
- SemiSpace* semi_space); |
- |
// Intialize a fake NewSpacePage used as sentinel at the ends |
// of a doubly-linked list of real NewSpacePages. |
// Only uses the prev/next links, and sets flags to not be in new-space. |
@@ -2354,7 +2375,6 @@ class SemiSpace : public Space { |
current_capacity_(0), |
maximum_capacity_(0), |
minimum_capacity_(0), |
- start_(nullptr), |
age_mark_(nullptr), |
committed_(false), |
id_(semispace), |
@@ -2365,39 +2385,38 @@ class SemiSpace : public Space { |
inline bool Contains(Object* o); |
inline bool ContainsSlow(Address a); |
- // Creates a space in the young generation. The constructor does not |
- // allocate memory from the OS. |
- void SetUp(Address start, int initial_capacity, int maximum_capacity); |
- |
- // Tear down the space. Heap memory was not allocated by the space, so it |
- // is not deallocated here. |
+ void SetUp(int initial_capacity, int maximum_capacity); |
void TearDown(); |
+ bool HasBeenSetUp() { return maximum_capacity_ != 0; } |
- // True if the space has been set up but not torn down. |
- bool HasBeenSetUp() { return start_ != nullptr; } |
+ bool Commit(); |
+ bool Uncommit(); |
+ bool is_committed() { return committed_; } |
- // Grow the semispace to the new capacity. The new capacity |
- // requested must be larger than the current capacity and less than |
- // the maximum capacity. |
+ // Grow the semispace to the new capacity. The new capacity requested must |
+ // be larger than the current capacity and less than the maximum capacity. |
bool GrowTo(int new_capacity); |
- // Shrinks the semispace to the new capacity. The new capacity |
- // requested must be more than the amount of used memory in the |
- // semispace and less than the current capacity. |
+ // Shrinks the semispace to the new capacity. The new capacity requested |
+ // must be more than the amount of used memory in the semispace and less |
+ // than the current capacity. |
bool ShrinkTo(int new_capacity); |
// Returns the start address of the first page of the space. |
Address space_start() { |
- DCHECK_NE(anchor_.next_page(), &anchor_); |
+ DCHECK_NE(anchor_.next_page(), anchor()); |
return anchor_.next_page()->area_start(); |
} |
- // Returns the start address of the current page of the space. |
- Address page_low() { return current_page_->area_start(); } |
+ NewSpacePage* first_page() { return anchor_.next_page(); } |
+ NewSpacePage* current_page() { return current_page_; } |
// Returns one past the end address of the space. |
Address space_end() { return anchor_.prev_page()->area_end(); } |
+ // Returns the start address of the current page of the space. |
+ Address page_low() { return current_page_->area_start(); } |
+ |
// Returns one past the end address of the current page of the space. |
Address page_high() { return current_page_->area_end(); } |
@@ -2415,17 +2434,10 @@ class SemiSpace : public Space { |
Address age_mark() { return age_mark_; } |
void set_age_mark(Address mark); |
- bool is_committed() { return committed_; } |
- bool Commit(); |
- bool Uncommit(); |
- |
- NewSpacePage* first_page() { return anchor_.next_page(); } |
- NewSpacePage* current_page() { return current_page_; } |
- |
- // Returns the current total capacity of the semispace. |
+ // Returns the current capacity of the semispace. |
int current_capacity() { return current_capacity_; } |
- // Returns the maximum total capacity of the semispace. |
+ // Returns the maximum capacity of the semispace. |
int maximum_capacity() { return maximum_capacity_; } |
// Returns the initial capacity of the semispace. |
@@ -2467,11 +2479,7 @@ class SemiSpace : public Space { |
#endif |
private: |
- NewSpacePage* anchor() { return &anchor_; } |
- |
- void set_current_capacity(int new_capacity) { |
- current_capacity_ = new_capacity; |
- } |
+ inline NewSpacePage* anchor() { return &anchor_; } |
// Copies the flags into the masked positions on all pages in the space. |
void FixPagesFlags(intptr_t flags, intptr_t flag_mask); |
@@ -2482,11 +2490,9 @@ class SemiSpace : public Space { |
// The maximum capacity that can be used by this space. |
int maximum_capacity_; |
- // The mimnimum capacity for the space. A space cannot shrink below this size. |
+ // The minimum capacity for the space. A space cannot shrink below this size. |
int minimum_capacity_; |
- // The start address of the space. |
- Address start_; |
// Used to govern object promotion during mark-compact collection. |
Address age_mark_; |
@@ -2562,20 +2568,21 @@ class NewSpacePageIterator BASE_EMBEDDED { |
class NewSpace : public Space { |
public: |
- // Constructor. |
explicit NewSpace(Heap* heap) |
: Space(heap, NEW_SPACE, NOT_EXECUTABLE), |
to_space_(heap, kToSpace), |
from_space_(heap, kFromSpace), |
reservation_(), |
- top_on_previous_step_(0) {} |
+ pages_used_(0), |
+ top_on_previous_step_(0), |
+ allocated_histogram_(nullptr), |
+ promoted_histogram_(nullptr) {} |
inline bool Contains(HeapObject* o); |
inline bool ContainsSlow(Address a); |
inline bool Contains(Object* o); |
- // Sets up the new space using the given chunk. |
- bool SetUp(int reserved_semispace_size_, int max_semi_space_size); |
+ bool SetUp(int initial_semispace_capacity, int max_semispace_capacity); |
// Tears down the space. Heap memory was not allocated by the space, so it |
// is not deallocated here. |
@@ -2638,22 +2645,40 @@ class NewSpace : public Space { |
// Return the available bytes without growing. |
intptr_t Available() override { return Capacity() - Size(); } |
- intptr_t PagesFromStart(Address addr) { |
- return static_cast<intptr_t>(addr - bottom()) / Page::kPageSize; |
- } |
- |
size_t AllocatedSinceLastGC() { |
- intptr_t allocated = top() - to_space_.age_mark(); |
- if (allocated < 0) { |
- // Runtime has lowered the top below the age mark. |
+ bool seen_age_mark = false; |
+ Address age_mark = to_space_.age_mark(); |
+ NewSpacePage* current_page = to_space_.first_page(); |
+ NewSpacePage* age_mark_page = NewSpacePage::FromAddress(age_mark); |
+ NewSpacePage* last_page = NewSpacePage::FromAddress(top() - kPointerSize); |
+ if (age_mark_page == last_page) { |
+ if (top() - age_mark >= 0) { |
+ return top() - age_mark; |
+ } |
+ // Top was reset at some point, invalidating this metric. |
return 0; |
} |
- // Correctly account for non-allocatable regions at the beginning of |
- // each page from the age_mark() to the top(). |
- intptr_t pages = |
- PagesFromStart(top()) - PagesFromStart(to_space_.age_mark()); |
- allocated -= pages * (NewSpacePage::kObjectStartOffset); |
- DCHECK(0 <= allocated && allocated <= Size()); |
+ while (current_page != last_page) { |
+ if (current_page == age_mark_page) { |
+ seen_age_mark = true; |
+ break; |
+ } |
+ current_page = current_page->next_page(); |
+ } |
+ if (!seen_age_mark) { |
+ // Top was reset at some point, invalidating this metric. |
+ return 0; |
+ } |
+ intptr_t allocated = age_mark_page->area_end() - age_mark; |
+ DCHECK_EQ(current_page, age_mark_page); |
+ current_page = age_mark_page->next_page(); |
+ while (current_page != last_page) { |
+ allocated += NewSpacePage::kAllocatableMemory; |
+ current_page = current_page->next_page(); |
+ } |
+ allocated += top() - current_page->area_start(); |
+ DCHECK_LE(0, allocated); |
+ DCHECK_LE(allocated, Size()); |
return static_cast<size_t>(allocated); |
} |
@@ -2805,9 +2830,6 @@ class NewSpace : public Space { |
base::Mutex mutex_; |
- Address chunk_base_; |
- uintptr_t chunk_size_; |
- |
// The semispaces. |
SemiSpace to_space_; |
SemiSpace from_space_; |