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