• 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_FRAME_ALLOCATOR_INL_H
16 #define PANDA_RUNTIME_MEM_FRAME_ALLOCATOR_INL_H
17 
18 #include "runtime/mem/frame_allocator.h"
19 
20 #include <cstring>
21 
22 #include "libpandabase/mem/pool_manager.h"
23 #include "libpandabase/utils/logger.h"
24 #include "libpandabase/mem/stack_like_allocator-inl.h"
25 
26 namespace ark::mem {
27 
28 using StackFrameAllocator = StackLikeAllocator<>;
29 
30 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
31 #define LOG_FRAME_ALLOCATOR(level) LOG(level, ALLOC) << "FrameAllocator: "
32 
33 template <Alignment ALIGNMENT, bool USE_MEMSET>
FrameAllocator(bool useMalloc,SpaceType spaceType)34 inline FrameAllocator<ALIGNMENT, USE_MEMSET>::FrameAllocator(bool useMalloc, SpaceType spaceType)
35     : useMalloc_(useMalloc), spaceType_(spaceType)
36 {
37     LOG_FRAME_ALLOCATOR(DEBUG) << "Initializing of FrameAllocator";
38     if (!useMalloc_) {
39         memPoolAlloc_ = PoolManager::GetMmapMemPool();
40     }
41     curArena_ = AllocateArenaImpl(FIRST_ARENA_SIZE);
42     lastAllocArena_ = curArena_;
43     biggestArenaSize_ = FIRST_ARENA_SIZE;
44     arenaSizeNeedToGrow_ = true;
45     LOG_FRAME_ALLOCATOR(DEBUG) << "Initializing of FrameAllocator finished";
46 }
47 
48 template <Alignment ALIGNMENT, bool USE_MEMSET>
~FrameAllocator()49 inline FrameAllocator<ALIGNMENT, USE_MEMSET>::~FrameAllocator()
50 {
51     LOG_FRAME_ALLOCATOR(DEBUG) << "Destroying of FrameAllocator";
52     while (lastAllocArena_ != nullptr) {
53         LOG_FRAME_ALLOCATOR(DEBUG) << "Free arena at addr " << std::hex << lastAllocArena_;
54         FramesArena *prevArena = lastAllocArena_->GetPrevArena();
55         FreeArenaImpl(lastAllocArena_);
56         lastAllocArena_ = prevArena;
57     }
58     curArena_ = nullptr;
59     LOG_FRAME_ALLOCATOR(DEBUG) << "Destroying of FrameAllocator finished";
60 }
61 
62 template <Alignment ALIGNMENT, bool USE_MEMSET>
TryAllocateNewArena(size_t size)63 inline bool FrameAllocator<ALIGNMENT, USE_MEMSET>::TryAllocateNewArena(size_t size)
64 {
65     size_t arenaSize = GetNextArenaSize(size);
66     LOG_FRAME_ALLOCATOR(DEBUG) << "Try to allocate a new arena with size " << arenaSize;
67     FramesArena *newArena = AllocateArenaImpl(arenaSize);
68     if (newArena == nullptr) {
69         LOG_FRAME_ALLOCATOR(DEBUG) << "Couldn't get memory for a new arena";
70         arenaSizeNeedToGrow_ = false;
71         return false;
72     }
73     lastAllocArena_->LinkNext(newArena);
74     newArena->LinkPrev(lastAllocArena_);
75     lastAllocArena_ = newArena;
76     emptyArenasCount_++;
77     LOG_FRAME_ALLOCATOR(DEBUG) << "Successfully allocate new arena with addr " << std::hex << newArena;
78     return true;
79 }
80 
81 template <Alignment ALIGNMENT, bool USE_MEMSET>
Alloc(size_t size)82 ALWAYS_INLINE inline void *FrameAllocator<ALIGNMENT, USE_MEMSET>::Alloc(size_t size)
83 {
84     ASSERT(AlignUp(size, GetAlignmentInBytes(ALIGNMENT)) == size);
85     // Try to get free memory from current arenas
86     void *mem = TryToAllocate(size);
87 
88     if (UNLIKELY(mem == nullptr)) {
89         LOG_FRAME_ALLOCATOR(DEBUG) << "Can't allocate " << size << " bytes for a new frame in current arenas";
90         if (!TryAllocateNewArena(size)) {
91             LOG_FRAME_ALLOCATOR(DEBUG) << "Can't allocate a new arena, return nullptr";
92             return nullptr;
93         }
94         mem = TryToAllocate(size);
95         if (mem == nullptr) {
96             LOG_FRAME_ALLOCATOR(DEBUG) << "Can't allocate memory in a totally free arena, change default arenas sizes";
97             return nullptr;
98         }
99     }
100 
101     ASSERT(AlignUp(ToUintPtr(mem), GetAlignmentInBytes(ALIGNMENT)) == ToUintPtr(mem));
102     LOG_FRAME_ALLOCATOR(DEBUG) << "Allocated memory at addr " << std::hex << mem;
103     // NOLINTNEXTLINE(readability-braces-around-statements, bugprone-suspicious-semicolon)
104     if constexpr (USE_MEMSET) {
105         memset_s(mem, size, 0x00, size);
106     }
107     allocatedSize_ += size;
108     return mem;
109 }
110 
111 template <Alignment ALIGNMENT, bool USE_MEMSET>
Free(void * mem)112 ALWAYS_INLINE inline void FrameAllocator<ALIGNMENT, USE_MEMSET>::Free(void *mem)
113 {
114     ASSERT(curArena_ != nullptr);  // must has been initialized!
115     ASSERT(ToUintPtr(mem) == AlignUp(ToUintPtr(mem), GetAlignmentInBytes(ALIGNMENT)));
116     if (curArena_->InArena(mem)) {
117         allocatedSize_ -= ToUintPtr(curArena_->GetTop()) - ToUintPtr(mem);
118         curArena_->Free(mem);
119     } else {
120         ASSERT(curArena_->GetOccupiedSize() == 0);
121         ASSERT(curArena_->GetPrevArena() != nullptr);
122 
123         curArena_ = curArena_->GetPrevArena();
124         ASSERT(curArena_->InArena(mem));
125         allocatedSize_ -= ToUintPtr(curArena_->GetTop()) - ToUintPtr(mem);
126         curArena_->Free(mem);
127         if (UNLIKELY((emptyArenasCount_ + 1) > FRAME_ALLOC_MAX_FREE_ARENAS_THRESHOLD)) {
128             FreeLastArena();
129         } else {
130             emptyArenasCount_++;
131         }
132     }
133     LOG_FRAME_ALLOCATOR(DEBUG) << "Free memory at addr " << std::hex << mem;
134 }
135 
136 template <Alignment ALIGNMENT, bool USE_MEMSET>
TryToAllocate(size_t size)137 inline void *FrameAllocator<ALIGNMENT, USE_MEMSET>::TryToAllocate(size_t size)
138 {
139     // Try to allocate memory in the current arena:
140     ASSERT(curArena_ != nullptr);
141     void *mem = curArena_->Alloc(size);
142     if (LIKELY(mem != nullptr)) {
143         return mem;
144     }
145     // We don't have enough memory in current arena, try to allocate in the next one:
146     FramesArena *nextArena = curArena_->GetNextArena();
147     if (nextArena == nullptr) {
148         LOG_FRAME_ALLOCATOR(DEBUG) << "TryToPush failed - we don't have a free arena";
149         return nullptr;
150     }
151     mem = nextArena->Alloc(size);
152     if (LIKELY(mem != nullptr)) {
153         ASSERT(emptyArenasCount_ > 0);
154         emptyArenasCount_--;
155         curArena_ = nextArena;
156         return mem;
157     }
158     LOG_FRAME_ALLOCATOR(DEBUG) << "Couldn't allocate " << size << " bytes of memory in the totally free arena."
159                                << " Change initial sizes of arenas";
160     return nullptr;
161 }
162 
163 template <Alignment ALIGNMENT, bool USE_MEMSET>
GetNextArenaSize(size_t size)164 inline size_t FrameAllocator<ALIGNMENT, USE_MEMSET>::GetNextArenaSize(size_t size)
165 {
166     size_t requestedSize = size + sizeof(FramesArena) + GetAlignmentInBytes(ALIGNMENT);
167     if ((arenaSizeNeedToGrow_) || (biggestArenaSize_ < requestedSize)) {
168         biggestArenaSize_ += ARENA_SIZE_GREW_LEVEL;
169         if (biggestArenaSize_ < requestedSize) {
170             biggestArenaSize_ = RoundUp(requestedSize, ARENA_SIZE_GREW_LEVEL);
171         }
172     } else {
173         arenaSizeNeedToGrow_ = true;
174     }
175     return biggestArenaSize_;
176 }
177 
178 template <Alignment ALIGNMENT, bool USE_MEMSET>
FreeLastArena()179 inline void FrameAllocator<ALIGNMENT, USE_MEMSET>::FreeLastArena()
180 {
181     ASSERT(lastAllocArena_ != nullptr);
182     FramesArena *arenaToFree = lastAllocArena_;
183     lastAllocArena_ = arenaToFree->GetPrevArena();
184     if (arenaToFree == curArena_) {
185         curArena_ = lastAllocArena_;
186     }
187     if (lastAllocArena_ == nullptr) {
188         ASSERT(lastAllocArena_ == curArena_);
189         // To fix clang tidy warning
190         // (it suggests that cur_arena_ can be not nullptr when
191         //  last_alloc_arena_ is equal to nullptr)
192         curArena_ = lastAllocArena_;
193         LOG_FRAME_ALLOCATOR(DEBUG) << "Clear the last arena in the list";
194     } else {
195         lastAllocArena_->ClearNextLink();
196     }
197     LOG_FRAME_ALLOCATOR(DEBUG) << "Free the arena at addr " << std::hex << arenaToFree;
198     FreeArenaImpl(arenaToFree);
199     arenaSizeNeedToGrow_ = false;
200 }
201 
202 template <Alignment ALIGNMENT, bool USE_MEMSET>
203 inline typename FrameAllocator<ALIGNMENT, USE_MEMSET>::FramesArena *
AllocateArenaImpl(size_t size)204 FrameAllocator<ALIGNMENT, USE_MEMSET>::AllocateArenaImpl(size_t size)
205 {
206     FramesArena *newArena = nullptr;
207     if (!useMalloc_) {
208         ASSERT(memPoolAlloc_ != nullptr);
209         newArena = memPoolAlloc_->AllocArena<FramesArena>(size, spaceType_, AllocatorType::FRAME_ALLOCATOR, this);
210     } else {
211         auto mem = ark::os::mem::AlignedAlloc(GetAlignmentInBytes(ARENA_DEFAULT_ALIGNMENT), size);
212         if (mem != nullptr) {
213             auto arenaBuffOffs = AlignUp(sizeof(FramesArena), GetAlignmentInBytes(ARENA_DEFAULT_ALIGNMENT));
214             newArena = new (mem) FramesArena(size - arenaBuffOffs, ToVoidPtr(ToUintPtr(mem) + arenaBuffOffs));
215         }
216     }
217     return newArena;
218 }
219 
220 template <Alignment ALIGNMENT, bool USE_MEMSET>
FreeArenaImpl(FramesArena * arena)221 inline void FrameAllocator<ALIGNMENT, USE_MEMSET>::FreeArenaImpl(FramesArena *arena)
222 {
223     ASSERT(arena != nullptr);
224     if (!useMalloc_) {
225         ASSERT(memPoolAlloc_ != nullptr);
226         memPoolAlloc_->FreeArena<FramesArena>(arena);
227     } else {
228         os::mem::AlignedFree(arena);
229     }
230 }
231 
232 template <Alignment ALIGNMENT, bool USE_MEMSET>
Contains(void * mem)233 inline bool FrameAllocator<ALIGNMENT, USE_MEMSET>::Contains(void *mem)
234 {
235     auto curArena = curArena_;
236 
237     while (curArena != nullptr) {
238         LOG_FRAME_ALLOCATOR(DEBUG) << "check InAllocator arena at addr " << std::hex << curArena;
239         if (curArena->InArena(mem)) {
240             return true;
241         }
242         curArena = curArena->GetPrevArena();
243     }
244     return false;
245 }
246 
247 #undef LOG_FRAME_ALLOCATOR
248 
249 }  // namespace ark::mem
250 #endif  // PANDA_RUNTIME_MEM_FRAME_ALLOCATOR_INL_H
251