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#ifndef ECMASCRIPT_MEM_ALLOCATOR_INL_H 17#define ECMASCRIPT_MEM_ALLOCATOR_INL_H 18 19#include <cstdlib> 20#include <type_traits> 21 22#include "ecmascript/free_object.h" 23#include "ecmascript/mem/allocator.h" 24#include "ecmascript/mem/heap.h" 25 26namespace panda::ecmascript { 27BumpPointerAllocator::BumpPointerAllocator(uintptr_t begin, uintptr_t end) : begin_(begin), top_(begin), end_(end) {} 28 29void BumpPointerAllocator::Reset() 30{ 31 begin_ = 0; 32 top_ = 0; 33 end_ = 0; 34} 35 36void BumpPointerAllocator::Reset(uintptr_t begin, uintptr_t end) 37{ 38 begin_ = begin; 39 top_ = begin; 40 end_ = end; 41#ifdef ARK_ASAN_ON 42 ASAN_POISON_MEMORY_REGION(reinterpret_cast<void *>(top_), (end_ - top_)); 43#endif 44} 45 46void BumpPointerAllocator::Reset(uintptr_t begin, uintptr_t end, uintptr_t top) 47{ 48 begin_ = begin; 49 top_ = top; 50 end_ = end; 51#ifdef ARK_ASAN_ON 52 ASAN_POISON_MEMORY_REGION(reinterpret_cast<void *>(top_), (end_ - top_)); 53#endif 54} 55 56void BumpPointerAllocator::ResetTopPointer(uintptr_t top) 57{ 58 top_ = top; 59} 60 61uintptr_t BumpPointerAllocator::Allocate(size_t size) 62{ 63 ASSERT(size != 0); 64 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) 65 if (UNLIKELY(top_ + size > end_)) { 66 return 0; 67 } 68 uintptr_t result = top_; 69 // It need to mark unpoison when object being allocated. 70 ASAN_UNPOISON_MEMORY_REGION(reinterpret_cast<void *>(result), size); 71 top_ += size; 72 return result; 73} 74 75template <typename T> 76FreeListAllocator<T>::FreeListAllocator(BaseHeap *heap) : heap_(heap) 77{ 78 freeList_ = std::make_unique<FreeObjectList<T>>(); 79} 80 81template <typename T> 82void FreeListAllocator<T>::Initialize(Region *region) 83{ 84 bpAllocator_.Reset(region->GetBegin(), region->GetEnd()); 85} 86 87template <typename T> 88void FreeListAllocator<T>::Reset(BaseHeap *heap) 89{ 90 heap_ = heap; 91 freeList_ = std::make_unique<FreeObjectList<T>>(); 92 FreeBumpPoint(); 93} 94 95template <typename T> 96void FreeListAllocator<T>::AddFree(Region *region) 97{ 98 auto begin = region->GetBegin(); 99 auto end = region->GetEnd(); 100 FreeBumpPoint(); 101 bpAllocator_.Reset(begin, end); 102} 103 104template <typename T> 105uintptr_t FreeListAllocator<T>::Allocate(size_t size) 106{ 107 auto ret = bpAllocator_.Allocate(size); 108 if (LIKELY(ret != 0)) { 109 allocationSizeAccumulator_ += size; 110 return ret; 111 } 112 T *object = freeList_->Allocate(size); 113 if (object != nullptr) { 114 ret = Allocate(object, size); 115 } 116 return ret; 117} 118 119 120template <typename T> 121uintptr_t FreeListAllocator<T>::Allocate(T *object, size_t size) 122{ 123 uintptr_t begin = object->GetBegin(); 124 uintptr_t end = object->GetEnd(); 125 uintptr_t remainSize = end - begin - size; 126 ASSERT(remainSize >= 0); 127 if constexpr (std::is_same<T, MemDesc>::value) { 128 memDescPool_->ReturnDescToPool(object); 129 } 130 // Keep a longest freeObject between bump-pointer and free object that just allocated 131 allocationSizeAccumulator_ += size; 132 if (remainSize <= bpAllocator_.Available()) { 133 Free(begin + size, remainSize); 134 return begin; 135 } else { 136 FreeBumpPoint(); 137 bpAllocator_.Reset(begin, end); 138 auto ret = bpAllocator_.Allocate(size); 139 return ret; 140 } 141} 142 143template <typename T> 144void FreeListAllocator<T>::FreeBumpPoint() 145{ 146 auto begin = bpAllocator_.GetTop(); 147 auto size = bpAllocator_.Available(); 148 bpAllocator_.Reset(); 149 Free(begin, size, true); 150} 151 152template <typename T> 153void FreeListAllocator<T>::FillBumpPointer() 154{ 155 if constexpr (std::is_same<T, MemDesc>::value) { 156 return; 157 } 158 size_t size = bpAllocator_.Available(); 159 if (size != 0) { 160 FreeObject::FillFreeObject(heap_, bpAllocator_.GetTop(), size); 161 } 162} 163 164template <typename T> 165void FreeListAllocator<T>::ResetBumpPointer(uintptr_t begin, uintptr_t end, uintptr_t top) 166{ 167 bpAllocator_.Reset(begin, end, top); 168} 169 170template <typename T> 171void FreeListAllocator<T>::ResetTopPointer(uintptr_t top) 172{ 173 bpAllocator_.ResetTopPointer(top); 174} 175 176// The object will be marked with poison after being put into the freelist when is_asan is true. 177template <typename T> 178void FreeListAllocator<T>::Free(uintptr_t begin, size_t size, bool isAdd) 179{ 180 ASSERT(size >= 0); 181 if (size != 0) { 182 if constexpr (!std::is_same<T, MemDesc>::value) { 183 ASSERT(heap_ != nullptr); 184 T::FillFreeObject(heap_, begin, size); 185 } 186 187 ASAN_UNPOISON_MEMORY_REGION(reinterpret_cast<void *>(begin), size); 188 freeList_->Free(begin, size, isAdd); 189#ifdef ARK_ASAN_ON 190 ASAN_POISON_MEMORY_REGION(reinterpret_cast<void *>(begin), size); 191#endif 192 } 193} 194 195template <typename T> 196uintptr_t FreeListAllocator<T>::LookupSuitableFreeObject(size_t size) 197{ 198 auto freeObject = freeList_->LookupSuitableFreeObject(size); 199 if (freeObject != nullptr) { 200 return freeObject->GetBegin(); 201 } 202 return 0; 203} 204 205template <typename T> 206void FreeListAllocator<T>::RebuildFreeList() 207{ 208 bpAllocator_.Reset(); 209 freeList_->Rebuild(); 210} 211 212template <typename T> 213inline void FreeListAllocator<T>::CollectFreeObjectSet(Region *region) 214{ 215 region->EnumerateFreeObjectSets([&](FreeObjectSet<T> *set) { 216 if (set == nullptr || set->Empty()) { 217 return; 218 } 219 freeList_->AddSet(set); 220 }); 221 freeList_->IncreaseWastedSize(region->GetWastedSize()); 222} 223 224template <typename T> 225inline bool FreeListAllocator<T>::MatchFreeObjectSet(Region *region, size_t size) 226{ 227 bool ret = false; 228 region->REnumerateFreeObjectSets([&](FreeObjectSet<T> *set) { 229 if (set == nullptr || set->Empty()) { 230 return true; 231 } 232 ret = freeList_->MatchFreeObjectInSet(set, size); 233 return false; 234 }); 235 return ret; 236} 237 238template <typename T> 239inline void FreeListAllocator<T>::DetachFreeObjectSet(Region *region) 240{ 241 region->EnumerateFreeObjectSets([&](FreeObjectSet<T> *set) { 242 if (set == nullptr || set->Empty()) { 243 return; 244 } 245 freeList_->RemoveSet(set); 246 }); 247 freeList_->DecreaseWastedSize(region->GetWastedSize()); 248} 249 250template <typename T> 251size_t FreeListAllocator<T>::GetAvailableSize() const 252{ 253 return freeList_->GetFreeObjectSize() + bpAllocator_.Available(); 254} 255 256template <typename T> 257size_t FreeListAllocator<T>::GetWastedSize() const 258{ 259 return freeList_->GetWastedSize(); 260} 261} // namespace panda::ecmascript 262#endif // ECMASCRIPT_MEM_ALLOCATOR_INL_H 263