11cb0ef41Sopenharmony_ci// Copyright 2020 the V8 project authors. All rights reserved. 21cb0ef41Sopenharmony_ci// Use of this source code is governed by a BSD-style license that can be 31cb0ef41Sopenharmony_ci// found in the LICENSE file. 41cb0ef41Sopenharmony_ci 51cb0ef41Sopenharmony_ci#ifndef V8_HEAP_CPPGC_OBJECT_ALLOCATOR_H_ 61cb0ef41Sopenharmony_ci#define V8_HEAP_CPPGC_OBJECT_ALLOCATOR_H_ 71cb0ef41Sopenharmony_ci 81cb0ef41Sopenharmony_ci#include "include/cppgc/allocation.h" 91cb0ef41Sopenharmony_ci#include "include/cppgc/internal/gc-info.h" 101cb0ef41Sopenharmony_ci#include "include/cppgc/macros.h" 111cb0ef41Sopenharmony_ci#include "src/base/logging.h" 121cb0ef41Sopenharmony_ci#include "src/heap/cppgc/globals.h" 131cb0ef41Sopenharmony_ci#include "src/heap/cppgc/heap-object-header.h" 141cb0ef41Sopenharmony_ci#include "src/heap/cppgc/heap-page.h" 151cb0ef41Sopenharmony_ci#include "src/heap/cppgc/heap-space.h" 161cb0ef41Sopenharmony_ci#include "src/heap/cppgc/memory.h" 171cb0ef41Sopenharmony_ci#include "src/heap/cppgc/object-start-bitmap.h" 181cb0ef41Sopenharmony_ci#include "src/heap/cppgc/raw-heap.h" 191cb0ef41Sopenharmony_ci 201cb0ef41Sopenharmony_cinamespace cppgc { 211cb0ef41Sopenharmony_ci 221cb0ef41Sopenharmony_cinamespace internal { 231cb0ef41Sopenharmony_ciclass ObjectAllocator; 241cb0ef41Sopenharmony_ciclass PreFinalizerHandler; 251cb0ef41Sopenharmony_ci} // namespace internal 261cb0ef41Sopenharmony_ci 271cb0ef41Sopenharmony_ciclass V8_EXPORT AllocationHandle { 281cb0ef41Sopenharmony_ci private: 291cb0ef41Sopenharmony_ci AllocationHandle() = default; 301cb0ef41Sopenharmony_ci friend class internal::ObjectAllocator; 311cb0ef41Sopenharmony_ci}; 321cb0ef41Sopenharmony_ci 331cb0ef41Sopenharmony_cinamespace internal { 341cb0ef41Sopenharmony_ci 351cb0ef41Sopenharmony_ciclass StatsCollector; 361cb0ef41Sopenharmony_ciclass PageBackend; 371cb0ef41Sopenharmony_ci 381cb0ef41Sopenharmony_ciclass V8_EXPORT_PRIVATE ObjectAllocator final : public cppgc::AllocationHandle { 391cb0ef41Sopenharmony_ci public: 401cb0ef41Sopenharmony_ci static constexpr size_t kSmallestSpaceSize = 32; 411cb0ef41Sopenharmony_ci 421cb0ef41Sopenharmony_ci ObjectAllocator(RawHeap& heap, PageBackend& page_backend, 431cb0ef41Sopenharmony_ci StatsCollector& stats_collector, 441cb0ef41Sopenharmony_ci PreFinalizerHandler& prefinalizer_handler); 451cb0ef41Sopenharmony_ci 461cb0ef41Sopenharmony_ci inline void* AllocateObject(size_t size, GCInfoIndex gcinfo); 471cb0ef41Sopenharmony_ci inline void* AllocateObject(size_t size, AlignVal alignment, 481cb0ef41Sopenharmony_ci GCInfoIndex gcinfo); 491cb0ef41Sopenharmony_ci inline void* AllocateObject(size_t size, GCInfoIndex gcinfo, 501cb0ef41Sopenharmony_ci CustomSpaceIndex space_index); 511cb0ef41Sopenharmony_ci inline void* AllocateObject(size_t size, AlignVal alignment, 521cb0ef41Sopenharmony_ci GCInfoIndex gcinfo, CustomSpaceIndex space_index); 531cb0ef41Sopenharmony_ci 541cb0ef41Sopenharmony_ci void ResetLinearAllocationBuffers(); 551cb0ef41Sopenharmony_ci 561cb0ef41Sopenharmony_ci // Terminate the allocator. Subsequent allocation calls result in a crash. 571cb0ef41Sopenharmony_ci void Terminate(); 581cb0ef41Sopenharmony_ci 591cb0ef41Sopenharmony_ci private: 601cb0ef41Sopenharmony_ci bool in_disallow_gc_scope() const; 611cb0ef41Sopenharmony_ci 621cb0ef41Sopenharmony_ci // Returns the initially tried SpaceType to allocate an object of |size| bytes 631cb0ef41Sopenharmony_ci // on. Returns the largest regular object size bucket for large objects. 641cb0ef41Sopenharmony_ci inline static RawHeap::RegularSpaceType GetInitialSpaceIndexForSize( 651cb0ef41Sopenharmony_ci size_t size); 661cb0ef41Sopenharmony_ci 671cb0ef41Sopenharmony_ci inline void* AllocateObjectOnSpace(NormalPageSpace& space, size_t size, 681cb0ef41Sopenharmony_ci GCInfoIndex gcinfo); 691cb0ef41Sopenharmony_ci inline void* AllocateObjectOnSpace(NormalPageSpace& space, size_t size, 701cb0ef41Sopenharmony_ci AlignVal alignment, GCInfoIndex gcinfo); 711cb0ef41Sopenharmony_ci void* OutOfLineAllocate(NormalPageSpace&, size_t, AlignVal, GCInfoIndex); 721cb0ef41Sopenharmony_ci void* OutOfLineAllocateImpl(NormalPageSpace&, size_t, AlignVal, GCInfoIndex); 731cb0ef41Sopenharmony_ci 741cb0ef41Sopenharmony_ci void RefillLinearAllocationBuffer(NormalPageSpace&, size_t); 751cb0ef41Sopenharmony_ci bool RefillLinearAllocationBufferFromFreeList(NormalPageSpace&, size_t); 761cb0ef41Sopenharmony_ci 771cb0ef41Sopenharmony_ci RawHeap& raw_heap_; 781cb0ef41Sopenharmony_ci PageBackend& page_backend_; 791cb0ef41Sopenharmony_ci StatsCollector& stats_collector_; 801cb0ef41Sopenharmony_ci PreFinalizerHandler& prefinalizer_handler_; 811cb0ef41Sopenharmony_ci}; 821cb0ef41Sopenharmony_ci 831cb0ef41Sopenharmony_civoid* ObjectAllocator::AllocateObject(size_t size, GCInfoIndex gcinfo) { 841cb0ef41Sopenharmony_ci DCHECK(!in_disallow_gc_scope()); 851cb0ef41Sopenharmony_ci const size_t allocation_size = 861cb0ef41Sopenharmony_ci RoundUp<kAllocationGranularity>(size + sizeof(HeapObjectHeader)); 871cb0ef41Sopenharmony_ci const RawHeap::RegularSpaceType type = 881cb0ef41Sopenharmony_ci GetInitialSpaceIndexForSize(allocation_size); 891cb0ef41Sopenharmony_ci return AllocateObjectOnSpace(NormalPageSpace::From(*raw_heap_.Space(type)), 901cb0ef41Sopenharmony_ci allocation_size, gcinfo); 911cb0ef41Sopenharmony_ci} 921cb0ef41Sopenharmony_ci 931cb0ef41Sopenharmony_civoid* ObjectAllocator::AllocateObject(size_t size, AlignVal alignment, 941cb0ef41Sopenharmony_ci GCInfoIndex gcinfo) { 951cb0ef41Sopenharmony_ci DCHECK(!in_disallow_gc_scope()); 961cb0ef41Sopenharmony_ci const size_t allocation_size = 971cb0ef41Sopenharmony_ci RoundUp<kAllocationGranularity>(size + sizeof(HeapObjectHeader)); 981cb0ef41Sopenharmony_ci const RawHeap::RegularSpaceType type = 991cb0ef41Sopenharmony_ci GetInitialSpaceIndexForSize(allocation_size); 1001cb0ef41Sopenharmony_ci return AllocateObjectOnSpace(NormalPageSpace::From(*raw_heap_.Space(type)), 1011cb0ef41Sopenharmony_ci allocation_size, alignment, gcinfo); 1021cb0ef41Sopenharmony_ci} 1031cb0ef41Sopenharmony_ci 1041cb0ef41Sopenharmony_civoid* ObjectAllocator::AllocateObject(size_t size, GCInfoIndex gcinfo, 1051cb0ef41Sopenharmony_ci CustomSpaceIndex space_index) { 1061cb0ef41Sopenharmony_ci DCHECK(!in_disallow_gc_scope()); 1071cb0ef41Sopenharmony_ci const size_t allocation_size = 1081cb0ef41Sopenharmony_ci RoundUp<kAllocationGranularity>(size + sizeof(HeapObjectHeader)); 1091cb0ef41Sopenharmony_ci return AllocateObjectOnSpace( 1101cb0ef41Sopenharmony_ci NormalPageSpace::From(*raw_heap_.CustomSpace(space_index)), 1111cb0ef41Sopenharmony_ci allocation_size, gcinfo); 1121cb0ef41Sopenharmony_ci} 1131cb0ef41Sopenharmony_ci 1141cb0ef41Sopenharmony_civoid* ObjectAllocator::AllocateObject(size_t size, AlignVal alignment, 1151cb0ef41Sopenharmony_ci GCInfoIndex gcinfo, 1161cb0ef41Sopenharmony_ci CustomSpaceIndex space_index) { 1171cb0ef41Sopenharmony_ci DCHECK(!in_disallow_gc_scope()); 1181cb0ef41Sopenharmony_ci const size_t allocation_size = 1191cb0ef41Sopenharmony_ci RoundUp<kAllocationGranularity>(size + sizeof(HeapObjectHeader)); 1201cb0ef41Sopenharmony_ci return AllocateObjectOnSpace( 1211cb0ef41Sopenharmony_ci NormalPageSpace::From(*raw_heap_.CustomSpace(space_index)), 1221cb0ef41Sopenharmony_ci allocation_size, alignment, gcinfo); 1231cb0ef41Sopenharmony_ci} 1241cb0ef41Sopenharmony_ci 1251cb0ef41Sopenharmony_ci// static 1261cb0ef41Sopenharmony_ciRawHeap::RegularSpaceType ObjectAllocator::GetInitialSpaceIndexForSize( 1271cb0ef41Sopenharmony_ci size_t size) { 1281cb0ef41Sopenharmony_ci static_assert(kSmallestSpaceSize == 32, 1291cb0ef41Sopenharmony_ci "should be half the next larger size"); 1301cb0ef41Sopenharmony_ci if (size < 64) { 1311cb0ef41Sopenharmony_ci if (size < kSmallestSpaceSize) return RawHeap::RegularSpaceType::kNormal1; 1321cb0ef41Sopenharmony_ci return RawHeap::RegularSpaceType::kNormal2; 1331cb0ef41Sopenharmony_ci } 1341cb0ef41Sopenharmony_ci if (size < 128) return RawHeap::RegularSpaceType::kNormal3; 1351cb0ef41Sopenharmony_ci return RawHeap::RegularSpaceType::kNormal4; 1361cb0ef41Sopenharmony_ci} 1371cb0ef41Sopenharmony_ci 1381cb0ef41Sopenharmony_civoid* ObjectAllocator::AllocateObjectOnSpace(NormalPageSpace& space, 1391cb0ef41Sopenharmony_ci size_t size, AlignVal alignment, 1401cb0ef41Sopenharmony_ci GCInfoIndex gcinfo) { 1411cb0ef41Sopenharmony_ci // The APIs are set up to support general alignment. Since we want to keep 1421cb0ef41Sopenharmony_ci // track of the actual usage there the alignment support currently only covers 1431cb0ef41Sopenharmony_ci // double-world alignment (8 bytes on 32bit and 16 bytes on 64bit 1441cb0ef41Sopenharmony_ci // architectures). This is enforced on the public API via static_asserts 1451cb0ef41Sopenharmony_ci // against alignof(T). 1461cb0ef41Sopenharmony_ci STATIC_ASSERT(2 * kAllocationGranularity == 1471cb0ef41Sopenharmony_ci api_constants::kMaxSupportedAlignment); 1481cb0ef41Sopenharmony_ci STATIC_ASSERT(kAllocationGranularity == sizeof(HeapObjectHeader)); 1491cb0ef41Sopenharmony_ci STATIC_ASSERT(kAllocationGranularity == 1501cb0ef41Sopenharmony_ci api_constants::kAllocationGranularity); 1511cb0ef41Sopenharmony_ci DCHECK_EQ(2 * sizeof(HeapObjectHeader), static_cast<size_t>(alignment)); 1521cb0ef41Sopenharmony_ci constexpr size_t kAlignment = 2 * kAllocationGranularity; 1531cb0ef41Sopenharmony_ci constexpr size_t kAlignmentMask = kAlignment - 1; 1541cb0ef41Sopenharmony_ci constexpr size_t kPaddingSize = kAlignment - sizeof(HeapObjectHeader); 1551cb0ef41Sopenharmony_ci 1561cb0ef41Sopenharmony_ci NormalPageSpace::LinearAllocationBuffer& current_lab = 1571cb0ef41Sopenharmony_ci space.linear_allocation_buffer(); 1581cb0ef41Sopenharmony_ci const size_t current_lab_size = current_lab.size(); 1591cb0ef41Sopenharmony_ci // Case 1: The LAB fits the request and the LAB start is already properly 1601cb0ef41Sopenharmony_ci // aligned. 1611cb0ef41Sopenharmony_ci bool lab_allocation_will_succeed = 1621cb0ef41Sopenharmony_ci current_lab_size >= size && 1631cb0ef41Sopenharmony_ci (reinterpret_cast<uintptr_t>(current_lab.start() + 1641cb0ef41Sopenharmony_ci sizeof(HeapObjectHeader)) & 1651cb0ef41Sopenharmony_ci kAlignmentMask) == 0; 1661cb0ef41Sopenharmony_ci // Case 2: The LAB fits an extended request to manually align the second 1671cb0ef41Sopenharmony_ci // allocation. 1681cb0ef41Sopenharmony_ci if (!lab_allocation_will_succeed && 1691cb0ef41Sopenharmony_ci (current_lab_size >= (size + kPaddingSize))) { 1701cb0ef41Sopenharmony_ci void* filler_memory = current_lab.Allocate(kPaddingSize); 1711cb0ef41Sopenharmony_ci auto& filler = Filler::CreateAt(filler_memory, kPaddingSize); 1721cb0ef41Sopenharmony_ci NormalPage::From(BasePage::FromPayload(&filler)) 1731cb0ef41Sopenharmony_ci ->object_start_bitmap() 1741cb0ef41Sopenharmony_ci .SetBit<AccessMode::kAtomic>(reinterpret_cast<ConstAddress>(&filler)); 1751cb0ef41Sopenharmony_ci lab_allocation_will_succeed = true; 1761cb0ef41Sopenharmony_ci } 1771cb0ef41Sopenharmony_ci if (lab_allocation_will_succeed) { 1781cb0ef41Sopenharmony_ci void* object = AllocateObjectOnSpace(space, size, gcinfo); 1791cb0ef41Sopenharmony_ci DCHECK_NOT_NULL(object); 1801cb0ef41Sopenharmony_ci DCHECK_EQ(0u, reinterpret_cast<uintptr_t>(object) & kAlignmentMask); 1811cb0ef41Sopenharmony_ci return object; 1821cb0ef41Sopenharmony_ci } 1831cb0ef41Sopenharmony_ci return OutOfLineAllocate(space, size, alignment, gcinfo); 1841cb0ef41Sopenharmony_ci} 1851cb0ef41Sopenharmony_ci 1861cb0ef41Sopenharmony_civoid* ObjectAllocator::AllocateObjectOnSpace(NormalPageSpace& space, 1871cb0ef41Sopenharmony_ci size_t size, GCInfoIndex gcinfo) { 1881cb0ef41Sopenharmony_ci DCHECK_LT(0u, gcinfo); 1891cb0ef41Sopenharmony_ci 1901cb0ef41Sopenharmony_ci NormalPageSpace::LinearAllocationBuffer& current_lab = 1911cb0ef41Sopenharmony_ci space.linear_allocation_buffer(); 1921cb0ef41Sopenharmony_ci if (current_lab.size() < size) { 1931cb0ef41Sopenharmony_ci return OutOfLineAllocate( 1941cb0ef41Sopenharmony_ci space, size, static_cast<AlignVal>(kAllocationGranularity), gcinfo); 1951cb0ef41Sopenharmony_ci } 1961cb0ef41Sopenharmony_ci 1971cb0ef41Sopenharmony_ci void* raw = current_lab.Allocate(size); 1981cb0ef41Sopenharmony_ci#if !defined(V8_USE_MEMORY_SANITIZER) && !defined(V8_USE_ADDRESS_SANITIZER) && \ 1991cb0ef41Sopenharmony_ci DEBUG 2001cb0ef41Sopenharmony_ci // For debug builds, unzap only the payload. 2011cb0ef41Sopenharmony_ci SetMemoryAccessible(static_cast<char*>(raw) + sizeof(HeapObjectHeader), 2021cb0ef41Sopenharmony_ci size - sizeof(HeapObjectHeader)); 2031cb0ef41Sopenharmony_ci#else 2041cb0ef41Sopenharmony_ci SetMemoryAccessible(raw, size); 2051cb0ef41Sopenharmony_ci#endif 2061cb0ef41Sopenharmony_ci auto* header = new (raw) HeapObjectHeader(size, gcinfo); 2071cb0ef41Sopenharmony_ci 2081cb0ef41Sopenharmony_ci // The marker needs to find the object start concurrently. 2091cb0ef41Sopenharmony_ci NormalPage::From(BasePage::FromPayload(header)) 2101cb0ef41Sopenharmony_ci ->object_start_bitmap() 2111cb0ef41Sopenharmony_ci .SetBit<AccessMode::kAtomic>(reinterpret_cast<ConstAddress>(header)); 2121cb0ef41Sopenharmony_ci 2131cb0ef41Sopenharmony_ci return header->ObjectStart(); 2141cb0ef41Sopenharmony_ci} 2151cb0ef41Sopenharmony_ci 2161cb0ef41Sopenharmony_ci} // namespace internal 2171cb0ef41Sopenharmony_ci} // namespace cppgc 2181cb0ef41Sopenharmony_ci 2191cb0ef41Sopenharmony_ci#endif // V8_HEAP_CPPGC_OBJECT_ALLOCATOR_H_ 220