1 /* 2 * Copyright (c) 2021 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 16 #ifndef PANDA_RUNTIME_MEM_ALLOC_CONFIG_H_ 17 #define PANDA_RUNTIME_MEM_ALLOC_CONFIG_H_ 18 19 #include "runtime/arch/memory_helpers.h" 20 #include "runtime/mem/gc/crossing_map_singleton.h" 21 #include "libpandabase/mem/mem.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 trust allocator and 32 * can record only approximate size. Because of this we force allocators to use specific config for their needs. 33 */ 34 35 /** 36 * Config for objects allocators with Crossing Map support. 37 */ 38 class ObjectAllocConfigWithCrossingMap { 39 public: OnAlloc(size_t size,SpaceType type_mem,MemStatsType * mem_stats)40 static void OnAlloc(size_t size, SpaceType type_mem, MemStatsType *mem_stats) 41 { 42 mem_stats->RecordAllocateObject(size, type_mem); 43 } 44 OnFree(size_t size,SpaceType type_mem,MemStatsType * mem_stats)45 static void OnFree(size_t size, SpaceType type_mem, MemStatsType *mem_stats) 46 { 47 mem_stats->RecordFreeObject(size, type_mem); 48 } 49 50 /** 51 * \brief Initialize an object memory allocated by an allocator. 52 */ MemoryInit(void * mem,size_t size)53 static void MemoryInit(void *mem, size_t size) 54 { 55 // zeroing according to newobj description in ISA 56 TSAN_ANNOTATE_IGNORE_WRITES_BEGIN(); 57 (void)memset_s(mem, size, 0, size); 58 TSAN_ANNOTATE_IGNORE_WRITES_END(); 59 // As per java spec, zero init should be visible from other threads even if pointer to object was fetched 60 // without 'volatile' specifier so full memory barrier is required 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 to 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 /** 125 * Config for objects allocators. 126 */ 127 class ObjectAllocConfig { 128 public: OnAlloc(size_t size,SpaceType type_mem,MemStatsType * mem_stats)129 static void OnAlloc(size_t size, SpaceType type_mem, MemStatsType *mem_stats) 130 { 131 mem_stats->RecordAllocateObject(size, type_mem); 132 } 133 OnFree(size_t size,SpaceType type_mem,MemStatsType * mem_stats)134 static void OnFree(size_t size, SpaceType type_mem, MemStatsType *mem_stats) 135 { 136 mem_stats->RecordFreeObject(size, type_mem); 137 } 138 139 /** 140 * \brief Initialize an object memory allocated by an allocator. 141 */ MemoryInit(void * mem,size_t size)142 static void MemoryInit(void *mem, size_t size) 143 { 144 // zeroing according to newobj description in ISA 145 TSAN_ANNOTATE_IGNORE_WRITES_BEGIN(); 146 (void)memset_s(mem, size, 0, size); 147 TSAN_ANNOTATE_IGNORE_WRITES_END(); 148 // As per java spec, 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 arch::FullMemoryBarrier(); 151 } 152 153 // We don't use crossing map in this config. AddToCrossingMap(void * obj_addr,size_t obj_size)154 static void AddToCrossingMap([[maybe_unused]] void *obj_addr, [[maybe_unused]] size_t obj_size) {} 155 156 // We don't use crossing map in this config. 157 static void RemoveFromCrossingMap([[maybe_unused]] void *obj_addr, [[maybe_unused]] size_t obj_size, 158 [[maybe_unused]] void *next_obj_addr = nullptr, 159 [[maybe_unused]] void *prev_obj_addr = nullptr, 160 [[maybe_unused]] size_t prev_obj_size = 0) 161 { 162 } 163 164 // We don't use crossing map in this config. FindFirstObjInCrossingMap(void * start_addr,void * end_addr)165 static void *FindFirstObjInCrossingMap([[maybe_unused]] void *start_addr, [[maybe_unused]] void *end_addr) 166 { 167 // We can't call CrossingMap when we don't use it 168 ASSERT(start_addr == nullptr); 169 return nullptr; 170 } 171 172 // We don't use crossing map in this config. InitializeCrossingMapForMemory(void * start_addr,size_t size)173 static void InitializeCrossingMapForMemory([[maybe_unused]] void *start_addr, [[maybe_unused]] size_t size) {} 174 175 // We don't use crossing map in this config. RemoveCrossingMapForMemory(void * start_addr,size_t size)176 static void RemoveCrossingMapForMemory([[maybe_unused]] void *start_addr, [[maybe_unused]] size_t size) {} 177 }; 178 179 /** 180 * Config for raw memory allocators. 181 */ 182 class RawMemoryConfig { 183 public: OnAlloc(size_t size,SpaceType type_mem,MemStatsType * mem_stats)184 static void OnAlloc(size_t size, SpaceType type_mem, MemStatsType *mem_stats) 185 { 186 ASSERT(type_mem == SpaceType::SPACE_TYPE_INTERNAL); 187 mem_stats->RecordAllocateRaw(size, type_mem); 188 } 189 OnFree(size_t size,SpaceType type_mem,MemStatsType * mem_stats)190 static void OnFree(size_t size, SpaceType type_mem, MemStatsType *mem_stats) 191 { 192 ASSERT(type_mem == SpaceType::SPACE_TYPE_INTERNAL); 193 mem_stats->RecordFreeRaw(size, type_mem); 194 } 195 196 /** 197 * \brief We don't need it for raw memory. 198 */ MemoryInit(void * mem,size_t size)199 static void MemoryInit([[maybe_unused]] void *mem, [[maybe_unused]] size_t size) {} 200 201 // We don't use crossing map for raw memory allocations. AddToCrossingMap(void * obj_addr,size_t obj_size)202 static void AddToCrossingMap([[maybe_unused]] void *obj_addr, [[maybe_unused]] size_t obj_size) {} 203 204 // We don't use crossing map for raw memory allocations. 205 static void RemoveFromCrossingMap([[maybe_unused]] void *obj_addr, [[maybe_unused]] size_t obj_size, 206 [[maybe_unused]] void *next_obj_addr = nullptr, 207 [[maybe_unused]] void *prev_obj_addr = nullptr, 208 [[maybe_unused]] size_t prev_obj_size = 0) 209 { 210 } 211 212 // We don't use crossing map for raw memory allocations. FindFirstObjInCrossingMap(void * start_addr,void * end_addr)213 static void *FindFirstObjInCrossingMap([[maybe_unused]] void *start_addr, [[maybe_unused]] void *end_addr) 214 { 215 // We can't call CrossingMap when we don't use it 216 ASSERT(start_addr == nullptr); 217 return nullptr; 218 } 219 220 // We don't use crossing map for raw memory allocations. InitializeCrossingMapForMemory(void * start_addr,size_t size)221 static void InitializeCrossingMapForMemory([[maybe_unused]] void *start_addr, [[maybe_unused]] size_t size) {} 222 223 // We don't use crossing map for raw memory allocations. RemoveCrossingMapForMemory(void * start_addr,size_t size)224 static void RemoveCrossingMapForMemory([[maybe_unused]] void *start_addr, [[maybe_unused]] size_t size) {} 225 }; 226 227 /** 228 * Debug config with empty MemStats calls and with Crossing Map support. 229 */ 230 class EmptyAllocConfigWithCrossingMap { 231 public: OnAlloc(size_t size,SpaceType type_mem,MemStatsType * mem_stats)232 static void OnAlloc([[maybe_unused]] size_t size, [[maybe_unused]] SpaceType type_mem, 233 [[maybe_unused]] MemStatsType *mem_stats) 234 { 235 } 236 OnFree(size_t size,SpaceType type_mem,MemStatsType * mem_stats)237 static void OnFree([[maybe_unused]] size_t size, [[maybe_unused]] SpaceType type_mem, 238 [[maybe_unused]] MemStatsType *mem_stats) 239 { 240 } 241 242 /** 243 * \brief Initialize memory for correct test execution. 244 */ MemoryInit(void * mem,size_t size)245 static void MemoryInit(void *mem, size_t size) 246 { 247 TSAN_ANNOTATE_IGNORE_WRITES_BEGIN(); 248 (void)memset_s(mem, size, 0, size); 249 TSAN_ANNOTATE_IGNORE_WRITES_END(); 250 // As per java spec, zero init should be visible from other threads even if pointer to object was fetched 251 // without 'volatile' specifier so full memory barrier is required 252 arch::FullMemoryBarrier(); 253 } 254 255 /** 256 * \brief Record new allocation of an object and add it to Crossing Map. 257 */ AddToCrossingMap(void * obj_addr,size_t obj_size)258 static void AddToCrossingMap(void *obj_addr, size_t obj_size) 259 { 260 CrossingMapSingleton::AddObject(obj_addr, obj_size); 261 } 262 263 /** 264 * \brief Record free call of an object and remove it from Crossing Map. 265 * @param obj_addr - pointer to the removing object (object header). 266 * @param obj_size - size of the removing object. 267 * @param next_obj_addr - pointer to the next object (object header). It can be nullptr. 268 * @param prev_obj_addr - pointer to the previous object (object header). It can be nullptr. 269 * @param prev_obj_size - size of the previous object. 270 * It is used check if previous object crosses the borders of the current map. 271 */ 272 static void RemoveFromCrossingMap(void *obj_addr, size_t obj_size, void *next_obj_addr, 273 void *prev_obj_addr = nullptr, size_t prev_obj_size = 0) 274 { 275 CrossingMapSingleton::RemoveObject(obj_addr, obj_size, next_obj_addr, prev_obj_addr, prev_obj_size); 276 } 277 278 /** 279 * \brief Find and return the first object, which starts in an interval inclusively 280 * or an object, which crosses the interval border. 281 * It is essential to check the previous object of the returned object to make sure that 282 * we find the first object, which crosses the border of this interval. 283 * @param start_addr - pointer to the first byte of the interval. 284 * @param end_addr - pointer to the last byte of the interval. 285 * @return Returns the first object which starts inside an interval, 286 * or an object which crosses a border of this interval 287 * or nullptr 288 */ FindFirstObjInCrossingMap(void * start_addr,void * end_addr)289 static void *FindFirstObjInCrossingMap(void *start_addr, void *end_addr) 290 { 291 return CrossingMapSingleton::FindFirstObject(start_addr, end_addr); 292 } 293 294 /** 295 * \brief Initialize a Crossing map for the corresponding memory ranges. 296 * @param start_addr - pointer to the first byte of the interval. 297 * @param size - size of the interval. 298 */ InitializeCrossingMapForMemory(void * start_addr,size_t size)299 static void InitializeCrossingMapForMemory(void *start_addr, size_t size) 300 { 301 return CrossingMapSingleton::InitializeCrossingMapForMemory(start_addr, size); 302 } 303 304 /** 305 * \brief Remove a Crossing map for the corresponding memory ranges. 306 * @param start_addr - pointer to the first byte of the interval. 307 * @param size - size of the interval. 308 */ RemoveCrossingMapForMemory(void * start_addr,size_t size)309 static void RemoveCrossingMapForMemory(void *start_addr, size_t size) 310 { 311 return CrossingMapSingleton::RemoveCrossingMapForMemory(start_addr, size); 312 } 313 }; 314 315 /* 316 * Config for disuse of stats for memory allocators 317 */ 318 class EmptyMemoryConfig { 319 public: OnAlloc(size_t size,SpaceType type_mem,MemStatsType * mem_stats)320 ALWAYS_INLINE static void OnAlloc([[maybe_unused]] size_t size, [[maybe_unused]] SpaceType type_mem, 321 [[maybe_unused]] MemStatsType *mem_stats) 322 { 323 } OnFree(size_t size,SpaceType type_mem,MemStatsType * mem_stats)324 ALWAYS_INLINE static void OnFree([[maybe_unused]] size_t size, [[maybe_unused]] SpaceType type_mem, 325 [[maybe_unused]] MemStatsType *mem_stats) 326 { 327 } MemoryInit(void * mem,size_t size)328 ALWAYS_INLINE static void MemoryInit([[maybe_unused]] void *mem, [[maybe_unused]] size_t size) {} AddToCrossingMap(void * obj_addr,size_t obj_size)329 ALWAYS_INLINE static void AddToCrossingMap([[maybe_unused]] void *obj_addr, [[maybe_unused]] size_t obj_size) {} 330 ALWAYS_INLINE static void RemoveFromCrossingMap([[maybe_unused]] void *obj_addr, [[maybe_unused]] size_t obj_size, 331 [[maybe_unused]] void *next_obj_addr = nullptr, 332 [[maybe_unused]] void *prev_obj_addr = nullptr, 333 [[maybe_unused]] size_t prev_obj_size = 0) 334 { 335 } 336 FindFirstObjInCrossingMap(void * start_addr,void * end_addr)337 ALWAYS_INLINE static void *FindFirstObjInCrossingMap([[maybe_unused]] void *start_addr, 338 [[maybe_unused]] void *end_addr) 339 { 340 // We can't call CrossingMap when we don't use it 341 ASSERT(start_addr == nullptr); 342 return nullptr; 343 } 344 InitializeCrossingMapForMemory(void * start_addr,size_t size)345 static void InitializeCrossingMapForMemory([[maybe_unused]] void *start_addr, [[maybe_unused]] size_t size) {} 346 RemoveCrossingMapForMemory(void * start_addr,size_t size)347 static void RemoveCrossingMapForMemory([[maybe_unused]] void *start_addr, [[maybe_unused]] size_t size) {} 348 }; 349 350 } // namespace panda::mem 351 352 #endif // PANDA_RUNTIME_MEM_ALLOC_CONFIG_H_ 353