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