• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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