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_LIBPANDABASE_MEM_STACK_LIKE_ALLOCATOR_INL_H
16 #define PANDA_LIBPANDABASE_MEM_STACK_LIKE_ALLOCATOR_INL_H
17
18 #include <securec.h>
19 #include "libpandabase/mem/stack_like_allocator.h"
20 #include "libpandabase/utils/logger.h"
21 #include "libpandabase/utils/asan_interface.h"
22
23 namespace ark::mem {
24 // NOLINTNEXTLINE(cppcoreguidelines-macro-usage)
25 #define LOG_STACK_LIKE_ALLOCATOR(level) LOG(level, ALLOC) << "StackLikeAllocator: "
26
27 template <Alignment ALIGNMENT, size_t MAX_SIZE>
28 // CC-OFFNXT(G.FUD.06) Splitting this function will degrade readability. Keyword "inline" needs to satisfy ODR rule.
StackLikeAllocator(bool usePoolManager,SpaceType spaceType)29 inline StackLikeAllocator<ALIGNMENT, MAX_SIZE>::StackLikeAllocator(bool usePoolManager, SpaceType spaceType)
30 : usePoolManager_(usePoolManager)
31 {
32 LOG_STACK_LIKE_ALLOCATOR(DEBUG) << "Initializing of StackLikeAllocator";
33 ASSERT(RELEASE_PAGES_SIZE == AlignUp(RELEASE_PAGES_SIZE, os::mem::GetPageSize()));
34 // MMAP!
35 if (usePoolManager_) {
36 // clang-format off
37 startAddr_ = PoolManager::GetMmapMemPool()
38 ->AllocPool(MAX_SIZE, spaceType, AllocatorType::STACK_LIKE_ALLOCATOR, this).GetMem();
39 // clang-format on
40 } else {
41 startAddr_ = ark::os::mem::MapRWAnonymousWithAlignmentRaw(
42 MAX_SIZE, std::max(GetAlignmentInBytes(ALIGNMENT), static_cast<size_t>(ark::os::mem::GetPageSize())));
43 }
44 if (startAddr_ == nullptr) {
45 LOG_STACK_LIKE_ALLOCATOR(FATAL) << "Can't get initial memory";
46 }
47 freePointer_ = startAddr_;
48 endAddr_ = ToVoidPtr(ToUintPtr(startAddr_) + MAX_SIZE);
49 allocatedEndAddr_ = endAddr_;
50 ASSERT(AlignUp(ToUintPtr(freePointer_), GetAlignmentInBytes(ALIGNMENT)) == ToUintPtr(freePointer_));
51 LOG_STACK_LIKE_ALLOCATOR(DEBUG) << "Initializing of StackLikeAllocator finished";
52 }
53
54 template <Alignment ALIGNMENT, size_t MAX_SIZE>
~StackLikeAllocator()55 inline StackLikeAllocator<ALIGNMENT, MAX_SIZE>::~StackLikeAllocator()
56 {
57 LOG_STACK_LIKE_ALLOCATOR(DEBUG) << "Destroying of StackLikeAllocator";
58 if (usePoolManager_) {
59 PoolManager::GetMmapMemPool()->FreePool(startAddr_, MAX_SIZE);
60 } else {
61 ark::os::mem::UnmapRaw(startAddr_, MAX_SIZE);
62 }
63 LOG_STACK_LIKE_ALLOCATOR(DEBUG) << "Destroying of StackLikeAllocator finished";
64 }
65
66 template <Alignment ALIGNMENT, size_t MAX_SIZE>
67 template <bool USE_MEMSET>
68 // CC-OFFNXT(G.FUD.06) perf critical, ODR
Alloc(size_t size)69 inline void *StackLikeAllocator<ALIGNMENT, MAX_SIZE>::Alloc(size_t size)
70 {
71 ASSERT(AlignUp(size, GetAlignmentInBytes(ALIGNMENT)) == size);
72
73 void *ret = nullptr;
74 uintptr_t newCurPos = ToUintPtr(freePointer_) + size;
75 if (LIKELY(newCurPos <= ToUintPtr(endAddr_))) {
76 ret = freePointer_;
77 freePointer_ = ToVoidPtr(newCurPos);
78 ASAN_UNPOISON_MEMORY_REGION(ret, size);
79 } else {
80 return nullptr;
81 }
82
83 ASSERT(AlignUp(ToUintPtr(ret), GetAlignmentInBytes(ALIGNMENT)) == ToUintPtr(ret));
84 // NOLINTNEXTLINE(readability-braces-around-statements, bugprone-suspicious-semicolon)
85 if constexpr (USE_MEMSET) {
86 memset_s(ret, size, 0x00, size);
87 }
88 LOG_STACK_LIKE_ALLOCATOR(DEBUG) << "Allocated memory at addr " << std::hex << ret;
89 return ret;
90 }
91
92 template <Alignment ALIGNMENT, size_t MAX_SIZE>
93 // CC-OFFNXT(G.FUD.06) perf critical, ODR
Free(void * mem)94 inline void StackLikeAllocator<ALIGNMENT, MAX_SIZE>::Free(void *mem)
95 {
96 ASSERT(ToUintPtr(mem) == AlignUp(ToUintPtr(mem), GetAlignmentInBytes(ALIGNMENT)));
97 ASSERT(Contains(mem));
98 if ((ToUintPtr(mem) >> RELEASE_PAGES_SHIFT) != (ToUintPtr(freePointer_) >> RELEASE_PAGES_SHIFT)) {
99 // Start address from which we can release pages
100 uintptr_t startAddr = AlignUp(ToUintPtr(mem), RELEASE_PAGES_SIZE);
101 // We do page release calls each RELEASE_PAGES_SIZE interval,
102 // Therefore, we should clear the last RELEASE_PAGES_SIZE interval
103 uintptr_t endAddr = AlignUp(ToUintPtr(freePointer_), RELEASE_PAGES_SIZE);
104 os::mem::ReleasePages(startAddr, endAddr);
105 LOG_STACK_LIKE_ALLOCATOR(DEBUG) << "Release " << std::dec << endAddr - startAddr
106 << " memory bytes in interval [" << std::hex << startAddr << "; " << endAddr
107 << "]";
108 }
109 ASAN_POISON_MEMORY_REGION(mem, ToUintPtr(freePointer_) - ToUintPtr(mem));
110 freePointer_ = mem;
111 LOG_STACK_LIKE_ALLOCATOR(DEBUG) << "Free memory at addr " << std::hex << mem;
112 }
113
114 template <Alignment ALIGNMENT, size_t MAX_SIZE>
Contains(void * mem)115 inline bool StackLikeAllocator<ALIGNMENT, MAX_SIZE>::Contains(void *mem)
116 {
117 return (ToUintPtr(mem) >= ToUintPtr(startAddr_)) && (ToUintPtr(mem) < ToUintPtr(freePointer_));
118 }
119
120 #undef LOG_STACK_LIKE_ALLOCATOR
121 } // namespace ark::mem
122
123 #endif // PANDA_LIBPANDABASE_MEM_STACK_LIKE_ALLOCATOR_INL_H
124