1 /* 2 * Copyright (c) 2025 Huawei Device Co., Ltd. 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15 16 #ifndef COMMON_COMPONENTS_HEAP_ALLOCATOR_REGION_SPACE_H 17 #define COMMON_COMPONENTS_HEAP_ALLOCATOR_REGION_SPACE_H 18 19 #include <list> 20 #include <map> 21 #include <set> 22 #include <thread> 23 #include <vector> 24 25 #include "common_components/heap/allocator/alloc_util.h" 26 #include "common_components/heap/allocator/allocator.h" 27 #include "common_components/heap/allocator/region_manager.h" 28 #include "common_components/heap/space/young_space.h" 29 #include "common_components/heap/space/old_space.h" 30 #include "common_components/heap/space/from_space.h" 31 #include "common_components/heap/space/to_space.h" 32 #include "common_components/mutator/mutator.h" 33 #if defined(COMMON_SANITIZER_SUPPORT) 34 #include "common_components/sanitizer/sanitizer_interface.h" 35 #endif 36 #include "common_interfaces/base_runtime.h" 37 38 namespace common { 39 class Taskpool; 40 41 // RegionSpace aims to be the API for other components of runtime 42 // the complication of implementation is delegated to RegionManager 43 // allocator should not depend on any assumptions on the details of RegionManager 44 45 // todo: Allocator -> BaseAllocator, RegionSpace -> RegionalHeap 46 class RegionSpace : public Allocator { 47 public: ToAllocatedSize(size_t objSize)48 static size_t ToAllocatedSize(size_t objSize) 49 { 50 size_t size = objSize + HEADER_SIZE; 51 return RoundUp<size_t>(size, ALLOC_ALIGN); 52 } 53 GetAllocSize(const BaseObject & obj)54 static size_t GetAllocSize(const BaseObject& obj) 55 { 56 size_t objSize = obj.GetSize(); 57 return ToAllocatedSize(objSize); 58 } 59 RegionSpace()60 RegionSpace() : youngSpace_(regionManager_), oldSpace_(regionManager_), 61 fromSpace_(regionManager_, *this), toSpace_(regionManager_) {} ~RegionSpace()62 NO_INLINE_CC virtual ~RegionSpace() 63 { 64 if (allocBufferManager_ != nullptr) { 65 delete allocBufferManager_; 66 allocBufferManager_ = nullptr; 67 } 68 #if defined(COMMON_SANITIZER_SUPPORT) 69 Sanitizer::OnHeapDeallocated(map->GetBaseAddr(), map->GetMappedSize()); 70 #endif 71 MemoryMap::DestroyMemoryMap(map_); 72 } 73 74 void Init(const RuntimeParam ¶m) override; 75 76 template <AllocBufferType type> 77 RegionDesc* AllocateThreadLocalRegion(bool expectPhysicalMem = false); 78 79 template <AllocBufferType type = AllocBufferType::YOUNG> HandleFullThreadLocalRegion(RegionDesc * region)80 void HandleFullThreadLocalRegion(RegionDesc* region) noexcept 81 { 82 if (region == RegionDesc::NullRegion()) { 83 return; 84 } 85 ASSERT_LOGF(region->IsThreadLocalRegion() || region->IsToRegion() || region->IsOldRegion(), 86 "unexpected region type"); 87 88 if constexpr (type == AllocBufferType::YOUNG) { 89 ASSERT_LOGF(!IsGcThread(), "unexpected gc thread for old space"); 90 youngSpace_.HandleFullThreadLocalRegion(region); 91 } else if constexpr (type == AllocBufferType::OLD) { 92 ASSERT_LOGF(!IsGcThread(), "unexpected gc thread for old space"); 93 oldSpace_.HandleFullThreadLocalRegion(region); 94 } else if constexpr (type == AllocBufferType::TO) { 95 toSpace_.HandleFullThreadLocalRegion(region); 96 } 97 } 98 99 // only used for deserialize allocation, allocate one region and regard it as full region 100 // todo: adapt for concurrent gc 101 uintptr_t AllocOldRegion(); 102 uintptr_t AllocPinnedRegion(); 103 uintptr_t AllocLargeRegion(size_t size); 104 uintptr_t AllocJitFortRegion(size_t size); 105 106 HeapAddress Allocate(size_t size, AllocType allocType) override; 107 108 HeapAddress AllocateNoGC(size_t size, AllocType allocType) override; 109 GetRegionManager()110 RegionManager& GetRegionManager() noexcept { return regionManager_; } 111 GetFromSpace()112 FromSpace& GetFromSpace() noexcept { return fromSpace_; } 113 GetToSpace()114 ToSpace& GetToSpace() noexcept { return toSpace_; } 115 GetOldSpace()116 OldSpace& GetOldSpace() noexcept { return oldSpace_; } 117 GetYoungSpace()118 YoungSpace& GetYoungSpace() noexcept { return youngSpace_; } 119 GetSpaceStartAddress()120 HeapAddress GetSpaceStartAddress() const override { return reservedStart_; } 121 GetSpaceEndAddress()122 HeapAddress GetSpaceEndAddress() const override { return reservedEnd_; } 123 GetCurrentCapacity()124 size_t GetCurrentCapacity() const override { return regionManager_.GetInactiveZone() - reservedStart_; } GetMaxCapacity()125 size_t GetMaxCapacity() const override { return reservedEnd_ - reservedStart_; } 126 GetRecentAllocatedSize()127 inline size_t GetRecentAllocatedSize() const 128 { 129 return youngSpace_.GetRecentAllocatedSize() + regionManager_.GetRecentAllocatedSize(); 130 } 131 132 // size of objects survived in previous gc. GetSurvivedSize()133 size_t GetSurvivedSize() const override 134 { 135 return fromSpace_.GetSurvivedSize() + toSpace_.GetAllocatedSize() + 136 youngSpace_.GetAllocatedSize() + oldSpace_.GetAllocatedSize() + regionManager_.GetSurvivedSize(); 137 } 138 GetUsedUnitCount()139 inline size_t GetUsedUnitCount() const 140 { 141 return fromSpace_.GetUsedUnitCount() + toSpace_.GetUsedUnitCount() + 142 youngSpace_.GetUsedUnitCount() + oldSpace_.GetUsedUnitCount() + regionManager_.GetUsedUnitCount(); 143 } 144 GetUsedPageSize()145 size_t GetUsedPageSize() const override 146 { 147 return GetUsedUnitCount() * RegionDesc::UNIT_SIZE; 148 } 149 GetTargetSize()150 inline size_t GetTargetSize() const 151 { 152 double heapUtilization = BaseRuntime::GetInstance()->GetHeapParam().heapUtilization; 153 return static_cast<size_t>(GetUsedPageSize() / heapUtilization); 154 } 155 GetAllocatedBytes()156 size_t GetAllocatedBytes() const override 157 { 158 return fromSpace_.GetAllocatedSize() + toSpace_.GetAllocatedSize() + 159 youngSpace_.GetAllocatedSize() + oldSpace_.GetAllocatedSize() + regionManager_.GetAllocatedSize(); 160 } 161 LargeObjectSize()162 size_t LargeObjectSize() const override { return regionManager_.GetLargeObjectSize(); } 163 FromSpaceSize()164 size_t FromSpaceSize() const { return fromSpace_.GetAllocatedSize(); } 165 // note: it doesn't contain exemptFromRegion FromRegionSize()166 size_t FromRegionSize() const { return fromSpace_.GetFromRegionAllocatedSize(); } ToSpaceSize()167 size_t ToSpaceSize() const { return toSpace_.GetAllocatedSize(); } 168 PinnedSpaceSize()169 size_t PinnedSpaceSize() const { return regionManager_.GetPinnedSpaceSize(); } 170 171 #ifndef NDEBUG 172 bool IsHeapObject(HeapAddress addr) const override; 173 #endif 174 ReclaimGarbageMemory(bool releaseAll)175 size_t ReclaimGarbageMemory(bool releaseAll) override 176 { 177 { 178 COMMON_PHASE_TIMER("ReclaimGarbageRegions"); 179 regionManager_.ReclaimGarbageRegions(); 180 } 181 182 COMMON_PHASE_TIMER("ReleaseGarbageMemory"); 183 if (releaseAll) { 184 return regionManager_.ReleaseGarbageRegions(0); 185 } else { 186 size_t size = GetAllocatedBytes(); 187 double cachedRatio = 1 - BaseRuntime::GetInstance()->GetHeapParam().heapUtilization; 188 size_t targetCachedSize = static_cast<size_t>(size * cachedRatio); 189 if (targetCachedSize > maxGarbageCacheSize_) { 190 targetCachedSize = maxGarbageCacheSize_; 191 } 192 return regionManager_.ReleaseGarbageRegions(targetCachedSize); 193 } 194 } 195 ForEachObject(const std::function<void (BaseObject *)> & visitor,bool safe)196 bool ForEachObject(const std::function<void(BaseObject*)>& visitor, bool safe) const override 197 { 198 if (UNLIKELY_CC(safe)) { 199 regionManager_.ForEachObjectSafe(visitor); 200 } else { 201 regionManager_.ForEachObjectUnsafe(visitor); 202 } 203 return true; 204 } 205 ExemptFromSpace()206 void ExemptFromSpace() 207 { 208 COMMON_PHASE_TIMER("ExemptFromRegions"); 209 fromSpace_.ExemptFromRegions(); 210 } 211 RouteObject(BaseObject * fromObj,size_t size)212 BaseObject* RouteObject(BaseObject* fromObj, size_t size) 213 { 214 AllocationBuffer* buffer = AllocationBuffer::GetOrCreateAllocBuffer(); 215 uintptr_t toAddr = buffer->ToSpaceAllocate(size); 216 return reinterpret_cast<BaseObject*>(toAddr); 217 } 218 CopyFromSpace(Taskpool * threadPool)219 void CopyFromSpace(Taskpool *threadPool) 220 { 221 COMMON_PHASE_TIMER("CopyFromRegions"); 222 fromSpace_.CopyFromRegions(threadPool); 223 } 224 CollectFixTasks()225 FixHeapTaskList CollectFixTasks() 226 { 227 FixHeapTaskList taskList; 228 youngSpace_.CollectFixTasks(taskList); 229 oldSpace_.CollectFixTasks(taskList); 230 fromSpace_.CollectFixTasks(taskList); 231 toSpace_.CollectFixTasks(taskList); 232 regionManager_.CollectFixTasks(taskList); 233 234 return taskList; 235 } 236 MarkAwaitingJitFort()237 void MarkAwaitingJitFort() 238 { 239 regionManager_.ForEachAwaitingJitFortUnsafe(MarkObject); 240 } 241 ClearJitFortAwaitingMark()242 void ClearJitFortAwaitingMark() 243 { 244 regionManager_.HandlePostGCJitFortInstallTask(); 245 } 246 247 using RootSet = MarkStack<BaseObject*>; 248 CollectLargeGarbage()249 size_t CollectLargeGarbage() { return regionManager_.CollectLargeGarbage(); } 250 CollectFromSpaceGarbage()251 void CollectFromSpaceGarbage() 252 { 253 regionManager_.CollectFromSpaceGarbage(fromSpace_.GetFromRegionList()); 254 } 255 HandlePromotion()256 void HandlePromotion() 257 { 258 fromSpace_.GetPromotedTo(oldSpace_); 259 toSpace_.GetPromotedTo(oldSpace_); 260 } 261 AssembleSmallGarbageCandidates()262 void AssembleSmallGarbageCandidates() 263 { 264 youngSpace_.AssembleGarbageCandidates(fromSpace_); 265 oldSpace_.AssembleRecentFull(); 266 if (Heap::GetHeap().GetGCReason() != GC_REASON_YOUNG) { 267 oldSpace_.ClearRSet(); 268 oldSpace_.AssembleGarbageCandidates(fromSpace_); 269 regionManager_.ClearRSet(); 270 } 271 } 272 CollectAppSpawnSpaceGarbage()273 void CollectAppSpawnSpaceGarbage() 274 { 275 regionManager_.CollectFromSpaceGarbage(fromSpace_.GetFromRegionList()); 276 regionManager_.ReassembleAppspawnSpace(fromSpace_.GetExemptedRegionList()); 277 regionManager_.ReassembleAppspawnSpace(toSpace_.GetTlToRegionList()); 278 regionManager_.ReassembleAppspawnSpace(toSpace_.GetFullToRegionList()); 279 } 280 ClearAllGCInfo()281 void ClearAllGCInfo() 282 { 283 regionManager_.ClearAllGCInfo(); 284 youngSpace_.ClearAllGCInfo(); 285 oldSpace_.ClearAllGCInfo(); 286 toSpace_.ClearAllGCInfo(); 287 fromSpace_.ClearAllGCInfo(); 288 } 289 AssembleGarbageCandidates()290 void AssembleGarbageCandidates() 291 { 292 AssembleSmallGarbageCandidates(); 293 regionManager_.AssemblePinnedGarbageCandidates(); 294 regionManager_.AssembleLargeGarbageCandidates(); 295 } 296 297 void DumpAllRegionSummary(const char* msg) const; 298 void DumpAllRegionStats(const char* msg) const; 299 CountLiveObject(const BaseObject * obj)300 void CountLiveObject(const BaseObject* obj) { regionManager_.CountLiveObject(obj); } 301 PrepareMarking()302 void PrepareMarking() { regionManager_.PrepareMarking(); } PrepareForward()303 void PrepareForward() { regionManager_.PrepareForward(); } 304 void FeedHungryBuffers() override; 305 306 // markObj MarkObject(const BaseObject * obj)307 static bool MarkObject(const BaseObject* obj) 308 { 309 RegionDesc* regionInfo = RegionDesc::GetAliveRegionDescAt(reinterpret_cast<HeapAddress>(obj)); 310 return regionInfo->MarkObject(obj); 311 } ResurrentObject(const BaseObject * obj)312 static bool ResurrentObject(const BaseObject* obj) 313 { 314 RegionDesc* regionInfo = RegionDesc::GetAliveRegionDescAt(reinterpret_cast<HeapAddress>(obj)); 315 return regionInfo->ResurrentObject(obj); 316 } 317 EnqueueObject(const BaseObject * obj)318 static bool EnqueueObject(const BaseObject* obj) 319 { 320 RegionDesc* regionInfo = RegionDesc::GetAliveRegionDescAt(reinterpret_cast<HeapAddress>(obj)); 321 return regionInfo->EnqueueObject(obj); 322 } 323 IsMarkedObject(const BaseObject * obj)324 static bool IsMarkedObject(const BaseObject* obj) 325 { 326 RegionDesc* regionInfo = RegionDesc::GetAliveRegionDescAt(reinterpret_cast<HeapAddress>(obj)); 327 return regionInfo->IsMarkedObject(obj); 328 } 329 IsResurrectedObject(const BaseObject * obj)330 static bool IsResurrectedObject(const BaseObject* obj) 331 { 332 RegionDesc* regionInfo = RegionDesc::GetAliveRegionDescAt(reinterpret_cast<HeapAddress>(obj)); 333 return regionInfo->IsResurrectedObject(obj); 334 } 335 IsEnqueuedObject(const BaseObject * obj)336 static bool IsEnqueuedObject(const BaseObject* obj) 337 { 338 RegionDesc* regionInfo = RegionDesc::GetAliveRegionDescAt(reinterpret_cast<HeapAddress>(obj)); 339 return regionInfo->IsEnqueuedObject(obj); 340 } 341 IsNewObjectSinceMarking(const BaseObject * object)342 static bool IsNewObjectSinceMarking(const BaseObject* object) 343 { 344 RegionDesc* region = RegionDesc::GetAliveRegionDescAt(reinterpret_cast<uintptr_t>(object)); 345 ASSERT_LOGF(region != nullptr, "region is nullptr"); 346 return region->IsNewObjectSinceMarking(object); 347 } 348 IsReadOnlyObject(const BaseObject * object)349 static bool IsReadOnlyObject(const BaseObject* object) 350 { 351 RegionDesc* region = RegionDesc::GetAliveRegionDescAt(reinterpret_cast<uintptr_t>(object)); 352 ASSERT_LOGF(region != nullptr, "region is nullptr"); 353 return region->IsReadOnlyRegion(); 354 } 355 IsYoungSpaceObject(const BaseObject * object)356 static bool IsYoungSpaceObject(const BaseObject* object) 357 { 358 RegionDesc* region = RegionDesc::GetAliveRegionDescAt(reinterpret_cast<uintptr_t>(object)); 359 ASSERT_LOGF(region != nullptr, "region is nullptr"); 360 return region->IsInYoungSpace(); 361 } 362 AddRawPointerObject(BaseObject * obj)363 void AddRawPointerObject(BaseObject* obj) 364 { 365 RegionDesc* region = RegionDesc::GetAliveRegionDescAt(reinterpret_cast<HeapAddress>(obj)); 366 region->IncRawPointerObjectCount(); 367 if (region->IsFromRegion() && fromSpace_.TryDeleteFromRegion(region, RegionDesc::RegionType::FROM_REGION, 368 RegionDesc::RegionType::RAW_POINTER_REGION)) { 369 GCPhase phase = Heap::GetHeap().GetGCPhase(); 370 CHECK(phase != GCPhase::GC_PHASE_COPY && phase != GCPhase::GC_PHASE_PRECOPY); 371 regionManager_.AddRawPointerRegion(region); 372 } else { 373 CHECK(region->GetRegionType() != RegionDesc::RegionType::LONE_FROM_REGION); 374 } 375 } 376 RemoveRawPointerObject(BaseObject * obj)377 void RemoveRawPointerObject(BaseObject* obj) 378 { 379 RegionDesc* region = RegionDesc::GetAliveRegionDescAt(reinterpret_cast<HeapAddress>(obj)); 380 region->DecRawPointerObjectCount(); 381 } 382 AddRawPointerRegion(RegionDesc * region)383 void AddRawPointerRegion(RegionDesc* region) 384 { 385 regionManager_.AddRawPointerRegion(region); 386 } 387 388 void CopyRegion(RegionDesc* region); 389 390 void MarkRememberSet(const std::function<void(BaseObject *)> &func); 391 392 friend class Allocator; 393 private: 394 enum class TryAllocationThreshold { 395 RESCHEDULE = 3, 396 TRIGGER_OOM = 4, 397 }; 398 HeapAddress TryAllocateOnce(size_t allocSize, AllocType allocType); 399 bool ShouldRetryAllocation(size_t& tryTimes) const; 400 HeapAddress reservedStart_ = 0; 401 HeapAddress reservedEnd_ = 0; 402 RegionManager regionManager_; 403 MemoryMap* map_{ nullptr }; 404 405 YoungSpace youngSpace_; 406 OldSpace oldSpace_; 407 408 FromSpace fromSpace_; 409 ToSpace toSpace_; 410 uint64_t maxGarbageCacheSize_ { 16 * MB }; 411 }; 412 413 using RegionalHeap = RegionSpace; 414 } // namespace common 415 416 #endif // COMMON_COMPONENTS_HEAP_ALLOCATOR_REGION_SPACE_H 417