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