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