Changed the PageIterator class so that it only returns pages existing

at construction time.  If allocation during iteration causes a paged
space to expand, the iterator will not return the new pages.

This makes it more closely match the HeapObjectIterator behavior, and
it removes a possible source of bugs (if the allocation top was in the
last page in the space, the old iterator would stop only when it
reached the end of the space, potentially returning invalid pages from
a freshly expanded space).

Review URL: http://codereview.chromium.org/115074

git-svn-id: http://v8.googlecode.com/svn/branches/bleeding_edge@1895 ce2b1a6d-e550-0410-aec6-3dcde31c8c00
parent 883b2826
...@@ -64,15 +64,16 @@ HeapObject* HeapObjectIterator::next() { ...@@ -64,15 +64,16 @@ HeapObject* HeapObjectIterator::next() {
// PageIterator // PageIterator
bool PageIterator::has_next() { bool PageIterator::has_next() {
return cur_page_ != stop_page_; return prev_page_ != stop_page_;
} }
Page* PageIterator::next() { Page* PageIterator::next() {
ASSERT(has_next()); ASSERT(has_next());
Page* result = cur_page_; prev_page_ = (prev_page_ == NULL)
cur_page_ = cur_page_->next_page(); ? space_->first_page_
return result; : prev_page_->next_page();
return prev_page_;
} }
......
...@@ -111,17 +111,17 @@ void HeapObjectIterator::Verify() { ...@@ -111,17 +111,17 @@ void HeapObjectIterator::Verify() {
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// PageIterator // PageIterator
PageIterator::PageIterator(PagedSpace* space, Mode mode) { PageIterator::PageIterator(PagedSpace* space, Mode mode) : space_(space) {
cur_page_ = space->first_page_; prev_page_ = NULL;
switch (mode) { switch (mode) {
case PAGES_IN_USE: case PAGES_IN_USE:
stop_page_ = space->AllocationTopPage()->next_page(); stop_page_ = space->AllocationTopPage();
break; break;
case PAGES_USED_BY_MC: case PAGES_USED_BY_MC:
stop_page_ = space->MCRelocationTopPage()->next_page(); stop_page_ = space->MCRelocationTopPage();
break; break;
case ALL_PAGES: case ALL_PAGES:
stop_page_ = Page::FromAddress(NULL); stop_page_ = space->last_page_;
break; break;
default: default:
UNREACHABLE(); UNREACHABLE();
...@@ -496,8 +496,11 @@ bool PagedSpace::Setup(Address start, size_t size) { ...@@ -496,8 +496,11 @@ bool PagedSpace::Setup(Address start, size_t size) {
accounting_stats_.ExpandSpace(num_pages * Page::kObjectAreaSize); accounting_stats_.ExpandSpace(num_pages * Page::kObjectAreaSize);
ASSERT(Capacity() <= max_capacity_); ASSERT(Capacity() <= max_capacity_);
// Sequentially initialize remembered sets in the newly allocated
// pages and cache the current last page in the space.
for (Page* p = first_page_; p->is_valid(); p = p->next_page()) { for (Page* p = first_page_; p->is_valid(); p = p->next_page()) {
p->ClearRSet(); p->ClearRSet();
last_page_ = p;
} }
// Use first_page_ for allocation. // Use first_page_ for allocation.
...@@ -676,9 +679,11 @@ bool PagedSpace::Expand(Page* last_page) { ...@@ -676,9 +679,11 @@ bool PagedSpace::Expand(Page* last_page) {
MemoryAllocator::SetNextPage(last_page, p); MemoryAllocator::SetNextPage(last_page, p);
// Clear remembered set of new pages. // Sequentially clear remembered set of new pages and and cache the
// new last page in the space.
while (p->is_valid()) { while (p->is_valid()) {
p->ClearRSet(); p->ClearRSet();
last_page_ = p;
p = p->next_page(); p = p->next_page();
} }
...@@ -723,10 +728,12 @@ void PagedSpace::Shrink() { ...@@ -723,10 +728,12 @@ void PagedSpace::Shrink() {
Page* p = MemoryAllocator::FreePages(last_page_to_keep->next_page()); Page* p = MemoryAllocator::FreePages(last_page_to_keep->next_page());
MemoryAllocator::SetNextPage(last_page_to_keep, p); MemoryAllocator::SetNextPage(last_page_to_keep, p);
// Since pages are only freed in whole chunks, we may have kept more than // Since pages are only freed in whole chunks, we may have kept more
// pages_to_keep. // than pages_to_keep. Count the extra pages and cache the new last
// page in the space.
while (p->is_valid()) { while (p->is_valid()) {
pages_to_keep++; pages_to_keep++;
last_page_ = p;
p = p->next_page(); p = p->next_page();
} }
......
...@@ -511,11 +511,22 @@ class ObjectIterator : public Malloced { ...@@ -511,11 +511,22 @@ class ObjectIterator : public Malloced {
// //
// A HeapObjectIterator iterates objects from a given address to the // A HeapObjectIterator iterates objects from a given address to the
// top of a space. The given address must be below the current // top of a space. The given address must be below the current
// allocation pointer (space top). If the space top changes during // allocation pointer (space top). There are some caveats.
// iteration (because of allocating new objects), the iterator does //
// not iterate new objects. The caller function must create a new // (1) If the space top changes upward during iteration (because of
// allocating new objects), the iterator does not iterate objects
// above the original space top. The caller must create a new
// iterator starting from the old top in order to visit these new // iterator starting from the old top in order to visit these new
// objects. Heap::Scavenage() is such an example. // objects. Heap::Scavenge() is such an example.
//
// (2) If new objects are allocated below the original allocation top
// (e.g., free-list allocation in paged spaces), the new objects
// may or may not be iterated depending on their position with
// respect to the current point of iteration.
//
// (3) The space top should not change downward during iteration,
// otherwise the iterator will return not-necessarily-valid
// objects.
class HeapObjectIterator: public ObjectIterator { class HeapObjectIterator: public ObjectIterator {
public: public:
...@@ -559,17 +570,35 @@ class HeapObjectIterator: public ObjectIterator { ...@@ -559,17 +570,35 @@ class HeapObjectIterator: public ObjectIterator {
// ----------------------------------------------------------------------------- // -----------------------------------------------------------------------------
// A PageIterator iterates pages in a space. // A PageIterator iterates the pages in a paged space.
// //
// The PageIterator class provides three modes for iterating pages in a space: // The PageIterator class provides three modes for iterating pages in a space:
// PAGES_IN_USE iterates pages that are in use by the allocator; // PAGES_IN_USE iterates pages containing allocated objects.
// PAGES_USED_BY_GC iterates pages that hold relocated objects during a // PAGES_USED_BY_MC iterates pages that hold relocated objects during a
// mark-compact collection; // mark-compact collection.
// ALL_PAGES iterates all pages in the space. // ALL_PAGES iterates all pages in the space.
//
// There are some caveats.
//
// (1) If the space expands during iteration, new pages will not be
// returned by the iterator in any mode.
//
// (2) If new objects are allocated during iteration, they will appear
// in pages returned by the iterator. Allocation may cause the
// allocation pointer or MC allocation pointer in the last page to
// change between constructing the iterator and iterating the last
// page.
//
// (3) The space should not shrink during iteration, otherwise the
// iterator will return deallocated pages.
class PageIterator BASE_EMBEDDED { class PageIterator BASE_EMBEDDED {
public: public:
enum Mode {PAGES_IN_USE, PAGES_USED_BY_MC, ALL_PAGES}; enum Mode {
PAGES_IN_USE,
PAGES_USED_BY_MC,
ALL_PAGES
};
PageIterator(PagedSpace* space, Mode mode); PageIterator(PagedSpace* space, Mode mode);
...@@ -577,8 +606,9 @@ class PageIterator BASE_EMBEDDED { ...@@ -577,8 +606,9 @@ class PageIterator BASE_EMBEDDED {
inline Page* next(); inline Page* next();
private: private:
Page* cur_page_; // next page to return PagedSpace* space_;
Page* stop_page_; // page where to stop Page* prev_page_; // Previous page returned.
Page* stop_page_; // Page to stop at (last page returned by the iterator).
}; };
...@@ -809,6 +839,10 @@ class PagedSpace : public Space { ...@@ -809,6 +839,10 @@ class PagedSpace : public Space {
// The first page in this space. // The first page in this space.
Page* first_page_; Page* first_page_;
// The last page in this space. Initially set in Setup, updated in
// Expand and Shrink.
Page* last_page_;
// Normal allocation information. // Normal allocation information.
AllocationInfo allocation_info_; AllocationInfo allocation_info_;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment