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