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 #include "ecmascript/mem/free_object_list.h"
17
18 #include "ecmascript/free_object.h"
19 #include "ecmascript/mem/free_object_set.h"
20 #include "ecmascript/mem/free_object_list.h"
21 #include "ecmascript/mem/mem.h"
22
23 namespace panda::ecmascript {
FreeObjectList()24 FreeObjectList::FreeObjectList() : sets_(new FreeObjectSet *[NUMBER_OF_SETS](), NUMBER_OF_SETS),
25 lastSets_(new FreeObjectSet *[NUMBER_OF_SETS](), NUMBER_OF_SETS)
26 {
27 for (int i = 0; i < NUMBER_OF_SETS; i++) {
28 sets_[i] = nullptr;
29 lastSets_[i] = nullptr;
30 }
31 noneEmptySetBitMap_ = 0;
32 }
33
~FreeObjectList()34 FreeObjectList::~FreeObjectList()
35 {
36 delete[] sets_.data();
37 delete[] lastSets_.data();
38 noneEmptySetBitMap_ = 0;
39 }
40
Allocate(size_t size)41 FreeObject *FreeObjectList::Allocate(size_t size)
42 {
43 if (noneEmptySetBitMap_ == 0) {
44 return nullptr;
45 }
46 // find from suitable
47 SetType type = SelectSetType(size);
48 if (type == FreeObjectSet::INVALID_SET_TYPE) {
49 return nullptr;
50 }
51
52 SetType lastType = type - 1;
53 for (type = static_cast<int32_t>(CalcNextNoneEmptyIndex(type)); type > lastType && type < NUMBER_OF_SETS;
54 type = static_cast<int32_t>(CalcNextNoneEmptyIndex(type + 1))) {
55 lastType = type;
56 FreeObjectSet *current = sets_[type];
57 while (current != nullptr) {
58 if (current->Available() < size) {
59 current = current->next_;
60 continue;
61 }
62 FreeObjectSet *next = nullptr;
63 FreeObject *object = INVALID_OBJECT;
64 if (type <= SMALL_SET_MAX_INDEX) {
65 object = current->ObtainSmallFreeObject(size);
66 } else {
67 next = current->next_;
68 object = current->ObtainLargeFreeObject(size);
69 }
70 if (current->Empty()) {
71 RemoveSet(current);
72 current->Rebuild();
73 }
74 if (object != INVALID_OBJECT) {
75 available_ -= object->Available();
76 return object;
77 }
78 current = next;
79 }
80 }
81 return nullptr;
82 }
83
LookupSuitableFreeObject(size_t size)84 FreeObject *FreeObjectList::LookupSuitableFreeObject(size_t size)
85 {
86 if (noneEmptySetBitMap_ == 0) {
87 return nullptr;
88 }
89 // find a suitable type
90 SetType type = SelectSetType(size);
91 if (type == FreeObjectSet::INVALID_SET_TYPE) {
92 return nullptr;
93 }
94
95 SetType lastType = type - 1;
96 for (type = static_cast<int32_t>(CalcNextNoneEmptyIndex(type)); type > lastType && type < NUMBER_OF_SETS;
97 type = static_cast<int32_t>(CalcNextNoneEmptyIndex(type + 1))) {
98 lastType = type;
99 FreeObjectSet *current = sets_[type];
100 while (current != nullptr) {
101 FreeObjectSet *next = nullptr;
102 FreeObject *object = INVALID_OBJECT;
103 if (type <= SMALL_SET_MAX_INDEX) {
104 object = current->LookupSmallFreeObject(size);
105 } else {
106 next = current->next_;
107 object = current->LookupLargeFreeObject(size);
108 }
109 if (object != INVALID_OBJECT) {
110 return object;
111 }
112 current = next;
113 }
114 }
115 return nullptr;
116 }
117
Free(uintptr_t start,size_t size,bool isAdd)118 void FreeObjectList::Free(uintptr_t start, size_t size, bool isAdd)
119 {
120 if (UNLIKELY(start == 0)) {
121 return;
122 }
123 if (UNLIKELY(size < MIN_SIZE)) {
124 Region *region = Region::ObjectAddressToRange(reinterpret_cast<TaggedObject *>(start));
125 region->IncreaseWasted(size);
126 if (isAdd) {
127 wasted_ += size;
128 }
129 return;
130 }
131 SetType type = SelectSetType(size);
132 if (type == FreeObjectSet::INVALID_SET_TYPE) {
133 return;
134 }
135
136 Region *region = Region::ObjectAddressToRange(reinterpret_cast<TaggedObject *>(start));
137 auto set = region->GetFreeObjectSet(type);
138 if (set == nullptr) {
139 LOG_FULL(FATAL) << "The set of region is nullptr";
140 return;
141 }
142 set->Free(start, size);
143
144 if (isAdd) {
145 if (!set->isAdded_) {
146 AddSet(set);
147 } else {
148 available_ += size;
149 }
150 }
151 }
152
Rebuild()153 void FreeObjectList::Rebuild()
154 {
155 EnumerateSets([](FreeObjectSet *set) { set->Rebuild(); });
156 for (int i = 0; i < NUMBER_OF_SETS; i++) {
157 sets_[i] = nullptr;
158 lastSets_[i] = nullptr;
159 }
160 available_ = 0;
161 wasted_ = 0;
162 noneEmptySetBitMap_ = 0;
163 }
164
MatchFreeObjectInSet(FreeObjectSet * set,size_t size)165 bool FreeObjectList::MatchFreeObjectInSet(FreeObjectSet *set, size_t size)
166 {
167 if (set == nullptr || set->Empty()) {
168 return false;
169 }
170 // find a suitable type
171 SetType type = SelectSetType(size);
172 if (type == FreeObjectSet::INVALID_SET_TYPE) {
173 return false;
174 }
175
176 FreeObject *object = nullptr;
177 if (type <= SMALL_SET_MAX_INDEX) {
178 object = set->LookupSmallFreeObject(size);
179 } else {
180 object = set->LookupLargeFreeObject(size);
181 }
182 return object != nullptr;
183 }
184
AddSet(FreeObjectSet * set)185 bool FreeObjectList::AddSet(FreeObjectSet *set)
186 {
187 if (set == nullptr || set->Empty() || set->isAdded_) {
188 return false;
189 }
190 SetType type = set->setType_;
191 FreeObjectSet *top = sets_[type];
192 if (set == top) {
193 return false;
194 }
195 if (top != nullptr) {
196 top->prev_ = set;
197 }
198 set->isAdded_ = true;
199 set->next_ = top;
200 set->prev_ = nullptr;
201 if (lastSets_[type] == nullptr) {
202 lastSets_[type] = set;
203 }
204 if (sets_[type] == nullptr) {
205 SetNoneEmptyBit(type);
206 }
207 sets_[type] = set;
208 available_ += set->Available();
209 return true;
210 }
211
RemoveSet(FreeObjectSet * set)212 void FreeObjectList::RemoveSet(FreeObjectSet *set)
213 {
214 if (set == nullptr) {
215 return;
216 }
217 SetType type = set->setType_;
218 FreeObjectSet *top = sets_[type];
219 FreeObjectSet *end = lastSets_[type];
220 if (top == set) {
221 sets_[type] = top->next_;
222 }
223 if (end == set) {
224 lastSets_[type] = end->prev_;
225 }
226 if (set->prev_ != nullptr) {
227 set->prev_->next_ = set->next_;
228 }
229 if (set->next_ != nullptr) {
230 set->next_->prev_ = set->prev_;
231 }
232 set->isAdded_ = false;
233 set->prev_ = nullptr;
234 set->next_ = nullptr;
235 if (sets_[type] == nullptr) {
236 ClearNoneEmptyBit(type);
237 }
238 available_ -= set->Available();
239 }
240
Merge(FreeObjectList * list)241 void FreeObjectList::Merge(FreeObjectList *list)
242 {
243 list->EnumerateTopAndLastSets([this](FreeObjectSet *set, FreeObjectSet *end) {
244 if (set == nullptr || set->Empty()) {
245 return;
246 }
247 SetType type = set->setType_;
248 FreeObjectSet *top = sets_[type];
249 if (top == nullptr) {
250 top = set;
251 } else {
252 lastSets_[type]->next_ = set;
253 set->prev_ = lastSets_[type];
254 }
255 lastSets_[type] = end;
256 SetNoneEmptyBit(type);
257 });
258 available_ += list->available_;
259 list->Rebuild();
260 }
261
262 template<class Callback>
EnumerateSets(const Callback & cb) const263 void FreeObjectList::EnumerateSets(const Callback &cb) const
264 {
265 for (SetType i = 0; i < NUMBER_OF_SETS; i++) {
266 EnumerateSets(i, cb);
267 }
268 }
269
270 template<class Callback>
EnumerateSets(SetType type,const Callback & cb) const271 void FreeObjectList::EnumerateSets(SetType type, const Callback &cb) const
272 {
273 FreeObjectSet *current = sets_[type];
274 while (current != nullptr) {
275 // maybe reset
276 FreeObjectSet *next = current->next_;
277 cb(current);
278 current = next;
279 }
280 }
281
282 template<class Callback>
EnumerateTopAndLastSets(const Callback & cb) const283 void FreeObjectList::EnumerateTopAndLastSets(const Callback &cb) const
284 {
285 for (SetType i = 0; i < NUMBER_OF_SETS; i++) {
286 cb(sets_[i], lastSets_[i]);
287 }
288 }
289 } // namespace panda::ecmascript
290