Home | History | Annotate | Download | only in heap
      1 // Copyright 2011 the V8 project authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #ifndef V8_HEAP_SPACES_INL_H_
      6 #define V8_HEAP_SPACES_INL_H_
      7 
      8 #include "src/heap/incremental-marking.h"
      9 #include "src/heap/spaces.h"
     10 #include "src/isolate.h"
     11 #include "src/msan.h"
     12 #include "src/profiler/heap-profiler.h"
     13 #include "src/v8memory.h"
     14 
     15 namespace v8 {
     16 namespace internal {
     17 
     18 template <class PAGE_TYPE>
     19 PageIteratorImpl<PAGE_TYPE>& PageIteratorImpl<PAGE_TYPE>::operator++() {
     20   p_ = p_->next_page();
     21   return *this;
     22 }
     23 
     24 template <class PAGE_TYPE>
     25 PageIteratorImpl<PAGE_TYPE> PageIteratorImpl<PAGE_TYPE>::operator++(int) {
     26   PageIteratorImpl<PAGE_TYPE> tmp(*this);
     27   operator++();
     28   return tmp;
     29 }
     30 
     31 NewSpacePageRange::NewSpacePageRange(Address start, Address limit)
     32     : range_(Page::FromAddress(start),
     33              Page::FromAllocationAreaAddress(limit)->next_page()) {
     34   SemiSpace::AssertValidRange(start, limit);
     35 }
     36 
     37 // -----------------------------------------------------------------------------
     38 // Bitmap
     39 
     40 void Bitmap::Clear(MemoryChunk* chunk) {
     41   Bitmap* bitmap = chunk->markbits();
     42   for (int i = 0; i < bitmap->CellsCount(); i++) bitmap->cells()[i] = 0;
     43   chunk->ResetLiveBytes();
     44 }
     45 
     46 void Bitmap::SetAllBits(MemoryChunk* chunk) {
     47   Bitmap* bitmap = chunk->markbits();
     48   for (int i = 0; i < bitmap->CellsCount(); i++)
     49     bitmap->cells()[i] = 0xffffffff;
     50 }
     51 
     52 
     53 // -----------------------------------------------------------------------------
     54 // SemiSpaceIterator
     55 
     56 HeapObject* SemiSpaceIterator::Next() {
     57   while (current_ != limit_) {
     58     if (Page::IsAlignedToPageSize(current_)) {
     59       Page* page = Page::FromAllocationAreaAddress(current_);
     60       page = page->next_page();
     61       DCHECK(!page->is_anchor());
     62       current_ = page->area_start();
     63       if (current_ == limit_) return nullptr;
     64     }
     65     HeapObject* object = HeapObject::FromAddress(current_);
     66     current_ += object->Size();
     67     if (!object->IsFiller()) {
     68       return object;
     69     }
     70   }
     71   return nullptr;
     72 }
     73 
     74 // -----------------------------------------------------------------------------
     75 // HeapObjectIterator
     76 
     77 HeapObject* HeapObjectIterator::Next() {
     78   do {
     79     HeapObject* next_obj = FromCurrentPage();
     80     if (next_obj != nullptr) return next_obj;
     81   } while (AdvanceToNextPage());
     82   return nullptr;
     83 }
     84 
     85 HeapObject* HeapObjectIterator::FromCurrentPage() {
     86   while (cur_addr_ != cur_end_) {
     87     if (cur_addr_ == space_->top() && cur_addr_ != space_->limit()) {
     88       cur_addr_ = space_->limit();
     89       continue;
     90     }
     91     HeapObject* obj = HeapObject::FromAddress(cur_addr_);
     92     const int obj_size = obj->Size();
     93     cur_addr_ += obj_size;
     94     DCHECK_LE(cur_addr_, cur_end_);
     95     if (!obj->IsFiller()) {
     96       if (obj->IsCode()) {
     97         DCHECK_EQ(space_, space_->heap()->code_space());
     98         DCHECK_CODEOBJECT_SIZE(obj_size, space_);
     99       } else {
    100         DCHECK_OBJECT_SIZE(obj_size);
    101       }
    102       return obj;
    103     }
    104   }
    105   return nullptr;
    106 }
    107 
    108 // -----------------------------------------------------------------------------
    109 // MemoryAllocator
    110 
    111 #ifdef ENABLE_HEAP_PROTECTION
    112 
    113 void MemoryAllocator::Protect(Address start, size_t size) {
    114   base::OS::Protect(start, size);
    115 }
    116 
    117 
    118 void MemoryAllocator::Unprotect(Address start, size_t size,
    119                                 Executability executable) {
    120   base::OS::Unprotect(start, size, executable);
    121 }
    122 
    123 
    124 void MemoryAllocator::ProtectChunkFromPage(Page* page) {
    125   int id = GetChunkId(page);
    126   base::OS::Protect(chunks_[id].address(), chunks_[id].size());
    127 }
    128 
    129 
    130 void MemoryAllocator::UnprotectChunkFromPage(Page* page) {
    131   int id = GetChunkId(page);
    132   base::OS::Unprotect(chunks_[id].address(), chunks_[id].size(),
    133                       chunks_[id].owner()->executable() == EXECUTABLE);
    134 }
    135 
    136 #endif
    137 
    138 // -----------------------------------------------------------------------------
    139 // SemiSpace
    140 
    141 bool SemiSpace::Contains(HeapObject* o) {
    142   return id_ == kToSpace
    143              ? MemoryChunk::FromAddress(o->address())->InToSpace()
    144              : MemoryChunk::FromAddress(o->address())->InFromSpace();
    145 }
    146 
    147 bool SemiSpace::Contains(Object* o) {
    148   return o->IsHeapObject() && Contains(HeapObject::cast(o));
    149 }
    150 
    151 bool SemiSpace::ContainsSlow(Address a) {
    152   for (Page* p : *this) {
    153     if (p == MemoryChunk::FromAddress(a)) return true;
    154   }
    155   return false;
    156 }
    157 
    158 // --------------------------------------------------------------------------
    159 // NewSpace
    160 
    161 bool NewSpace::Contains(HeapObject* o) {
    162   return MemoryChunk::FromAddress(o->address())->InNewSpace();
    163 }
    164 
    165 bool NewSpace::Contains(Object* o) {
    166   return o->IsHeapObject() && Contains(HeapObject::cast(o));
    167 }
    168 
    169 bool NewSpace::ContainsSlow(Address a) {
    170   return from_space_.ContainsSlow(a) || to_space_.ContainsSlow(a);
    171 }
    172 
    173 bool NewSpace::ToSpaceContainsSlow(Address a) {
    174   return to_space_.ContainsSlow(a);
    175 }
    176 
    177 bool NewSpace::FromSpaceContainsSlow(Address a) {
    178   return from_space_.ContainsSlow(a);
    179 }
    180 
    181 bool NewSpace::ToSpaceContains(Object* o) { return to_space_.Contains(o); }
    182 bool NewSpace::FromSpaceContains(Object* o) { return from_space_.Contains(o); }
    183 
    184 // --------------------------------------------------------------------------
    185 // AllocationResult
    186 
    187 AllocationSpace AllocationResult::RetrySpace() {
    188   DCHECK(IsRetry());
    189   return static_cast<AllocationSpace>(Smi::cast(object_)->value());
    190 }
    191 
    192 Page* Page::Initialize(Heap* heap, MemoryChunk* chunk, Executability executable,
    193                        SemiSpace* owner) {
    194   DCHECK_EQ(executable, Executability::NOT_EXECUTABLE);
    195   bool in_to_space = (owner->id() != kFromSpace);
    196   chunk->SetFlag(in_to_space ? MemoryChunk::IN_TO_SPACE
    197                              : MemoryChunk::IN_FROM_SPACE);
    198   DCHECK(!chunk->IsFlagSet(in_to_space ? MemoryChunk::IN_FROM_SPACE
    199                                        : MemoryChunk::IN_TO_SPACE));
    200   Page* page = static_cast<Page*>(chunk);
    201   heap->incremental_marking()->SetNewSpacePageFlags(page);
    202   page->AllocateLocalTracker();
    203   return page;
    204 }
    205 
    206 // --------------------------------------------------------------------------
    207 // PagedSpace
    208 
    209 template <Page::InitializationMode mode>
    210 Page* Page::Initialize(Heap* heap, MemoryChunk* chunk, Executability executable,
    211                        PagedSpace* owner) {
    212   Page* page = reinterpret_cast<Page*>(chunk);
    213   DCHECK(page->area_size() <= kAllocatableMemory);
    214   DCHECK(chunk->owner() == owner);
    215 
    216   owner->IncreaseCapacity(page->area_size());
    217   heap->incremental_marking()->SetOldSpacePageFlags(chunk);
    218 
    219   // Make sure that categories are initialized before freeing the area.
    220   page->InitializeFreeListCategories();
    221   // In the case we do not free the memory, we effectively account for the whole
    222   // page as allocated memory that cannot be used for further allocations.
    223   if (mode == kFreeMemory) {
    224     owner->Free(page->area_start(), page->area_size());
    225   }
    226 
    227   return page;
    228 }
    229 
    230 Page* Page::ConvertNewToOld(Page* old_page, PagedSpace* new_owner) {
    231   DCHECK(old_page->InNewSpace());
    232   old_page->set_owner(new_owner);
    233   old_page->SetFlags(0, ~0);
    234   new_owner->AccountCommitted(old_page->size());
    235   Page* new_page = Page::Initialize<kDoNotFreeMemory>(
    236       old_page->heap(), old_page, NOT_EXECUTABLE, new_owner);
    237   new_page->InsertAfter(new_owner->anchor()->prev_page());
    238   return new_page;
    239 }
    240 
    241 void Page::InitializeFreeListCategories() {
    242   for (int i = kFirstCategory; i < kNumberOfCategories; i++) {
    243     categories_[i].Initialize(static_cast<FreeListCategoryType>(i));
    244   }
    245 }
    246 
    247 void MemoryChunk::IncrementLiveBytesFromGC(HeapObject* object, int by) {
    248   MemoryChunk::FromAddress(object->address())->IncrementLiveBytes(by);
    249 }
    250 
    251 void MemoryChunk::ResetLiveBytes() {
    252   if (FLAG_trace_live_bytes) {
    253     PrintIsolate(heap()->isolate(), "live-bytes: reset page=%p %d->0\n",
    254                  static_cast<void*>(this), live_byte_count_);
    255   }
    256   live_byte_count_ = 0;
    257 }
    258 
    259 void MemoryChunk::IncrementLiveBytes(int by) {
    260   if (IsFlagSet(BLACK_PAGE)) return;
    261   if (FLAG_trace_live_bytes) {
    262     PrintIsolate(
    263         heap()->isolate(), "live-bytes: update page=%p delta=%d %d->%d\n",
    264         static_cast<void*>(this), by, live_byte_count_, live_byte_count_ + by);
    265   }
    266   live_byte_count_ += by;
    267   DCHECK_GE(live_byte_count_, 0);
    268   DCHECK_LE(static_cast<size_t>(live_byte_count_), size_);
    269 }
    270 
    271 void MemoryChunk::IncrementLiveBytesFromMutator(HeapObject* object, int by) {
    272   MemoryChunk* chunk = MemoryChunk::FromAddress(object->address());
    273   if (!chunk->InNewSpace() && !static_cast<Page*>(chunk)->SweepingDone()) {
    274     static_cast<PagedSpace*>(chunk->owner())->Allocate(by);
    275   }
    276   chunk->IncrementLiveBytes(by);
    277 }
    278 
    279 bool PagedSpace::Contains(Address addr) {
    280   Page* p = Page::FromAddress(addr);
    281   if (!Page::IsValid(p)) return false;
    282   return p->owner() == this;
    283 }
    284 
    285 bool PagedSpace::Contains(Object* o) {
    286   if (!o->IsHeapObject()) return false;
    287   Page* p = Page::FromAddress(HeapObject::cast(o)->address());
    288   if (!Page::IsValid(p)) return false;
    289   return p->owner() == this;
    290 }
    291 
    292 void PagedSpace::UnlinkFreeListCategories(Page* page) {
    293   DCHECK_EQ(this, page->owner());
    294   page->ForAllFreeListCategories([this](FreeListCategory* category) {
    295     DCHECK_EQ(free_list(), category->owner());
    296     free_list()->RemoveCategory(category);
    297   });
    298 }
    299 
    300 intptr_t PagedSpace::RelinkFreeListCategories(Page* page) {
    301   DCHECK_EQ(this, page->owner());
    302   intptr_t added = 0;
    303   page->ForAllFreeListCategories([&added](FreeListCategory* category) {
    304     added += category->available();
    305     category->Relink();
    306   });
    307   return added;
    308 }
    309 
    310 MemoryChunk* MemoryChunk::FromAnyPointerAddress(Heap* heap, Address addr) {
    311   MemoryChunk* chunk = MemoryChunk::FromAddress(addr);
    312   uintptr_t offset = addr - chunk->address();
    313   if (offset < MemoryChunk::kHeaderSize || !chunk->HasPageHeader()) {
    314     chunk = heap->lo_space()->FindPage(addr);
    315   }
    316   return chunk;
    317 }
    318 
    319 Page* Page::FromAnyPointerAddress(Heap* heap, Address addr) {
    320   return static_cast<Page*>(MemoryChunk::FromAnyPointerAddress(heap, addr));
    321 }
    322 
    323 void Page::MarkNeverAllocateForTesting() {
    324   DCHECK(this->owner()->identity() != NEW_SPACE);
    325   DCHECK(!IsFlagSet(NEVER_ALLOCATE_ON_PAGE));
    326   SetFlag(NEVER_ALLOCATE_ON_PAGE);
    327   reinterpret_cast<PagedSpace*>(owner())->free_list()->EvictFreeListItems(this);
    328 }
    329 
    330 void Page::MarkEvacuationCandidate() {
    331   DCHECK(!IsFlagSet(NEVER_EVACUATE));
    332   DCHECK_NULL(old_to_old_slots_);
    333   DCHECK_NULL(typed_old_to_old_slots_);
    334   SetFlag(EVACUATION_CANDIDATE);
    335   reinterpret_cast<PagedSpace*>(owner())->free_list()->EvictFreeListItems(this);
    336 }
    337 
    338 void Page::ClearEvacuationCandidate() {
    339   if (!IsFlagSet(COMPACTION_WAS_ABORTED)) {
    340     DCHECK_NULL(old_to_old_slots_);
    341     DCHECK_NULL(typed_old_to_old_slots_);
    342   }
    343   ClearFlag(EVACUATION_CANDIDATE);
    344   InitializeFreeListCategories();
    345 }
    346 
    347 MemoryChunkIterator::MemoryChunkIterator(Heap* heap)
    348     : heap_(heap),
    349       state_(kOldSpaceState),
    350       old_iterator_(heap->old_space()->begin()),
    351       code_iterator_(heap->code_space()->begin()),
    352       map_iterator_(heap->map_space()->begin()),
    353       lo_iterator_(heap->lo_space()->begin()) {}
    354 
    355 MemoryChunk* MemoryChunkIterator::next() {
    356   switch (state_) {
    357     case kOldSpaceState: {
    358       if (old_iterator_ != heap_->old_space()->end()) return *(old_iterator_++);
    359       state_ = kMapState;
    360       // Fall through.
    361     }
    362     case kMapState: {
    363       if (map_iterator_ != heap_->map_space()->end()) return *(map_iterator_++);
    364       state_ = kCodeState;
    365       // Fall through.
    366     }
    367     case kCodeState: {
    368       if (code_iterator_ != heap_->code_space()->end())
    369         return *(code_iterator_++);
    370       state_ = kLargeObjectState;
    371       // Fall through.
    372     }
    373     case kLargeObjectState: {
    374       if (lo_iterator_ != heap_->lo_space()->end()) return *(lo_iterator_++);
    375       state_ = kFinishedState;
    376       // Fall through;
    377     }
    378     case kFinishedState:
    379       return nullptr;
    380     default:
    381       break;
    382   }
    383   UNREACHABLE();
    384   return nullptr;
    385 }
    386 
    387 Page* FreeListCategory::page() {
    388   return Page::FromAddress(reinterpret_cast<Address>(this));
    389 }
    390 
    391 FreeList* FreeListCategory::owner() {
    392   return reinterpret_cast<PagedSpace*>(
    393              Page::FromAddress(reinterpret_cast<Address>(this))->owner())
    394       ->free_list();
    395 }
    396 
    397 bool FreeListCategory::is_linked() {
    398   return prev_ != nullptr || next_ != nullptr || owner()->top(type_) == this;
    399 }
    400 
    401 // Try linear allocation in the page of alloc_info's allocation top.  Does
    402 // not contain slow case logic (e.g. move to the next page or try free list
    403 // allocation) so it can be used by all the allocation functions and for all
    404 // the paged spaces.
    405 HeapObject* PagedSpace::AllocateLinearly(int size_in_bytes) {
    406   Address current_top = allocation_info_.top();
    407   Address new_top = current_top + size_in_bytes;
    408   if (new_top > allocation_info_.limit()) return NULL;
    409 
    410   allocation_info_.set_top(new_top);
    411   return HeapObject::FromAddress(current_top);
    412 }
    413 
    414 
    415 AllocationResult LocalAllocationBuffer::AllocateRawAligned(
    416     int size_in_bytes, AllocationAlignment alignment) {
    417   Address current_top = allocation_info_.top();
    418   int filler_size = Heap::GetFillToAlign(current_top, alignment);
    419 
    420   Address new_top = current_top + filler_size + size_in_bytes;
    421   if (new_top > allocation_info_.limit()) return AllocationResult::Retry();
    422 
    423   allocation_info_.set_top(new_top);
    424   if (filler_size > 0) {
    425     return heap_->PrecedeWithFiller(HeapObject::FromAddress(current_top),
    426                                     filler_size);
    427   }
    428 
    429   return AllocationResult(HeapObject::FromAddress(current_top));
    430 }
    431 
    432 
    433 HeapObject* PagedSpace::AllocateLinearlyAligned(int* size_in_bytes,
    434                                                 AllocationAlignment alignment) {
    435   Address current_top = allocation_info_.top();
    436   int filler_size = Heap::GetFillToAlign(current_top, alignment);
    437 
    438   Address new_top = current_top + filler_size + *size_in_bytes;
    439   if (new_top > allocation_info_.limit()) return NULL;
    440 
    441   allocation_info_.set_top(new_top);
    442   if (filler_size > 0) {
    443     *size_in_bytes += filler_size;
    444     return heap()->PrecedeWithFiller(HeapObject::FromAddress(current_top),
    445                                      filler_size);
    446   }
    447 
    448   return HeapObject::FromAddress(current_top);
    449 }
    450 
    451 
    452 // Raw allocation.
    453 AllocationResult PagedSpace::AllocateRawUnaligned(
    454     int size_in_bytes, UpdateSkipList update_skip_list) {
    455   HeapObject* object = AllocateLinearly(size_in_bytes);
    456 
    457   if (object == NULL) {
    458     object = free_list_.Allocate(size_in_bytes);
    459     if (object == NULL) {
    460       object = SlowAllocateRaw(size_in_bytes);
    461     }
    462   }
    463 
    464   if (object != NULL) {
    465     if (update_skip_list == UPDATE_SKIP_LIST && identity() == CODE_SPACE) {
    466       SkipList::Update(object->address(), size_in_bytes);
    467     }
    468     MSAN_ALLOCATED_UNINITIALIZED_MEMORY(object->address(), size_in_bytes);
    469     return object;
    470   }
    471 
    472   return AllocationResult::Retry(identity());
    473 }
    474 
    475 
    476 AllocationResult PagedSpace::AllocateRawUnalignedSynchronized(
    477     int size_in_bytes) {
    478   base::LockGuard<base::Mutex> lock_guard(&space_mutex_);
    479   return AllocateRawUnaligned(size_in_bytes);
    480 }
    481 
    482 
    483 // Raw allocation.
    484 AllocationResult PagedSpace::AllocateRawAligned(int size_in_bytes,
    485                                                 AllocationAlignment alignment) {
    486   DCHECK(identity() == OLD_SPACE);
    487   int allocation_size = size_in_bytes;
    488   HeapObject* object = AllocateLinearlyAligned(&allocation_size, alignment);
    489 
    490   if (object == NULL) {
    491     // We don't know exactly how much filler we need to align until space is
    492     // allocated, so assume the worst case.
    493     int filler_size = Heap::GetMaximumFillToAlign(alignment);
    494     allocation_size += filler_size;
    495     object = free_list_.Allocate(allocation_size);
    496     if (object == NULL) {
    497       object = SlowAllocateRaw(allocation_size);
    498     }
    499     if (object != NULL && filler_size != 0) {
    500       object = heap()->AlignWithFiller(object, size_in_bytes, allocation_size,
    501                                        alignment);
    502       // Filler objects are initialized, so mark only the aligned object memory
    503       // as uninitialized.
    504       allocation_size = size_in_bytes;
    505     }
    506   }
    507 
    508   if (object != NULL) {
    509     MSAN_ALLOCATED_UNINITIALIZED_MEMORY(object->address(), allocation_size);
    510     return object;
    511   }
    512 
    513   return AllocationResult::Retry(identity());
    514 }
    515 
    516 
    517 AllocationResult PagedSpace::AllocateRaw(int size_in_bytes,
    518                                          AllocationAlignment alignment) {
    519 #ifdef V8_HOST_ARCH_32_BIT
    520   AllocationResult result =
    521       alignment == kDoubleAligned
    522           ? AllocateRawAligned(size_in_bytes, kDoubleAligned)
    523           : AllocateRawUnaligned(size_in_bytes);
    524 #else
    525   AllocationResult result = AllocateRawUnaligned(size_in_bytes);
    526 #endif
    527   HeapObject* heap_obj = nullptr;
    528   if (!result.IsRetry() && result.To(&heap_obj)) {
    529     AllocationStep(heap_obj->address(), size_in_bytes);
    530   }
    531   return result;
    532 }
    533 
    534 
    535 // -----------------------------------------------------------------------------
    536 // NewSpace
    537 
    538 
    539 AllocationResult NewSpace::AllocateRawAligned(int size_in_bytes,
    540                                               AllocationAlignment alignment) {
    541   Address top = allocation_info_.top();
    542   int filler_size = Heap::GetFillToAlign(top, alignment);
    543   int aligned_size_in_bytes = size_in_bytes + filler_size;
    544 
    545   if (allocation_info_.limit() - top < aligned_size_in_bytes) {
    546     // See if we can create room.
    547     if (!EnsureAllocation(size_in_bytes, alignment)) {
    548       return AllocationResult::Retry();
    549     }
    550 
    551     top = allocation_info_.top();
    552     filler_size = Heap::GetFillToAlign(top, alignment);
    553     aligned_size_in_bytes = size_in_bytes + filler_size;
    554   }
    555 
    556   HeapObject* obj = HeapObject::FromAddress(top);
    557   allocation_info_.set_top(top + aligned_size_in_bytes);
    558   DCHECK_SEMISPACE_ALLOCATION_INFO(allocation_info_, to_space_);
    559 
    560   if (filler_size > 0) {
    561     obj = heap()->PrecedeWithFiller(obj, filler_size);
    562   }
    563 
    564   MSAN_ALLOCATED_UNINITIALIZED_MEMORY(obj->address(), size_in_bytes);
    565 
    566   return obj;
    567 }
    568 
    569 
    570 AllocationResult NewSpace::AllocateRawUnaligned(int size_in_bytes) {
    571   Address top = allocation_info_.top();
    572   if (allocation_info_.limit() < top + size_in_bytes) {
    573     // See if we can create room.
    574     if (!EnsureAllocation(size_in_bytes, kWordAligned)) {
    575       return AllocationResult::Retry();
    576     }
    577 
    578     top = allocation_info_.top();
    579   }
    580 
    581   HeapObject* obj = HeapObject::FromAddress(top);
    582   allocation_info_.set_top(top + size_in_bytes);
    583   DCHECK_SEMISPACE_ALLOCATION_INFO(allocation_info_, to_space_);
    584 
    585   MSAN_ALLOCATED_UNINITIALIZED_MEMORY(obj->address(), size_in_bytes);
    586 
    587   return obj;
    588 }
    589 
    590 
    591 AllocationResult NewSpace::AllocateRaw(int size_in_bytes,
    592                                        AllocationAlignment alignment) {
    593 #ifdef V8_HOST_ARCH_32_BIT
    594   return alignment == kDoubleAligned
    595              ? AllocateRawAligned(size_in_bytes, kDoubleAligned)
    596              : AllocateRawUnaligned(size_in_bytes);
    597 #else
    598   return AllocateRawUnaligned(size_in_bytes);
    599 #endif
    600 }
    601 
    602 
    603 MUST_USE_RESULT inline AllocationResult NewSpace::AllocateRawSynchronized(
    604     int size_in_bytes, AllocationAlignment alignment) {
    605   base::LockGuard<base::Mutex> guard(&mutex_);
    606   return AllocateRaw(size_in_bytes, alignment);
    607 }
    608 
    609 LargePage* LargePage::Initialize(Heap* heap, MemoryChunk* chunk,
    610                                  Executability executable, Space* owner) {
    611   if (executable && chunk->size() > LargePage::kMaxCodePageSize) {
    612     STATIC_ASSERT(LargePage::kMaxCodePageSize <= TypedSlotSet::kMaxOffset);
    613     FATAL("Code page is too large.");
    614   }
    615   heap->incremental_marking()->SetOldSpacePageFlags(chunk);
    616   return static_cast<LargePage*>(chunk);
    617 }
    618 
    619 
    620 intptr_t LargeObjectSpace::Available() {
    621   return ObjectSizeFor(heap()->memory_allocator()->Available());
    622 }
    623 
    624 
    625 LocalAllocationBuffer LocalAllocationBuffer::InvalidBuffer() {
    626   return LocalAllocationBuffer(nullptr, AllocationInfo(nullptr, nullptr));
    627 }
    628 
    629 
    630 LocalAllocationBuffer LocalAllocationBuffer::FromResult(Heap* heap,
    631                                                         AllocationResult result,
    632                                                         intptr_t size) {
    633   if (result.IsRetry()) return InvalidBuffer();
    634   HeapObject* obj = nullptr;
    635   bool ok = result.To(&obj);
    636   USE(ok);
    637   DCHECK(ok);
    638   Address top = HeapObject::cast(obj)->address();
    639   return LocalAllocationBuffer(heap, AllocationInfo(top, top + size));
    640 }
    641 
    642 
    643 bool LocalAllocationBuffer::TryMerge(LocalAllocationBuffer* other) {
    644   if (allocation_info_.top() == other->allocation_info_.limit()) {
    645     allocation_info_.set_top(other->allocation_info_.top());
    646     other->allocation_info_.Reset(nullptr, nullptr);
    647     return true;
    648   }
    649   return false;
    650 }
    651 
    652 }  // namespace internal
    653 }  // namespace v8
    654 
    655 #endif  // V8_HEAP_SPACES_INL_H_
    656