| // Copyright 2020 the V8 project authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #ifndef V8_HEAP_PAGED_SPACES_INL_H_ |
| #define V8_HEAP_PAGED_SPACES_INL_H_ |
| |
| #include "src/common/globals.h" |
| #include "src/heap/heap-inl.h" |
| #include "src/heap/incremental-marking.h" |
| #include "src/heap/paged-spaces.h" |
| #include "src/objects/code-inl.h" |
| #include "src/objects/heap-object.h" |
| #include "src/objects/objects-inl.h" |
| |
| namespace v8 { |
| namespace internal { |
| |
| // ----------------------------------------------------------------------------- |
| // PagedSpaceObjectIterator |
| |
| HeapObject PagedSpaceObjectIterator::Next() { |
| do { |
| HeapObject next_obj = FromCurrentPage(); |
| if (!next_obj.is_null()) return next_obj; |
| } while (AdvanceToNextPage()); |
| return HeapObject(); |
| } |
| |
| HeapObject PagedSpaceObjectIterator::FromCurrentPage() { |
| while (cur_addr_ != cur_end_) { |
| HeapObject obj = HeapObject::FromAddress(cur_addr_); |
| const int obj_size = obj.Size(); |
| cur_addr_ += obj_size; |
| DCHECK_LE(cur_addr_, cur_end_); |
| if (!obj.IsFreeSpaceOrFiller()) { |
| if (obj.IsCode()) { |
| DCHECK_EQ(space_->identity(), CODE_SPACE); |
| DCHECK_CODEOBJECT_SIZE(obj_size, space_); |
| } else { |
| DCHECK_OBJECT_SIZE(obj_size); |
| } |
| return obj; |
| } |
| } |
| return HeapObject(); |
| } |
| |
| bool PagedSpace::Contains(Address addr) const { |
| if (V8_ENABLE_THIRD_PARTY_HEAP_BOOL) { |
| return true; |
| } |
| return Page::FromAddress(addr)->owner() == this; |
| } |
| |
| bool PagedSpace::Contains(Object o) const { |
| if (!o.IsHeapObject()) return false; |
| return Page::FromAddress(o.ptr())->owner() == this; |
| } |
| |
| void PagedSpace::UnlinkFreeListCategories(Page* page) { |
| DCHECK_EQ(this, page->owner()); |
| page->ForAllFreeListCategories([this](FreeListCategory* category) { |
| free_list()->RemoveCategory(category); |
| }); |
| } |
| |
| size_t PagedSpace::RelinkFreeListCategories(Page* page) { |
| DCHECK_EQ(this, page->owner()); |
| size_t added = 0; |
| page->ForAllFreeListCategories([this, &added](FreeListCategory* category) { |
| added += category->available(); |
| category->Relink(free_list()); |
| }); |
| |
| DCHECK_IMPLIES(!page->IsFlagSet(Page::NEVER_ALLOCATE_ON_PAGE), |
| page->AvailableInFreeList() == |
| page->AvailableInFreeListFromAllocatedBytes()); |
| return added; |
| } |
| |
| bool PagedSpace::TryFreeLast(HeapObject object, int object_size) { |
| if (allocation_info_.top() != kNullAddress) { |
| const Address object_address = object.address(); |
| if ((allocation_info_.top() - object_size) == object_address) { |
| allocation_info_.set_top(object_address); |
| return true; |
| } |
| } |
| return false; |
| } |
| |
| bool PagedSpace::EnsureLabMain(int size_in_bytes, AllocationOrigin origin) { |
| if (allocation_info_.top() + size_in_bytes <= allocation_info_.limit()) { |
| return true; |
| } |
| return RefillLabMain(size_in_bytes, origin); |
| } |
| |
| AllocationResult PagedSpace::AllocateFastUnaligned(int size_in_bytes) { |
| Address current_top = allocation_info_.top(); |
| Address new_top = current_top + size_in_bytes; |
| if (new_top > allocation_info_.limit()) |
| return AllocationResult::Retry(identity()); |
| DCHECK_LE(new_top, allocation_info_.limit()); |
| allocation_info_.set_top(new_top); |
| |
| return AllocationResult(HeapObject::FromAddress(current_top)); |
| } |
| |
| AllocationResult PagedSpace::AllocateFastAligned( |
| int size_in_bytes, int* aligned_size_in_bytes, |
| AllocationAlignment alignment) { |
| Address current_top = allocation_info_.top(); |
| int filler_size = Heap::GetFillToAlign(current_top, alignment); |
| |
| Address new_top = current_top + filler_size + size_in_bytes; |
| if (new_top > allocation_info_.limit()) |
| return AllocationResult::Retry(identity()); |
| |
| allocation_info_.set_top(new_top); |
| if (aligned_size_in_bytes) |
| *aligned_size_in_bytes = filler_size + size_in_bytes; |
| if (filler_size > 0) { |
| Heap::PrecedeWithFiller(ReadOnlyRoots(heap()), |
| HeapObject::FromAddress(current_top), filler_size); |
| } |
| |
| return AllocationResult(HeapObject::FromAddress(current_top + filler_size)); |
| } |
| |
| AllocationResult PagedSpace::AllocateRawUnaligned(int size_in_bytes, |
| AllocationOrigin origin) { |
| if (!EnsureLabMain(size_in_bytes, origin)) { |
| return AllocationResult::Retry(identity()); |
| } |
| |
| AllocationResult result = AllocateFastUnaligned(size_in_bytes); |
| DCHECK(!result.IsRetry()); |
| MSAN_ALLOCATED_UNINITIALIZED_MEMORY(result.ToObjectChecked().address(), |
| size_in_bytes); |
| |
| if (FLAG_trace_allocations_origins) { |
| UpdateAllocationOrigins(origin); |
| } |
| |
| InvokeAllocationObservers(result.ToAddress(), size_in_bytes, size_in_bytes, |
| size_in_bytes); |
| |
| return result; |
| } |
| |
| AllocationResult PagedSpace::AllocateRawAligned(int size_in_bytes, |
| AllocationAlignment alignment, |
| AllocationOrigin origin) { |
| DCHECK_EQ(identity(), OLD_SPACE); |
| int allocation_size = size_in_bytes; |
| // We don't know exactly how much filler we need to align until space is |
| // allocated, so assume the worst case. |
| int filler_size = Heap::GetMaximumFillToAlign(alignment); |
| allocation_size += filler_size; |
| if (!EnsureLabMain(allocation_size, origin)) { |
| return AllocationResult::Retry(identity()); |
| } |
| int aligned_size_in_bytes; |
| AllocationResult result = |
| AllocateFastAligned(size_in_bytes, &aligned_size_in_bytes, alignment); |
| DCHECK(!result.IsRetry()); |
| MSAN_ALLOCATED_UNINITIALIZED_MEMORY(result.ToObjectChecked().address(), |
| size_in_bytes); |
| |
| if (FLAG_trace_allocations_origins) { |
| UpdateAllocationOrigins(origin); |
| } |
| |
| InvokeAllocationObservers(result.ToAddress(), size_in_bytes, |
| aligned_size_in_bytes, allocation_size); |
| |
| return result; |
| } |
| |
| AllocationResult PagedSpace::AllocateRaw(int size_in_bytes, |
| AllocationAlignment alignment, |
| AllocationOrigin origin) { |
| AllocationResult result; |
| |
| if (alignment != kWordAligned) { |
| result = AllocateFastAligned(size_in_bytes, nullptr, alignment); |
| } else { |
| result = AllocateFastUnaligned(size_in_bytes); |
| } |
| |
| if (!result.IsRetry()) { |
| return result; |
| } else { |
| return AllocateRawSlow(size_in_bytes, alignment, origin); |
| } |
| } |
| |
| } // namespace internal |
| } // namespace v8 |
| |
| #endif // V8_HEAP_PAGED_SPACES_INL_H_ |