1 // Copyright 2020 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_CPPGC_OBJECT_ALLOCATOR_H_
6 #define V8_HEAP_CPPGC_OBJECT_ALLOCATOR_H_
7 
8 #include "include/cppgc/allocation.h"
9 #include "include/cppgc/internal/gc-info.h"
10 #include "include/cppgc/macros.h"
11 #include "src/base/logging.h"
12 #include "src/heap/cppgc/heap-object-header.h"
13 #include "src/heap/cppgc/heap-page.h"
14 #include "src/heap/cppgc/heap-space.h"
15 #include "src/heap/cppgc/memory.h"
16 #include "src/heap/cppgc/object-start-bitmap.h"
17 #include "src/heap/cppgc/raw-heap.h"
18 
19 namespace cppgc {
20 
21 namespace internal {
22 class ObjectAllocator;
23 class PreFinalizerHandler;
24 }  // namespace internal
25 
26 class V8_EXPORT AllocationHandle {
27  private:
28   AllocationHandle() = default;
29   friend class internal::ObjectAllocator;
30 };
31 
32 namespace internal {
33 
34 class StatsCollector;
35 class PageBackend;
36 
37 class V8_EXPORT_PRIVATE ObjectAllocator final : public cppgc::AllocationHandle {
38  public:
39   static constexpr size_t kSmallestSpaceSize = 32;
40 
41   ObjectAllocator(RawHeap& heap, PageBackend& page_backend,
42                   StatsCollector& stats_collector,
43                   PreFinalizerHandler& prefinalizer_handler);
44 
45   inline void* AllocateObject(size_t size, GCInfoIndex gcinfo);
46   inline void* AllocateObject(size_t size, GCInfoIndex gcinfo,
47                               CustomSpaceIndex space_index);
48 
49   void ResetLinearAllocationBuffers();
50 
51   // Terminate the allocator. Subsequent allocation calls result in a crash.
52   void Terminate();
53 
54  private:
55   bool in_disallow_gc_scope() const;
56 
57   // Returns the initially tried SpaceType to allocate an object of |size| bytes
58   // on. Returns the largest regular object size bucket for large objects.
59   inline static RawHeap::RegularSpaceType GetInitialSpaceIndexForSize(
60       size_t size);
61 
62   inline void* AllocateObjectOnSpace(NormalPageSpace& space, size_t size,
63                                      GCInfoIndex gcinfo);
64   void* OutOfLineAllocate(NormalPageSpace&, size_t, GCInfoIndex);
65   void* OutOfLineAllocateImpl(NormalPageSpace&, size_t, GCInfoIndex);
66   void* AllocateFromFreeList(NormalPageSpace&, size_t, GCInfoIndex);
67 
68   RawHeap& raw_heap_;
69   PageBackend& page_backend_;
70   StatsCollector& stats_collector_;
71   PreFinalizerHandler& prefinalizer_handler_;
72 };
73 
AllocateObject(size_t size,GCInfoIndex gcinfo)74 void* ObjectAllocator::AllocateObject(size_t size, GCInfoIndex gcinfo) {
75   DCHECK(!in_disallow_gc_scope());
76   const size_t allocation_size =
77       RoundUp<kAllocationGranularity>(size + sizeof(HeapObjectHeader));
78   const RawHeap::RegularSpaceType type =
79       GetInitialSpaceIndexForSize(allocation_size);
80   return AllocateObjectOnSpace(NormalPageSpace::From(*raw_heap_.Space(type)),
81                                allocation_size, gcinfo);
82 }
83 
AllocateObject(size_t size,GCInfoIndex gcinfo,CustomSpaceIndex space_index)84 void* ObjectAllocator::AllocateObject(size_t size, GCInfoIndex gcinfo,
85                                       CustomSpaceIndex space_index) {
86   DCHECK(!in_disallow_gc_scope());
87   const size_t allocation_size =
88       RoundUp<kAllocationGranularity>(size + sizeof(HeapObjectHeader));
89   return AllocateObjectOnSpace(
90       NormalPageSpace::From(*raw_heap_.CustomSpace(space_index)),
91       allocation_size, gcinfo);
92 }
93 
94 // static
GetInitialSpaceIndexForSize(size_t size)95 RawHeap::RegularSpaceType ObjectAllocator::GetInitialSpaceIndexForSize(
96     size_t size) {
97   static_assert(kSmallestSpaceSize == 32,
98                 "should be half the next larger size");
99   if (size < 64) {
100     if (size < kSmallestSpaceSize) return RawHeap::RegularSpaceType::kNormal1;
101     return RawHeap::RegularSpaceType::kNormal2;
102   }
103   if (size < 128) return RawHeap::RegularSpaceType::kNormal3;
104   return RawHeap::RegularSpaceType::kNormal4;
105 }
106 
AllocateObjectOnSpace(NormalPageSpace & space,size_t size,GCInfoIndex gcinfo)107 void* ObjectAllocator::AllocateObjectOnSpace(NormalPageSpace& space,
108                                              size_t size, GCInfoIndex gcinfo) {
109   DCHECK_LT(0u, gcinfo);
110 
111   NormalPageSpace::LinearAllocationBuffer& current_lab =
112       space.linear_allocation_buffer();
113   if (current_lab.size() < size) {
114     return OutOfLineAllocate(space, size, gcinfo);
115   }
116 
117   void* raw = current_lab.Allocate(size);
118 #if !defined(V8_USE_MEMORY_SANITIZER) && !defined(V8_USE_ADDRESS_SANITIZER) && \
119     DEBUG
120   // For debug builds, unzap only the payload.
121   SetMemoryAccessible(static_cast<char*>(raw) + sizeof(HeapObjectHeader),
122                       size - sizeof(HeapObjectHeader));
123 #else
124   SetMemoryAccessible(raw, size);
125 #endif
126   auto* header = new (raw) HeapObjectHeader(size, gcinfo);
127 
128   // The marker needs to find the object start concurrently.
129   NormalPage::From(BasePage::FromPayload(header))
130       ->object_start_bitmap()
131       .SetBit<AccessMode::kAtomic>(reinterpret_cast<ConstAddress>(header));
132 
133   return header->ObjectStart();
134 }
135 
136 }  // namespace internal
137 }  // namespace cppgc
138 
139 #endif  // V8_HEAP_CPPGC_OBJECT_ALLOCATOR_H_
140