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_set.h"
17
18 #include "ecmascript/free_object.h"
19
20 namespace panda::ecmascript {
21 template <typename T>
Free(uintptr_t begin,size_t size)22 void FreeObjectSet<T>::Free(uintptr_t begin, size_t size)
23 {
24 auto freeObject = T::Cast(begin);
25 ASSERT(freeObject->IsFreeObject());
26 freeObject->SetNext(freeObject_);
27 freeObject_ = freeObject;
28 available_ += size;
29 maxAvailableFreeSize_ = std::max(maxAvailableFreeSize_, size);
30 }
31
32 template void FreeObjectSet<FreeObject>::Free(uintptr_t, size_t);
33 template <>
Free(uintptr_t begin,size_t size)34 void FreeObjectSet<MemDesc>::Free(uintptr_t begin, size_t size)
35 {
36 ASSERT(begin >= memDescPool_->JitFortBegin() &&
37 size <= memDescPool_->JitFortSize());
38
39 auto freeObject = memDescPool_->GetDescFromPool();
40 ASSERT(freeObject != nullptr);
41 freeObject->SetMem(begin);
42 freeObject->SetSize(size);
43 freeObject->SetNext(freeObject_);
44 freeObject_ = freeObject;
45 available_ += size;
46 maxAvailableFreeSize_ = std::max(maxAvailableFreeSize_, size);
47 }
48
49 template <typename T>
Rebuild()50 void FreeObjectSet<T>::Rebuild()
51 {
52 freeObject_ = T::Cast(INVALID_OBJPTR);
53 available_ = 0;
54 maxAvailableFreeSize_ = 0;
55 isAdded_ = 0;
56 next_ = nullptr;
57 prev_ = nullptr;
58 }
59
60 template void FreeObjectSet<FreeObject>::Rebuild();
61 template <>
Rebuild()62 void FreeObjectSet<MemDesc>::Rebuild()
63 {
64 MemDesc *current = freeObject_;
65 while (!MemDescPool::IsEmpty(current)) {
66 // put desc back to free pool
67 auto next = current->GetNext();
68 memDescPool_->ReturnDescToPool(current);
69 current = next;
70 }
71 freeObject_ = MemDesc::Cast(INVALID_OBJPTR);
72 available_ = 0;
73 maxAvailableFreeSize_ = 0;
74 isAdded_ = 0;
75 next_ = nullptr;
76 prev_ = nullptr;
77 }
78
79 template <typename T>
ObtainSmallFreeObject(size_t size)80 T *FreeObjectSet<T>::ObtainSmallFreeObject(size_t size)
81 {
82 T *curFreeObject = T::Cast(INVALID_OBJPTR);
83 if (freeObject_ != T::Cast(INVALID_OBJPTR)) {
84 freeObject_->AsanUnPoisonFreeObject();
85 if (freeObject_->Available() >= size) {
86 curFreeObject = freeObject_;
87 freeObject_ = freeObject_->GetNext();
88 curFreeObject->SetNext(T::Cast(INVALID_OBJPTR));
89 available_ -= curFreeObject->Available();
90 // It need to mark unpoison when object being allocated in freelist.
91 ASAN_UNPOISON_MEMORY_REGION(curFreeObject, curFreeObject->Available());
92 } else {
93 freeObject_->AsanPoisonFreeObject();
94 }
95 }
96 return curFreeObject;
97 }
98
99 template FreeObject *FreeObjectSet<FreeObject>::ObtainSmallFreeObject(size_t);
100 template MemDesc *FreeObjectSet<MemDesc>::ObtainSmallFreeObject(size_t);
101
102 template <typename T>
ObtainLargeFreeObject(size_t size)103 T *FreeObjectSet<T>::ObtainLargeFreeObject(size_t size)
104 {
105 T *prevFreeObject = freeObject_;
106 T *curFreeObject = freeObject_;
107 while (curFreeObject != T::Cast(INVALID_OBJPTR)) {
108 curFreeObject->AsanUnPoisonFreeObject();
109 if (curFreeObject->Available() >= size) {
110 if (curFreeObject == freeObject_) {
111 freeObject_ = curFreeObject->GetNext();
112 } else {
113 prevFreeObject->SetNext(curFreeObject->GetNext());
114 prevFreeObject->AsanPoisonFreeObject();
115 }
116 curFreeObject->SetNext(T::Cast(INVALID_OBJPTR));
117 available_ -= curFreeObject->Available();
118 ASAN_UNPOISON_MEMORY_REGION(curFreeObject, curFreeObject->Available());
119 return curFreeObject;
120 }
121 if (prevFreeObject != curFreeObject) {
122 prevFreeObject->AsanPoisonFreeObject();
123 }
124 prevFreeObject = curFreeObject;
125 curFreeObject = curFreeObject->GetNext();
126 }
127 // When looking up suitable freeobject fails, available free size should update to a value less than size.
128 maxAvailableFreeSize_ = std::min(maxAvailableFreeSize_, size - sizeof(JSTaggedType));
129 return T::Cast(INVALID_OBJPTR);
130 }
131
132 template FreeObject *FreeObjectSet<FreeObject>::ObtainLargeFreeObject(size_t);
133 template MemDesc *FreeObjectSet<MemDesc>::ObtainLargeFreeObject(size_t);
134
135 template <typename T>
LookupSmallFreeObject(size_t size)136 T *FreeObjectSet<T>::LookupSmallFreeObject(size_t size)
137 {
138 if (freeObject_ != INVALID_OBJECT) {
139 freeObject_->AsanUnPoisonFreeObject();
140 if (freeObject_->Available() >= size) {
141 freeObject_->AsanPoisonFreeObject();
142 return freeObject_;
143 }
144 freeObject_->AsanPoisonFreeObject();
145 }
146 return INVALID_OBJECT;
147 }
148
149 template FreeObject *FreeObjectSet<FreeObject>::LookupSmallFreeObject(size_t);
150
151 template <typename T>
LookupLargeFreeObject(size_t size)152 T *FreeObjectSet<T>::LookupLargeFreeObject(size_t size)
153 {
154 if (available_ < size) {
155 return INVALID_OBJECT;
156 }
157 T *curFreeObject = freeObject_;
158 while (curFreeObject != INVALID_OBJECT) {
159 curFreeObject->AsanUnPoisonFreeObject();
160 if (curFreeObject->Available() >= size) {
161 curFreeObject->AsanPoisonFreeObject();
162 return curFreeObject;
163 }
164 T *preFreeObject = curFreeObject;
165 curFreeObject = curFreeObject->GetNext();
166 preFreeObject->AsanPoisonFreeObject();
167 }
168 return INVALID_OBJECT;
169 }
170
171 template FreeObject *FreeObjectSet<FreeObject>::LookupLargeFreeObject(size_t);
172
173 } // namespace panda::ecmascript
174