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