• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 &param) 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