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-inl.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 = CalcNextNoneEmptyIndex(type); type > lastType && type < NUMBER_OF_SETS;
54 type = 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 = nullptr;
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 != nullptr) {
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 = CalcNextNoneEmptyIndex(type); type > lastType && type < NUMBER_OF_SETS;
97 type = CalcNextNoneEmptyIndex(type + 1)) {
98 lastType = type;
99 FreeObjectSet *current = sets_[type];
100 while (current != nullptr) {
101 FreeObjectSet *next = nullptr;
102 FreeObject *object = nullptr;
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 != nullptr) {
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->IncrementWasted(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_ECMA(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
AddSet(FreeObjectSet * set)165 bool FreeObjectList::AddSet(FreeObjectSet *set)
166 {
167 if (set == nullptr || set->Empty() || set->isAdded_) {
168 return false;
169 }
170 SetType type = set->setType_;
171 FreeObjectSet *top = sets_[type];
172 if (set == top) {
173 return false;
174 }
175 if (top != nullptr) {
176 top->prev_ = set;
177 }
178 set->isAdded_ = true;
179 set->next_ = top;
180 set->prev_ = nullptr;
181 if (lastSets_[type] == nullptr) {
182 lastSets_[type] = set;
183 }
184 if (sets_[type] == nullptr) {
185 SetNoneEmptyBit(type);
186 }
187 sets_[type] = set;
188 available_ += set->Available();
189 return true;
190 }
191
RemoveSet(FreeObjectSet * set)192 void FreeObjectList::RemoveSet(FreeObjectSet *set)
193 {
194 if (set == nullptr) {
195 return;
196 }
197 SetType type = set->setType_;
198 FreeObjectSet *top = sets_[type];
199 FreeObjectSet *end = lastSets_[type];
200 if (top == set) {
201 sets_[type] = top->next_;
202 }
203 if (end == set) {
204 lastSets_[type] = end->prev_;
205 }
206 if (set->prev_ != nullptr) {
207 set->prev_->next_ = set->next_;
208 }
209 if (set->next_ != nullptr) {
210 set->next_->prev_ = set->prev_;
211 }
212 set->isAdded_ = false;
213 set->prev_ = nullptr;
214 set->next_ = nullptr;
215 if (sets_[type] == nullptr) {
216 ClearNoneEmptyBit(type);
217 }
218 available_ -= set->Available();
219 }
220
Merge(FreeObjectList * list)221 void FreeObjectList::Merge(FreeObjectList *list)
222 {
223 list->EnumerateTopAndLastSets([this](FreeObjectSet *set, FreeObjectSet *end) {
224 if (set == nullptr || set->Empty()) {
225 return;
226 }
227 SetType type = set->setType_;
228 FreeObjectSet *top = sets_[type];
229 if (top == nullptr) {
230 top = set;
231 } else {
232 lastSets_[type]->next_ = set;
233 set->prev_ = lastSets_[type];
234 }
235 lastSets_[type] = end;
236 SetNoneEmptyBit(type);
237 });
238 available_ += list->available_;
239 list->Rebuild();
240 }
241
242 template<class Callback>
EnumerateSets(const Callback & cb) const243 void FreeObjectList::EnumerateSets(const Callback &cb) const
244 {
245 for (SetType i = 0; i < NUMBER_OF_SETS; i++) {
246 EnumerateSets(i, cb);
247 }
248 }
249
250 template<class Callback>
EnumerateSets(SetType type,const Callback & cb) const251 void FreeObjectList::EnumerateSets(SetType type, const Callback &cb) const
252 {
253 FreeObjectSet *current = sets_[type];
254 while (current != nullptr) {
255 // maybe reset
256 FreeObjectSet *next = current->next_;
257 cb(current);
258 current = next;
259 }
260 }
261
262 template<class Callback>
EnumerateTopAndLastSets(const Callback & cb) const263 void FreeObjectList::EnumerateTopAndLastSets(const Callback &cb) const
264 {
265 for (SetType i = 0; i < NUMBER_OF_SETS; i++) {
266 cb(sets_[i], lastSets_[i]);
267 }
268 }
269 } // namespace panda::ecmascript
270