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