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