14514f5e3Sopenharmony_ci/*
24514f5e3Sopenharmony_ci * Copyright (c) 2021-2024 Huawei Device Co., Ltd.
34514f5e3Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License");
44514f5e3Sopenharmony_ci * you may not use this file except in compliance with the License.
54514f5e3Sopenharmony_ci * You may obtain a copy of the License at
64514f5e3Sopenharmony_ci *
74514f5e3Sopenharmony_ci *     http://www.apache.org/licenses/LICENSE-2.0
84514f5e3Sopenharmony_ci *
94514f5e3Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software
104514f5e3Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS,
114514f5e3Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
124514f5e3Sopenharmony_ci * See the License for the specific language governing permissions and
134514f5e3Sopenharmony_ci * limitations under the License.
144514f5e3Sopenharmony_ci */
154514f5e3Sopenharmony_ci
164514f5e3Sopenharmony_ci#include "ecmascript/mem/free_object_list.h"
174514f5e3Sopenharmony_ci
184514f5e3Sopenharmony_ci#include "ecmascript/free_object.h"
194514f5e3Sopenharmony_ci#include "ecmascript/mem/jit_fort.h"
204514f5e3Sopenharmony_ci
214514f5e3Sopenharmony_cinamespace panda::ecmascript {
224514f5e3Sopenharmony_citemplate <typename T>
234514f5e3Sopenharmony_ciFreeObjectList<T>::FreeObjectList(JitFort * fort) : sets_(new FreeObjectSet<T> *[NUMBER_OF_SETS](), NUMBER_OF_SETS),
244514f5e3Sopenharmony_ci    lastSets_(new FreeObjectSet<T> *[NUMBER_OF_SETS](), NUMBER_OF_SETS), jitFort_(fort)
254514f5e3Sopenharmony_ci{
264514f5e3Sopenharmony_ci    for (int i = 0; i < NUMBER_OF_SETS; i++) {
274514f5e3Sopenharmony_ci        sets_[i] = nullptr;
284514f5e3Sopenharmony_ci        lastSets_[i] = nullptr;
294514f5e3Sopenharmony_ci    }
304514f5e3Sopenharmony_ci    noneEmptySetBitMap_ = 0;
314514f5e3Sopenharmony_ci}
324514f5e3Sopenharmony_citemplate FreeObjectList<FreeObject>::FreeObjectList(JitFort* fort);
334514f5e3Sopenharmony_citemplate FreeObjectList<MemDesc>::FreeObjectList(JitFort* fort);
344514f5e3Sopenharmony_ci
354514f5e3Sopenharmony_citemplate <typename T>
364514f5e3Sopenharmony_ciFreeObjectList<T>::~FreeObjectList()
374514f5e3Sopenharmony_ci{
384514f5e3Sopenharmony_ci    delete[] sets_.data();
394514f5e3Sopenharmony_ci    delete[] lastSets_.data();
404514f5e3Sopenharmony_ci    noneEmptySetBitMap_ = 0;
414514f5e3Sopenharmony_ci}
424514f5e3Sopenharmony_citemplate FreeObjectList<FreeObject>::~FreeObjectList();
434514f5e3Sopenharmony_citemplate FreeObjectList<MemDesc>::~FreeObjectList();
444514f5e3Sopenharmony_ci
454514f5e3Sopenharmony_citemplate <typename T>
464514f5e3Sopenharmony_ciT *FreeObjectList<T>::Allocate(size_t size)
474514f5e3Sopenharmony_ci{
484514f5e3Sopenharmony_ci    if (noneEmptySetBitMap_ == 0) {
494514f5e3Sopenharmony_ci        return nullptr;
504514f5e3Sopenharmony_ci    }
514514f5e3Sopenharmony_ci    // find from suitable
524514f5e3Sopenharmony_ci    SetType type = SelectSetType(size);
534514f5e3Sopenharmony_ci    if (type == FreeObjectSet<T>::INVALID_SET_TYPE) {
544514f5e3Sopenharmony_ci        return nullptr;
554514f5e3Sopenharmony_ci    }
564514f5e3Sopenharmony_ci
574514f5e3Sopenharmony_ci    SetType lastType = type - 1;
584514f5e3Sopenharmony_ci    for (type = static_cast<int32_t>(CalcNextNoneEmptyIndex(type)); type > lastType && type < NUMBER_OF_SETS;
594514f5e3Sopenharmony_ci        type = static_cast<int32_t>(CalcNextNoneEmptyIndex(type + 1))) {
604514f5e3Sopenharmony_ci        lastType = type;
614514f5e3Sopenharmony_ci        FreeObjectSet<T> *current = sets_[type];
624514f5e3Sopenharmony_ci        while (current != nullptr) {
634514f5e3Sopenharmony_ci            if (current->Available() < size) {
644514f5e3Sopenharmony_ci                current = current->next_;
654514f5e3Sopenharmony_ci                continue;
664514f5e3Sopenharmony_ci            }
674514f5e3Sopenharmony_ci            FreeObjectSet<T> *next = nullptr;
684514f5e3Sopenharmony_ci            T *object = T::Cast(INVALID_OBJPTR);
694514f5e3Sopenharmony_ci            if (type <= SMALL_SET_MAX_INDEX) {
704514f5e3Sopenharmony_ci                object = current->ObtainSmallFreeObject(size);
714514f5e3Sopenharmony_ci            } else {
724514f5e3Sopenharmony_ci                next = current->next_;
734514f5e3Sopenharmony_ci                object = current->ObtainLargeFreeObject(size);
744514f5e3Sopenharmony_ci            }
754514f5e3Sopenharmony_ci            if (current->Empty()) {
764514f5e3Sopenharmony_ci                RemoveSet(current);
774514f5e3Sopenharmony_ci                current->Rebuild();
784514f5e3Sopenharmony_ci            }
794514f5e3Sopenharmony_ci            if (object != T::Cast(INVALID_OBJPTR)) {
804514f5e3Sopenharmony_ci                available_ -= object->Available();
814514f5e3Sopenharmony_ci                return object;
824514f5e3Sopenharmony_ci            }
834514f5e3Sopenharmony_ci            current = next;
844514f5e3Sopenharmony_ci        }
854514f5e3Sopenharmony_ci    }
864514f5e3Sopenharmony_ci    return nullptr;
874514f5e3Sopenharmony_ci}
884514f5e3Sopenharmony_citemplate FreeObject *FreeObjectList<FreeObject>::Allocate(size_t size);
894514f5e3Sopenharmony_citemplate MemDesc *FreeObjectList<MemDesc>::Allocate(size_t size);
904514f5e3Sopenharmony_ci
914514f5e3Sopenharmony_citemplate <typename T>
924514f5e3Sopenharmony_ciT *FreeObjectList<T>::LookupSuitableFreeObject(size_t size)
934514f5e3Sopenharmony_ci{
944514f5e3Sopenharmony_ci    if (noneEmptySetBitMap_ == 0) {
954514f5e3Sopenharmony_ci        return nullptr;
964514f5e3Sopenharmony_ci    }
974514f5e3Sopenharmony_ci    // find a suitable type
984514f5e3Sopenharmony_ci    SetType type = SelectSetType(size);
994514f5e3Sopenharmony_ci    if (type == FreeObjectSet<T>::INVALID_SET_TYPE) {
1004514f5e3Sopenharmony_ci        return nullptr;
1014514f5e3Sopenharmony_ci    }
1024514f5e3Sopenharmony_ci
1034514f5e3Sopenharmony_ci    SetType lastType = type - 1;
1044514f5e3Sopenharmony_ci    for (type = static_cast<int32_t>(CalcNextNoneEmptyIndex(type)); type > lastType && type < NUMBER_OF_SETS;
1054514f5e3Sopenharmony_ci        type = static_cast<int32_t>(CalcNextNoneEmptyIndex(type + 1))) {
1064514f5e3Sopenharmony_ci        lastType = type;
1074514f5e3Sopenharmony_ci        FreeObjectSet<T> *current = sets_[type];
1084514f5e3Sopenharmony_ci        while (current != nullptr) {
1094514f5e3Sopenharmony_ci            FreeObjectSet<T> *next = nullptr;
1104514f5e3Sopenharmony_ci            T *object = INVALID_OBJECT;
1114514f5e3Sopenharmony_ci            if (type <= SMALL_SET_MAX_INDEX) {
1124514f5e3Sopenharmony_ci                object = current->LookupSmallFreeObject(size);
1134514f5e3Sopenharmony_ci            } else {
1144514f5e3Sopenharmony_ci                next = current->next_;
1154514f5e3Sopenharmony_ci                object = current->LookupLargeFreeObject(size);
1164514f5e3Sopenharmony_ci            }
1174514f5e3Sopenharmony_ci            if (object != INVALID_OBJECT) {
1184514f5e3Sopenharmony_ci                return object;
1194514f5e3Sopenharmony_ci            }
1204514f5e3Sopenharmony_ci            current = next;
1214514f5e3Sopenharmony_ci        }
1224514f5e3Sopenharmony_ci    }
1234514f5e3Sopenharmony_ci    return nullptr;
1244514f5e3Sopenharmony_ci}
1254514f5e3Sopenharmony_citemplate FreeObject *FreeObjectList<FreeObject>::LookupSuitableFreeObject(size_t);
1264514f5e3Sopenharmony_ci
1274514f5e3Sopenharmony_citemplate <typename T>
1284514f5e3Sopenharmony_citemplate <typename U>
1294514f5e3Sopenharmony_civoid FreeObjectList<T>::FreeImpl(U* region, uintptr_t start, size_t size, bool isAdd)
1304514f5e3Sopenharmony_ci{
1314514f5e3Sopenharmony_ci    if (UNLIKELY(start == 0)) {
1324514f5e3Sopenharmony_ci        return;
1334514f5e3Sopenharmony_ci    }
1344514f5e3Sopenharmony_ci    if (UNLIKELY(size < MIN_SIZE)) {
1354514f5e3Sopenharmony_ci        region->IncreaseWasted(size);
1364514f5e3Sopenharmony_ci        if (isAdd) {
1374514f5e3Sopenharmony_ci            wasted_ += size;
1384514f5e3Sopenharmony_ci        }
1394514f5e3Sopenharmony_ci        return;
1404514f5e3Sopenharmony_ci    }
1414514f5e3Sopenharmony_ci
1424514f5e3Sopenharmony_ci    SetType type = SelectSetType(size);
1434514f5e3Sopenharmony_ci    if (type == FreeObjectSet<T>::INVALID_SET_TYPE) {
1444514f5e3Sopenharmony_ci        return;
1454514f5e3Sopenharmony_ci    }
1464514f5e3Sopenharmony_ci
1474514f5e3Sopenharmony_ci    auto set = region->GetFreeObjectSet(type);
1484514f5e3Sopenharmony_ci    if (set == nullptr) {
1494514f5e3Sopenharmony_ci        LOG_FULL(FATAL) << "The set of region is nullptr";
1504514f5e3Sopenharmony_ci        return;
1514514f5e3Sopenharmony_ci    }
1524514f5e3Sopenharmony_ci    set->Free(start, size);
1534514f5e3Sopenharmony_ci
1544514f5e3Sopenharmony_ci    if (isAdd) {
1554514f5e3Sopenharmony_ci        if (set->isAdded_ == 0) {
1564514f5e3Sopenharmony_ci            AddSet(set);
1574514f5e3Sopenharmony_ci        } else {
1584514f5e3Sopenharmony_ci            available_ += size;
1594514f5e3Sopenharmony_ci        }
1604514f5e3Sopenharmony_ci    }
1614514f5e3Sopenharmony_ci}
1624514f5e3Sopenharmony_citemplate void FreeObjectList<FreeObject>::FreeImpl<Region>(Region* region, uintptr_t start, size_t size, bool isAdd);
1634514f5e3Sopenharmony_citemplate void FreeObjectList<MemDesc>::FreeImpl<JitFortRegion>(JitFortRegion* region,
1644514f5e3Sopenharmony_ci    uintptr_t start, size_t size, bool isAdd);
1654514f5e3Sopenharmony_ci
1664514f5e3Sopenharmony_citemplate <typename T>
1674514f5e3Sopenharmony_civoid FreeObjectList<T>::Free(uintptr_t start, size_t size, bool isAdd)
1684514f5e3Sopenharmony_ci{
1694514f5e3Sopenharmony_ci    return FreeImpl<Region>(Region::ObjectAddressToRange(reinterpret_cast<TaggedObject *>(start)), start, size, isAdd);
1704514f5e3Sopenharmony_ci}
1714514f5e3Sopenharmony_ci
1724514f5e3Sopenharmony_ci// template class instance for non JitFort space uses FreeObject and Region.
1734514f5e3Sopenharmony_citemplate void FreeObjectList<FreeObject>::Free(uintptr_t, size_t, bool);
1744514f5e3Sopenharmony_ci// template class instance for JitFort space uses MemDesc and JitFortRegion
1754514f5e3Sopenharmony_citemplate <>
1764514f5e3Sopenharmony_civoid FreeObjectList<MemDesc>::Free(uintptr_t start, size_t size, bool isAdd)
1774514f5e3Sopenharmony_ci{
1784514f5e3Sopenharmony_ci    return FreeImpl<JitFortRegion>(jitFort_->ObjectAddressToRange(start), start, size, isAdd);
1794514f5e3Sopenharmony_ci}
1804514f5e3Sopenharmony_ci
1814514f5e3Sopenharmony_citemplate <typename T>
1824514f5e3Sopenharmony_civoid FreeObjectList<T>::Rebuild()
1834514f5e3Sopenharmony_ci{
1844514f5e3Sopenharmony_ci    EnumerateSets([](FreeObjectSet<T> *set) { set->Rebuild(); });
1854514f5e3Sopenharmony_ci    for (int i = 0; i < NUMBER_OF_SETS; i++) {
1864514f5e3Sopenharmony_ci        sets_[i] = nullptr;
1874514f5e3Sopenharmony_ci        lastSets_[i] = nullptr;
1884514f5e3Sopenharmony_ci    }
1894514f5e3Sopenharmony_ci    available_ = 0;
1904514f5e3Sopenharmony_ci    wasted_ = 0;
1914514f5e3Sopenharmony_ci    noneEmptySetBitMap_ = 0;
1924514f5e3Sopenharmony_ci}
1934514f5e3Sopenharmony_citemplate void FreeObjectList<FreeObject>::Rebuild();
1944514f5e3Sopenharmony_citemplate void FreeObjectList<MemDesc>::Rebuild();
1954514f5e3Sopenharmony_ci
1964514f5e3Sopenharmony_citemplate <typename T>
1974514f5e3Sopenharmony_cibool FreeObjectList<T>::MatchFreeObjectInSet(FreeObjectSet<T> *set, size_t size)
1984514f5e3Sopenharmony_ci{
1994514f5e3Sopenharmony_ci    if (set == nullptr || set->Empty()) {
2004514f5e3Sopenharmony_ci        return false;
2014514f5e3Sopenharmony_ci    }
2024514f5e3Sopenharmony_ci    // find a suitable type
2034514f5e3Sopenharmony_ci    SetType type = SelectSetType(size);
2044514f5e3Sopenharmony_ci    if (type == FreeObjectSet<T>::INVALID_SET_TYPE) {
2054514f5e3Sopenharmony_ci        return false;
2064514f5e3Sopenharmony_ci    }
2074514f5e3Sopenharmony_ci
2084514f5e3Sopenharmony_ci    T *object = nullptr;
2094514f5e3Sopenharmony_ci    if (type <= SMALL_SET_MAX_INDEX) {
2104514f5e3Sopenharmony_ci        object = set->LookupSmallFreeObject(size);
2114514f5e3Sopenharmony_ci    } else {
2124514f5e3Sopenharmony_ci        object = set->LookupLargeFreeObject(size);
2134514f5e3Sopenharmony_ci    }
2144514f5e3Sopenharmony_ci    return object != nullptr;
2154514f5e3Sopenharmony_ci}
2164514f5e3Sopenharmony_citemplate bool FreeObjectList<FreeObject>::MatchFreeObjectInSet(FreeObjectSet<FreeObject> *, size_t);
2174514f5e3Sopenharmony_ci
2184514f5e3Sopenharmony_citemplate <typename T>
2194514f5e3Sopenharmony_cibool FreeObjectList<T>::AddSet(FreeObjectSet<T> *set)
2204514f5e3Sopenharmony_ci{
2214514f5e3Sopenharmony_ci    if (set == nullptr || set->Empty() || set->isAdded_ != 0) {
2224514f5e3Sopenharmony_ci        return false;
2234514f5e3Sopenharmony_ci    }
2244514f5e3Sopenharmony_ci    SetType type = set->setType_;
2254514f5e3Sopenharmony_ci    FreeObjectSet<T> *top = sets_[type];
2264514f5e3Sopenharmony_ci    if (set == top) {
2274514f5e3Sopenharmony_ci        return false;
2284514f5e3Sopenharmony_ci    }
2294514f5e3Sopenharmony_ci    if (top != nullptr) {
2304514f5e3Sopenharmony_ci        top->prev_ = set;
2314514f5e3Sopenharmony_ci    }
2324514f5e3Sopenharmony_ci    set->isAdded_ = 1; // 1: added
2334514f5e3Sopenharmony_ci    set->next_ = top;
2344514f5e3Sopenharmony_ci    set->prev_ = nullptr;
2354514f5e3Sopenharmony_ci    if (lastSets_[type] == nullptr) {
2364514f5e3Sopenharmony_ci        lastSets_[type] = set;
2374514f5e3Sopenharmony_ci    }
2384514f5e3Sopenharmony_ci    if (sets_[type] == nullptr) {
2394514f5e3Sopenharmony_ci        SetNoneEmptyBit(type);
2404514f5e3Sopenharmony_ci    }
2414514f5e3Sopenharmony_ci    sets_[type] = set;
2424514f5e3Sopenharmony_ci    available_ += set->Available();
2434514f5e3Sopenharmony_ci    return true;
2444514f5e3Sopenharmony_ci}
2454514f5e3Sopenharmony_citemplate bool FreeObjectList<FreeObject>::AddSet(FreeObjectSet<FreeObject> *);
2464514f5e3Sopenharmony_citemplate bool FreeObjectList<MemDesc>::AddSet(FreeObjectSet<MemDesc> *);
2474514f5e3Sopenharmony_ci
2484514f5e3Sopenharmony_citemplate <typename T>
2494514f5e3Sopenharmony_civoid FreeObjectList<T>::RemoveSet(FreeObjectSet<T> *set)
2504514f5e3Sopenharmony_ci{
2514514f5e3Sopenharmony_ci    if (set == nullptr) {
2524514f5e3Sopenharmony_ci        return;
2534514f5e3Sopenharmony_ci    }
2544514f5e3Sopenharmony_ci    SetType type = set->setType_;
2554514f5e3Sopenharmony_ci    FreeObjectSet<T> *top = sets_[type];
2564514f5e3Sopenharmony_ci    FreeObjectSet<T> *end = lastSets_[type];
2574514f5e3Sopenharmony_ci    if (top == set) {
2584514f5e3Sopenharmony_ci        sets_[type] = top->next_;
2594514f5e3Sopenharmony_ci    }
2604514f5e3Sopenharmony_ci    if (end == set) {
2614514f5e3Sopenharmony_ci        lastSets_[type] = end->prev_;
2624514f5e3Sopenharmony_ci    }
2634514f5e3Sopenharmony_ci    if (set->prev_ != nullptr) {
2644514f5e3Sopenharmony_ci        set->prev_->next_ = set->next_;
2654514f5e3Sopenharmony_ci    }
2664514f5e3Sopenharmony_ci    if (set->next_ != nullptr) {
2674514f5e3Sopenharmony_ci        set->next_->prev_ = set->prev_;
2684514f5e3Sopenharmony_ci    }
2694514f5e3Sopenharmony_ci    set->isAdded_ = 0;
2704514f5e3Sopenharmony_ci    set->prev_ = nullptr;
2714514f5e3Sopenharmony_ci    set->next_ = nullptr;
2724514f5e3Sopenharmony_ci    if (sets_[type] == nullptr) {
2734514f5e3Sopenharmony_ci        ClearNoneEmptyBit(type);
2744514f5e3Sopenharmony_ci    }
2754514f5e3Sopenharmony_ci    available_ -= set->Available();
2764514f5e3Sopenharmony_ci}
2774514f5e3Sopenharmony_citemplate void FreeObjectList<FreeObject>::RemoveSet(FreeObjectSet<FreeObject> *);
2784514f5e3Sopenharmony_ci
2794514f5e3Sopenharmony_citemplate <typename T>
2804514f5e3Sopenharmony_civoid FreeObjectList<T>::Merge(FreeObjectList<T> *list)
2814514f5e3Sopenharmony_ci{
2824514f5e3Sopenharmony_ci    list->EnumerateTopAndLastSets([this](FreeObjectSet<T> *set, FreeObjectSet<T> *end) {
2834514f5e3Sopenharmony_ci        if (set == nullptr || set->Empty()) {
2844514f5e3Sopenharmony_ci            return;
2854514f5e3Sopenharmony_ci        }
2864514f5e3Sopenharmony_ci        SetType type = set->setType_;
2874514f5e3Sopenharmony_ci        FreeObjectSet<T> *top = sets_[type];
2884514f5e3Sopenharmony_ci        if (top == nullptr) {
2894514f5e3Sopenharmony_ci            top = set;
2904514f5e3Sopenharmony_ci        } else {
2914514f5e3Sopenharmony_ci            lastSets_[type]->next_ = set;
2924514f5e3Sopenharmony_ci            set->prev_ = lastSets_[type];
2934514f5e3Sopenharmony_ci        }
2944514f5e3Sopenharmony_ci        lastSets_[type] = end;
2954514f5e3Sopenharmony_ci        SetNoneEmptyBit(type);
2964514f5e3Sopenharmony_ci    });
2974514f5e3Sopenharmony_ci    available_ += list->available_;
2984514f5e3Sopenharmony_ci    list->Rebuild();
2994514f5e3Sopenharmony_ci}
3004514f5e3Sopenharmony_ci
3014514f5e3Sopenharmony_citemplate<typename T>
3024514f5e3Sopenharmony_citemplate<class Callback>
3034514f5e3Sopenharmony_civoid FreeObjectList<T>::EnumerateSets(const Callback &cb) const
3044514f5e3Sopenharmony_ci{
3054514f5e3Sopenharmony_ci    for (SetType i = 0; i < NUMBER_OF_SETS; i++) {
3064514f5e3Sopenharmony_ci        EnumerateSets(i, cb);
3074514f5e3Sopenharmony_ci    }
3084514f5e3Sopenharmony_ci}
3094514f5e3Sopenharmony_ci
3104514f5e3Sopenharmony_citemplate<typename T>
3114514f5e3Sopenharmony_citemplate<class Callback>
3124514f5e3Sopenharmony_civoid FreeObjectList<T>::EnumerateSets(SetType type, const Callback &cb) const
3134514f5e3Sopenharmony_ci{
3144514f5e3Sopenharmony_ci    FreeObjectSet<T> *current = sets_[type];
3154514f5e3Sopenharmony_ci    while (current != nullptr) {
3164514f5e3Sopenharmony_ci        // maybe reset
3174514f5e3Sopenharmony_ci        FreeObjectSet<T> *next = current->next_;
3184514f5e3Sopenharmony_ci        cb(current);
3194514f5e3Sopenharmony_ci        current = next;
3204514f5e3Sopenharmony_ci    }
3214514f5e3Sopenharmony_ci}
3224514f5e3Sopenharmony_ci
3234514f5e3Sopenharmony_citemplate<typename T>
3244514f5e3Sopenharmony_citemplate<class Callback>
3254514f5e3Sopenharmony_civoid FreeObjectList<T>::EnumerateTopAndLastSets(const Callback &cb) const
3264514f5e3Sopenharmony_ci{
3274514f5e3Sopenharmony_ci    for (SetType i = 0; i < NUMBER_OF_SETS; i++) {
3284514f5e3Sopenharmony_ci        cb(sets_[i], lastSets_[i]);
3294514f5e3Sopenharmony_ci    }
3304514f5e3Sopenharmony_ci}
3314514f5e3Sopenharmony_ci}  // namespace panda::ecmascript
332