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