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