• 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-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