1 /** 2 * Copyright (c) 2021-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_RUNTIME_MEM_ALLOC_CONFIG_H 16 #define PANDA_RUNTIME_MEM_ALLOC_CONFIG_H 17 18 #include "runtime/include/object_header.h" 19 #include "runtime/arch/memory_helpers.h" 20 #include "runtime/mem/gc/heap-space-misc/crossing_map_singleton.h" 21 #include "libpandabase/mem/mem.h" 22 #include "libpandabase/mem/mem_range.h" 23 #include "runtime/mem/mem_stats_additional_info.h" 24 #include "runtime/mem/mem_stats_default.h" 25 #include "libpandabase/utils/tsan_interface.h" 26 27 namespace ark::mem { 28 29 /** 30 * We want to record stats about allocations and free events. Allocators don't care about the type of allocated memory. 31 * It could be raw memory for any reason or memory for object in the programming language. If it's a memory for object - 32 * we can cast void* to object and get the specific size of this object, otherwise we should believe to allocator and 33 * can record only approximate size. Because of this we force allocators to use specific config for their needs. 34 */ 35 /// Config for objects allocators with Crossing Map support. 36 class ObjectAllocConfigWithCrossingMap { 37 public: OnAlloc(size_t size,SpaceType typeMem,MemStatsType * memStats)38 static void OnAlloc(size_t size, SpaceType typeMem, MemStatsType *memStats) 39 { 40 memStats->RecordAllocateObject(size, typeMem); 41 } 42 OnFree(size_t size,SpaceType typeMem,MemStatsType * memStats)43 static void OnFree(size_t size, SpaceType typeMem, MemStatsType *memStats) 44 { 45 memStats->RecordFreeObject(size, typeMem); 46 } 47 48 /// @brief Initialize an object memory allocated by an allocator. MemoryInit(void * mem)49 static void MemoryInit(void *mem) 50 { 51 // zeroing according to newobj description in ISA 52 TSAN_ANNOTATE_IGNORE_WRITES_BEGIN(); 53 memset_s(mem, ObjectHeader::ObjectHeaderSize(), 0, ObjectHeader::ObjectHeaderSize()); 54 TSAN_ANNOTATE_IGNORE_WRITES_END(); 55 // zero init should be visible from other threads even if pointer to object was fetched 56 // without 'volatile' specifier so full memory barrier is required 57 // required by some language-specs 58 arch::FullMemoryBarrier(); 59 } 60 61 /// @brief Record new allocation of an object and add it to Crossing Map. AddToCrossingMap(void * objAddr,size_t objSize)62 static void AddToCrossingMap(void *objAddr, size_t objSize) 63 { 64 CrossingMapSingleton::AddObject(objAddr, objSize); 65 } 66 67 /** 68 * @brief Record free call of an object and remove it from Crossing Map. 69 * @param obj_addr - pointer to the removing object (object header). 70 * @param obj_size - size of the removing object. 71 * @param next_obj_addr - pointer to the next object (object header). It can be nullptr. 72 * @param prev_obj_addr - pointer to the previous object (object header). It can be nullptr. 73 * @param prev_obj_size - size of the previous object. 74 * It is used check if previous object crosses the borders of the current map. 75 */ 76 static void RemoveFromCrossingMap(void *objAddr, size_t objSize, void *nextObjAddr, void *prevObjAddr = nullptr, 77 size_t prevObjSize = 0) 78 { 79 CrossingMapSingleton::RemoveObject(objAddr, objSize, nextObjAddr, prevObjAddr, prevObjSize); 80 } 81 82 /** 83 * @brief Find and return the first object, which starts in an interval inclusively 84 * or an object, which crosses the interval border. 85 * It is essential to check the previous object of the returned object to make sure that 86 * we find the first object, which crosses the border of this interval. 87 * @param start_addr - pointer to the first byte of the interval. 88 * @param end_addr - pointer to the last byte of the interval. 89 * @return Returns the first object which starts inside an interval, 90 * or an object which crosses a border of this interval 91 * or nullptr 92 */ FindFirstObjInCrossingMap(void * startAddr,void * endAddr)93 static void *FindFirstObjInCrossingMap(void *startAddr, void *endAddr) 94 { 95 return CrossingMapSingleton::FindFirstObject(startAddr, endAddr); 96 } 97 98 /** 99 * @brief Initialize a Crossing map for the corresponding memory ranges. 100 * @param start_addr - pointer to the first byte of the interval. 101 * @param size - size of the interval. 102 */ InitializeCrossingMapForMemory(void * startAddr,size_t size)103 static void InitializeCrossingMapForMemory(void *startAddr, size_t size) 104 { 105 return CrossingMapSingleton::InitializeCrossingMapForMemory(startAddr, size); 106 } 107 108 /** 109 * @brief Remove a Crossing map for the corresponding memory ranges. 110 * @param start_addr - pointer to the first byte of the interval. 111 * @param size - size of the interval. 112 */ RemoveCrossingMapForMemory(void * startAddr,size_t size)113 static void RemoveCrossingMapForMemory(void *startAddr, size_t size) 114 { 115 return CrossingMapSingleton::RemoveCrossingMapForMemory(startAddr, size); 116 } 117 118 /** 119 * @brief Record new allocation of the young range. 120 * @param mem_range - range of a new young memory. 121 */ OnInitYoungRegion(const MemRange & memRange)122 static void OnInitYoungRegion(const MemRange &memRange) 123 { 124 CrossingMapSingleton::MarkCardsAsYoung(memRange); 125 } 126 }; 127 128 /// Config for objects allocators. 129 class ObjectAllocConfig { 130 public: OnAlloc(size_t size,SpaceType typeMem,MemStatsType * memStats)131 static void OnAlloc(size_t size, SpaceType typeMem, MemStatsType *memStats) 132 { 133 memStats->RecordAllocateObject(size, typeMem); 134 } 135 OnFree(size_t size,SpaceType typeMem,MemStatsType * memStats)136 static void OnFree(size_t size, SpaceType typeMem, MemStatsType *memStats) 137 { 138 memStats->RecordFreeObject(size, typeMem); 139 } 140 141 /// @brief Initialize an object memory allocated by an allocator. MemoryInit(void * mem)142 static void MemoryInit(void *mem) 143 { 144 // zeroing only ObjectHeader size according to newobj description in ISA 145 TSAN_ANNOTATE_IGNORE_WRITES_BEGIN(); 146 memset_s(mem, ObjectHeader::ObjectHeaderSize(), 0, ObjectHeader::ObjectHeaderSize()); 147 TSAN_ANNOTATE_IGNORE_WRITES_END(); 148 // zero init should be visible from other threads even if pointer to object was fetched 149 // without 'volatile' specifier so full memory barrier is required 150 // required by some language-specs 151 arch::FullMemoryBarrier(); 152 } 153 154 // We don't use crossing map in this config. AddToCrossingMap(void * objAddr,size_t objSize)155 static void AddToCrossingMap([[maybe_unused]] void *objAddr, [[maybe_unused]] size_t objSize) {} 156 157 // We don't use crossing map in this config. 158 static void RemoveFromCrossingMap([[maybe_unused]] void *objAddr, [[maybe_unused]] size_t objSize, 159 [[maybe_unused]] void *nextObjAddr = nullptr, 160 [[maybe_unused]] void *prevObjAddr = nullptr, 161 [[maybe_unused]] size_t prevObjSize = 0) 162 { 163 } 164 165 // We don't use crossing map in this config. FindFirstObjInCrossingMap(void * startAddr,void * endAddr)166 static void *FindFirstObjInCrossingMap([[maybe_unused]] void *startAddr, [[maybe_unused]] void *endAddr) 167 { 168 // We can't call CrossingMap when we don't use it 169 ASSERT(startAddr == nullptr); 170 return nullptr; 171 } 172 173 // We don't use crossing map in this config. InitializeCrossingMapForMemory(void * startAddr,size_t size)174 static void InitializeCrossingMapForMemory([[maybe_unused]] void *startAddr, [[maybe_unused]] size_t size) {} 175 176 // We don't use crossing map in this config. RemoveCrossingMapForMemory(void * startAddr,size_t size)177 static void RemoveCrossingMapForMemory([[maybe_unused]] void *startAddr, [[maybe_unused]] size_t size) {} 178 179 /** 180 * @brief Record new allocation of the young range. 181 * @param mem_range - range of a new young memory. 182 */ OnInitYoungRegion(const MemRange & memRange)183 static void OnInitYoungRegion(const MemRange &memRange) 184 { 185 CrossingMapSingleton::MarkCardsAsYoung(memRange); 186 } 187 }; 188 189 /// Config for raw memory allocators. 190 class RawMemoryConfig { 191 public: OnAlloc(size_t size,SpaceType typeMem,MemStatsType * memStats)192 static void OnAlloc(size_t size, SpaceType typeMem, MemStatsType *memStats) 193 { 194 ASSERT(typeMem == SpaceType::SPACE_TYPE_INTERNAL); 195 memStats->RecordAllocateRaw(size, typeMem); 196 } 197 OnFree(size_t size,SpaceType typeMem,MemStatsType * memStats)198 static void OnFree(size_t size, SpaceType typeMem, MemStatsType *memStats) 199 { 200 ASSERT(typeMem == SpaceType::SPACE_TYPE_INTERNAL); 201 memStats->RecordFreeRaw(size, typeMem); 202 } 203 204 /// @brief We don't need it for raw memory. MemoryInit(void * mem)205 static void MemoryInit([[maybe_unused]] void *mem) {} 206 207 // We don't use crossing map for raw memory allocations. AddToCrossingMap(void * objAddr,size_t objSize)208 static void AddToCrossingMap([[maybe_unused]] void *objAddr, [[maybe_unused]] size_t objSize) {} 209 210 // We don't use crossing map for raw memory allocations. 211 static void RemoveFromCrossingMap([[maybe_unused]] void *objAddr, [[maybe_unused]] size_t objSize, 212 [[maybe_unused]] void *nextObjAddr = nullptr, 213 [[maybe_unused]] void *prevObjAddr = nullptr, 214 [[maybe_unused]] size_t prevObjSize = 0) 215 { 216 } 217 218 // We don't use crossing map for raw memory allocations. FindFirstObjInCrossingMap(void * startAddr,void * endAddr)219 static void *FindFirstObjInCrossingMap([[maybe_unused]] void *startAddr, [[maybe_unused]] void *endAddr) 220 { 221 // We can't call CrossingMap when we don't use it 222 ASSERT(startAddr == nullptr); 223 return nullptr; 224 } 225 226 // We don't use crossing map for raw memory allocations. InitializeCrossingMapForMemory(void * startAddr,size_t size)227 static void InitializeCrossingMapForMemory([[maybe_unused]] void *startAddr, [[maybe_unused]] size_t size) {} 228 229 // We don't use crossing map for raw memory allocations. RemoveCrossingMapForMemory(void * startAddr,size_t size)230 static void RemoveCrossingMapForMemory([[maybe_unused]] void *startAddr, [[maybe_unused]] size_t size) {} 231 232 // We don't need to track young memory for raw allocations. OnInitYoungRegion(const MemRange & memRange)233 static void OnInitYoungRegion([[maybe_unused]] const MemRange &memRange) {} 234 }; 235 236 /// Debug config with empty MemStats calls and with Crossing Map support. 237 class EmptyAllocConfigWithCrossingMap { 238 public: OnAlloc(size_t size,SpaceType typeMem,MemStatsType * memStats)239 static void OnAlloc([[maybe_unused]] size_t size, [[maybe_unused]] SpaceType typeMem, 240 [[maybe_unused]] MemStatsType *memStats) 241 { 242 } 243 OnFree(size_t size,SpaceType typeMem,MemStatsType * memStats)244 static void OnFree([[maybe_unused]] size_t size, [[maybe_unused]] SpaceType typeMem, 245 [[maybe_unused]] MemStatsType *memStats) 246 { 247 } 248 249 /// @brief Initialize memory for correct test execution. MemoryInit(void * mem)250 static void MemoryInit([[maybe_unused]] void *mem) {} 251 252 /// @brief Record new allocation of an object and add it to Crossing Map. AddToCrossingMap(void * objAddr,size_t objSize)253 static void AddToCrossingMap(void *objAddr, size_t objSize) 254 { 255 CrossingMapSingleton::AddObject(objAddr, objSize); 256 } 257 258 /** 259 * @brief Record free call of an object and remove it from Crossing Map. 260 * @param obj_addr - pointer to the removing object (object header). 261 * @param obj_size - size of the removing object. 262 * @param next_obj_addr - pointer to the next object (object header). It can be nullptr. 263 * @param prev_obj_addr - pointer to the previous object (object header). It can be nullptr. 264 * @param prev_obj_size - size of the previous object. 265 * It is used check if previous object crosses the borders of the current map. 266 */ 267 static void RemoveFromCrossingMap(void *objAddr, size_t objSize, void *nextObjAddr, void *prevObjAddr = nullptr, 268 size_t prevObjSize = 0) 269 { 270 CrossingMapSingleton::RemoveObject(objAddr, objSize, nextObjAddr, prevObjAddr, prevObjSize); 271 } 272 273 /** 274 * @brief Find and return the first object, which starts in an interval inclusively 275 * or an object, which crosses the interval border. 276 * It is essential to check the previous object of the returned object to make sure that 277 * we find the first object, which crosses the border of this interval. 278 * @param start_addr - pointer to the first byte of the interval. 279 * @param end_addr - pointer to the last byte of the interval. 280 * @return Returns the first object which starts inside an interval, 281 * or an object which crosses a border of this interval 282 * or nullptr 283 */ FindFirstObjInCrossingMap(void * startAddr,void * endAddr)284 static void *FindFirstObjInCrossingMap(void *startAddr, void *endAddr) 285 { 286 return CrossingMapSingleton::FindFirstObject(startAddr, endAddr); 287 } 288 289 /** 290 * @brief Initialize a Crossing map for the corresponding memory ranges. 291 * @param start_addr - pointer to the first byte of the interval. 292 * @param size - size of the interval. 293 */ InitializeCrossingMapForMemory(void * startAddr,size_t size)294 static void InitializeCrossingMapForMemory(void *startAddr, size_t size) 295 { 296 return CrossingMapSingleton::InitializeCrossingMapForMemory(startAddr, size); 297 } 298 299 /** 300 * @brief Remove a Crossing map for the corresponding memory ranges. 301 * @param start_addr - pointer to the first byte of the interval. 302 * @param size - size of the interval. 303 */ RemoveCrossingMapForMemory(void * startAddr,size_t size)304 static void RemoveCrossingMapForMemory(void *startAddr, size_t size) 305 { 306 return CrossingMapSingleton::RemoveCrossingMapForMemory(startAddr, size); 307 } 308 309 // We don't need to track young memory for these allocations. OnInitYoungRegion(const MemRange & memRange)310 static void OnInitYoungRegion([[maybe_unused]] const MemRange &memRange) {} 311 }; 312 313 /* 314 * Config for disuse of stats for memory allocators 315 */ 316 class EmptyMemoryConfig { 317 public: OnAlloc(size_t size,SpaceType typeMem,MemStatsType * memStats)318 ALWAYS_INLINE static void OnAlloc([[maybe_unused]] size_t size, [[maybe_unused]] SpaceType typeMem, 319 [[maybe_unused]] MemStatsType *memStats) 320 { 321 } OnFree(size_t size,SpaceType typeMem,MemStatsType * memStats)322 ALWAYS_INLINE static void OnFree([[maybe_unused]] size_t size, [[maybe_unused]] SpaceType typeMem, 323 [[maybe_unused]] MemStatsType *memStats) 324 { 325 } MemoryInit(void * mem)326 ALWAYS_INLINE static void MemoryInit([[maybe_unused]] void *mem) {} AddToCrossingMap(void * objAddr,size_t objSize)327 ALWAYS_INLINE static void AddToCrossingMap([[maybe_unused]] void *objAddr, [[maybe_unused]] size_t objSize) {} 328 ALWAYS_INLINE static void RemoveFromCrossingMap([[maybe_unused]] void *objAddr, [[maybe_unused]] size_t objSize, 329 [[maybe_unused]] void *nextObjAddr = nullptr, 330 [[maybe_unused]] void *prevObjAddr = nullptr, 331 [[maybe_unused]] size_t prevObjSize = 0) 332 { 333 } 334 FindFirstObjInCrossingMap(void * startAddr,void * endAddr)335 ALWAYS_INLINE static void *FindFirstObjInCrossingMap([[maybe_unused]] void *startAddr, 336 [[maybe_unused]] void *endAddr) 337 { 338 // We can't call CrossingMap when we don't use it 339 ASSERT(startAddr == nullptr); 340 return nullptr; 341 } 342 InitializeCrossingMapForMemory(void * startAddr,size_t size)343 static void InitializeCrossingMapForMemory([[maybe_unused]] void *startAddr, [[maybe_unused]] size_t size) {} 344 RemoveCrossingMapForMemory(void * startAddr,size_t size)345 static void RemoveCrossingMapForMemory([[maybe_unused]] void *startAddr, [[maybe_unused]] size_t size) {} 346 OnInitYoungRegion(const MemRange & memRange)347 static void OnInitYoungRegion([[maybe_unused]] const MemRange &memRange) {} 348 }; 349 350 } // namespace ark::mem 351 #endif // PANDA_RUNTIME_MEM_ALLOC_CONFIG_H 352