• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /**
2  * Copyright (c) 2024 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 #ifndef PANDA_MEM_HEAP_MANAGER_H
16 #define PANDA_MEM_HEAP_MANAGER_H
17 
18 #include <cstddef>
19 #include <memory>
20 
21 #include "libpandabase/utils/logger.h"
22 #include "libpandabase/macros.h"
23 #include "runtime/include/class.h"
24 #include "runtime/include/mem/allocator.h"
25 #include "runtime/include/mem/panda_containers.h"
26 #include "runtime/include/object_header.h"
27 #include "runtime/include/thread.h"
28 #include "runtime/mem/frame_allocator-inl.h"
29 #include "runtime/mem/gc/heap-space-misc/crossing_map_singleton.h"
30 #include "runtime/mem/heap_verifier.h"
31 #include "runtime/mem/lock_config_helper.h"
32 #include "runtime/mem/tlab.h"
33 
34 namespace ark {
35 // Forward declaration
36 class Runtime;
37 class PandaVM;
38 class RuntimeNotificationManager;
39 }  //  namespace ark
40 
41 namespace ark::mem {
42 
43 // Forward declaration
44 class MemoryManager;
45 
46 class HeapManager {
47 public:
48     bool Initialize(GCType gcType, MTModeT multithreadingMode, bool useTlab, MemStatsType *memStats,
49                     InternalAllocatorPtr internalAllocator, bool createPygoteSpace);
50 
51     bool Finalize();
52 
53     [[nodiscard]] PANDA_PUBLIC_API ObjectHeader *AllocateObject(
54         BaseClass *cls, size_t size, Alignment align = DEFAULT_ALIGNMENT, ManagedThread *thread = nullptr,
55         ObjectAllocatorBase::ObjMemInitPolicy objInitType = ObjectAllocatorBase::ObjMemInitPolicy::REQUIRE_INIT,
56         bool pinned = false);
57 
58     template <bool IS_FIRST_CLASS_CLASS = false>
59     [[nodiscard]] ObjectHeader *AllocateNonMovableObject(
60         BaseClass *cls, size_t size, Alignment align = DEFAULT_ALIGNMENT, ManagedThread *thread = nullptr,
61         ObjectAllocatorBase::ObjMemInitPolicy objInitType = ObjectAllocatorBase::ObjMemInitPolicy::REQUIRE_INIT);
62 
63     /**
64      * @brief Allocates memory for ExtFrame, but do not construct it
65      * @param size - size of allocation (ExtFrame) in bytes
66      * @param ext_sz - size of frame extension in bytes
67      * @return pointer to Frame
68      */
69     [[nodiscard]] PANDA_PUBLIC_API Frame *AllocateExtFrame(size_t size, size_t extSz);
70 
71     /**
72      * @brief Frees memory occupied by ExtFrame
73      * @param frame - pointer to Frame
74      * @param ext_sz - size of frame extension in bytes
75      */
76     void PANDA_PUBLIC_API FreeExtFrame(Frame *frame, size_t extSz);
77 
78     CodeAllocator *GetCodeAllocator() const;
79 
80     PANDA_PUBLIC_API InternalAllocatorPtr GetInternalAllocator();
81 
UseTLABForAllocations()82     bool UseTLABForAllocations()
83     {
84         return useTlabForAllocations_;
85     }
86 
87     bool CreateNewTLAB(ManagedThread *thread);
88 
GetTLABMaxAllocSize()89     size_t GetTLABMaxAllocSize()
90     {
91         return UseTLABForAllocations() ? objectAllocator_.AsObjectAllocator()->GetTLABMaxAllocSize() : 0;
92     }
93 
94     /**
95      * Register TLAB information in MemStats during changing TLAB in a thread
96      * or during thread destroying.
97      */
98     void RegisterTLAB(const TLAB *tlab);
99 
100     /**
101      * Prepare the heap before the fork process, The main function is to compact zygote space for fork subprocess
102      *
103      * @param
104      * @return void
105      */
106     void PreZygoteFork();
107 
108     /**
109      *  NOTE :  Not yet implemented
110      *  To implement the getTargetHeapUtilization and nativeSetTargetHeapUtilization,
111      *  I set two functions and a fixed initial value here. They may need to be rewritten
112      */
113     float GetTargetHeapUtilization() const;
114 
115     void SetTargetHeapUtilization(float target);
116 
VerifyHeapReferences()117     size_t VerifyHeapReferences()
118     {
119         trace::ScopedTrace scopedTrace(__FUNCTION__);
120         size_t failCount = 0;
121         HeapObjectVerifier verifier(this, &failCount);
122         objectAllocator_->IterateOverObjects(verifier);
123         return verifier.GetFailCount();
124     }
125 
126     // Returns the maximum amount of memory a program can consume.
GetMaxMemory()127     size_t GetMaxMemory() const
128     {
129         return MemConfig::GetHeapSizeLimit();
130     }
131 
132     // Returns approximate amount of memory currently consumed by an application.
133     PANDA_PUBLIC_API size_t GetTotalMemory() const;
134 
135     // Returns how much free memory we have until we need to grow the heap to perform an allocation.
136     PANDA_PUBLIC_API size_t GetFreeMemory() const;
137 
138     /// Clamp current accessable heap size as maximum heap size
139     void ClampNewMaxHeapSize();
140 
141     // added for VMDebug::countInstancesOfClass and countInstancesOfClasses
142     void CountInstances(const PandaVector<Class *> &classes, bool assignable, uint64_t *counts);
143 
144     using IsObjectFinalizebleFunc = bool (*)(BaseClass *);
145     using RegisterFinalizeReferenceFunc = void (*)(ObjectHeader *, BaseClass *);
146     void SetIsFinalizableFunc(IsObjectFinalizebleFunc func);
147     void SetRegisterFinalizeReferenceFunc(RegisterFinalizeReferenceFunc func);
148 
149     bool IsObjectFinalized(BaseClass *cls);
150     void RegisterFinalizedObject(ObjectHeader *object, BaseClass *cls, bool isObjectFinalizable);
151 
152     void SetPandaVM(PandaVM *vm);
153 
GetPandaVM()154     PandaVM *GetPandaVM() const
155     {
156         return vm_;
157     }
158 
GetGC()159     mem::GC *GetGC() const
160     {
161         return gc_;
162     }
163 
GetNotificationManager()164     RuntimeNotificationManager *GetNotificationManager() const
165     {
166         return notificationManager_;
167     }
168 
GetMemStats()169     MemStatsType *GetMemStats() const
170     {
171         return memStats_;
172     }
173 
IterateOverObjects(const ObjectVisitor & objectVisitor)174     ALWAYS_INLINE void IterateOverObjects(const ObjectVisitor &objectVisitor)
175     {
176         GetObjectAllocator()->IterateOverObjects(objectVisitor);
177     }
178 
PinObject(ObjectHeader * object)179     ALWAYS_INLINE void PinObject(ObjectHeader *object)
180     {
181         GetObjectAllocator().AsObjectAllocator()->PinObject(object);
182     }
183 
UnpinObject(ObjectHeader * object)184     ALWAYS_INLINE void UnpinObject(ObjectHeader *object)
185     {
186         GetObjectAllocator().AsObjectAllocator()->UnpinObject(object);
187     }
188 
IsObjectInYoungSpace(const ObjectHeader * obj)189     ALWAYS_INLINE bool IsObjectInYoungSpace(const ObjectHeader *obj)
190     {
191         return GetObjectAllocator().AsObjectAllocator()->IsObjectInYoungSpace(obj);
192     }
193 
IsObjectInNonMovableSpace(const ObjectHeader * obj)194     ALWAYS_INLINE bool IsObjectInNonMovableSpace(const ObjectHeader *obj)
195     {
196         return GetObjectAllocator().AsObjectAllocator()->IsObjectInNonMovableSpace(obj);
197     }
198 
IsLiveObject(const ObjectHeader * obj)199     ALWAYS_INLINE bool IsLiveObject(const ObjectHeader *obj)
200     {
201         return GetObjectAllocator().AsObjectAllocator()->IsLive(obj);
202     }
203 
ContainObject(const ObjectHeader * obj)204     ALWAYS_INLINE bool ContainObject(const ObjectHeader *obj)
205     {
206         return GetObjectAllocator().AsObjectAllocator()->ContainObject(obj);
207     }
208 
HeapManager()209     HeapManager() : targetUtilization_(DEFAULT_TARGET_UTILIZATION) {}
210 
211     ~HeapManager() = default;
212 
213     NO_COPY_SEMANTIC(HeapManager);
214     NO_MOVE_SEMANTIC(HeapManager);
215 
216 private:
217     template <GCType GC_TYPE, MTModeT MT_MODE = MT_MODE_MULTI>
Initialize(MemStatsType * memStats,bool createPygoteSpace)218     bool Initialize(MemStatsType *memStats, bool createPygoteSpace)
219     {
220         ASSERT(!isInitialized_);
221         isInitialized_ = true;
222 
223         codeAllocator_ = new (std::nothrow) CodeAllocator(memStats);
224         // For now, crossing map is shared by diffrent VMs.
225         if (!CrossingMapSingleton::IsCreated()) {
226             CrossingMapSingleton::Create();
227         }
228         objectAllocator_ =
229             new (std::nothrow) typename AllocConfig<GC_TYPE, MT_MODE>::ObjectAllocatorType(memStats, createPygoteSpace);
230         return (codeAllocator_ != nullptr) && (internalAllocator_ != nullptr) && (objectAllocator_ != nullptr);
231     }
232 
233     template <GCType GC_TYPE>
Initialize(MemStatsType * memStats,MTModeT multithreadingMode,bool createPygoteSpace)234     bool Initialize(MemStatsType *memStats, MTModeT multithreadingMode, bool createPygoteSpace)
235     {
236         switch (multithreadingMode) {
237             case MT_MODE_SINGLE: {
238                 return Initialize<GC_TYPE, MT_MODE_SINGLE>(memStats, createPygoteSpace);
239             }
240             case MT_MODE_MULTI: {
241                 return Initialize<GC_TYPE, MT_MODE_MULTI>(memStats, createPygoteSpace);
242             }
243             case MT_MODE_TASK: {
244                 return Initialize<GC_TYPE, MT_MODE_TASK>(memStats, createPygoteSpace);
245             }
246             default: {
247                 UNREACHABLE();
248             }
249         }
250     }
251 
252     /**
253      * Initialize GC bits and also zeroing memory for the whole Object memory
254      * @param cls - class
255      * @param mem - pointer to the ObjectHeader
256      * @return pointer to the ObjectHeader
257      */
258     ObjectHeader *InitObjectHeaderAtMem(BaseClass *cls, void *mem);
259 
260     /// Triggers GC if needed
261     void TriggerGCIfNeeded();
262 
263     void *TryGCAndAlloc(size_t size, Alignment align, ManagedThread *thread,
264                         ObjectAllocatorBase::ObjMemInitPolicy objInitType, bool pinned = false);
265 
266     void *AllocByTLAB(size_t size, ManagedThread *thread);
267 
268     void *AllocateMemoryForObject(size_t size, Alignment align, ManagedThread *thread,
269                                   ObjectAllocatorBase::ObjMemInitPolicy objInitType, bool pinned = false);
270 
271     ObjectAllocatorPtr GetObjectAllocator() const;
272 
273     static constexpr float DEFAULT_TARGET_UTILIZATION = 0.5;
274 
275     bool isInitialized_ = false;
276     bool useRuntimeInternalAllocator_ {true};
277     CodeAllocator *codeAllocator_ = nullptr;
278     InternalAllocatorPtr internalAllocator_ = nullptr;
279     ObjectAllocatorPtr objectAllocator_ = nullptr;
280 
281     bool useTlabForAllocations_ = false;
282     bool isAdaptiveTlabSize_ = false;
283 
284     /// StackFrameAllocator is per thread
285     StackFrameAllocator *GetCurrentStackFrameAllocator();
286 
287     friend class ::ark::Runtime;
288 
289     // Needed to extract object allocator created during HeapManager initialization
290     // to pass it to GC creation method;
291     friend class ::ark::mem::MemoryManager;
292 
293     /**
294      * NOTE : Target ideal heap utilization ratio.
295      * To implement the getTargetHeapUtilization and nativeSetTargetHeapUtilization, I set a variable here.
296      * It may need to be initialized, but now I give it a fixed initial value 0.5
297      */
298     float targetUtilization_;
299 
300     IsObjectFinalizebleFunc isObjectFinalizebleFunc_ = nullptr;
301     RegisterFinalizeReferenceFunc registerFinalizeReferenceFunc_ = nullptr;
302     PandaVM *vm_ {nullptr};
303     MemStatsType *memStats_ {nullptr};
304     mem::GC *gc_ = nullptr;
305     RuntimeNotificationManager *notificationManager_ = nullptr;
306 };
307 
308 }  // namespace ark::mem
309 
310 #endif  // PANDA_MEM_HEAP_MANAGER_H
311