1 /** 2 * Copyright (c) 2023-2024 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 #ifndef PANDA_PLUGINS_ETS_RUNTIME_INTEROP_JS_ITEM_POOL_H_ 17 #define PANDA_PLUGINS_ETS_RUNTIME_INTEROP_JS_ITEM_POOL_H_ 18 19 #include "libpandabase/macros.h" 20 #include "libpandabase/utils/math_helpers.h" 21 22 namespace ark::ets::interop::js::ets_proxy { 23 24 namespace testing { 25 class ItemsPoolTest; 26 } // namespace testing 27 28 template <typename Item, uint32_t NR_INDEX_BITS> 29 class ItemsPool { 30 union PaddedItem { 31 Item item; 32 PaddedItem *next; 33 std::array<uint8_t, helpers::math::GetPowerOfTwoValue32(sizeof(Item))> aligned; 34 PaddedItem()35 PaddedItem() 36 { 37 new (&item) Item(); 38 } ~PaddedItem()39 ~PaddedItem() 40 { 41 item.~Item(); 42 } 43 NO_COPY_SEMANTIC(PaddedItem); 44 NO_MOVE_SEMANTIC(PaddedItem); 45 }; 46 47 static constexpr size_t MAX_INDEX = 1U << NR_INDEX_BITS; 48 static constexpr size_t PADDED_ITEM_SIZE = sizeof(PaddedItem); 49 GetPaddedItem(Item * item)50 static PaddedItem *GetPaddedItem(Item *item) 51 { 52 ASSERT(uintptr_t(item) % PADDED_ITEM_SIZE == 0); 53 return reinterpret_cast<PaddedItem *>(item); 54 } 55 56 public: 57 static constexpr size_t MAX_POOL_SIZE = (1U << NR_INDEX_BITS) * PADDED_ITEM_SIZE; 58 ItemsPool(void * data,size_t size)59 ItemsPool(void *data, size_t size) 60 : data_(reinterpret_cast<PaddedItem *>(data)), 61 dataEnd_(reinterpret_cast<PaddedItem *>(uintptr_t(data_) + size)), 62 currentPos_(reinterpret_cast<PaddedItem *>(data)) 63 { 64 ASSERT(data != nullptr); 65 ASSERT(size % PADDED_ITEM_SIZE == 0); 66 } 67 ~ItemsPool() = default; 68 GetNextAlloc()69 Item *GetNextAlloc() const 70 { 71 if (freeList_ != nullptr) { 72 return &freeList_->item; 73 } 74 return (currentPos_ < dataEnd_) ? ¤tPos_->item : nullptr; 75 } 76 AllocItem()77 Item *AllocItem() 78 { 79 if (freeList_ != nullptr) { 80 PaddedItem *newItem = freeList_; 81 freeList_ = freeList_->next; 82 return &(new (newItem) PaddedItem())->item; 83 } 84 85 if (UNLIKELY(currentPos_ >= dataEnd_)) { 86 // Out of memory 87 return nullptr; 88 } 89 90 PaddedItem *newItem = currentPos_; 91 ++currentPos_; // NOLINT(cppcoreguidelines-pro-bounds-pointer-arithmetic) 92 return &(new (newItem) PaddedItem())->item; 93 } 94 FreeItem(Item * item)95 void FreeItem(Item *item) 96 { 97 PaddedItem *paddedItem = GetPaddedItem(item); 98 paddedItem->~PaddedItem(); 99 paddedItem->next = freeList_; 100 freeList_ = paddedItem; 101 } 102 103 // This method only checks the validity of the item in the allocated interval 104 // This method does not check whether the item has been allocated or not IsValidItem(const Item * item)105 bool IsValidItem(const Item *item) const 106 { 107 if (UNLIKELY(!IsAligned<alignof(Item)>(uintptr_t(item)))) { 108 return false; 109 } 110 auto addr = uintptr_t(item); 111 return uintptr_t(data_) <= addr && addr < uintptr_t(dataEnd_); 112 } 113 GetIndexByItem(Item * item)114 inline uint32_t GetIndexByItem(Item *item) 115 { 116 ASSERT(IsValidItem(item)); 117 ASSERT(uintptr_t(item) % PADDED_ITEM_SIZE == 0); 118 119 PaddedItem *paddedItem = GetPaddedItem(item); 120 return paddedItem - data_; 121 } 122 GetItemByIndex(uint32_t idx)123 inline Item *GetItemByIndex(uint32_t idx) 124 { 125 ASSERT(idx < MAX_INDEX); 126 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic,cppcoreguidelines-pro-type-union-access) 127 return &data_[idx].item; 128 } 129 130 NO_COPY_SEMANTIC(ItemsPool); 131 NO_MOVE_SEMANTIC(ItemsPool); 132 133 private: 134 PaddedItem *const data_ {}; 135 PaddedItem *const dataEnd_ {}; 136 PaddedItem *currentPos_ {}; 137 PaddedItem *freeList_ {}; 138 139 friend testing::ItemsPoolTest; 140 }; 141 142 } // namespace ark::ets::interop::js::ets_proxy 143 144 #endif // !PANDA_PLUGINS_ETS_RUNTIME_INTEROP_JS_ITEM_POOL_H_ 145