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