• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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