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
20namespace panda::ecmascript {
21template <typename T>
22void 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
31template void FreeObjectSet<FreeObject>::Free(uintptr_t, size_t);
32template <>
33void 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
47template <typename T>
48void FreeObjectSet<T>::Rebuild()
49{
50    freeObject_ = T::Cast(INVALID_OBJPTR);
51    available_ = 0;
52    isAdded_ = 0;
53    next_ = nullptr;
54    prev_ = nullptr;
55}
56
57template void FreeObjectSet<FreeObject>::Rebuild();
58template <>
59void 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
75template <typename T>
76T *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
95template FreeObject *FreeObjectSet<FreeObject>::ObtainSmallFreeObject(size_t);
96template MemDesc *FreeObjectSet<MemDesc>::ObtainSmallFreeObject(size_t);
97
98template <typename T>
99T *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
126template FreeObject *FreeObjectSet<FreeObject>::ObtainLargeFreeObject(size_t);
127template MemDesc *FreeObjectSet<MemDesc>::ObtainLargeFreeObject(size_t);
128
129template <typename T>
130T *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
143template FreeObject *FreeObjectSet<FreeObject>::LookupSmallFreeObject(size_t);
144
145template <typename T>
146T *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
165template FreeObject *FreeObjectSet<FreeObject>::LookupLargeFreeObject(size_t);
166
167}  // namespace panda::ecmascript
168