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_HEAP_ALLOCATOR_INL_H_
6#define V8_HEAP_HEAP_ALLOCATOR_INL_H_
7
8#include "src/base/logging.h"
9#include "src/common/globals.h"
10#include "src/heap/concurrent-allocator-inl.h"
11#include "src/heap/heap-allocator.h"
12#include "src/heap/large-spaces.h"
13#include "src/heap/new-spaces.h"
14#include "src/heap/paged-spaces.h"
15#include "src/heap/read-only-spaces.h"
16#include "src/heap/third-party/heap-api.h"
17
18namespace v8 {
19namespace internal {
20
21PagedSpace* HeapAllocator::code_space() const {
22  return static_cast<PagedSpace*>(spaces_[CODE_SPACE]);
23}
24
25CodeLargeObjectSpace* HeapAllocator::code_lo_space() const {
26  return static_cast<CodeLargeObjectSpace*>(spaces_[CODE_LO_SPACE]);
27}
28
29OldLargeObjectSpace* HeapAllocator::lo_space() const {
30  return static_cast<OldLargeObjectSpace*>(spaces_[LO_SPACE]);
31}
32
33PagedSpace* HeapAllocator::space_for_maps() const { return space_for_maps_; }
34
35NewSpace* HeapAllocator::new_space() const {
36  return static_cast<NewSpace*>(spaces_[NEW_SPACE]);
37}
38
39NewLargeObjectSpace* HeapAllocator::new_lo_space() const {
40  return static_cast<NewLargeObjectSpace*>(spaces_[NEW_LO_SPACE]);
41}
42
43PagedSpace* HeapAllocator::old_space() const {
44  return static_cast<PagedSpace*>(spaces_[OLD_SPACE]);
45}
46
47ReadOnlySpace* HeapAllocator::read_only_space() const {
48  return read_only_space_;
49}
50
51bool HeapAllocator::CanAllocateInReadOnlySpace() const {
52  return read_only_space()->writable();
53}
54
55template <AllocationType type>
56V8_WARN_UNUSED_RESULT V8_INLINE AllocationResult HeapAllocator::AllocateRaw(
57    int size_in_bytes, AllocationOrigin origin, AllocationAlignment alignment) {
58  DCHECK_EQ(heap_->gc_state(), Heap::NOT_IN_GC);
59  DCHECK(AllowHandleAllocation::IsAllowed());
60  DCHECK(AllowHeapAllocation::IsAllowed());
61
62  if (FLAG_single_generation && type == AllocationType::kYoung) {
63    return AllocateRaw(size_in_bytes, AllocationType::kOld, origin, alignment);
64  }
65
66#ifdef V8_ENABLE_ALLOCATION_TIMEOUT
67  if (FLAG_random_gc_interval > 0 || FLAG_gc_interval >= 0) {
68    if (!heap_->always_allocate() && allocation_timeout_-- <= 0) {
69      return AllocationResult::Failure();
70    }
71  }
72#endif  // V8_ENABLE_ALLOCATION_TIMEOUT
73
74#ifdef DEBUG
75  IncrementObjectCounters();
76#endif  // DEBUG
77
78  if (heap_->CanSafepoint()) {
79    heap_->main_thread_local_heap()->Safepoint();
80  }
81
82  const size_t large_object_threshold = heap_->MaxRegularHeapObjectSize(type);
83  const bool large_object =
84      static_cast<size_t>(size_in_bytes) > large_object_threshold;
85
86  HeapObject object;
87  AllocationResult allocation;
88
89  if (V8_ENABLE_THIRD_PARTY_HEAP_BOOL) {
90    allocation = heap_->tp_heap_->Allocate(size_in_bytes, type, alignment);
91  } else {
92    if (V8_UNLIKELY(large_object)) {
93      allocation =
94          AllocateRawLargeInternal(size_in_bytes, type, origin, alignment);
95    } else {
96      switch (type) {
97        case AllocationType::kYoung:
98          allocation =
99              new_space()->AllocateRaw(size_in_bytes, alignment, origin);
100          break;
101        case AllocationType::kOld:
102          allocation =
103              old_space()->AllocateRaw(size_in_bytes, alignment, origin);
104          break;
105        case AllocationType::kCode:
106          DCHECK_EQ(alignment, AllocationAlignment::kTaggedAligned);
107          DCHECK(AllowCodeAllocation::IsAllowed());
108          allocation = code_space()->AllocateRawUnaligned(size_in_bytes);
109          break;
110        case AllocationType::kMap:
111          DCHECK_EQ(alignment, AllocationAlignment::kTaggedAligned);
112          allocation = space_for_maps()->AllocateRawUnaligned(size_in_bytes);
113          break;
114        case AllocationType::kReadOnly:
115          DCHECK(read_only_space()->writable());
116          DCHECK_EQ(AllocationOrigin::kRuntime, origin);
117          allocation = read_only_space()->AllocateRaw(size_in_bytes, alignment);
118          break;
119        case AllocationType::kSharedMap:
120          allocation = shared_map_allocator_->AllocateRaw(size_in_bytes,
121                                                          alignment, origin);
122          break;
123        case AllocationType::kSharedOld:
124          allocation = shared_old_allocator_->AllocateRaw(size_in_bytes,
125                                                          alignment, origin);
126          break;
127      }
128    }
129  }
130
131  if (allocation.To(&object)) {
132    if (AllocationType::kCode == type && !V8_ENABLE_THIRD_PARTY_HEAP_BOOL) {
133      // Unprotect the memory chunk of the object if it was not unprotected
134      // already.
135      heap_->UnprotectAndRegisterMemoryChunk(
136          object, UnprotectMemoryOrigin::kMainThread);
137      heap_->ZapCodeObject(object.address(), size_in_bytes);
138      if (!large_object) {
139        MemoryChunk::FromHeapObject(object)
140            ->GetCodeObjectRegistry()
141            ->RegisterNewlyAllocatedCodeObject(object.address());
142      }
143    }
144
145#ifdef V8_ENABLE_CONSERVATIVE_STACK_SCANNING
146    if (AllocationType::kReadOnly != type) {
147      DCHECK_TAG_ALIGNED(object.address());
148      Page::FromHeapObject(object)->object_start_bitmap()->SetBit(
149          object.address());
150    }
151#endif  // V8_ENABLE_CONSERVATIVE_STACK_SCANNING
152
153    for (auto& tracker : heap_->allocation_trackers_) {
154      tracker->AllocationEvent(object.address(), size_in_bytes);
155    }
156  }
157
158  return allocation;
159}
160
161AllocationResult HeapAllocator::AllocateRaw(int size_in_bytes,
162                                            AllocationType type,
163                                            AllocationOrigin origin,
164                                            AllocationAlignment alignment) {
165  switch (type) {
166    case AllocationType::kYoung:
167      return AllocateRaw<AllocationType::kYoung>(size_in_bytes, origin,
168                                                 alignment);
169    case AllocationType::kOld:
170      return AllocateRaw<AllocationType::kOld>(size_in_bytes, origin,
171                                               alignment);
172    case AllocationType::kCode:
173      return AllocateRaw<AllocationType::kCode>(size_in_bytes, origin,
174                                                alignment);
175    case AllocationType::kMap:
176      return AllocateRaw<AllocationType::kMap>(size_in_bytes, origin,
177                                               alignment);
178    case AllocationType::kReadOnly:
179      return AllocateRaw<AllocationType::kReadOnly>(size_in_bytes, origin,
180                                                    alignment);
181    case AllocationType::kSharedMap:
182      return AllocateRaw<AllocationType::kSharedMap>(size_in_bytes, origin,
183                                                     alignment);
184    case AllocationType::kSharedOld:
185      return AllocateRaw<AllocationType::kSharedOld>(size_in_bytes, origin,
186                                                     alignment);
187  }
188  UNREACHABLE();
189}
190
191AllocationResult HeapAllocator::AllocateRawData(int size_in_bytes,
192                                                AllocationType type,
193                                                AllocationOrigin origin,
194                                                AllocationAlignment alignment) {
195  switch (type) {
196    case AllocationType::kYoung:
197      return AllocateRaw<AllocationType::kYoung>(size_in_bytes, origin,
198                                                 alignment);
199    case AllocationType::kOld:
200      return AllocateRaw<AllocationType::kOld>(size_in_bytes, origin,
201                                               alignment);
202    case AllocationType::kCode:
203    case AllocationType::kMap:
204    case AllocationType::kReadOnly:
205    case AllocationType::kSharedMap:
206    case AllocationType::kSharedOld:
207      UNREACHABLE();
208  }
209  UNREACHABLE();
210}
211
212template <HeapAllocator::AllocationRetryMode mode>
213V8_WARN_UNUSED_RESULT V8_INLINE HeapObject HeapAllocator::AllocateRawWith(
214    int size, AllocationType allocation, AllocationOrigin origin,
215    AllocationAlignment alignment) {
216  AllocationResult result;
217  HeapObject object;
218  if (allocation == AllocationType::kYoung) {
219    result = AllocateRaw<AllocationType::kYoung>(size, origin, alignment);
220    if (result.To(&object)) {
221      return object;
222    }
223  } else if (allocation == AllocationType::kOld) {
224    result = AllocateRaw<AllocationType::kOld>(size, origin, alignment);
225    if (result.To(&object)) {
226      return object;
227    }
228  }
229  switch (mode) {
230    case kLightRetry:
231      result = AllocateRawWithLightRetrySlowPath(size, allocation, origin,
232                                                 alignment);
233      break;
234    case kRetryOrFail:
235      result = AllocateRawWithRetryOrFailSlowPath(size, allocation, origin,
236                                                  alignment);
237      break;
238  }
239  if (result.To(&object)) {
240    return object;
241  }
242  return HeapObject();
243}
244
245}  // namespace internal
246}  // namespace v8
247
248#endif  // V8_HEAP_HEAP_ALLOCATOR_INL_H_
249