/* * Copyright (c) 2021-2024 Huawei Device Co., Ltd. * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ #include "ecmascript/mem/free_object_list.h" #include "ecmascript/free_object.h" #include "ecmascript/mem/jit_fort.h" namespace panda::ecmascript { template FreeObjectList::FreeObjectList(JitFort * fort) : sets_(new FreeObjectSet *[NUMBER_OF_SETS](), NUMBER_OF_SETS), lastSets_(new FreeObjectSet *[NUMBER_OF_SETS](), NUMBER_OF_SETS), jitFort_(fort) { for (int i = 0; i < NUMBER_OF_SETS; i++) { sets_[i] = nullptr; lastSets_[i] = nullptr; } noneEmptySetBitMap_ = 0; } template FreeObjectList::FreeObjectList(JitFort* fort); template FreeObjectList::FreeObjectList(JitFort* fort); template FreeObjectList::~FreeObjectList() { delete[] sets_.data(); delete[] lastSets_.data(); noneEmptySetBitMap_ = 0; } template FreeObjectList::~FreeObjectList(); template FreeObjectList::~FreeObjectList(); template T *FreeObjectList::Allocate(size_t size) { if (noneEmptySetBitMap_ == 0) { return nullptr; } // find from suitable SetType type = SelectSetType(size); if (type == FreeObjectSet::INVALID_SET_TYPE) { return nullptr; } SetType lastType = type - 1; for (type = static_cast(CalcNextNoneEmptyIndex(type)); type > lastType && type < NUMBER_OF_SETS; type = static_cast(CalcNextNoneEmptyIndex(type + 1))) { lastType = type; FreeObjectSet *current = sets_[type]; while (current != nullptr) { if (current->Available() < size) { current = current->next_; continue; } FreeObjectSet *next = nullptr; T *object = T::Cast(INVALID_OBJPTR); if (type <= SMALL_SET_MAX_INDEX) { object = current->ObtainSmallFreeObject(size); } else { next = current->next_; object = current->ObtainLargeFreeObject(size); } if (current->Empty()) { RemoveSet(current); current->Rebuild(); } if (object != T::Cast(INVALID_OBJPTR)) { available_ -= object->Available(); return object; } current = next; } } return nullptr; } template FreeObject *FreeObjectList::Allocate(size_t size); template MemDesc *FreeObjectList::Allocate(size_t size); template T *FreeObjectList::LookupSuitableFreeObject(size_t size) { if (noneEmptySetBitMap_ == 0) { return nullptr; } // find a suitable type SetType type = SelectSetType(size); if (type == FreeObjectSet::INVALID_SET_TYPE) { return nullptr; } SetType lastType = type - 1; for (type = static_cast(CalcNextNoneEmptyIndex(type)); type > lastType && type < NUMBER_OF_SETS; type = static_cast(CalcNextNoneEmptyIndex(type + 1))) { lastType = type; FreeObjectSet *current = sets_[type]; while (current != nullptr) { FreeObjectSet *next = nullptr; T *object = INVALID_OBJECT; if (type <= SMALL_SET_MAX_INDEX) { object = current->LookupSmallFreeObject(size); } else { next = current->next_; object = current->LookupLargeFreeObject(size); } if (object != INVALID_OBJECT) { return object; } current = next; } } return nullptr; } template FreeObject *FreeObjectList::LookupSuitableFreeObject(size_t); template template void FreeObjectList::FreeImpl(U* region, uintptr_t start, size_t size, bool isAdd) { if (UNLIKELY(start == 0)) { return; } if (UNLIKELY(size < MIN_SIZE)) { region->IncreaseWasted(size); if (isAdd) { wasted_ += size; } return; } SetType type = SelectSetType(size); if (type == FreeObjectSet::INVALID_SET_TYPE) { return; } auto set = region->GetFreeObjectSet(type); if (set == nullptr) { LOG_FULL(FATAL) << "The set of region is nullptr"; return; } set->Free(start, size); if (isAdd) { if (set->isAdded_ == 0) { AddSet(set); } else { available_ += size; } } } template void FreeObjectList::FreeImpl(Region* region, uintptr_t start, size_t size, bool isAdd); template void FreeObjectList::FreeImpl(JitFortRegion* region, uintptr_t start, size_t size, bool isAdd); template void FreeObjectList::Free(uintptr_t start, size_t size, bool isAdd) { return FreeImpl(Region::ObjectAddressToRange(reinterpret_cast(start)), start, size, isAdd); } // template class instance for non JitFort space uses FreeObject and Region. template void FreeObjectList::Free(uintptr_t, size_t, bool); // template class instance for JitFort space uses MemDesc and JitFortRegion template <> void FreeObjectList::Free(uintptr_t start, size_t size, bool isAdd) { return FreeImpl(jitFort_->ObjectAddressToRange(start), start, size, isAdd); } template void FreeObjectList::Rebuild() { EnumerateSets([](FreeObjectSet *set) { set->Rebuild(); }); for (int i = 0; i < NUMBER_OF_SETS; i++) { sets_[i] = nullptr; lastSets_[i] = nullptr; } available_ = 0; wasted_ = 0; noneEmptySetBitMap_ = 0; } template void FreeObjectList::Rebuild(); template void FreeObjectList::Rebuild(); template bool FreeObjectList::MatchFreeObjectInSet(FreeObjectSet *set, size_t size) { if (set == nullptr || set->Empty()) { return false; } // find a suitable type SetType type = SelectSetType(size); if (type == FreeObjectSet::INVALID_SET_TYPE) { return false; } T *object = nullptr; if (type <= SMALL_SET_MAX_INDEX) { object = set->LookupSmallFreeObject(size); } else { object = set->LookupLargeFreeObject(size); } return object != nullptr; } template bool FreeObjectList::MatchFreeObjectInSet(FreeObjectSet *, size_t); template bool FreeObjectList::AddSet(FreeObjectSet *set) { if (set == nullptr || set->Empty() || set->isAdded_ != 0) { return false; } SetType type = set->setType_; FreeObjectSet *top = sets_[type]; if (set == top) { return false; } if (top != nullptr) { top->prev_ = set; } set->isAdded_ = 1; // 1: added set->next_ = top; set->prev_ = nullptr; if (lastSets_[type] == nullptr) { lastSets_[type] = set; } if (sets_[type] == nullptr) { SetNoneEmptyBit(type); } sets_[type] = set; available_ += set->Available(); return true; } template bool FreeObjectList::AddSet(FreeObjectSet *); template bool FreeObjectList::AddSet(FreeObjectSet *); template void FreeObjectList::RemoveSet(FreeObjectSet *set) { if (set == nullptr) { return; } SetType type = set->setType_; FreeObjectSet *top = sets_[type]; FreeObjectSet *end = lastSets_[type]; if (top == set) { sets_[type] = top->next_; } if (end == set) { lastSets_[type] = end->prev_; } if (set->prev_ != nullptr) { set->prev_->next_ = set->next_; } if (set->next_ != nullptr) { set->next_->prev_ = set->prev_; } set->isAdded_ = 0; set->prev_ = nullptr; set->next_ = nullptr; if (sets_[type] == nullptr) { ClearNoneEmptyBit(type); } available_ -= set->Available(); } template void FreeObjectList::RemoveSet(FreeObjectSet *); template void FreeObjectList::Merge(FreeObjectList *list) { list->EnumerateTopAndLastSets([this](FreeObjectSet *set, FreeObjectSet *end) { if (set == nullptr || set->Empty()) { return; } SetType type = set->setType_; FreeObjectSet *top = sets_[type]; if (top == nullptr) { top = set; } else { lastSets_[type]->next_ = set; set->prev_ = lastSets_[type]; } lastSets_[type] = end; SetNoneEmptyBit(type); }); available_ += list->available_; list->Rebuild(); } template template void FreeObjectList::EnumerateSets(const Callback &cb) const { for (SetType i = 0; i < NUMBER_OF_SETS; i++) { EnumerateSets(i, cb); } } template template void FreeObjectList::EnumerateSets(SetType type, const Callback &cb) const { FreeObjectSet *current = sets_[type]; while (current != nullptr) { // maybe reset FreeObjectSet *next = current->next_; cb(current); current = next; } } template template void FreeObjectList::EnumerateTopAndLastSets(const Callback &cb) const { for (SetType i = 0; i < NUMBER_OF_SETS; i++) { cb(sets_[i], lastSets_[i]); } } } // namespace panda::ecmascript