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 ECMASCRIPT_MEM_ALLOCATOR_INL_H
17 #define ECMASCRIPT_MEM_ALLOCATOR_INL_H
18
19 #include <cstdlib>
20 #include <type_traits>
21
22 #include "ecmascript/free_object.h"
23 #include "ecmascript/mem/allocator.h"
24 #include "ecmascript/mem/heap.h"
25
26 namespace panda::ecmascript {
BumpPointerAllocator(uintptr_t begin, uintptr_t end)27 BumpPointerAllocator::BumpPointerAllocator(uintptr_t begin, uintptr_t end) : begin_(begin), top_(begin), end_(end) {}
28
Reset()29 void BumpPointerAllocator::Reset()
30 {
31 begin_ = 0;
32 top_ = 0;
33 end_ = 0;
34 }
35
Reset(uintptr_t begin, uintptr_t end)36 void BumpPointerAllocator::Reset(uintptr_t begin, uintptr_t end)
37 {
38 begin_ = begin;
39 top_ = begin;
40 end_ = end;
41 #ifdef ARK_ASAN_ON
42 ASAN_POISON_MEMORY_REGION(reinterpret_cast<void *>(top_), (end_ - top_));
43 #endif
44 }
45
Reset(uintptr_t begin, uintptr_t end, uintptr_t top)46 void BumpPointerAllocator::Reset(uintptr_t begin, uintptr_t end, uintptr_t top)
47 {
48 begin_ = begin;
49 top_ = top;
50 end_ = end;
51 #ifdef ARK_ASAN_ON
52 ASAN_POISON_MEMORY_REGION(reinterpret_cast<void *>(top_), (end_ - top_));
53 #endif
54 }
55
ResetTopPointer(uintptr_t top)56 void BumpPointerAllocator::ResetTopPointer(uintptr_t top)
57 {
58 top_ = top;
59 }
60
Allocate(size_t size)61 uintptr_t BumpPointerAllocator::Allocate(size_t size)
62 {
63 ASSERT(size != 0);
64 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
65 if (UNLIKELY(top_ + size > end_)) {
66 return 0;
67 }
68 uintptr_t result = top_;
69 // It need to mark unpoison when object being allocated.
70 ASAN_UNPOISON_MEMORY_REGION(reinterpret_cast<void *>(result), size);
71 top_ += size;
72 return result;
73 }
74
75 template <typename T>
FreeListAllocator(BaseHeap *heap)76 FreeListAllocator<T>::FreeListAllocator(BaseHeap *heap) : heap_(heap)
77 {
78 freeList_ = std::make_unique<FreeObjectList<T>>();
79 }
80
81 template <typename T>
Initialize(Region *region)82 void FreeListAllocator<T>::Initialize(Region *region)
83 {
84 bpAllocator_.Reset(region->GetBegin(), region->GetEnd());
85 }
86
87 template <typename T>
Reset(BaseHeap *heap)88 void FreeListAllocator<T>::Reset(BaseHeap *heap)
89 {
90 heap_ = heap;
91 freeList_ = std::make_unique<FreeObjectList<T>>();
92 FreeBumpPoint();
93 }
94
95 template <typename T>
AddFree(Region *region)96 void FreeListAllocator<T>::AddFree(Region *region)
97 {
98 auto begin = region->GetBegin();
99 auto end = region->GetEnd();
100 FreeBumpPoint();
101 bpAllocator_.Reset(begin, end);
102 }
103
104 template <typename T>
Allocate(size_t size)105 uintptr_t FreeListAllocator<T>::Allocate(size_t size)
106 {
107 auto ret = bpAllocator_.Allocate(size);
108 if (LIKELY(ret != 0)) {
109 allocationSizeAccumulator_ += size;
110 return ret;
111 }
112 T *object = freeList_->Allocate(size);
113 if (object != nullptr) {
114 ret = Allocate(object, size);
115 }
116 return ret;
117 }
118
119
120 template <typename T>
Allocate(T *object, size_t size)121 uintptr_t FreeListAllocator<T>::Allocate(T *object, size_t size)
122 {
123 uintptr_t begin = object->GetBegin();
124 uintptr_t end = object->GetEnd();
125 uintptr_t remainSize = end - begin - size;
126 ASSERT(remainSize >= 0);
127 if constexpr (std::is_same<T, MemDesc>::value) {
128 memDescPool_->ReturnDescToPool(object);
129 }
130 // Keep a longest freeObject between bump-pointer and free object that just allocated
131 allocationSizeAccumulator_ += size;
132 if (remainSize <= bpAllocator_.Available()) {
133 Free(begin + size, remainSize);
134 return begin;
135 } else {
136 FreeBumpPoint();
137 bpAllocator_.Reset(begin, end);
138 auto ret = bpAllocator_.Allocate(size);
139 return ret;
140 }
141 }
142
143 template <typename T>
FreeBumpPoint()144 void FreeListAllocator<T>::FreeBumpPoint()
145 {
146 auto begin = bpAllocator_.GetTop();
147 auto size = bpAllocator_.Available();
148 bpAllocator_.Reset();
149 Free(begin, size, true);
150 }
151
152 template <typename T>
FillBumpPointer()153 void FreeListAllocator<T>::FillBumpPointer()
154 {
155 if constexpr (std::is_same<T, MemDesc>::value) {
156 return;
157 }
158 size_t size = bpAllocator_.Available();
159 if (size != 0) {
160 FreeObject::FillFreeObject(heap_, bpAllocator_.GetTop(), size);
161 }
162 }
163
164 template <typename T>
ResetBumpPointer(uintptr_t begin, uintptr_t end, uintptr_t top)165 void FreeListAllocator<T>::ResetBumpPointer(uintptr_t begin, uintptr_t end, uintptr_t top)
166 {
167 bpAllocator_.Reset(begin, end, top);
168 }
169
170 template <typename T>
ResetTopPointer(uintptr_t top)171 void FreeListAllocator<T>::ResetTopPointer(uintptr_t top)
172 {
173 bpAllocator_.ResetTopPointer(top);
174 }
175
176 // The object will be marked with poison after being put into the freelist when is_asan is true.
177 template <typename T>
Free(uintptr_t begin, size_t size, bool isAdd)178 void FreeListAllocator<T>::Free(uintptr_t begin, size_t size, bool isAdd)
179 {
180 ASSERT(size >= 0);
181 if (size != 0) {
182 if constexpr (!std::is_same<T, MemDesc>::value) {
183 ASSERT(heap_ != nullptr);
184 T::FillFreeObject(heap_, begin, size);
185 }
186
187 ASAN_UNPOISON_MEMORY_REGION(reinterpret_cast<void *>(begin), size);
188 freeList_->Free(begin, size, isAdd);
189 #ifdef ARK_ASAN_ON
190 ASAN_POISON_MEMORY_REGION(reinterpret_cast<void *>(begin), size);
191 #endif
192 }
193 }
194
195 template <typename T>
LookupSuitableFreeObject(size_t size)196 uintptr_t FreeListAllocator<T>::LookupSuitableFreeObject(size_t size)
197 {
198 auto freeObject = freeList_->LookupSuitableFreeObject(size);
199 if (freeObject != nullptr) {
200 return freeObject->GetBegin();
201 }
202 return 0;
203 }
204
205 template <typename T>
RebuildFreeList()206 void FreeListAllocator<T>::RebuildFreeList()
207 {
208 bpAllocator_.Reset();
209 freeList_->Rebuild();
210 }
211
212 template <typename T>
CollectFreeObjectSet(Region *region)213 inline void FreeListAllocator<T>::CollectFreeObjectSet(Region *region)
214 {
215 region->EnumerateFreeObjectSets([&](FreeObjectSet<T> *set) {
216 if (set == nullptr || set->Empty()) {
217 return;
218 }
219 freeList_->AddSet(set);
220 });
221 freeList_->IncreaseWastedSize(region->GetWastedSize());
222 }
223
224 template <typename T>
MatchFreeObjectSet(Region *region, size_t size)225 inline bool FreeListAllocator<T>::MatchFreeObjectSet(Region *region, size_t size)
226 {
227 bool ret = false;
228 region->REnumerateFreeObjectSets([&](FreeObjectSet<T> *set) {
229 if (set == nullptr || set->Empty()) {
230 return true;
231 }
232 ret = freeList_->MatchFreeObjectInSet(set, size);
233 return false;
234 });
235 return ret;
236 }
237
238 template <typename T>
DetachFreeObjectSet(Region *region)239 inline void FreeListAllocator<T>::DetachFreeObjectSet(Region *region)
240 {
241 region->EnumerateFreeObjectSets([&](FreeObjectSet<T> *set) {
242 if (set == nullptr || set->Empty()) {
243 return;
244 }
245 freeList_->RemoveSet(set);
246 });
247 freeList_->DecreaseWastedSize(region->GetWastedSize());
248 }
249
250 template <typename T>
GetAvailableSize() const251 size_t FreeListAllocator<T>::GetAvailableSize() const
252 {
253 return freeList_->GetFreeObjectSize() + bpAllocator_.Available();
254 }
255
256 template <typename T>
GetWastedSize() const257 size_t FreeListAllocator<T>::GetWastedSize() const
258 {
259 return freeList_->GetWastedSize();
260 }
261 } // namespace panda::ecmascript
262 #endif // ECMASCRIPT_MEM_ALLOCATOR_INL_H
263