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