Home | History | Annotate | Download | only in src
      1 // Copyright 2011 the V8 project authors. All rights reserved.
      2 // Redistribution and use in source and binary forms, with or without
      3 // modification, are permitted provided that the following conditions are
      4 // met:
      5 //
      6 //     * Redistributions of source code must retain the above copyright
      7 //       notice, this list of conditions and the following disclaimer.
      8 //     * Redistributions in binary form must reproduce the above
      9 //       copyright notice, this list of conditions and the following
     10 //       disclaimer in the documentation and/or other materials provided
     11 //       with the distribution.
     12 //     * Neither the name of Google Inc. nor the names of its
     13 //       contributors may be used to endorse or promote products derived
     14 //       from this software without specific prior written permission.
     15 //
     16 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
     17 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
     18 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
     19 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
     20 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
     21 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
     22 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
     23 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
     24 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
     25 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
     26 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
     27 
     28 #include "v8.h"
     29 
     30 #include "liveobjectlist-inl.h"
     31 #include "macro-assembler.h"
     32 #include "mark-compact.h"
     33 #include "platform.h"
     34 
     35 namespace v8 {
     36 namespace internal {
     37 
     38 
     39 // ----------------------------------------------------------------------------
     40 // HeapObjectIterator
     41 
     42 HeapObjectIterator::HeapObjectIterator(PagedSpace* space) {
     43   // You can't actually iterate over the anchor page.  It is not a real page,
     44   // just an anchor for the double linked page list.  Initialize as if we have
     45   // reached the end of the anchor page, then the first iteration will move on
     46   // to the first page.
     47   Initialize(space,
     48              NULL,
     49              NULL,
     50              kAllPagesInSpace,
     51              NULL);
     52 }
     53 
     54 
     55 HeapObjectIterator::HeapObjectIterator(PagedSpace* space,
     56                                        HeapObjectCallback size_func) {
     57   // You can't actually iterate over the anchor page.  It is not a real page,
     58   // just an anchor for the double linked page list.  Initialize the current
     59   // address and end as NULL, then the first iteration will move on
     60   // to the first page.
     61   Initialize(space,
     62              NULL,
     63              NULL,
     64              kAllPagesInSpace,
     65              size_func);
     66 }
     67 
     68 
     69 HeapObjectIterator::HeapObjectIterator(Page* page,
     70                                        HeapObjectCallback size_func) {
     71   Space* owner = page->owner();
     72   ASSERT(owner == HEAP->old_pointer_space() ||
     73          owner == HEAP->old_data_space() ||
     74          owner == HEAP->map_space() ||
     75          owner == HEAP->cell_space() ||
     76          owner == HEAP->code_space());
     77   Initialize(reinterpret_cast<PagedSpace*>(owner),
     78              page->area_start(),
     79              page->area_end(),
     80              kOnePageOnly,
     81              size_func);
     82   ASSERT(page->WasSweptPrecisely());
     83 }
     84 
     85 
     86 void HeapObjectIterator::Initialize(PagedSpace* space,
     87                                     Address cur, Address end,
     88                                     HeapObjectIterator::PageMode mode,
     89                                     HeapObjectCallback size_f) {
     90   // Check that we actually can iterate this space.
     91   ASSERT(!space->was_swept_conservatively());
     92 
     93   space_ = space;
     94   cur_addr_ = cur;
     95   cur_end_ = end;
     96   page_mode_ = mode;
     97   size_func_ = size_f;
     98 }
     99 
    100 
    101 // We have hit the end of the page and should advance to the next block of
    102 // objects.  This happens at the end of the page.
    103 bool HeapObjectIterator::AdvanceToNextPage() {
    104   ASSERT(cur_addr_ == cur_end_);
    105   if (page_mode_ == kOnePageOnly) return false;
    106   Page* cur_page;
    107   if (cur_addr_ == NULL) {
    108     cur_page = space_->anchor();
    109   } else {
    110     cur_page = Page::FromAddress(cur_addr_ - 1);
    111     ASSERT(cur_addr_ == cur_page->area_end());
    112   }
    113   cur_page = cur_page->next_page();
    114   if (cur_page == space_->anchor()) return false;
    115   cur_addr_ = cur_page->area_start();
    116   cur_end_ = cur_page->area_end();
    117   ASSERT(cur_page->WasSweptPrecisely());
    118   return true;
    119 }
    120 
    121 
    122 // -----------------------------------------------------------------------------
    123 // CodeRange
    124 
    125 
    126 CodeRange::CodeRange(Isolate* isolate)
    127     : isolate_(isolate),
    128       code_range_(NULL),
    129       free_list_(0),
    130       allocation_list_(0),
    131       current_allocation_block_index_(0) {
    132 }
    133 
    134 
    135 bool CodeRange::SetUp(const size_t requested) {
    136   ASSERT(code_range_ == NULL);
    137 
    138   code_range_ = new VirtualMemory(requested);
    139   CHECK(code_range_ != NULL);
    140   if (!code_range_->IsReserved()) {
    141     delete code_range_;
    142     code_range_ = NULL;
    143     return false;
    144   }
    145 
    146   // We are sure that we have mapped a block of requested addresses.
    147   ASSERT(code_range_->size() == requested);
    148   LOG(isolate_, NewEvent("CodeRange", code_range_->address(), requested));
    149   Address base = reinterpret_cast<Address>(code_range_->address());
    150   Address aligned_base =
    151       RoundUp(reinterpret_cast<Address>(code_range_->address()),
    152               MemoryChunk::kAlignment);
    153   size_t size = code_range_->size() - (aligned_base - base);
    154   allocation_list_.Add(FreeBlock(aligned_base, size));
    155   current_allocation_block_index_ = 0;
    156   return true;
    157 }
    158 
    159 
    160 int CodeRange::CompareFreeBlockAddress(const FreeBlock* left,
    161                                        const FreeBlock* right) {
    162   // The entire point of CodeRange is that the difference between two
    163   // addresses in the range can be represented as a signed 32-bit int,
    164   // so the cast is semantically correct.
    165   return static_cast<int>(left->start - right->start);
    166 }
    167 
    168 
    169 void CodeRange::GetNextAllocationBlock(size_t requested) {
    170   for (current_allocation_block_index_++;
    171        current_allocation_block_index_ < allocation_list_.length();
    172        current_allocation_block_index_++) {
    173     if (requested <= allocation_list_[current_allocation_block_index_].size) {
    174       return;  // Found a large enough allocation block.
    175     }
    176   }
    177 
    178   // Sort and merge the free blocks on the free list and the allocation list.
    179   free_list_.AddAll(allocation_list_);
    180   allocation_list_.Clear();
    181   free_list_.Sort(&CompareFreeBlockAddress);
    182   for (int i = 0; i < free_list_.length();) {
    183     FreeBlock merged = free_list_[i];
    184     i++;
    185     // Add adjacent free blocks to the current merged block.
    186     while (i < free_list_.length() &&
    187            free_list_[i].start == merged.start + merged.size) {
    188       merged.size += free_list_[i].size;
    189       i++;
    190     }
    191     if (merged.size > 0) {
    192       allocation_list_.Add(merged);
    193     }
    194   }
    195   free_list_.Clear();
    196 
    197   for (current_allocation_block_index_ = 0;
    198        current_allocation_block_index_ < allocation_list_.length();
    199        current_allocation_block_index_++) {
    200     if (requested <= allocation_list_[current_allocation_block_index_].size) {
    201       return;  // Found a large enough allocation block.
    202     }
    203   }
    204 
    205   // Code range is full or too fragmented.
    206   V8::FatalProcessOutOfMemory("CodeRange::GetNextAllocationBlock");
    207 }
    208 
    209 
    210 
    211 Address CodeRange::AllocateRawMemory(const size_t requested,
    212                                      size_t* allocated) {
    213   ASSERT(current_allocation_block_index_ < allocation_list_.length());
    214   if (requested > allocation_list_[current_allocation_block_index_].size) {
    215     // Find an allocation block large enough.  This function call may
    216     // call V8::FatalProcessOutOfMemory if it cannot find a large enough block.
    217     GetNextAllocationBlock(requested);
    218   }
    219   // Commit the requested memory at the start of the current allocation block.
    220   size_t aligned_requested = RoundUp(requested, MemoryChunk::kAlignment);
    221   FreeBlock current = allocation_list_[current_allocation_block_index_];
    222   if (aligned_requested >= (current.size - Page::kPageSize)) {
    223     // Don't leave a small free block, useless for a large object or chunk.
    224     *allocated = current.size;
    225   } else {
    226     *allocated = aligned_requested;
    227   }
    228   ASSERT(*allocated <= current.size);
    229   ASSERT(IsAddressAligned(current.start, MemoryChunk::kAlignment));
    230   if (!MemoryAllocator::CommitCodePage(code_range_,
    231                                        current.start,
    232                                        *allocated)) {
    233     *allocated = 0;
    234     return NULL;
    235   }
    236   allocation_list_[current_allocation_block_index_].start += *allocated;
    237   allocation_list_[current_allocation_block_index_].size -= *allocated;
    238   if (*allocated == current.size) {
    239     GetNextAllocationBlock(0);  // This block is used up, get the next one.
    240   }
    241   return current.start;
    242 }
    243 
    244 
    245 void CodeRange::FreeRawMemory(Address address, size_t length) {
    246   ASSERT(IsAddressAligned(address, MemoryChunk::kAlignment));
    247   free_list_.Add(FreeBlock(address, length));
    248   code_range_->Uncommit(address, length);
    249 }
    250 
    251 
    252 void CodeRange::TearDown() {
    253     delete code_range_;  // Frees all memory in the virtual memory range.
    254     code_range_ = NULL;
    255     free_list_.Free();
    256     allocation_list_.Free();
    257 }
    258 
    259 
    260 // -----------------------------------------------------------------------------
    261 // MemoryAllocator
    262 //
    263 
    264 MemoryAllocator::MemoryAllocator(Isolate* isolate)
    265     : isolate_(isolate),
    266       capacity_(0),
    267       capacity_executable_(0),
    268       size_(0),
    269       size_executable_(0) {
    270 }
    271 
    272 
    273 bool MemoryAllocator::SetUp(intptr_t capacity, intptr_t capacity_executable) {
    274   capacity_ = RoundUp(capacity, Page::kPageSize);
    275   capacity_executable_ = RoundUp(capacity_executable, Page::kPageSize);
    276   ASSERT_GE(capacity_, capacity_executable_);
    277 
    278   size_ = 0;
    279   size_executable_ = 0;
    280 
    281   return true;
    282 }
    283 
    284 
    285 void MemoryAllocator::TearDown() {
    286   // Check that spaces were torn down before MemoryAllocator.
    287   ASSERT(size_ == 0);
    288   // TODO(gc) this will be true again when we fix FreeMemory.
    289   // ASSERT(size_executable_ == 0);
    290   capacity_ = 0;
    291   capacity_executable_ = 0;
    292 }
    293 
    294 
    295 void MemoryAllocator::FreeMemory(VirtualMemory* reservation,
    296                                  Executability executable) {
    297   // TODO(gc) make code_range part of memory allocator?
    298   ASSERT(reservation->IsReserved());
    299   size_t size = reservation->size();
    300   ASSERT(size_ >= size);
    301   size_ -= size;
    302 
    303   isolate_->counters()->memory_allocated()->Decrement(static_cast<int>(size));
    304 
    305   if (executable == EXECUTABLE) {
    306     ASSERT(size_executable_ >= size);
    307     size_executable_ -= size;
    308   }
    309   // Code which is part of the code-range does not have its own VirtualMemory.
    310   ASSERT(!isolate_->code_range()->contains(
    311       static_cast<Address>(reservation->address())));
    312   ASSERT(executable == NOT_EXECUTABLE || !isolate_->code_range()->exists());
    313   reservation->Release();
    314 }
    315 
    316 
    317 void MemoryAllocator::FreeMemory(Address base,
    318                                  size_t size,
    319                                  Executability executable) {
    320   // TODO(gc) make code_range part of memory allocator?
    321   ASSERT(size_ >= size);
    322   size_ -= size;
    323 
    324   isolate_->counters()->memory_allocated()->Decrement(static_cast<int>(size));
    325 
    326   if (executable == EXECUTABLE) {
    327     ASSERT(size_executable_ >= size);
    328     size_executable_ -= size;
    329   }
    330   if (isolate_->code_range()->contains(static_cast<Address>(base))) {
    331     ASSERT(executable == EXECUTABLE);
    332     isolate_->code_range()->FreeRawMemory(base, size);
    333   } else {
    334     ASSERT(executable == NOT_EXECUTABLE || !isolate_->code_range()->exists());
    335     bool result = VirtualMemory::ReleaseRegion(base, size);
    336     USE(result);
    337     ASSERT(result);
    338   }
    339 }
    340 
    341 
    342 Address MemoryAllocator::ReserveAlignedMemory(size_t size,
    343                                               size_t alignment,
    344                                               VirtualMemory* controller) {
    345   VirtualMemory reservation(size, alignment);
    346 
    347   if (!reservation.IsReserved()) return NULL;
    348   size_ += reservation.size();
    349   Address base = RoundUp(static_cast<Address>(reservation.address()),
    350                          alignment);
    351   controller->TakeControl(&reservation);
    352   return base;
    353 }
    354 
    355 
    356 Address MemoryAllocator::AllocateAlignedMemory(size_t size,
    357                                                size_t alignment,
    358                                                Executability executable,
    359                                                VirtualMemory* controller) {
    360   VirtualMemory reservation;
    361   Address base = ReserveAlignedMemory(size, alignment, &reservation);
    362   if (base == NULL) return NULL;
    363 
    364   if (executable == EXECUTABLE) {
    365     if (!CommitCodePage(&reservation, base, size)) {
    366       base = NULL;
    367     }
    368   } else {
    369     if (!reservation.Commit(base, size, false)) {
    370       base = NULL;
    371     }
    372   }
    373 
    374   if (base == NULL) {
    375     // Failed to commit the body. Release the mapping and any partially
    376     // commited regions inside it.
    377     reservation.Release();
    378     return NULL;
    379   }
    380 
    381   controller->TakeControl(&reservation);
    382   return base;
    383 }
    384 
    385 
    386 void Page::InitializeAsAnchor(PagedSpace* owner) {
    387   set_owner(owner);
    388   set_prev_page(this);
    389   set_next_page(this);
    390 }
    391 
    392 
    393 NewSpacePage* NewSpacePage::Initialize(Heap* heap,
    394                                        Address start,
    395                                        SemiSpace* semi_space) {
    396   Address area_start = start + NewSpacePage::kObjectStartOffset;
    397   Address area_end = start + Page::kPageSize;
    398 
    399   MemoryChunk* chunk = MemoryChunk::Initialize(heap,
    400                                                start,
    401                                                Page::kPageSize,
    402                                                area_start,
    403                                                area_end,
    404                                                NOT_EXECUTABLE,
    405                                                semi_space);
    406   chunk->set_next_chunk(NULL);
    407   chunk->set_prev_chunk(NULL);
    408   chunk->initialize_scan_on_scavenge(true);
    409   bool in_to_space = (semi_space->id() != kFromSpace);
    410   chunk->SetFlag(in_to_space ? MemoryChunk::IN_TO_SPACE
    411                              : MemoryChunk::IN_FROM_SPACE);
    412   ASSERT(!chunk->IsFlagSet(in_to_space ? MemoryChunk::IN_FROM_SPACE
    413                                        : MemoryChunk::IN_TO_SPACE));
    414   NewSpacePage* page = static_cast<NewSpacePage*>(chunk);
    415   heap->incremental_marking()->SetNewSpacePageFlags(page);
    416   return page;
    417 }
    418 
    419 
    420 void NewSpacePage::InitializeAsAnchor(SemiSpace* semi_space) {
    421   set_owner(semi_space);
    422   set_next_chunk(this);
    423   set_prev_chunk(this);
    424   // Flags marks this invalid page as not being in new-space.
    425   // All real new-space pages will be in new-space.
    426   SetFlags(0, ~0);
    427 }
    428 
    429 
    430 MemoryChunk* MemoryChunk::Initialize(Heap* heap,
    431                                      Address base,
    432                                      size_t size,
    433                                      Address area_start,
    434                                      Address area_end,
    435                                      Executability executable,
    436                                      Space* owner) {
    437   MemoryChunk* chunk = FromAddress(base);
    438 
    439   ASSERT(base == chunk->address());
    440 
    441   chunk->heap_ = heap;
    442   chunk->size_ = size;
    443   chunk->area_start_ = area_start;
    444   chunk->area_end_ = area_end;
    445   chunk->flags_ = 0;
    446   chunk->set_owner(owner);
    447   chunk->InitializeReservedMemory();
    448   chunk->slots_buffer_ = NULL;
    449   chunk->skip_list_ = NULL;
    450   chunk->ResetLiveBytes();
    451   Bitmap::Clear(chunk);
    452   chunk->initialize_scan_on_scavenge(false);
    453   chunk->SetFlag(WAS_SWEPT_PRECISELY);
    454 
    455   ASSERT(OFFSET_OF(MemoryChunk, flags_) == kFlagsOffset);
    456   ASSERT(OFFSET_OF(MemoryChunk, live_byte_count_) == kLiveBytesOffset);
    457 
    458   if (executable == EXECUTABLE) {
    459     chunk->SetFlag(IS_EXECUTABLE);
    460   }
    461 
    462   if (owner == heap->old_data_space()) {
    463     chunk->SetFlag(CONTAINS_ONLY_DATA);
    464   }
    465 
    466   return chunk;
    467 }
    468 
    469 
    470 void MemoryChunk::InsertAfter(MemoryChunk* other) {
    471   next_chunk_ = other->next_chunk_;
    472   prev_chunk_ = other;
    473   other->next_chunk_->prev_chunk_ = this;
    474   other->next_chunk_ = this;
    475 }
    476 
    477 
    478 void MemoryChunk::Unlink() {
    479   if (!InNewSpace() && IsFlagSet(SCAN_ON_SCAVENGE)) {
    480     heap_->decrement_scan_on_scavenge_pages();
    481     ClearFlag(SCAN_ON_SCAVENGE);
    482   }
    483   next_chunk_->prev_chunk_ = prev_chunk_;
    484   prev_chunk_->next_chunk_ = next_chunk_;
    485   prev_chunk_ = NULL;
    486   next_chunk_ = NULL;
    487 }
    488 
    489 
    490 MemoryChunk* MemoryAllocator::AllocateChunk(intptr_t body_size,
    491                                             Executability executable,
    492                                             Space* owner) {
    493   size_t chunk_size;
    494   Heap* heap = isolate_->heap();
    495   Address base = NULL;
    496   VirtualMemory reservation;
    497   Address area_start = NULL;
    498   Address area_end = NULL;
    499   if (executable == EXECUTABLE) {
    500     chunk_size = RoundUp(CodePageAreaStartOffset() + body_size,
    501                          OS::CommitPageSize()) + CodePageGuardSize();
    502 
    503     // Check executable memory limit.
    504     if (size_executable_ + chunk_size > capacity_executable_) {
    505       LOG(isolate_,
    506           StringEvent("MemoryAllocator::AllocateRawMemory",
    507                       "V8 Executable Allocation capacity exceeded"));
    508       return NULL;
    509     }
    510 
    511     // Allocate executable memory either from code range or from the
    512     // OS.
    513     if (isolate_->code_range()->exists()) {
    514       base = isolate_->code_range()->AllocateRawMemory(chunk_size, &chunk_size);
    515       ASSERT(IsAligned(reinterpret_cast<intptr_t>(base),
    516                        MemoryChunk::kAlignment));
    517       if (base == NULL) return NULL;
    518       size_ += chunk_size;
    519       // Update executable memory size.
    520       size_executable_ += chunk_size;
    521     } else {
    522       base = AllocateAlignedMemory(chunk_size,
    523                                    MemoryChunk::kAlignment,
    524                                    executable,
    525                                    &reservation);
    526       if (base == NULL) return NULL;
    527       // Update executable memory size.
    528       size_executable_ += reservation.size();
    529     }
    530 
    531 #ifdef DEBUG
    532     ZapBlock(base, CodePageGuardStartOffset());
    533     ZapBlock(base + CodePageAreaStartOffset(), body_size);
    534 #endif
    535     area_start = base + CodePageAreaStartOffset();
    536     area_end = area_start + body_size;
    537   } else {
    538     chunk_size = MemoryChunk::kObjectStartOffset + body_size;
    539     base = AllocateAlignedMemory(chunk_size,
    540                                  MemoryChunk::kAlignment,
    541                                  executable,
    542                                  &reservation);
    543 
    544     if (base == NULL) return NULL;
    545 
    546 #ifdef DEBUG
    547     ZapBlock(base, chunk_size);
    548 #endif
    549 
    550     area_start = base + Page::kObjectStartOffset;
    551     area_end = base + chunk_size;
    552   }
    553 
    554   isolate_->counters()->memory_allocated()->
    555       Increment(static_cast<int>(chunk_size));
    556 
    557   LOG(isolate_, NewEvent("MemoryChunk", base, chunk_size));
    558   if (owner != NULL) {
    559     ObjectSpace space = static_cast<ObjectSpace>(1 << owner->identity());
    560     PerformAllocationCallback(space, kAllocationActionAllocate, chunk_size);
    561   }
    562 
    563   MemoryChunk* result = MemoryChunk::Initialize(heap,
    564                                                 base,
    565                                                 chunk_size,
    566                                                 area_start,
    567                                                 area_end,
    568                                                 executable,
    569                                                 owner);
    570   result->set_reserved_memory(&reservation);
    571   return result;
    572 }
    573 
    574 
    575 Page* MemoryAllocator::AllocatePage(PagedSpace* owner,
    576                                     Executability executable) {
    577   MemoryChunk* chunk = AllocateChunk(owner->AreaSize(),
    578                                      executable,
    579                                      owner);
    580 
    581   if (chunk == NULL) return NULL;
    582 
    583   return Page::Initialize(isolate_->heap(), chunk, executable, owner);
    584 }
    585 
    586 
    587 LargePage* MemoryAllocator::AllocateLargePage(intptr_t object_size,
    588                                               Executability executable,
    589                                               Space* owner) {
    590   MemoryChunk* chunk = AllocateChunk(object_size, executable, owner);
    591   if (chunk == NULL) return NULL;
    592   return LargePage::Initialize(isolate_->heap(), chunk);
    593 }
    594 
    595 
    596 void MemoryAllocator::Free(MemoryChunk* chunk) {
    597   LOG(isolate_, DeleteEvent("MemoryChunk", chunk));
    598   if (chunk->owner() != NULL) {
    599     ObjectSpace space =
    600         static_cast<ObjectSpace>(1 << chunk->owner()->identity());
    601     PerformAllocationCallback(space, kAllocationActionFree, chunk->size());
    602   }
    603 
    604   isolate_->heap()->RememberUnmappedPage(
    605       reinterpret_cast<Address>(chunk), chunk->IsEvacuationCandidate());
    606 
    607   delete chunk->slots_buffer();
    608   delete chunk->skip_list();
    609 
    610   VirtualMemory* reservation = chunk->reserved_memory();
    611   if (reservation->IsReserved()) {
    612     FreeMemory(reservation, chunk->executable());
    613   } else {
    614     FreeMemory(chunk->address(),
    615                chunk->size(),
    616                chunk->executable());
    617   }
    618 }
    619 
    620 
    621 bool MemoryAllocator::CommitBlock(Address start,
    622                                   size_t size,
    623                                   Executability executable) {
    624   if (!VirtualMemory::CommitRegion(start, size, executable)) return false;
    625 #ifdef DEBUG
    626   ZapBlock(start, size);
    627 #endif
    628   isolate_->counters()->memory_allocated()->Increment(static_cast<int>(size));
    629   return true;
    630 }
    631 
    632 
    633 bool MemoryAllocator::UncommitBlock(Address start, size_t size) {
    634   if (!VirtualMemory::UncommitRegion(start, size)) return false;
    635   isolate_->counters()->memory_allocated()->Decrement(static_cast<int>(size));
    636   return true;
    637 }
    638 
    639 
    640 void MemoryAllocator::ZapBlock(Address start, size_t size) {
    641   for (size_t s = 0; s + kPointerSize <= size; s += kPointerSize) {
    642     Memory::Address_at(start + s) = kZapValue;
    643   }
    644 }
    645 
    646 
    647 void MemoryAllocator::PerformAllocationCallback(ObjectSpace space,
    648                                                 AllocationAction action,
    649                                                 size_t size) {
    650   for (int i = 0; i < memory_allocation_callbacks_.length(); ++i) {
    651     MemoryAllocationCallbackRegistration registration =
    652       memory_allocation_callbacks_[i];
    653     if ((registration.space & space) == space &&
    654         (registration.action & action) == action)
    655       registration.callback(space, action, static_cast<int>(size));
    656   }
    657 }
    658 
    659 
    660 bool MemoryAllocator::MemoryAllocationCallbackRegistered(
    661     MemoryAllocationCallback callback) {
    662   for (int i = 0; i < memory_allocation_callbacks_.length(); ++i) {
    663     if (memory_allocation_callbacks_[i].callback == callback) return true;
    664   }
    665   return false;
    666 }
    667 
    668 
    669 void MemoryAllocator::AddMemoryAllocationCallback(
    670     MemoryAllocationCallback callback,
    671     ObjectSpace space,
    672     AllocationAction action) {
    673   ASSERT(callback != NULL);
    674   MemoryAllocationCallbackRegistration registration(callback, space, action);
    675   ASSERT(!MemoryAllocator::MemoryAllocationCallbackRegistered(callback));
    676   return memory_allocation_callbacks_.Add(registration);
    677 }
    678 
    679 
    680 void MemoryAllocator::RemoveMemoryAllocationCallback(
    681      MemoryAllocationCallback callback) {
    682   ASSERT(callback != NULL);
    683   for (int i = 0; i < memory_allocation_callbacks_.length(); ++i) {
    684     if (memory_allocation_callbacks_[i].callback == callback) {
    685       memory_allocation_callbacks_.Remove(i);
    686       return;
    687     }
    688   }
    689   UNREACHABLE();
    690 }
    691 
    692 
    693 #ifdef DEBUG
    694 void MemoryAllocator::ReportStatistics() {
    695   float pct = static_cast<float>(capacity_ - size_) / capacity_;
    696   PrintF("  capacity: %" V8_PTR_PREFIX "d"
    697              ", used: %" V8_PTR_PREFIX "d"
    698              ", available: %%%d\n\n",
    699          capacity_, size_, static_cast<int>(pct*100));
    700 }
    701 #endif
    702 
    703 
    704 int MemoryAllocator::CodePageGuardStartOffset() {
    705   // We are guarding code pages: the first OS page after the header
    706   // will be protected as non-writable.
    707   return RoundUp(Page::kObjectStartOffset, OS::CommitPageSize());
    708 }
    709 
    710 
    711 int MemoryAllocator::CodePageGuardSize() {
    712   return static_cast<int>(OS::CommitPageSize());
    713 }
    714 
    715 
    716 int MemoryAllocator::CodePageAreaStartOffset() {
    717   // We are guarding code pages: the first OS page after the header
    718   // will be protected as non-writable.
    719   return CodePageGuardStartOffset() + CodePageGuardSize();
    720 }
    721 
    722 
    723 int MemoryAllocator::CodePageAreaEndOffset() {
    724   // We are guarding code pages: the last OS page will be protected as
    725   // non-writable.
    726   return Page::kPageSize - static_cast<int>(OS::CommitPageSize());
    727 }
    728 
    729 
    730 bool MemoryAllocator::CommitCodePage(VirtualMemory* vm,
    731                                      Address start,
    732                                      size_t size) {
    733   // Commit page header (not executable).
    734   if (!vm->Commit(start,
    735                   CodePageGuardStartOffset(),
    736                   false)) {
    737     return false;
    738   }
    739 
    740   // Create guard page after the header.
    741   if (!vm->Guard(start + CodePageGuardStartOffset())) {
    742     return false;
    743   }
    744 
    745   // Commit page body (executable).
    746   size_t area_size = size - CodePageAreaStartOffset() - CodePageGuardSize();
    747   if (!vm->Commit(start + CodePageAreaStartOffset(),
    748                   area_size,
    749                   true)) {
    750     return false;
    751   }
    752 
    753   // Create guard page after the allocatable area.
    754   if (!vm->Guard(start + CodePageAreaStartOffset() + area_size)) {
    755     return false;
    756   }
    757 
    758   return true;
    759 }
    760 
    761 
    762 // -----------------------------------------------------------------------------
    763 // MemoryChunk implementation
    764 
    765 void MemoryChunk::IncrementLiveBytesFromMutator(Address address, int by) {
    766   MemoryChunk* chunk = MemoryChunk::FromAddress(address);
    767   if (!chunk->InNewSpace() && !static_cast<Page*>(chunk)->WasSwept()) {
    768     static_cast<PagedSpace*>(chunk->owner())->IncrementUnsweptFreeBytes(-by);
    769   }
    770   chunk->IncrementLiveBytes(by);
    771 }
    772 
    773 // -----------------------------------------------------------------------------
    774 // PagedSpace implementation
    775 
    776 PagedSpace::PagedSpace(Heap* heap,
    777                        intptr_t max_capacity,
    778                        AllocationSpace id,
    779                        Executability executable)
    780     : Space(heap, id, executable),
    781       free_list_(this),
    782       was_swept_conservatively_(false),
    783       first_unswept_page_(Page::FromAddress(NULL)),
    784       unswept_free_bytes_(0) {
    785   if (id == CODE_SPACE) {
    786     area_size_ = heap->isolate()->memory_allocator()->
    787         CodePageAreaSize();
    788   } else {
    789     area_size_ = Page::kPageSize - Page::kObjectStartOffset;
    790   }
    791   max_capacity_ = (RoundDown(max_capacity, Page::kPageSize) / Page::kPageSize)
    792       * AreaSize();
    793   accounting_stats_.Clear();
    794 
    795   allocation_info_.top = NULL;
    796   allocation_info_.limit = NULL;
    797 
    798   anchor_.InitializeAsAnchor(this);
    799 }
    800 
    801 
    802 bool PagedSpace::SetUp() {
    803   return true;
    804 }
    805 
    806 
    807 bool PagedSpace::HasBeenSetUp() {
    808   return true;
    809 }
    810 
    811 
    812 void PagedSpace::TearDown() {
    813   PageIterator iterator(this);
    814   while (iterator.has_next()) {
    815     heap()->isolate()->memory_allocator()->Free(iterator.next());
    816   }
    817   anchor_.set_next_page(&anchor_);
    818   anchor_.set_prev_page(&anchor_);
    819   accounting_stats_.Clear();
    820 }
    821 
    822 
    823 MaybeObject* PagedSpace::FindObject(Address addr) {
    824   // Note: this function can only be called on precisely swept spaces.
    825   ASSERT(!heap()->mark_compact_collector()->in_use());
    826 
    827   if (!Contains(addr)) return Failure::Exception();
    828 
    829   Page* p = Page::FromAddress(addr);
    830   HeapObjectIterator it(p, NULL);
    831   for (HeapObject* obj = it.Next(); obj != NULL; obj = it.Next()) {
    832     Address cur = obj->address();
    833     Address next = cur + obj->Size();
    834     if ((cur <= addr) && (addr < next)) return obj;
    835   }
    836 
    837   UNREACHABLE();
    838   return Failure::Exception();
    839 }
    840 
    841 bool PagedSpace::CanExpand() {
    842   ASSERT(max_capacity_ % AreaSize() == 0);
    843   ASSERT(Capacity() % AreaSize() == 0);
    844 
    845   if (Capacity() == max_capacity_) return false;
    846 
    847   ASSERT(Capacity() < max_capacity_);
    848 
    849   // Are we going to exceed capacity for this space?
    850   if ((Capacity() + Page::kPageSize) > max_capacity_) return false;
    851 
    852   return true;
    853 }
    854 
    855 bool PagedSpace::Expand() {
    856   if (!CanExpand()) return false;
    857 
    858   Page* p = heap()->isolate()->memory_allocator()->
    859       AllocatePage(this, executable());
    860   if (p == NULL) return false;
    861 
    862   ASSERT(Capacity() <= max_capacity_);
    863 
    864   p->InsertAfter(anchor_.prev_page());
    865 
    866   return true;
    867 }
    868 
    869 
    870 int PagedSpace::CountTotalPages() {
    871   PageIterator it(this);
    872   int count = 0;
    873   while (it.has_next()) {
    874     it.next();
    875     count++;
    876   }
    877   return count;
    878 }
    879 
    880 
    881 void PagedSpace::ReleasePage(Page* page) {
    882   ASSERT(page->LiveBytes() == 0);
    883   ASSERT(AreaSize() == page->area_size());
    884 
    885   // Adjust list of unswept pages if the page is the head of the list.
    886   if (first_unswept_page_ == page) {
    887     first_unswept_page_ = page->next_page();
    888     if (first_unswept_page_ == anchor()) {
    889       first_unswept_page_ = Page::FromAddress(NULL);
    890     }
    891   }
    892 
    893   if (page->WasSwept()) {
    894     intptr_t size = free_list_.EvictFreeListItems(page);
    895     accounting_stats_.AllocateBytes(size);
    896     ASSERT_EQ(AreaSize(), static_cast<int>(size));
    897   } else {
    898     DecreaseUnsweptFreeBytes(page);
    899   }
    900 
    901   if (Page::FromAllocationTop(allocation_info_.top) == page) {
    902     allocation_info_.top = allocation_info_.limit = NULL;
    903   }
    904 
    905   page->Unlink();
    906   if (page->IsFlagSet(MemoryChunk::CONTAINS_ONLY_DATA)) {
    907     heap()->isolate()->memory_allocator()->Free(page);
    908   } else {
    909     heap()->QueueMemoryChunkForFree(page);
    910   }
    911 
    912   ASSERT(Capacity() > 0);
    913   ASSERT(Capacity() % AreaSize() == 0);
    914   accounting_stats_.ShrinkSpace(AreaSize());
    915 }
    916 
    917 
    918 void PagedSpace::ReleaseAllUnusedPages() {
    919   PageIterator it(this);
    920   while (it.has_next()) {
    921     Page* page = it.next();
    922     if (!page->WasSwept()) {
    923       if (page->LiveBytes() == 0) ReleasePage(page);
    924     } else {
    925       HeapObject* obj = HeapObject::FromAddress(page->area_start());
    926       if (obj->IsFreeSpace() &&
    927           FreeSpace::cast(obj)->size() == AreaSize()) {
    928         // Sometimes we allocate memory from free list but don't
    929         // immediately initialize it (e.g. see PagedSpace::ReserveSpace
    930         // called from Heap::ReserveSpace that can cause GC before
    931         // reserved space is actually initialized).
    932         // Thus we can't simply assume that obj represents a valid
    933         // node still owned by a free list
    934         // Instead we should verify that the page is fully covered
    935         // by free list items.
    936         FreeList::SizeStats sizes;
    937         free_list_.CountFreeListItems(page, &sizes);
    938         if (sizes.Total() == AreaSize()) {
    939           ReleasePage(page);
    940         }
    941       }
    942     }
    943   }
    944   heap()->FreeQueuedChunks();
    945 }
    946 
    947 
    948 #ifdef DEBUG
    949 void PagedSpace::Print() { }
    950 #endif
    951 
    952 
    953 #ifdef DEBUG
    954 void PagedSpace::Verify(ObjectVisitor* visitor) {
    955   // We can only iterate over the pages if they were swept precisely.
    956   if (was_swept_conservatively_) return;
    957 
    958   bool allocation_pointer_found_in_space =
    959       (allocation_info_.top == allocation_info_.limit);
    960   PageIterator page_iterator(this);
    961   while (page_iterator.has_next()) {
    962     Page* page = page_iterator.next();
    963     ASSERT(page->owner() == this);
    964     if (page == Page::FromAllocationTop(allocation_info_.top)) {
    965       allocation_pointer_found_in_space = true;
    966     }
    967     ASSERT(page->WasSweptPrecisely());
    968     HeapObjectIterator it(page, NULL);
    969     Address end_of_previous_object = page->area_start();
    970     Address top = page->area_end();
    971     int black_size = 0;
    972     for (HeapObject* object = it.Next(); object != NULL; object = it.Next()) {
    973       ASSERT(end_of_previous_object <= object->address());
    974 
    975       // The first word should be a map, and we expect all map pointers to
    976       // be in map space.
    977       Map* map = object->map();
    978       ASSERT(map->IsMap());
    979       ASSERT(heap()->map_space()->Contains(map));
    980 
    981       // Perform space-specific object verification.
    982       VerifyObject(object);
    983 
    984       // The object itself should look OK.
    985       object->Verify();
    986 
    987       // All the interior pointers should be contained in the heap.
    988       int size = object->Size();
    989       object->IterateBody(map->instance_type(), size, visitor);
    990       if (Marking::IsBlack(Marking::MarkBitFrom(object))) {
    991         black_size += size;
    992       }
    993 
    994       ASSERT(object->address() + size <= top);
    995       end_of_previous_object = object->address() + size;
    996     }
    997     ASSERT_LE(black_size, page->LiveBytes());
    998   }
    999   ASSERT(allocation_pointer_found_in_space);
   1000 }
   1001 #endif
   1002 
   1003 
   1004 // -----------------------------------------------------------------------------
   1005 // NewSpace implementation
   1006 
   1007 
   1008 bool NewSpace::SetUp(int reserved_semispace_capacity,
   1009                      int maximum_semispace_capacity) {
   1010   // Set up new space based on the preallocated memory block defined by
   1011   // start and size. The provided space is divided into two semi-spaces.
   1012   // To support fast containment testing in the new space, the size of
   1013   // this chunk must be a power of two and it must be aligned to its size.
   1014   int initial_semispace_capacity = heap()->InitialSemiSpaceSize();
   1015 
   1016   size_t size = 2 * reserved_semispace_capacity;
   1017   Address base =
   1018       heap()->isolate()->memory_allocator()->ReserveAlignedMemory(
   1019           size, size, &reservation_);
   1020   if (base == NULL) return false;
   1021 
   1022   chunk_base_ = base;
   1023   chunk_size_ = static_cast<uintptr_t>(size);
   1024   LOG(heap()->isolate(), NewEvent("InitialChunk", chunk_base_, chunk_size_));
   1025 
   1026   ASSERT(initial_semispace_capacity <= maximum_semispace_capacity);
   1027   ASSERT(IsPowerOf2(maximum_semispace_capacity));
   1028 
   1029   // Allocate and set up the histogram arrays if necessary.
   1030   allocated_histogram_ = NewArray<HistogramInfo>(LAST_TYPE + 1);
   1031   promoted_histogram_ = NewArray<HistogramInfo>(LAST_TYPE + 1);
   1032 
   1033 #define SET_NAME(name) allocated_histogram_[name].set_name(#name); \
   1034                        promoted_histogram_[name].set_name(#name);
   1035   INSTANCE_TYPE_LIST(SET_NAME)
   1036 #undef SET_NAME
   1037 
   1038   ASSERT(reserved_semispace_capacity == heap()->ReservedSemiSpaceSize());
   1039   ASSERT(static_cast<intptr_t>(chunk_size_) >=
   1040          2 * heap()->ReservedSemiSpaceSize());
   1041   ASSERT(IsAddressAligned(chunk_base_, 2 * reserved_semispace_capacity, 0));
   1042 
   1043   to_space_.SetUp(chunk_base_,
   1044                   initial_semispace_capacity,
   1045                   maximum_semispace_capacity);
   1046   from_space_.SetUp(chunk_base_ + reserved_semispace_capacity,
   1047                     initial_semispace_capacity,
   1048                     maximum_semispace_capacity);
   1049   if (!to_space_.Commit()) {
   1050     return false;
   1051   }
   1052 
   1053   start_ = chunk_base_;
   1054   address_mask_ = ~(2 * reserved_semispace_capacity - 1);
   1055   object_mask_ = address_mask_ | kHeapObjectTagMask;
   1056   object_expected_ = reinterpret_cast<uintptr_t>(start_) | kHeapObjectTag;
   1057 
   1058   ResetAllocationInfo();
   1059 
   1060   return true;
   1061 }
   1062 
   1063 
   1064 void NewSpace::TearDown() {
   1065   if (allocated_histogram_) {
   1066     DeleteArray(allocated_histogram_);
   1067     allocated_histogram_ = NULL;
   1068   }
   1069   if (promoted_histogram_) {
   1070     DeleteArray(promoted_histogram_);
   1071     promoted_histogram_ = NULL;
   1072   }
   1073 
   1074   start_ = NULL;
   1075   allocation_info_.top = NULL;
   1076   allocation_info_.limit = NULL;
   1077 
   1078   to_space_.TearDown();
   1079   from_space_.TearDown();
   1080 
   1081   LOG(heap()->isolate(), DeleteEvent("InitialChunk", chunk_base_));
   1082 
   1083   ASSERT(reservation_.IsReserved());
   1084   heap()->isolate()->memory_allocator()->FreeMemory(&reservation_,
   1085                                                     NOT_EXECUTABLE);
   1086   chunk_base_ = NULL;
   1087   chunk_size_ = 0;
   1088 }
   1089 
   1090 
   1091 void NewSpace::Flip() {
   1092   SemiSpace::Swap(&from_space_, &to_space_);
   1093 }
   1094 
   1095 
   1096 void NewSpace::Grow() {
   1097   // Double the semispace size but only up to maximum capacity.
   1098   ASSERT(Capacity() < MaximumCapacity());
   1099   int new_capacity = Min(MaximumCapacity(), 2 * static_cast<int>(Capacity()));
   1100   if (to_space_.GrowTo(new_capacity)) {
   1101     // Only grow from space if we managed to grow to-space.
   1102     if (!from_space_.GrowTo(new_capacity)) {
   1103       // If we managed to grow to-space but couldn't grow from-space,
   1104       // attempt to shrink to-space.
   1105       if (!to_space_.ShrinkTo(from_space_.Capacity())) {
   1106         // We are in an inconsistent state because we could not
   1107         // commit/uncommit memory from new space.
   1108         V8::FatalProcessOutOfMemory("Failed to grow new space.");
   1109       }
   1110     }
   1111   }
   1112   ASSERT_SEMISPACE_ALLOCATION_INFO(allocation_info_, to_space_);
   1113 }
   1114 
   1115 
   1116 void NewSpace::Shrink() {
   1117   int new_capacity = Max(InitialCapacity(), 2 * SizeAsInt());
   1118   int rounded_new_capacity = RoundUp(new_capacity, Page::kPageSize);
   1119   if (rounded_new_capacity < Capacity() &&
   1120       to_space_.ShrinkTo(rounded_new_capacity))  {
   1121     // Only shrink from-space if we managed to shrink to-space.
   1122     from_space_.Reset();
   1123     if (!from_space_.ShrinkTo(rounded_new_capacity)) {
   1124       // If we managed to shrink to-space but couldn't shrink from
   1125       // space, attempt to grow to-space again.
   1126       if (!to_space_.GrowTo(from_space_.Capacity())) {
   1127         // We are in an inconsistent state because we could not
   1128         // commit/uncommit memory from new space.
   1129         V8::FatalProcessOutOfMemory("Failed to shrink new space.");
   1130       }
   1131     }
   1132   }
   1133   allocation_info_.limit = to_space_.page_high();
   1134   ASSERT_SEMISPACE_ALLOCATION_INFO(allocation_info_, to_space_);
   1135 }
   1136 
   1137 
   1138 void NewSpace::UpdateAllocationInfo() {
   1139   allocation_info_.top = to_space_.page_low();
   1140   allocation_info_.limit = to_space_.page_high();
   1141 
   1142   // Lower limit during incremental marking.
   1143   if (heap()->incremental_marking()->IsMarking() &&
   1144       inline_allocation_limit_step() != 0) {
   1145     Address new_limit =
   1146         allocation_info_.top + inline_allocation_limit_step();
   1147     allocation_info_.limit = Min(new_limit, allocation_info_.limit);
   1148   }
   1149   ASSERT_SEMISPACE_ALLOCATION_INFO(allocation_info_, to_space_);
   1150 }
   1151 
   1152 
   1153 void NewSpace::ResetAllocationInfo() {
   1154   to_space_.Reset();
   1155   UpdateAllocationInfo();
   1156   pages_used_ = 0;
   1157   // Clear all mark-bits in the to-space.
   1158   NewSpacePageIterator it(&to_space_);
   1159   while (it.has_next()) {
   1160     Bitmap::Clear(it.next());
   1161   }
   1162 }
   1163 
   1164 
   1165 bool NewSpace::AddFreshPage() {
   1166   Address top = allocation_info_.top;
   1167   if (NewSpacePage::IsAtStart(top)) {
   1168     // The current page is already empty. Don't try to make another.
   1169 
   1170     // We should only get here if someone asks to allocate more
   1171     // than what can be stored in a single page.
   1172     // TODO(gc): Change the limit on new-space allocation to prevent this
   1173     // from happening (all such allocations should go directly to LOSpace).
   1174     return false;
   1175   }
   1176   if (!to_space_.AdvancePage()) {
   1177     // Failed to get a new page in to-space.
   1178     return false;
   1179   }
   1180 
   1181   // Clear remainder of current page.
   1182   Address limit = NewSpacePage::FromLimit(top)->area_end();
   1183   if (heap()->gc_state() == Heap::SCAVENGE) {
   1184     heap()->promotion_queue()->SetNewLimit(limit);
   1185     heap()->promotion_queue()->ActivateGuardIfOnTheSamePage();
   1186   }
   1187 
   1188   int remaining_in_page = static_cast<int>(limit - top);
   1189   heap()->CreateFillerObjectAt(top, remaining_in_page);
   1190   pages_used_++;
   1191   UpdateAllocationInfo();
   1192 
   1193   return true;
   1194 }
   1195 
   1196 
   1197 MaybeObject* NewSpace::SlowAllocateRaw(int size_in_bytes) {
   1198   Address old_top = allocation_info_.top;
   1199   Address new_top = old_top + size_in_bytes;
   1200   Address high = to_space_.page_high();
   1201   if (allocation_info_.limit < high) {
   1202     // Incremental marking has lowered the limit to get a
   1203     // chance to do a step.
   1204     allocation_info_.limit = Min(
   1205         allocation_info_.limit + inline_allocation_limit_step_,
   1206         high);
   1207     int bytes_allocated = static_cast<int>(new_top - top_on_previous_step_);
   1208     heap()->incremental_marking()->Step(
   1209         bytes_allocated, IncrementalMarking::GC_VIA_STACK_GUARD);
   1210     top_on_previous_step_ = new_top;
   1211     return AllocateRaw(size_in_bytes);
   1212   } else if (AddFreshPage()) {
   1213     // Switched to new page. Try allocating again.
   1214     int bytes_allocated = static_cast<int>(old_top - top_on_previous_step_);
   1215     heap()->incremental_marking()->Step(
   1216         bytes_allocated, IncrementalMarking::GC_VIA_STACK_GUARD);
   1217     top_on_previous_step_ = to_space_.page_low();
   1218     return AllocateRaw(size_in_bytes);
   1219   } else {
   1220     return Failure::RetryAfterGC();
   1221   }
   1222 }
   1223 
   1224 
   1225 #ifdef DEBUG
   1226 // We do not use the SemiSpaceIterator because verification doesn't assume
   1227 // that it works (it depends on the invariants we are checking).
   1228 void NewSpace::Verify() {
   1229   // The allocation pointer should be in the space or at the very end.
   1230   ASSERT_SEMISPACE_ALLOCATION_INFO(allocation_info_, to_space_);
   1231 
   1232   // There should be objects packed in from the low address up to the
   1233   // allocation pointer.
   1234   Address current = to_space_.first_page()->area_start();
   1235   CHECK_EQ(current, to_space_.space_start());
   1236 
   1237   while (current != top()) {
   1238     if (!NewSpacePage::IsAtEnd(current)) {
   1239       // The allocation pointer should not be in the middle of an object.
   1240       CHECK(!NewSpacePage::FromLimit(current)->ContainsLimit(top()) ||
   1241             current < top());
   1242 
   1243       HeapObject* object = HeapObject::FromAddress(current);
   1244 
   1245       // The first word should be a map, and we expect all map pointers to
   1246       // be in map space.
   1247       Map* map = object->map();
   1248       CHECK(map->IsMap());
   1249       CHECK(heap()->map_space()->Contains(map));
   1250 
   1251       // The object should not be code or a map.
   1252       CHECK(!object->IsMap());
   1253       CHECK(!object->IsCode());
   1254 
   1255       // The object itself should look OK.
   1256       object->Verify();
   1257 
   1258       // All the interior pointers should be contained in the heap.
   1259       VerifyPointersVisitor visitor;
   1260       int size = object->Size();
   1261       object->IterateBody(map->instance_type(), size, &visitor);
   1262 
   1263       current += size;
   1264     } else {
   1265       // At end of page, switch to next page.
   1266       NewSpacePage* page = NewSpacePage::FromLimit(current)->next_page();
   1267       // Next page should be valid.
   1268       CHECK(!page->is_anchor());
   1269       current = page->area_start();
   1270     }
   1271   }
   1272 
   1273   // Check semi-spaces.
   1274   ASSERT_EQ(from_space_.id(), kFromSpace);
   1275   ASSERT_EQ(to_space_.id(), kToSpace);
   1276   from_space_.Verify();
   1277   to_space_.Verify();
   1278 }
   1279 #endif
   1280 
   1281 // -----------------------------------------------------------------------------
   1282 // SemiSpace implementation
   1283 
   1284 void SemiSpace::SetUp(Address start,
   1285                       int initial_capacity,
   1286                       int maximum_capacity) {
   1287   // Creates a space in the young generation. The constructor does not
   1288   // allocate memory from the OS.  A SemiSpace is given a contiguous chunk of
   1289   // memory of size 'capacity' when set up, and does not grow or shrink
   1290   // otherwise.  In the mark-compact collector, the memory region of the from
   1291   // space is used as the marking stack. It requires contiguous memory
   1292   // addresses.
   1293   ASSERT(maximum_capacity >= Page::kPageSize);
   1294   initial_capacity_ = RoundDown(initial_capacity, Page::kPageSize);
   1295   capacity_ = initial_capacity;
   1296   maximum_capacity_ = RoundDown(maximum_capacity, Page::kPageSize);
   1297   committed_ = false;
   1298   start_ = start;
   1299   address_mask_ = ~(maximum_capacity - 1);
   1300   object_mask_ = address_mask_ | kHeapObjectTagMask;
   1301   object_expected_ = reinterpret_cast<uintptr_t>(start) | kHeapObjectTag;
   1302   age_mark_ = start_;
   1303 }
   1304 
   1305 
   1306 void SemiSpace::TearDown() {
   1307   start_ = NULL;
   1308   capacity_ = 0;
   1309 }
   1310 
   1311 
   1312 bool SemiSpace::Commit() {
   1313   ASSERT(!is_committed());
   1314   int pages = capacity_ / Page::kPageSize;
   1315   Address end = start_ + maximum_capacity_;
   1316   Address start = end - pages * Page::kPageSize;
   1317   if (!heap()->isolate()->memory_allocator()->CommitBlock(start,
   1318                                                           capacity_,
   1319                                                           executable())) {
   1320     return false;
   1321   }
   1322 
   1323   NewSpacePage* page = anchor();
   1324   for (int i = 1; i <= pages; i++) {
   1325     NewSpacePage* new_page =
   1326       NewSpacePage::Initialize(heap(), end - i * Page::kPageSize, this);
   1327     new_page->InsertAfter(page);
   1328     page = new_page;
   1329   }
   1330 
   1331   committed_ = true;
   1332   Reset();
   1333   return true;
   1334 }
   1335 
   1336 
   1337 bool SemiSpace::Uncommit() {
   1338   ASSERT(is_committed());
   1339   Address start = start_ + maximum_capacity_ - capacity_;
   1340   if (!heap()->isolate()->memory_allocator()->UncommitBlock(start, capacity_)) {
   1341     return false;
   1342   }
   1343   anchor()->set_next_page(anchor());
   1344   anchor()->set_prev_page(anchor());
   1345 
   1346   committed_ = false;
   1347   return true;
   1348 }
   1349 
   1350 
   1351 bool SemiSpace::GrowTo(int new_capacity) {
   1352   if (!is_committed()) {
   1353     if (!Commit()) return false;
   1354   }
   1355   ASSERT((new_capacity & Page::kPageAlignmentMask) == 0);
   1356   ASSERT(new_capacity <= maximum_capacity_);
   1357   ASSERT(new_capacity > capacity_);
   1358   int pages_before = capacity_ / Page::kPageSize;
   1359   int pages_after = new_capacity / Page::kPageSize;
   1360 
   1361   Address end = start_ + maximum_capacity_;
   1362   Address start = end - new_capacity;
   1363   size_t delta = new_capacity - capacity_;
   1364 
   1365   ASSERT(IsAligned(delta, OS::AllocateAlignment()));
   1366   if (!heap()->isolate()->memory_allocator()->CommitBlock(
   1367       start, delta, executable())) {
   1368     return false;
   1369   }
   1370   capacity_ = new_capacity;
   1371   NewSpacePage* last_page = anchor()->prev_page();
   1372   ASSERT(last_page != anchor());
   1373   for (int i = pages_before + 1; i <= pages_after; i++) {
   1374     Address page_address = end - i * Page::kPageSize;
   1375     NewSpacePage* new_page = NewSpacePage::Initialize(heap(),
   1376                                                       page_address,
   1377                                                       this);
   1378     new_page->InsertAfter(last_page);
   1379     Bitmap::Clear(new_page);
   1380     // Duplicate the flags that was set on the old page.
   1381     new_page->SetFlags(last_page->GetFlags(),
   1382                        NewSpacePage::kCopyOnFlipFlagsMask);
   1383     last_page = new_page;
   1384   }
   1385   return true;
   1386 }
   1387 
   1388 
   1389 bool SemiSpace::ShrinkTo(int new_capacity) {
   1390   ASSERT((new_capacity & Page::kPageAlignmentMask) == 0);
   1391   ASSERT(new_capacity >= initial_capacity_);
   1392   ASSERT(new_capacity < capacity_);
   1393   if (is_committed()) {
   1394     // Semispaces grow backwards from the end of their allocated capacity,
   1395     // so we find the before and after start addresses relative to the
   1396     // end of the space.
   1397     Address space_end = start_ + maximum_capacity_;
   1398     Address old_start = space_end - capacity_;
   1399     size_t delta = capacity_ - new_capacity;
   1400     ASSERT(IsAligned(delta, OS::AllocateAlignment()));
   1401 
   1402     MemoryAllocator* allocator = heap()->isolate()->memory_allocator();
   1403     if (!allocator->UncommitBlock(old_start, delta)) {
   1404       return false;
   1405     }
   1406 
   1407     int pages_after = new_capacity / Page::kPageSize;
   1408     NewSpacePage* new_last_page =
   1409         NewSpacePage::FromAddress(space_end - pages_after * Page::kPageSize);
   1410     new_last_page->set_next_page(anchor());
   1411     anchor()->set_prev_page(new_last_page);
   1412     ASSERT((current_page_ <= first_page()) && (current_page_ >= new_last_page));
   1413   }
   1414 
   1415   capacity_ = new_capacity;
   1416 
   1417   return true;
   1418 }
   1419 
   1420 
   1421 void SemiSpace::FlipPages(intptr_t flags, intptr_t mask) {
   1422   anchor_.set_owner(this);
   1423   // Fixup back-pointers to anchor. Address of anchor changes
   1424   // when we swap.
   1425   anchor_.prev_page()->set_next_page(&anchor_);
   1426   anchor_.next_page()->set_prev_page(&anchor_);
   1427 
   1428   bool becomes_to_space = (id_ == kFromSpace);
   1429   id_ = becomes_to_space ? kToSpace : kFromSpace;
   1430   NewSpacePage* page = anchor_.next_page();
   1431   while (page != &anchor_) {
   1432     page->set_owner(this);
   1433     page->SetFlags(flags, mask);
   1434     if (becomes_to_space) {
   1435       page->ClearFlag(MemoryChunk::IN_FROM_SPACE);
   1436       page->SetFlag(MemoryChunk::IN_TO_SPACE);
   1437       page->ClearFlag(MemoryChunk::NEW_SPACE_BELOW_AGE_MARK);
   1438       page->ResetLiveBytes();
   1439     } else {
   1440       page->SetFlag(MemoryChunk::IN_FROM_SPACE);
   1441       page->ClearFlag(MemoryChunk::IN_TO_SPACE);
   1442     }
   1443     ASSERT(page->IsFlagSet(MemoryChunk::SCAN_ON_SCAVENGE));
   1444     ASSERT(page->IsFlagSet(MemoryChunk::IN_TO_SPACE) ||
   1445            page->IsFlagSet(MemoryChunk::IN_FROM_SPACE));
   1446     page = page->next_page();
   1447   }
   1448 }
   1449 
   1450 
   1451 void SemiSpace::Reset() {
   1452   ASSERT(anchor_.next_page() != &anchor_);
   1453   current_page_ = anchor_.next_page();
   1454 }
   1455 
   1456 
   1457 void SemiSpace::Swap(SemiSpace* from, SemiSpace* to) {
   1458   // We won't be swapping semispaces without data in them.
   1459   ASSERT(from->anchor_.next_page() != &from->anchor_);
   1460   ASSERT(to->anchor_.next_page() != &to->anchor_);
   1461 
   1462   // Swap bits.
   1463   SemiSpace tmp = *from;
   1464   *from = *to;
   1465   *to = tmp;
   1466 
   1467   // Fixup back-pointers to the page list anchor now that its address
   1468   // has changed.
   1469   // Swap to/from-space bits on pages.
   1470   // Copy GC flags from old active space (from-space) to new (to-space).
   1471   intptr_t flags = from->current_page()->GetFlags();
   1472   to->FlipPages(flags, NewSpacePage::kCopyOnFlipFlagsMask);
   1473 
   1474   from->FlipPages(0, 0);
   1475 }
   1476 
   1477 
   1478 void SemiSpace::set_age_mark(Address mark) {
   1479   ASSERT(NewSpacePage::FromLimit(mark)->semi_space() == this);
   1480   age_mark_ = mark;
   1481   // Mark all pages up to the one containing mark.
   1482   NewSpacePageIterator it(space_start(), mark);
   1483   while (it.has_next()) {
   1484     it.next()->SetFlag(MemoryChunk::NEW_SPACE_BELOW_AGE_MARK);
   1485   }
   1486 }
   1487 
   1488 
   1489 #ifdef DEBUG
   1490 void SemiSpace::Print() { }
   1491 
   1492 
   1493 void SemiSpace::Verify() {
   1494   bool is_from_space = (id_ == kFromSpace);
   1495   NewSpacePage* page = anchor_.next_page();
   1496   CHECK(anchor_.semi_space() == this);
   1497   while (page != &anchor_) {
   1498     CHECK(page->semi_space() == this);
   1499     CHECK(page->InNewSpace());
   1500     CHECK(page->IsFlagSet(is_from_space ? MemoryChunk::IN_FROM_SPACE
   1501                                         : MemoryChunk::IN_TO_SPACE));
   1502     CHECK(!page->IsFlagSet(is_from_space ? MemoryChunk::IN_TO_SPACE
   1503                                          : MemoryChunk::IN_FROM_SPACE));
   1504     CHECK(page->IsFlagSet(MemoryChunk::POINTERS_TO_HERE_ARE_INTERESTING));
   1505     if (!is_from_space) {
   1506       // The pointers-from-here-are-interesting flag isn't updated dynamically
   1507       // on from-space pages, so it might be out of sync with the marking state.
   1508       if (page->heap()->incremental_marking()->IsMarking()) {
   1509         CHECK(page->IsFlagSet(MemoryChunk::POINTERS_FROM_HERE_ARE_INTERESTING));
   1510       } else {
   1511         CHECK(!page->IsFlagSet(
   1512             MemoryChunk::POINTERS_FROM_HERE_ARE_INTERESTING));
   1513       }
   1514       // TODO(gc): Check that the live_bytes_count_ field matches the
   1515       // black marking on the page (if we make it match in new-space).
   1516     }
   1517     CHECK(page->IsFlagSet(MemoryChunk::SCAN_ON_SCAVENGE));
   1518     CHECK(page->prev_page()->next_page() == page);
   1519     page = page->next_page();
   1520   }
   1521 }
   1522 
   1523 
   1524 void SemiSpace::AssertValidRange(Address start, Address end) {
   1525   // Addresses belong to same semi-space
   1526   NewSpacePage* page = NewSpacePage::FromLimit(start);
   1527   NewSpacePage* end_page = NewSpacePage::FromLimit(end);
   1528   SemiSpace* space = page->semi_space();
   1529   CHECK_EQ(space, end_page->semi_space());
   1530   // Start address is before end address, either on same page,
   1531   // or end address is on a later page in the linked list of
   1532   // semi-space pages.
   1533   if (page == end_page) {
   1534     CHECK(start <= end);
   1535   } else {
   1536     while (page != end_page) {
   1537       page = page->next_page();
   1538       CHECK_NE(page, space->anchor());
   1539     }
   1540   }
   1541 }
   1542 #endif
   1543 
   1544 
   1545 // -----------------------------------------------------------------------------
   1546 // SemiSpaceIterator implementation.
   1547 SemiSpaceIterator::SemiSpaceIterator(NewSpace* space) {
   1548   Initialize(space->bottom(), space->top(), NULL);
   1549 }
   1550 
   1551 
   1552 SemiSpaceIterator::SemiSpaceIterator(NewSpace* space,
   1553                                      HeapObjectCallback size_func) {
   1554   Initialize(space->bottom(), space->top(), size_func);
   1555 }
   1556 
   1557 
   1558 SemiSpaceIterator::SemiSpaceIterator(NewSpace* space, Address start) {
   1559   Initialize(start, space->top(), NULL);
   1560 }
   1561 
   1562 
   1563 SemiSpaceIterator::SemiSpaceIterator(Address from, Address to) {
   1564   Initialize(from, to, NULL);
   1565 }
   1566 
   1567 
   1568 void SemiSpaceIterator::Initialize(Address start,
   1569                                    Address end,
   1570                                    HeapObjectCallback size_func) {
   1571   SemiSpace::AssertValidRange(start, end);
   1572   current_ = start;
   1573   limit_ = end;
   1574   size_func_ = size_func;
   1575 }
   1576 
   1577 
   1578 #ifdef DEBUG
   1579 // heap_histograms is shared, always clear it before using it.
   1580 static void ClearHistograms() {
   1581   Isolate* isolate = Isolate::Current();
   1582   // We reset the name each time, though it hasn't changed.
   1583 #define DEF_TYPE_NAME(name) isolate->heap_histograms()[name].set_name(#name);
   1584   INSTANCE_TYPE_LIST(DEF_TYPE_NAME)
   1585 #undef DEF_TYPE_NAME
   1586 
   1587 #define CLEAR_HISTOGRAM(name) isolate->heap_histograms()[name].clear();
   1588   INSTANCE_TYPE_LIST(CLEAR_HISTOGRAM)
   1589 #undef CLEAR_HISTOGRAM
   1590 
   1591   isolate->js_spill_information()->Clear();
   1592 }
   1593 
   1594 
   1595 static void ClearCodeKindStatistics() {
   1596   Isolate* isolate = Isolate::Current();
   1597   for (int i = 0; i < Code::NUMBER_OF_KINDS; i++) {
   1598     isolate->code_kind_statistics()[i] = 0;
   1599   }
   1600 }
   1601 
   1602 
   1603 static void ReportCodeKindStatistics() {
   1604   Isolate* isolate = Isolate::Current();
   1605   const char* table[Code::NUMBER_OF_KINDS] = { NULL };
   1606 
   1607 #define CASE(name)                            \
   1608   case Code::name: table[Code::name] = #name; \
   1609   break
   1610 
   1611   for (int i = 0; i < Code::NUMBER_OF_KINDS; i++) {
   1612     switch (static_cast<Code::Kind>(i)) {
   1613       CASE(FUNCTION);
   1614       CASE(OPTIMIZED_FUNCTION);
   1615       CASE(STUB);
   1616       CASE(BUILTIN);
   1617       CASE(LOAD_IC);
   1618       CASE(KEYED_LOAD_IC);
   1619       CASE(STORE_IC);
   1620       CASE(KEYED_STORE_IC);
   1621       CASE(CALL_IC);
   1622       CASE(KEYED_CALL_IC);
   1623       CASE(UNARY_OP_IC);
   1624       CASE(BINARY_OP_IC);
   1625       CASE(COMPARE_IC);
   1626       CASE(TO_BOOLEAN_IC);
   1627     }
   1628   }
   1629 
   1630 #undef CASE
   1631 
   1632   PrintF("\n   Code kind histograms: \n");
   1633   for (int i = 0; i < Code::NUMBER_OF_KINDS; i++) {
   1634     if (isolate->code_kind_statistics()[i] > 0) {
   1635       PrintF("     %-20s: %10d bytes\n", table[i],
   1636           isolate->code_kind_statistics()[i]);
   1637     }
   1638   }
   1639   PrintF("\n");
   1640 }
   1641 
   1642 
   1643 static int CollectHistogramInfo(HeapObject* obj) {
   1644   Isolate* isolate = Isolate::Current();
   1645   InstanceType type = obj->map()->instance_type();
   1646   ASSERT(0 <= type && type <= LAST_TYPE);
   1647   ASSERT(isolate->heap_histograms()[type].name() != NULL);
   1648   isolate->heap_histograms()[type].increment_number(1);
   1649   isolate->heap_histograms()[type].increment_bytes(obj->Size());
   1650 
   1651   if (FLAG_collect_heap_spill_statistics && obj->IsJSObject()) {
   1652     JSObject::cast(obj)->IncrementSpillStatistics(
   1653         isolate->js_spill_information());
   1654   }
   1655 
   1656   return obj->Size();
   1657 }
   1658 
   1659 
   1660 static void ReportHistogram(bool print_spill) {
   1661   Isolate* isolate = Isolate::Current();
   1662   PrintF("\n  Object Histogram:\n");
   1663   for (int i = 0; i <= LAST_TYPE; i++) {
   1664     if (isolate->heap_histograms()[i].number() > 0) {
   1665       PrintF("    %-34s%10d (%10d bytes)\n",
   1666              isolate->heap_histograms()[i].name(),
   1667              isolate->heap_histograms()[i].number(),
   1668              isolate->heap_histograms()[i].bytes());
   1669     }
   1670   }
   1671   PrintF("\n");
   1672 
   1673   // Summarize string types.
   1674   int string_number = 0;
   1675   int string_bytes = 0;
   1676 #define INCREMENT(type, size, name, camel_name)      \
   1677     string_number += isolate->heap_histograms()[type].number(); \
   1678     string_bytes += isolate->heap_histograms()[type].bytes();
   1679   STRING_TYPE_LIST(INCREMENT)
   1680 #undef INCREMENT
   1681   if (string_number > 0) {
   1682     PrintF("    %-34s%10d (%10d bytes)\n\n", "STRING_TYPE", string_number,
   1683            string_bytes);
   1684   }
   1685 
   1686   if (FLAG_collect_heap_spill_statistics && print_spill) {
   1687     isolate->js_spill_information()->Print();
   1688   }
   1689 }
   1690 #endif  // DEBUG
   1691 
   1692 
   1693 // Support for statistics gathering for --heap-stats and --log-gc.
   1694 void NewSpace::ClearHistograms() {
   1695   for (int i = 0; i <= LAST_TYPE; i++) {
   1696     allocated_histogram_[i].clear();
   1697     promoted_histogram_[i].clear();
   1698   }
   1699 }
   1700 
   1701 // Because the copying collector does not touch garbage objects, we iterate
   1702 // the new space before a collection to get a histogram of allocated objects.
   1703 // This only happens when --log-gc flag is set.
   1704 void NewSpace::CollectStatistics() {
   1705   ClearHistograms();
   1706   SemiSpaceIterator it(this);
   1707   for (HeapObject* obj = it.Next(); obj != NULL; obj = it.Next())
   1708     RecordAllocation(obj);
   1709 }
   1710 
   1711 
   1712 static void DoReportStatistics(Isolate* isolate,
   1713                                HistogramInfo* info, const char* description) {
   1714   LOG(isolate, HeapSampleBeginEvent("NewSpace", description));
   1715   // Lump all the string types together.
   1716   int string_number = 0;
   1717   int string_bytes = 0;
   1718 #define INCREMENT(type, size, name, camel_name)       \
   1719     string_number += info[type].number();             \
   1720     string_bytes += info[type].bytes();
   1721   STRING_TYPE_LIST(INCREMENT)
   1722 #undef INCREMENT
   1723   if (string_number > 0) {
   1724     LOG(isolate,
   1725         HeapSampleItemEvent("STRING_TYPE", string_number, string_bytes));
   1726   }
   1727 
   1728   // Then do the other types.
   1729   for (int i = FIRST_NONSTRING_TYPE; i <= LAST_TYPE; ++i) {
   1730     if (info[i].number() > 0) {
   1731       LOG(isolate,
   1732           HeapSampleItemEvent(info[i].name(), info[i].number(),
   1733                               info[i].bytes()));
   1734     }
   1735   }
   1736   LOG(isolate, HeapSampleEndEvent("NewSpace", description));
   1737 }
   1738 
   1739 
   1740 void NewSpace::ReportStatistics() {
   1741 #ifdef DEBUG
   1742   if (FLAG_heap_stats) {
   1743     float pct = static_cast<float>(Available()) / Capacity();
   1744     PrintF("  capacity: %" V8_PTR_PREFIX "d"
   1745                ", available: %" V8_PTR_PREFIX "d, %%%d\n",
   1746            Capacity(), Available(), static_cast<int>(pct*100));
   1747     PrintF("\n  Object Histogram:\n");
   1748     for (int i = 0; i <= LAST_TYPE; i++) {
   1749       if (allocated_histogram_[i].number() > 0) {
   1750         PrintF("    %-34s%10d (%10d bytes)\n",
   1751                allocated_histogram_[i].name(),
   1752                allocated_histogram_[i].number(),
   1753                allocated_histogram_[i].bytes());
   1754       }
   1755     }
   1756     PrintF("\n");
   1757   }
   1758 #endif  // DEBUG
   1759 
   1760   if (FLAG_log_gc) {
   1761     Isolate* isolate = ISOLATE;
   1762     DoReportStatistics(isolate, allocated_histogram_, "allocated");
   1763     DoReportStatistics(isolate, promoted_histogram_, "promoted");
   1764   }
   1765 }
   1766 
   1767 
   1768 void NewSpace::RecordAllocation(HeapObject* obj) {
   1769   InstanceType type = obj->map()->instance_type();
   1770   ASSERT(0 <= type && type <= LAST_TYPE);
   1771   allocated_histogram_[type].increment_number(1);
   1772   allocated_histogram_[type].increment_bytes(obj->Size());
   1773 }
   1774 
   1775 
   1776 void NewSpace::RecordPromotion(HeapObject* obj) {
   1777   InstanceType type = obj->map()->instance_type();
   1778   ASSERT(0 <= type && type <= LAST_TYPE);
   1779   promoted_histogram_[type].increment_number(1);
   1780   promoted_histogram_[type].increment_bytes(obj->Size());
   1781 }
   1782 
   1783 // -----------------------------------------------------------------------------
   1784 // Free lists for old object spaces implementation
   1785 
   1786 void FreeListNode::set_size(Heap* heap, int size_in_bytes) {
   1787   ASSERT(size_in_bytes > 0);
   1788   ASSERT(IsAligned(size_in_bytes, kPointerSize));
   1789 
   1790   // We write a map and possibly size information to the block.  If the block
   1791   // is big enough to be a FreeSpace with at least one extra word (the next
   1792   // pointer), we set its map to be the free space map and its size to an
   1793   // appropriate array length for the desired size from HeapObject::Size().
   1794   // If the block is too small (eg, one or two words), to hold both a size
   1795   // field and a next pointer, we give it a filler map that gives it the
   1796   // correct size.
   1797   if (size_in_bytes > FreeSpace::kHeaderSize) {
   1798     set_map_no_write_barrier(heap->raw_unchecked_free_space_map());
   1799     // Can't use FreeSpace::cast because it fails during deserialization.
   1800     FreeSpace* this_as_free_space = reinterpret_cast<FreeSpace*>(this);
   1801     this_as_free_space->set_size(size_in_bytes);
   1802   } else if (size_in_bytes == kPointerSize) {
   1803     set_map_no_write_barrier(heap->raw_unchecked_one_pointer_filler_map());
   1804   } else if (size_in_bytes == 2 * kPointerSize) {
   1805     set_map_no_write_barrier(heap->raw_unchecked_two_pointer_filler_map());
   1806   } else {
   1807     UNREACHABLE();
   1808   }
   1809   // We would like to ASSERT(Size() == size_in_bytes) but this would fail during
   1810   // deserialization because the free space map is not done yet.
   1811 }
   1812 
   1813 
   1814 FreeListNode* FreeListNode::next() {
   1815   ASSERT(IsFreeListNode(this));
   1816   if (map() == HEAP->raw_unchecked_free_space_map()) {
   1817     ASSERT(map() == NULL || Size() >= kNextOffset + kPointerSize);
   1818     return reinterpret_cast<FreeListNode*>(
   1819         Memory::Address_at(address() + kNextOffset));
   1820   } else {
   1821     return reinterpret_cast<FreeListNode*>(
   1822         Memory::Address_at(address() + kPointerSize));
   1823   }
   1824 }
   1825 
   1826 
   1827 FreeListNode** FreeListNode::next_address() {
   1828   ASSERT(IsFreeListNode(this));
   1829   if (map() == HEAP->raw_unchecked_free_space_map()) {
   1830     ASSERT(Size() >= kNextOffset + kPointerSize);
   1831     return reinterpret_cast<FreeListNode**>(address() + kNextOffset);
   1832   } else {
   1833     return reinterpret_cast<FreeListNode**>(address() + kPointerSize);
   1834   }
   1835 }
   1836 
   1837 
   1838 void FreeListNode::set_next(FreeListNode* next) {
   1839   ASSERT(IsFreeListNode(this));
   1840   // While we are booting the VM the free space map will actually be null.  So
   1841   // we have to make sure that we don't try to use it for anything at that
   1842   // stage.
   1843   if (map() == HEAP->raw_unchecked_free_space_map()) {
   1844     ASSERT(map() == NULL || Size() >= kNextOffset + kPointerSize);
   1845     Memory::Address_at(address() + kNextOffset) =
   1846         reinterpret_cast<Address>(next);
   1847   } else {
   1848     Memory::Address_at(address() + kPointerSize) =
   1849         reinterpret_cast<Address>(next);
   1850   }
   1851 }
   1852 
   1853 
   1854 FreeList::FreeList(PagedSpace* owner)
   1855     : owner_(owner), heap_(owner->heap()) {
   1856   Reset();
   1857 }
   1858 
   1859 
   1860 void FreeList::Reset() {
   1861   available_ = 0;
   1862   small_list_ = NULL;
   1863   medium_list_ = NULL;
   1864   large_list_ = NULL;
   1865   huge_list_ = NULL;
   1866 }
   1867 
   1868 
   1869 int FreeList::Free(Address start, int size_in_bytes) {
   1870   if (size_in_bytes == 0) return 0;
   1871   FreeListNode* node = FreeListNode::FromAddress(start);
   1872   node->set_size(heap_, size_in_bytes);
   1873 
   1874   // Early return to drop too-small blocks on the floor.
   1875   if (size_in_bytes < kSmallListMin) return size_in_bytes;
   1876 
   1877   // Insert other blocks at the head of a free list of the appropriate
   1878   // magnitude.
   1879   if (size_in_bytes <= kSmallListMax) {
   1880     node->set_next(small_list_);
   1881     small_list_ = node;
   1882   } else if (size_in_bytes <= kMediumListMax) {
   1883     node->set_next(medium_list_);
   1884     medium_list_ = node;
   1885   } else if (size_in_bytes <= kLargeListMax) {
   1886     node->set_next(large_list_);
   1887     large_list_ = node;
   1888   } else {
   1889     node->set_next(huge_list_);
   1890     huge_list_ = node;
   1891   }
   1892   available_ += size_in_bytes;
   1893   ASSERT(IsVeryLong() || available_ == SumFreeLists());
   1894   return 0;
   1895 }
   1896 
   1897 
   1898 FreeListNode* FreeList::PickNodeFromList(FreeListNode** list, int* node_size) {
   1899   FreeListNode* node = *list;
   1900 
   1901   if (node == NULL) return NULL;
   1902 
   1903   while (node != NULL &&
   1904          Page::FromAddress(node->address())->IsEvacuationCandidate()) {
   1905     available_ -= node->Size();
   1906     node = node->next();
   1907   }
   1908 
   1909   if (node != NULL) {
   1910     *node_size = node->Size();
   1911     *list = node->next();
   1912   } else {
   1913     *list = NULL;
   1914   }
   1915 
   1916   return node;
   1917 }
   1918 
   1919 
   1920 FreeListNode* FreeList::FindNodeFor(int size_in_bytes, int* node_size) {
   1921   FreeListNode* node = NULL;
   1922 
   1923   if (size_in_bytes <= kSmallAllocationMax) {
   1924     node = PickNodeFromList(&small_list_, node_size);
   1925     if (node != NULL) return node;
   1926   }
   1927 
   1928   if (size_in_bytes <= kMediumAllocationMax) {
   1929     node = PickNodeFromList(&medium_list_, node_size);
   1930     if (node != NULL) return node;
   1931   }
   1932 
   1933   if (size_in_bytes <= kLargeAllocationMax) {
   1934     node = PickNodeFromList(&large_list_, node_size);
   1935     if (node != NULL) return node;
   1936   }
   1937 
   1938   for (FreeListNode** cur = &huge_list_;
   1939        *cur != NULL;
   1940        cur = (*cur)->next_address()) {
   1941     FreeListNode* cur_node = *cur;
   1942     while (cur_node != NULL &&
   1943            Page::FromAddress(cur_node->address())->IsEvacuationCandidate()) {
   1944       available_ -= reinterpret_cast<FreeSpace*>(cur_node)->Size();
   1945       cur_node = cur_node->next();
   1946     }
   1947 
   1948     *cur = cur_node;
   1949     if (cur_node == NULL) break;
   1950 
   1951     ASSERT((*cur)->map() == HEAP->raw_unchecked_free_space_map());
   1952     FreeSpace* cur_as_free_space = reinterpret_cast<FreeSpace*>(*cur);
   1953     int size = cur_as_free_space->Size();
   1954     if (size >= size_in_bytes) {
   1955       // Large enough node found.  Unlink it from the list.
   1956       node = *cur;
   1957       *node_size = size;
   1958       *cur = node->next();
   1959       break;
   1960     }
   1961   }
   1962 
   1963   return node;
   1964 }
   1965 
   1966 
   1967 // Allocation on the old space free list.  If it succeeds then a new linear
   1968 // allocation space has been set up with the top and limit of the space.  If
   1969 // the allocation fails then NULL is returned, and the caller can perform a GC
   1970 // or allocate a new page before retrying.
   1971 HeapObject* FreeList::Allocate(int size_in_bytes) {
   1972   ASSERT(0 < size_in_bytes);
   1973   ASSERT(size_in_bytes <= kMaxBlockSize);
   1974   ASSERT(IsAligned(size_in_bytes, kPointerSize));
   1975   // Don't free list allocate if there is linear space available.
   1976   ASSERT(owner_->limit() - owner_->top() < size_in_bytes);
   1977 
   1978   int new_node_size = 0;
   1979   FreeListNode* new_node = FindNodeFor(size_in_bytes, &new_node_size);
   1980   if (new_node == NULL) return NULL;
   1981 
   1982   available_ -= new_node_size;
   1983   ASSERT(IsVeryLong() || available_ == SumFreeLists());
   1984 
   1985   int bytes_left = new_node_size - size_in_bytes;
   1986   ASSERT(bytes_left >= 0);
   1987 
   1988   int old_linear_size = static_cast<int>(owner_->limit() - owner_->top());
   1989   // Mark the old linear allocation area with a free space map so it can be
   1990   // skipped when scanning the heap.  This also puts it back in the free list
   1991   // if it is big enough.
   1992   owner_->Free(owner_->top(), old_linear_size);
   1993 
   1994 #ifdef DEBUG
   1995   for (int i = 0; i < size_in_bytes / kPointerSize; i++) {
   1996     reinterpret_cast<Object**>(new_node->address())[i] = Smi::FromInt(0);
   1997   }
   1998 #endif
   1999 
   2000   owner_->heap()->incremental_marking()->OldSpaceStep(
   2001       size_in_bytes - old_linear_size);
   2002 
   2003   // The old-space-step might have finished sweeping and restarted marking.
   2004   // Verify that it did not turn the page of the new node into an evacuation
   2005   // candidate.
   2006   ASSERT(!MarkCompactCollector::IsOnEvacuationCandidate(new_node));
   2007 
   2008   const int kThreshold = IncrementalMarking::kAllocatedThreshold;
   2009 
   2010   // Memory in the linear allocation area is counted as allocated.  We may free
   2011   // a little of this again immediately - see below.
   2012   owner_->Allocate(new_node_size);
   2013 
   2014   if (bytes_left > kThreshold &&
   2015       owner_->heap()->incremental_marking()->IsMarkingIncomplete() &&
   2016       FLAG_incremental_marking_steps) {
   2017     int linear_size = owner_->RoundSizeDownToObjectAlignment(kThreshold);
   2018     // We don't want to give too large linear areas to the allocator while
   2019     // incremental marking is going on, because we won't check again whether
   2020     // we want to do another increment until the linear area is used up.
   2021     owner_->Free(new_node->address() + size_in_bytes + linear_size,
   2022                  new_node_size - size_in_bytes - linear_size);
   2023     owner_->SetTop(new_node->address() + size_in_bytes,
   2024                    new_node->address() + size_in_bytes + linear_size);
   2025   } else if (bytes_left > 0) {
   2026     // Normally we give the rest of the node to the allocator as its new
   2027     // linear allocation area.
   2028     owner_->SetTop(new_node->address() + size_in_bytes,
   2029                    new_node->address() + new_node_size);
   2030   } else {
   2031     // TODO(gc) Try not freeing linear allocation region when bytes_left
   2032     // are zero.
   2033     owner_->SetTop(NULL, NULL);
   2034   }
   2035 
   2036   return new_node;
   2037 }
   2038 
   2039 
   2040 static intptr_t CountFreeListItemsInList(FreeListNode* n, Page* p) {
   2041   intptr_t sum = 0;
   2042   while (n != NULL) {
   2043     if (Page::FromAddress(n->address()) == p) {
   2044       FreeSpace* free_space = reinterpret_cast<FreeSpace*>(n);
   2045       sum += free_space->Size();
   2046     }
   2047     n = n->next();
   2048   }
   2049   return sum;
   2050 }
   2051 
   2052 
   2053 void FreeList::CountFreeListItems(Page* p, SizeStats* sizes) {
   2054   sizes->huge_size_ = CountFreeListItemsInList(huge_list_, p);
   2055   if (sizes->huge_size_ < p->area_size()) {
   2056     sizes->small_size_ = CountFreeListItemsInList(small_list_, p);
   2057     sizes->medium_size_ = CountFreeListItemsInList(medium_list_, p);
   2058     sizes->large_size_ = CountFreeListItemsInList(large_list_, p);
   2059   } else {
   2060     sizes->small_size_ = 0;
   2061     sizes->medium_size_ = 0;
   2062     sizes->large_size_ = 0;
   2063   }
   2064 }
   2065 
   2066 
   2067 static intptr_t EvictFreeListItemsInList(FreeListNode** n, Page* p) {
   2068   intptr_t sum = 0;
   2069   while (*n != NULL) {
   2070     if (Page::FromAddress((*n)->address()) == p) {
   2071       FreeSpace* free_space = reinterpret_cast<FreeSpace*>(*n);
   2072       sum += free_space->Size();
   2073       *n = (*n)->next();
   2074     } else {
   2075       n = (*n)->next_address();
   2076     }
   2077   }
   2078   return sum;
   2079 }
   2080 
   2081 
   2082 intptr_t FreeList::EvictFreeListItems(Page* p) {
   2083   intptr_t sum = EvictFreeListItemsInList(&huge_list_, p);
   2084 
   2085   if (sum < p->area_size()) {
   2086     sum += EvictFreeListItemsInList(&small_list_, p) +
   2087         EvictFreeListItemsInList(&medium_list_, p) +
   2088         EvictFreeListItemsInList(&large_list_, p);
   2089   }
   2090 
   2091   available_ -= static_cast<int>(sum);
   2092 
   2093   return sum;
   2094 }
   2095 
   2096 
   2097 #ifdef DEBUG
   2098 intptr_t FreeList::SumFreeList(FreeListNode* cur) {
   2099   intptr_t sum = 0;
   2100   while (cur != NULL) {
   2101     ASSERT(cur->map() == HEAP->raw_unchecked_free_space_map());
   2102     FreeSpace* cur_as_free_space = reinterpret_cast<FreeSpace*>(cur);
   2103     sum += cur_as_free_space->Size();
   2104     cur = cur->next();
   2105   }
   2106   return sum;
   2107 }
   2108 
   2109 
   2110 static const int kVeryLongFreeList = 500;
   2111 
   2112 
   2113 int FreeList::FreeListLength(FreeListNode* cur) {
   2114   int length = 0;
   2115   while (cur != NULL) {
   2116     length++;
   2117     cur = cur->next();
   2118     if (length == kVeryLongFreeList) return length;
   2119   }
   2120   return length;
   2121 }
   2122 
   2123 
   2124 bool FreeList::IsVeryLong() {
   2125   if (FreeListLength(small_list_) == kVeryLongFreeList) return  true;
   2126   if (FreeListLength(medium_list_) == kVeryLongFreeList) return  true;
   2127   if (FreeListLength(large_list_) == kVeryLongFreeList) return  true;
   2128   if (FreeListLength(huge_list_) == kVeryLongFreeList) return  true;
   2129   return false;
   2130 }
   2131 
   2132 
   2133 // This can take a very long time because it is linear in the number of entries
   2134 // on the free list, so it should not be called if FreeListLength returns
   2135 // kVeryLongFreeList.
   2136 intptr_t FreeList::SumFreeLists() {
   2137   intptr_t sum = SumFreeList(small_list_);
   2138   sum += SumFreeList(medium_list_);
   2139   sum += SumFreeList(large_list_);
   2140   sum += SumFreeList(huge_list_);
   2141   return sum;
   2142 }
   2143 #endif
   2144 
   2145 
   2146 // -----------------------------------------------------------------------------
   2147 // OldSpace implementation
   2148 
   2149 bool NewSpace::ReserveSpace(int bytes) {
   2150   // We can't reliably unpack a partial snapshot that needs more new space
   2151   // space than the minimum NewSpace size.  The limit can be set lower than
   2152   // the end of new space either because there is more space on the next page
   2153   // or because we have lowered the limit in order to get periodic incremental
   2154   // marking.  The most reliable way to ensure that there is linear space is
   2155   // to do the allocation, then rewind the limit.
   2156   ASSERT(bytes <= InitialCapacity());
   2157   MaybeObject* maybe = AllocateRaw(bytes);
   2158   Object* object = NULL;
   2159   if (!maybe->ToObject(&object)) return false;
   2160   HeapObject* allocation = HeapObject::cast(object);
   2161   Address top = allocation_info_.top;
   2162   if ((top - bytes) == allocation->address()) {
   2163     allocation_info_.top = allocation->address();
   2164     return true;
   2165   }
   2166   // There may be a borderline case here where the allocation succeeded, but
   2167   // the limit and top have moved on to a new page.  In that case we try again.
   2168   return ReserveSpace(bytes);
   2169 }
   2170 
   2171 
   2172 void PagedSpace::PrepareForMarkCompact() {
   2173   // We don't have a linear allocation area while sweeping.  It will be restored
   2174   // on the first allocation after the sweep.
   2175   // Mark the old linear allocation area with a free space map so it can be
   2176   // skipped when scanning the heap.
   2177   int old_linear_size = static_cast<int>(limit() - top());
   2178   Free(top(), old_linear_size);
   2179   SetTop(NULL, NULL);
   2180 
   2181   // Stop lazy sweeping and clear marking bits for unswept pages.
   2182   if (first_unswept_page_ != NULL) {
   2183     Page* p = first_unswept_page_;
   2184     do {
   2185       // Do not use ShouldBeSweptLazily predicate here.
   2186       // New evacuation candidates were selected but they still have
   2187       // to be swept before collection starts.
   2188       if (!p->WasSwept()) {
   2189         Bitmap::Clear(p);
   2190         if (FLAG_gc_verbose) {
   2191           PrintF("Sweeping 0x%" V8PRIxPTR " lazily abandoned.\n",
   2192                  reinterpret_cast<intptr_t>(p));
   2193         }
   2194       }
   2195       p = p->next_page();
   2196     } while (p != anchor());
   2197   }
   2198   first_unswept_page_ = Page::FromAddress(NULL);
   2199   unswept_free_bytes_ = 0;
   2200 
   2201   // Clear the free list before a full GC---it will be rebuilt afterward.
   2202   free_list_.Reset();
   2203 }
   2204 
   2205 
   2206 bool PagedSpace::ReserveSpace(int size_in_bytes) {
   2207   ASSERT(size_in_bytes <= AreaSize());
   2208   ASSERT(size_in_bytes == RoundSizeDownToObjectAlignment(size_in_bytes));
   2209   Address current_top = allocation_info_.top;
   2210   Address new_top = current_top + size_in_bytes;
   2211   if (new_top <= allocation_info_.limit) return true;
   2212 
   2213   HeapObject* new_area = free_list_.Allocate(size_in_bytes);
   2214   if (new_area == NULL) new_area = SlowAllocateRaw(size_in_bytes);
   2215   if (new_area == NULL) return false;
   2216 
   2217   int old_linear_size = static_cast<int>(limit() - top());
   2218   // Mark the old linear allocation area with a free space so it can be
   2219   // skipped when scanning the heap.  This also puts it back in the free list
   2220   // if it is big enough.
   2221   Free(top(), old_linear_size);
   2222 
   2223   SetTop(new_area->address(), new_area->address() + size_in_bytes);
   2224   Allocate(size_in_bytes);
   2225   return true;
   2226 }
   2227 
   2228 
   2229 // You have to call this last, since the implementation from PagedSpace
   2230 // doesn't know that memory was 'promised' to large object space.
   2231 bool LargeObjectSpace::ReserveSpace(int bytes) {
   2232   return heap()->OldGenerationCapacityAvailable() >= bytes &&
   2233          (!heap()->incremental_marking()->IsStopped() ||
   2234            heap()->OldGenerationSpaceAvailable() >= bytes);
   2235 }
   2236 
   2237 
   2238 bool PagedSpace::AdvanceSweeper(intptr_t bytes_to_sweep) {
   2239   if (IsSweepingComplete()) return true;
   2240 
   2241   intptr_t freed_bytes = 0;
   2242   Page* p = first_unswept_page_;
   2243   do {
   2244     Page* next_page = p->next_page();
   2245     if (ShouldBeSweptLazily(p)) {
   2246       if (FLAG_gc_verbose) {
   2247         PrintF("Sweeping 0x%" V8PRIxPTR " lazily advanced.\n",
   2248                reinterpret_cast<intptr_t>(p));
   2249       }
   2250       DecreaseUnsweptFreeBytes(p);
   2251       freed_bytes += MarkCompactCollector::SweepConservatively(this, p);
   2252     }
   2253     p = next_page;
   2254   } while (p != anchor() && freed_bytes < bytes_to_sweep);
   2255 
   2256   if (p == anchor()) {
   2257     first_unswept_page_ = Page::FromAddress(NULL);
   2258   } else {
   2259     first_unswept_page_ = p;
   2260   }
   2261 
   2262   heap()->LowerOldGenLimits(freed_bytes);
   2263 
   2264   heap()->FreeQueuedChunks();
   2265 
   2266   return IsSweepingComplete();
   2267 }
   2268 
   2269 
   2270 void PagedSpace::EvictEvacuationCandidatesFromFreeLists() {
   2271   if (allocation_info_.top >= allocation_info_.limit) return;
   2272 
   2273   if (Page::FromAllocationTop(allocation_info_.top)->IsEvacuationCandidate()) {
   2274     // Create filler object to keep page iterable if it was iterable.
   2275     int remaining =
   2276         static_cast<int>(allocation_info_.limit - allocation_info_.top);
   2277     heap()->CreateFillerObjectAt(allocation_info_.top, remaining);
   2278 
   2279     allocation_info_.top = NULL;
   2280     allocation_info_.limit = NULL;
   2281   }
   2282 }
   2283 
   2284 
   2285 HeapObject* PagedSpace::SlowAllocateRaw(int size_in_bytes) {
   2286   // Allocation in this space has failed.
   2287 
   2288   // If there are unswept pages advance lazy sweeper then sweep one page before
   2289   // allocating a new page.
   2290   if (first_unswept_page_->is_valid()) {
   2291     AdvanceSweeper(size_in_bytes);
   2292 
   2293     // Retry the free list allocation.
   2294     HeapObject* object = free_list_.Allocate(size_in_bytes);
   2295     if (object != NULL) return object;
   2296   }
   2297 
   2298   // Free list allocation failed and there is no next page.  Fail if we have
   2299   // hit the old generation size limit that should cause a garbage
   2300   // collection.
   2301   if (!heap()->always_allocate() &&
   2302       heap()->OldGenerationAllocationLimitReached()) {
   2303     return NULL;
   2304   }
   2305 
   2306   // Try to expand the space and allocate in the new next page.
   2307   if (Expand()) {
   2308     return free_list_.Allocate(size_in_bytes);
   2309   }
   2310 
   2311   // Last ditch, sweep all the remaining pages to try to find space.  This may
   2312   // cause a pause.
   2313   if (!IsSweepingComplete()) {
   2314     AdvanceSweeper(kMaxInt);
   2315 
   2316     // Retry the free list allocation.
   2317     HeapObject* object = free_list_.Allocate(size_in_bytes);
   2318     if (object != NULL) return object;
   2319   }
   2320 
   2321   // Finally, fail.
   2322   return NULL;
   2323 }
   2324 
   2325 
   2326 #ifdef DEBUG
   2327 void PagedSpace::ReportCodeStatistics() {
   2328   Isolate* isolate = Isolate::Current();
   2329   CommentStatistic* comments_statistics =
   2330       isolate->paged_space_comments_statistics();
   2331   ReportCodeKindStatistics();
   2332   PrintF("Code comment statistics (\"   [ comment-txt   :    size/   "
   2333          "count  (average)\"):\n");
   2334   for (int i = 0; i <= CommentStatistic::kMaxComments; i++) {
   2335     const CommentStatistic& cs = comments_statistics[i];
   2336     if (cs.size > 0) {
   2337       PrintF("   %-30s: %10d/%6d     (%d)\n", cs.comment, cs.size, cs.count,
   2338              cs.size/cs.count);
   2339     }
   2340   }
   2341   PrintF("\n");
   2342 }
   2343 
   2344 
   2345 void PagedSpace::ResetCodeStatistics() {
   2346   Isolate* isolate = Isolate::Current();
   2347   CommentStatistic* comments_statistics =
   2348       isolate->paged_space_comments_statistics();
   2349   ClearCodeKindStatistics();
   2350   for (int i = 0; i < CommentStatistic::kMaxComments; i++) {
   2351     comments_statistics[i].Clear();
   2352   }
   2353   comments_statistics[CommentStatistic::kMaxComments].comment = "Unknown";
   2354   comments_statistics[CommentStatistic::kMaxComments].size = 0;
   2355   comments_statistics[CommentStatistic::kMaxComments].count = 0;
   2356 }
   2357 
   2358 
   2359 // Adds comment to 'comment_statistics' table. Performance OK as long as
   2360 // 'kMaxComments' is small
   2361 static void EnterComment(Isolate* isolate, const char* comment, int delta) {
   2362   CommentStatistic* comments_statistics =
   2363       isolate->paged_space_comments_statistics();
   2364   // Do not count empty comments
   2365   if (delta <= 0) return;
   2366   CommentStatistic* cs = &comments_statistics[CommentStatistic::kMaxComments];
   2367   // Search for a free or matching entry in 'comments_statistics': 'cs'
   2368   // points to result.
   2369   for (int i = 0; i < CommentStatistic::kMaxComments; i++) {
   2370     if (comments_statistics[i].comment == NULL) {
   2371       cs = &comments_statistics[i];
   2372       cs->comment = comment;
   2373       break;
   2374     } else if (strcmp(comments_statistics[i].comment, comment) == 0) {
   2375       cs = &comments_statistics[i];
   2376       break;
   2377     }
   2378   }
   2379   // Update entry for 'comment'
   2380   cs->size += delta;
   2381   cs->count += 1;
   2382 }
   2383 
   2384 
   2385 // Call for each nested comment start (start marked with '[ xxx', end marked
   2386 // with ']'.  RelocIterator 'it' must point to a comment reloc info.
   2387 static void CollectCommentStatistics(Isolate* isolate, RelocIterator* it) {
   2388   ASSERT(!it->done());
   2389   ASSERT(it->rinfo()->rmode() == RelocInfo::COMMENT);
   2390   const char* tmp = reinterpret_cast<const char*>(it->rinfo()->data());
   2391   if (tmp[0] != '[') {
   2392     // Not a nested comment; skip
   2393     return;
   2394   }
   2395 
   2396   // Search for end of nested comment or a new nested comment
   2397   const char* const comment_txt =
   2398       reinterpret_cast<const char*>(it->rinfo()->data());
   2399   const byte* prev_pc = it->rinfo()->pc();
   2400   int flat_delta = 0;
   2401   it->next();
   2402   while (true) {
   2403     // All nested comments must be terminated properly, and therefore exit
   2404     // from loop.
   2405     ASSERT(!it->done());
   2406     if (it->rinfo()->rmode() == RelocInfo::COMMENT) {
   2407       const char* const txt =
   2408           reinterpret_cast<const char*>(it->rinfo()->data());
   2409       flat_delta += static_cast<int>(it->rinfo()->pc() - prev_pc);
   2410       if (txt[0] == ']') break;  // End of nested  comment
   2411       // A new comment
   2412       CollectCommentStatistics(isolate, it);
   2413       // Skip code that was covered with previous comment
   2414       prev_pc = it->rinfo()->pc();
   2415     }
   2416     it->next();
   2417   }
   2418   EnterComment(isolate, comment_txt, flat_delta);
   2419 }
   2420 
   2421 
   2422 // Collects code size statistics:
   2423 // - by code kind
   2424 // - by code comment
   2425 void PagedSpace::CollectCodeStatistics() {
   2426   Isolate* isolate = heap()->isolate();
   2427   HeapObjectIterator obj_it(this);
   2428   for (HeapObject* obj = obj_it.Next(); obj != NULL; obj = obj_it.Next()) {
   2429     if (obj->IsCode()) {
   2430       Code* code = Code::cast(obj);
   2431       isolate->code_kind_statistics()[code->kind()] += code->Size();
   2432       RelocIterator it(code);
   2433       int delta = 0;
   2434       const byte* prev_pc = code->instruction_start();
   2435       while (!it.done()) {
   2436         if (it.rinfo()->rmode() == RelocInfo::COMMENT) {
   2437           delta += static_cast<int>(it.rinfo()->pc() - prev_pc);
   2438           CollectCommentStatistics(isolate, &it);
   2439           prev_pc = it.rinfo()->pc();
   2440         }
   2441         it.next();
   2442       }
   2443 
   2444       ASSERT(code->instruction_start() <= prev_pc &&
   2445              prev_pc <= code->instruction_end());
   2446       delta += static_cast<int>(code->instruction_end() - prev_pc);
   2447       EnterComment(isolate, "NoComment", delta);
   2448     }
   2449   }
   2450 }
   2451 
   2452 
   2453 void PagedSpace::ReportStatistics() {
   2454   int pct = static_cast<int>(Available() * 100 / Capacity());
   2455   PrintF("  capacity: %" V8_PTR_PREFIX "d"
   2456              ", waste: %" V8_PTR_PREFIX "d"
   2457              ", available: %" V8_PTR_PREFIX "d, %%%d\n",
   2458          Capacity(), Waste(), Available(), pct);
   2459 
   2460   if (was_swept_conservatively_) return;
   2461   ClearHistograms();
   2462   HeapObjectIterator obj_it(this);
   2463   for (HeapObject* obj = obj_it.Next(); obj != NULL; obj = obj_it.Next())
   2464     CollectHistogramInfo(obj);
   2465   ReportHistogram(true);
   2466 }
   2467 #endif
   2468 
   2469 // -----------------------------------------------------------------------------
   2470 // FixedSpace implementation
   2471 
   2472 void FixedSpace::PrepareForMarkCompact() {
   2473   // Call prepare of the super class.
   2474   PagedSpace::PrepareForMarkCompact();
   2475 
   2476   // During a non-compacting collection, everything below the linear
   2477   // allocation pointer except wasted top-of-page blocks is considered
   2478   // allocated and we will rediscover available bytes during the
   2479   // collection.
   2480   accounting_stats_.AllocateBytes(free_list_.available());
   2481 
   2482   // Clear the free list before a full GC---it will be rebuilt afterward.
   2483   free_list_.Reset();
   2484 }
   2485 
   2486 
   2487 // -----------------------------------------------------------------------------
   2488 // MapSpace implementation
   2489 
   2490 #ifdef DEBUG
   2491 void MapSpace::VerifyObject(HeapObject* object) {
   2492   // The object should be a map or a free-list node.
   2493   ASSERT(object->IsMap() || object->IsFreeSpace());
   2494 }
   2495 #endif
   2496 
   2497 
   2498 // -----------------------------------------------------------------------------
   2499 // GlobalPropertyCellSpace implementation
   2500 
   2501 #ifdef DEBUG
   2502 void CellSpace::VerifyObject(HeapObject* object) {
   2503   // The object should be a global object property cell or a free-list node.
   2504   ASSERT(object->IsJSGlobalPropertyCell() ||
   2505          object->map() == heap()->two_pointer_filler_map());
   2506 }
   2507 #endif
   2508 
   2509 
   2510 // -----------------------------------------------------------------------------
   2511 // LargeObjectIterator
   2512 
   2513 LargeObjectIterator::LargeObjectIterator(LargeObjectSpace* space) {
   2514   current_ = space->first_page_;
   2515   size_func_ = NULL;
   2516 }
   2517 
   2518 
   2519 LargeObjectIterator::LargeObjectIterator(LargeObjectSpace* space,
   2520                                          HeapObjectCallback size_func) {
   2521   current_ = space->first_page_;
   2522   size_func_ = size_func;
   2523 }
   2524 
   2525 
   2526 HeapObject* LargeObjectIterator::Next() {
   2527   if (current_ == NULL) return NULL;
   2528 
   2529   HeapObject* object = current_->GetObject();
   2530   current_ = current_->next_page();
   2531   return object;
   2532 }
   2533 
   2534 
   2535 // -----------------------------------------------------------------------------
   2536 // LargeObjectSpace
   2537 static bool ComparePointers(void* key1, void* key2) {
   2538     return key1 == key2;
   2539 }
   2540 
   2541 
   2542 LargeObjectSpace::LargeObjectSpace(Heap* heap,
   2543                                    intptr_t max_capacity,
   2544                                    AllocationSpace id)
   2545     : Space(heap, id, NOT_EXECUTABLE),  // Managed on a per-allocation basis
   2546       max_capacity_(max_capacity),
   2547       first_page_(NULL),
   2548       size_(0),
   2549       page_count_(0),
   2550       objects_size_(0),
   2551       chunk_map_(ComparePointers, 1024) {}
   2552 
   2553 
   2554 bool LargeObjectSpace::SetUp() {
   2555   first_page_ = NULL;
   2556   size_ = 0;
   2557   page_count_ = 0;
   2558   objects_size_ = 0;
   2559   chunk_map_.Clear();
   2560   return true;
   2561 }
   2562 
   2563 
   2564 void LargeObjectSpace::TearDown() {
   2565   while (first_page_ != NULL) {
   2566     LargePage* page = first_page_;
   2567     first_page_ = first_page_->next_page();
   2568     LOG(heap()->isolate(), DeleteEvent("LargeObjectChunk", page->address()));
   2569 
   2570     ObjectSpace space = static_cast<ObjectSpace>(1 << identity());
   2571     heap()->isolate()->memory_allocator()->PerformAllocationCallback(
   2572         space, kAllocationActionFree, page->size());
   2573     heap()->isolate()->memory_allocator()->Free(page);
   2574   }
   2575   SetUp();
   2576 }
   2577 
   2578 
   2579 MaybeObject* LargeObjectSpace::AllocateRaw(int object_size,
   2580                                            Executability executable) {
   2581   // Check if we want to force a GC before growing the old space further.
   2582   // If so, fail the allocation.
   2583   if (!heap()->always_allocate() &&
   2584       heap()->OldGenerationAllocationLimitReached()) {
   2585     return Failure::RetryAfterGC(identity());
   2586   }
   2587 
   2588   if (Size() + object_size > max_capacity_) {
   2589     return Failure::RetryAfterGC(identity());
   2590   }
   2591 
   2592   LargePage* page = heap()->isolate()->memory_allocator()->
   2593       AllocateLargePage(object_size, executable, this);
   2594   if (page == NULL) return Failure::RetryAfterGC(identity());
   2595   ASSERT(page->area_size() >= object_size);
   2596 
   2597   size_ += static_cast<int>(page->size());
   2598   objects_size_ += object_size;
   2599   page_count_++;
   2600   page->set_next_page(first_page_);
   2601   first_page_ = page;
   2602 
   2603   // Register all MemoryChunk::kAlignment-aligned chunks covered by
   2604   // this large page in the chunk map.
   2605   uintptr_t base = reinterpret_cast<uintptr_t>(page) / MemoryChunk::kAlignment;
   2606   uintptr_t limit = base + (page->size() - 1) / MemoryChunk::kAlignment;
   2607   for (uintptr_t key = base; key <= limit; key++) {
   2608     HashMap::Entry* entry = chunk_map_.Lookup(reinterpret_cast<void*>(key),
   2609                                               static_cast<uint32_t>(key),
   2610                                               true);
   2611     ASSERT(entry != NULL);
   2612     entry->value = page;
   2613   }
   2614 
   2615   HeapObject* object = page->GetObject();
   2616 
   2617 #ifdef DEBUG
   2618   // Make the object consistent so the heap can be vefified in OldSpaceStep.
   2619   reinterpret_cast<Object**>(object->address())[0] =
   2620       heap()->fixed_array_map();
   2621   reinterpret_cast<Object**>(object->address())[1] = Smi::FromInt(0);
   2622 #endif
   2623 
   2624   heap()->incremental_marking()->OldSpaceStep(object_size);
   2625   return object;
   2626 }
   2627 
   2628 
   2629 // GC support
   2630 MaybeObject* LargeObjectSpace::FindObject(Address a) {
   2631   LargePage* page = FindPage(a);
   2632   if (page != NULL) {
   2633     return page->GetObject();
   2634   }
   2635   return Failure::Exception();
   2636 }
   2637 
   2638 
   2639 LargePage* LargeObjectSpace::FindPage(Address a) {
   2640   uintptr_t key = reinterpret_cast<uintptr_t>(a) / MemoryChunk::kAlignment;
   2641   HashMap::Entry* e = chunk_map_.Lookup(reinterpret_cast<void*>(key),
   2642                                         static_cast<uint32_t>(key),
   2643                                         false);
   2644   if (e != NULL) {
   2645     ASSERT(e->value != NULL);
   2646     LargePage* page = reinterpret_cast<LargePage*>(e->value);
   2647     ASSERT(page->is_valid());
   2648     if (page->Contains(a)) {
   2649       return page;
   2650     }
   2651   }
   2652   return NULL;
   2653 }
   2654 
   2655 
   2656 void LargeObjectSpace::FreeUnmarkedObjects() {
   2657   LargePage* previous = NULL;
   2658   LargePage* current = first_page_;
   2659   while (current != NULL) {
   2660     HeapObject* object = current->GetObject();
   2661     // Can this large page contain pointers to non-trivial objects.  No other
   2662     // pointer object is this big.
   2663     bool is_pointer_object = object->IsFixedArray();
   2664     MarkBit mark_bit = Marking::MarkBitFrom(object);
   2665     if (mark_bit.Get()) {
   2666       mark_bit.Clear();
   2667       MemoryChunk::IncrementLiveBytesFromGC(object->address(), -object->Size());
   2668       previous = current;
   2669       current = current->next_page();
   2670     } else {
   2671       LargePage* page = current;
   2672       // Cut the chunk out from the chunk list.
   2673       current = current->next_page();
   2674       if (previous == NULL) {
   2675         first_page_ = current;
   2676       } else {
   2677         previous->set_next_page(current);
   2678       }
   2679 
   2680       // Free the chunk.
   2681       heap()->mark_compact_collector()->ReportDeleteIfNeeded(
   2682           object, heap()->isolate());
   2683       size_ -= static_cast<int>(page->size());
   2684       objects_size_ -= object->Size();
   2685       page_count_--;
   2686 
   2687       // Remove entries belonging to this page.
   2688       // Use variable alignment to help pass length check (<= 80 characters)
   2689       // of single line in tools/presubmit.py.
   2690       const intptr_t alignment = MemoryChunk::kAlignment;
   2691       uintptr_t base = reinterpret_cast<uintptr_t>(page)/alignment;
   2692       uintptr_t limit = base + (page->size()-1)/alignment;
   2693       for (uintptr_t key = base; key <= limit; key++) {
   2694         chunk_map_.Remove(reinterpret_cast<void*>(key),
   2695                           static_cast<uint32_t>(key));
   2696       }
   2697 
   2698       if (is_pointer_object) {
   2699         heap()->QueueMemoryChunkForFree(page);
   2700       } else {
   2701         heap()->isolate()->memory_allocator()->Free(page);
   2702       }
   2703     }
   2704   }
   2705   heap()->FreeQueuedChunks();
   2706 }
   2707 
   2708 
   2709 bool LargeObjectSpace::Contains(HeapObject* object) {
   2710   Address address = object->address();
   2711   MemoryChunk* chunk = MemoryChunk::FromAddress(address);
   2712 
   2713   bool owned = (chunk->owner() == this);
   2714 
   2715   SLOW_ASSERT(!owned || !FindObject(address)->IsFailure());
   2716 
   2717   return owned;
   2718 }
   2719 
   2720 
   2721 #ifdef DEBUG
   2722 // We do not assume that the large object iterator works, because it depends
   2723 // on the invariants we are checking during verification.
   2724 void LargeObjectSpace::Verify() {
   2725   for (LargePage* chunk = first_page_;
   2726        chunk != NULL;
   2727        chunk = chunk->next_page()) {
   2728     // Each chunk contains an object that starts at the large object page's
   2729     // object area start.
   2730     HeapObject* object = chunk->GetObject();
   2731     Page* page = Page::FromAddress(object->address());
   2732     ASSERT(object->address() == page->area_start());
   2733 
   2734     // The first word should be a map, and we expect all map pointers to be
   2735     // in map space.
   2736     Map* map = object->map();
   2737     ASSERT(map->IsMap());
   2738     ASSERT(heap()->map_space()->Contains(map));
   2739 
   2740     // We have only code, sequential strings, external strings
   2741     // (sequential strings that have been morphed into external
   2742     // strings), fixed arrays, and byte arrays in large object space.
   2743     ASSERT(object->IsCode() || object->IsSeqString() ||
   2744            object->IsExternalString() || object->IsFixedArray() ||
   2745            object->IsFixedDoubleArray() || object->IsByteArray());
   2746 
   2747     // The object itself should look OK.
   2748     object->Verify();
   2749 
   2750     // Byte arrays and strings don't have interior pointers.
   2751     if (object->IsCode()) {
   2752       VerifyPointersVisitor code_visitor;
   2753       object->IterateBody(map->instance_type(),
   2754                           object->Size(),
   2755                           &code_visitor);
   2756     } else if (object->IsFixedArray()) {
   2757       FixedArray* array = FixedArray::cast(object);
   2758       for (int j = 0; j < array->length(); j++) {
   2759         Object* element = array->get(j);
   2760         if (element->IsHeapObject()) {
   2761           HeapObject* element_object = HeapObject::cast(element);
   2762           ASSERT(heap()->Contains(element_object));
   2763           ASSERT(element_object->map()->IsMap());
   2764         }
   2765       }
   2766     }
   2767   }
   2768 }
   2769 
   2770 
   2771 void LargeObjectSpace::Print() {
   2772   LargeObjectIterator it(this);
   2773   for (HeapObject* obj = it.Next(); obj != NULL; obj = it.Next()) {
   2774     obj->Print();
   2775   }
   2776 }
   2777 
   2778 
   2779 void LargeObjectSpace::ReportStatistics() {
   2780   PrintF("  size: %" V8_PTR_PREFIX "d\n", size_);
   2781   int num_objects = 0;
   2782   ClearHistograms();
   2783   LargeObjectIterator it(this);
   2784   for (HeapObject* obj = it.Next(); obj != NULL; obj = it.Next()) {
   2785     num_objects++;
   2786     CollectHistogramInfo(obj);
   2787   }
   2788 
   2789   PrintF("  number of objects %d, "
   2790          "size of objects %" V8_PTR_PREFIX "d\n", num_objects, objects_size_);
   2791   if (num_objects > 0) ReportHistogram(false);
   2792 }
   2793 
   2794 
   2795 void LargeObjectSpace::CollectCodeStatistics() {
   2796   Isolate* isolate = heap()->isolate();
   2797   LargeObjectIterator obj_it(this);
   2798   for (HeapObject* obj = obj_it.Next(); obj != NULL; obj = obj_it.Next()) {
   2799     if (obj->IsCode()) {
   2800       Code* code = Code::cast(obj);
   2801       isolate->code_kind_statistics()[code->kind()] += code->Size();
   2802     }
   2803   }
   2804 }
   2805 
   2806 
   2807 void Page::Print() {
   2808   // Make a best-effort to print the objects in the page.
   2809   PrintF("Page@%p in %s\n",
   2810          this->address(),
   2811          AllocationSpaceName(this->owner()->identity()));
   2812   printf(" --------------------------------------\n");
   2813   HeapObjectIterator objects(this, heap()->GcSafeSizeOfOldObjectFunction());
   2814   unsigned mark_size = 0;
   2815   for (HeapObject* object = objects.Next();
   2816        object != NULL;
   2817        object = objects.Next()) {
   2818     bool is_marked = Marking::MarkBitFrom(object).Get();
   2819     PrintF(" %c ", (is_marked ? '!' : ' '));  // Indent a little.
   2820     if (is_marked) {
   2821       mark_size += heap()->GcSafeSizeOfOldObjectFunction()(object);
   2822     }
   2823     object->ShortPrint();
   2824     PrintF("\n");
   2825   }
   2826   printf(" --------------------------------------\n");
   2827   printf(" Marked: %x, LiveCount: %x\n", mark_size, LiveBytes());
   2828 }
   2829 
   2830 #endif  // DEBUG
   2831 
   2832 } }  // namespace v8::internal
   2833