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 "runtime/include/class.h" 23 #include "runtime/include/mem/allocator.h" 24 #include "runtime/include/mem/panda_containers.h" 25 #include "runtime/include/object_header.h" 26 #include "runtime/include/thread.h" 27 #include "runtime/mem/frame_allocator-inl.h" 28 #include "runtime/mem/heap_verifier.h" 29 #include "runtime/mem/tlab.h" 30 #include "runtime/mem/gc/heap-space-misc/crossing_map_singleton.h" 31 32 namespace panda { 33 // Forward declaration 34 class Runtime; 35 class PandaVM; 36 class RuntimeNotificationManager; 37 } // namespace panda 38 39 namespace panda::mem { 40 41 class HeapManager { 42 public: 43 bool Initialize(GCType gc_type, bool single_threaded, bool use_tlab, MemStatsType *mem_stats, 44 InternalAllocatorPtr internal_allocator, bool create_pygote_space); 45 46 bool Finalize(); 47 48 [[nodiscard]] ObjectHeader *AllocateObject(BaseClass *cls, size_t size, Alignment align = DEFAULT_ALIGNMENT, 49 ManagedThread *thread = nullptr); 50 51 template <bool IsFirstClassClass = false> 52 [[nodiscard]] ObjectHeader *AllocateNonMovableObject(BaseClass *cls, size_t size, 53 Alignment align = DEFAULT_ALIGNMENT, 54 ManagedThread *thread = nullptr); 55 56 /** 57 * \brief Allocates memory for ExtFrame, but do not construct it 58 * @param size - size of allocation (ExtFrame) in bytes 59 * @param ext_sz - size of frame extension in bytes 60 * @return pointer to Frame 61 */ 62 [[nodiscard]] Frame *AllocateExtFrame(size_t size, size_t ext_sz); 63 64 /** 65 * \brief Frees memory occupied by ExtFrame 66 * @param frame - pointer to Frame 67 * @param ext_sz - size of frame extension in bytes 68 */ 69 void FreeExtFrame(Frame *frame, size_t ext_sz); 70 71 CodeAllocator *GetCodeAllocator() const; 72 73 InternalAllocatorPtr GetInternalAllocator(); 74 75 ObjectAllocatorPtr GetObjectAllocator(); 76 UseTLABForAllocations()77 bool UseTLABForAllocations() 78 { 79 return use_tlab_for_allocations_; 80 } 81 82 bool CreateNewTLAB(ManagedThread *thread); 83 GetTLABMaxAllocSize()84 size_t GetTLABMaxAllocSize() 85 { 86 return UseTLABForAllocations() ? objectAllocator_.AsObjectAllocator()->GetTLABMaxAllocSize() : 0; 87 } 88 89 /** 90 * Register TLAB information in MemStats during changing TLAB in a thread 91 * or during thread destroying. 92 */ 93 void RegisterTLAB(const TLAB *tlab); 94 95 /** 96 * Prepare the heap before the fork process, The main function is to compact zygote space for fork subprocess 97 * 98 * @param 99 * @return void 100 */ 101 void PreZygoteFork(); 102 103 /** 104 * TODO : Not yet implemented 105 * To implement the getTargetHeapUtilization and nativeSetTargetHeapUtilization, 106 * I set two functions and a fixed initial value here. They may need to be rewritten 107 */ 108 float GetTargetHeapUtilization() const; 109 110 void SetTargetHeapUtilization(float target); 111 112 void DumpHeap(PandaOStringStream *o_string_stream); 113 VerifyHeapReferences()114 size_t VerifyHeapReferences() 115 { 116 trace::ScopedTrace scoped_trace(__FUNCTION__); 117 size_t fail_count = 0; 118 HeapObjectVerifier verifier(this, &fail_count); 119 objectAllocator_->IterateOverObjects(verifier); 120 return verifier.GetFailCount(); 121 } 122 123 // Returns the maximum amount of memory a program can consume. GetMaxMemory()124 size_t GetMaxMemory() const 125 { 126 return MemConfig::GetHeapSizeLimit(); 127 } 128 129 // Returns approximate amount of memory currently consumed by an application. 130 size_t GetTotalMemory() const; 131 132 // Returns how much free memory we have until we need to grow the heap to perform an allocation. 133 size_t GetFreeMemory() const; 134 135 // added for VMDebug::countInstancesOfClass and countInstancesOfClasses 136 void CountInstances(const PandaVector<Class *> &classes, bool assignable, uint64_t *counts); 137 138 using IsObjectFinalizebleFunc = bool (*)(BaseClass *); 139 using RegisterFinalizeReferenceFunc = void (*)(ObjectHeader *, BaseClass *); 140 void SetIsFinalizableFunc(IsObjectFinalizebleFunc func); 141 void SetRegisterFinalizeReferenceFunc(RegisterFinalizeReferenceFunc func); 142 143 bool IsObjectFinalized(BaseClass *cls); 144 void RegisterFinalizedObject(ObjectHeader *object, BaseClass *cls, bool is_object_finalizable); 145 146 void SetPandaVM(PandaVM *vm); 147 GetPandaVM()148 PandaVM *GetPandaVM() const 149 { 150 return vm_; 151 } 152 GetGC()153 mem::GC *GetGC() const 154 { 155 return gc_; 156 } 157 GetNotificationManager()158 RuntimeNotificationManager *GetNotificationManager() const 159 { 160 return notification_manager_; 161 } 162 GetMemStats()163 MemStatsType *GetMemStats() const 164 { 165 return mem_stats_; 166 } 167 HeapManager()168 HeapManager() : target_utilization_(DEFAULT_TARGET_UTILIZATION) {} 169 170 ~HeapManager() = default; 171 172 NO_COPY_SEMANTIC(HeapManager); 173 NO_MOVE_SEMANTIC(HeapManager); 174 175 private: 176 template <GCType gc_type, MTModeT MTMode = MT_MODE_MULTI> Initialize(MemStatsType * mem_stats,bool create_pygote_space)177 bool Initialize(MemStatsType *mem_stats, bool create_pygote_space) 178 { 179 ASSERT(!isInitialized_); 180 isInitialized_ = true; 181 182 codeAllocator_ = new (std::nothrow) CodeAllocator(mem_stats); 183 // For now, crossing map is shared by diffrent VMs. 184 if (!CrossingMapSingleton::IsCreated()) { 185 CrossingMapSingleton::Create(); 186 } 187 objectAllocator_ = new (std::nothrow) 188 typename AllocConfig<gc_type, MTMode>::ObjectAllocatorType(mem_stats, create_pygote_space); 189 return (codeAllocator_ != nullptr) && (internalAllocator_ != nullptr) && (objectAllocator_ != nullptr); 190 } 191 192 /** 193 * Initialize GC bits and also zeroing memory for the whole Object memory 194 * @param cls - class 195 * @param mem - pointer to the ObjectHeader 196 * @return pointer to the ObjectHeader 197 */ 198 ObjectHeader *InitObjectHeaderAtMem(BaseClass *cls, void *mem); 199 200 /** 201 * Triggers GC if needed 202 */ 203 void TriggerGCIfNeeded(); 204 205 void *TryGCAndAlloc(size_t size, Alignment align, ManagedThread *thread); 206 207 void *AllocByTLAB(size_t size, ManagedThread *thread); 208 209 void *AllocateMemoryForObject(size_t size, Alignment align, ManagedThread *thread); 210 211 static constexpr float DEFAULT_TARGET_UTILIZATION = 0.5; 212 213 bool isInitialized_ = false; 214 bool use_runtime_internal_allocator_ {true}; 215 CodeAllocator *codeAllocator_ = nullptr; 216 InternalAllocatorPtr internalAllocator_ = nullptr; 217 ObjectAllocatorPtr objectAllocator_ = nullptr; 218 219 bool use_tlab_for_allocations_ = false; 220 221 /** 222 * StackFrameAllocator is per thread 223 */ 224 StackFrameAllocator *GetCurrentStackFrameAllocator(); 225 226 friend class ::panda::Runtime; 227 228 /** 229 * TODO : Target ideal heap utilization ratio. 230 * To implement the getTargetHeapUtilization and nativeSetTargetHeapUtilization, I set a variable here. 231 * It may need to be initialized, but now I give it a fixed initial value 0.5 232 */ 233 float target_utilization_; 234 235 IsObjectFinalizebleFunc IsObjectFinalizebleFunc_ = nullptr; 236 RegisterFinalizeReferenceFunc RegisterFinalizeReferenceFunc_ = nullptr; 237 PandaVM *vm_ {nullptr}; 238 MemStatsType *mem_stats_ {nullptr}; 239 mem::GC *gc_ = nullptr; 240 RuntimeNotificationManager *notification_manager_ = nullptr; 241 }; 242 243 } // namespace panda::mem 244 245 #endif // PANDA_MEM_HEAP_MANAGER_H 246