1 /* 2 * Copyright (c) 2022 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_MEM_MAP_ALLOCATOR_H 17 #define ECMASCRIPT_MEM_MEM_MAP_ALLOCATOR_H 18 19 #include <deque> 20 #include <map> 21 22 #include "ecmascript/platform/map.h" 23 #include "ecmascript/mem/mem.h" 24 #include "ecmascript/mem/mem_common.h" 25 #include "ecmascript/log_wrapper.h" 26 #include "libpandabase/os/mutex.h" 27 28 namespace panda::ecmascript { 29 // Regular region with length of DEFAULT_REGION_SIZE(256kb) 30 class MemMapPool { 31 public: 32 explicit MemMapPool() = default; 33 ~MemMapPool() = default; 34 Finalize()35 void Finalize() 36 { 37 os::memory::LockHolder lock(lock_); 38 for (auto &it : memMapVector_) { 39 PageUnmap(it); 40 } 41 memMapVector_.clear(); 42 memMapCache_.clear(); 43 } 44 45 NO_COPY_SEMANTIC(MemMapPool); 46 NO_MOVE_SEMANTIC(MemMapPool); 47 GetMemFromCache(size_t size)48 MemMap GetMemFromCache([[maybe_unused]]size_t size) 49 { 50 ASSERT(size == REGULAR_MMAP_SIZE); 51 os::memory::LockHolder lock(lock_); 52 if (!memMapCache_.empty()) { 53 MemMap mem = memMapCache_.front(); 54 memMapCache_.pop_front(); 55 return mem; 56 } 57 return MemMap(); 58 } 59 AddMemToCache(void * mem,size_t size)60 void AddMemToCache(void *mem, size_t size) 61 { 62 ASSERT(size == REGULAR_MMAP_SIZE); 63 os::memory::LockHolder lock(lock_); 64 memMapCache_.emplace_back(mem, size); 65 } 66 SplitMemFromCache(MemMap memMap)67 MemMap SplitMemFromCache(MemMap memMap) 68 { 69 os::memory::LockHolder lock(lock_); 70 auto remainderMem = reinterpret_cast<uintptr_t>(memMap.GetMem()) + REGULAR_MMAP_SIZE; 71 size_t remainderSize = AlignDown(memMap.GetSize() - REGULAR_MMAP_SIZE, REGULAR_MMAP_SIZE); 72 size_t count = remainderSize / REGULAR_MMAP_SIZE; 73 while (count-- > 0) { 74 memMapCache_.emplace_back(reinterpret_cast<void *>(remainderMem), REGULAR_MMAP_SIZE); 75 remainderMem = remainderMem + REGULAR_MMAP_SIZE; 76 } 77 return MemMap(memMap.GetMem(), REGULAR_MMAP_SIZE); 78 } 79 InsertMemMap(MemMap memMap)80 void InsertMemMap(MemMap memMap) 81 { 82 os::memory::LockHolder lock(lock_); 83 memMapVector_.emplace_back(memMap); 84 } 85 86 private: 87 static constexpr size_t REGULAR_MMAP_SIZE = 256_KB; 88 os::memory::Mutex lock_; 89 std::deque<MemMap> memMapCache_; 90 std::vector<MemMap> memMapVector_; 91 }; 92 93 // Non regular region with length of DEFAULT_REGION_SIZE(256kb) multiple 94 class MemMapFreeList { 95 public: 96 MemMapFreeList() = default; 97 ~MemMapFreeList() = default; 98 Initialize(MemMap memMap)99 void Initialize(MemMap memMap) 100 { 101 memMap_ = memMap; 102 freeList_.emplace(memMap.GetSize(), memMap); 103 capacity_ = memMap.GetSize(); 104 } 105 Finalize()106 void Finalize() 107 { 108 PageUnmap(memMap_); 109 freeList_.clear(); 110 } 111 112 NO_COPY_SEMANTIC(MemMapFreeList); 113 NO_MOVE_SEMANTIC(MemMapFreeList); 114 GetMemFromList(size_t size)115 MemMap GetMemFromList(size_t size) 116 { 117 if (freeListPoolSize_ + size > capacity_) { 118 LOG_GC(ERROR) << "Freelist pool oom: overflow(" << freeListPoolSize_ << ")"; 119 return MemMap(); 120 } 121 os::memory::LockHolder lock(lock_); 122 auto iterate = freeList_.lower_bound(size); 123 if (iterate == freeList_.end()) { 124 LOG_GC(ERROR) << "Freelist pool oom: memory fragment(" << freeListPoolSize_ << ")"; 125 return MemMap(); 126 } 127 MemMap memMap = iterate->second; 128 size_t remainderSize = memMap.GetSize() - size; 129 freeList_.erase(iterate); 130 if (remainderSize >= DEFAULT_REGION_SIZE) { 131 auto next = reinterpret_cast<void *>(reinterpret_cast<uintptr_t>(memMap.GetMem()) + size); 132 freeList_.emplace(remainderSize, MemMap(next, remainderSize)); 133 } 134 freeListPoolSize_ += size; 135 return MemMap(memMap.GetMem(), size); 136 } 137 AddMemToList(MemMap memMap)138 void AddMemToList(MemMap memMap) 139 { 140 os::memory::LockHolder lock(lock_); 141 freeListPoolSize_ -= memMap.GetSize(); 142 freeList_.emplace(memMap.GetSize(), memMap); 143 } 144 145 private: 146 os::memory::Mutex lock_; 147 MemMap memMap_; 148 std::multimap<size_t, MemMap> freeList_; 149 std::atomic_size_t freeListPoolSize_ {0}; 150 size_t capacity_ {0}; 151 }; 152 153 class MemMapAllocator { 154 public: 155 MemMapAllocator() = default; 156 ~MemMapAllocator() = default; 157 158 NO_COPY_SEMANTIC(MemMapAllocator); 159 NO_MOVE_SEMANTIC(MemMapAllocator); 160 Initialize(size_t alignment)161 void Initialize(size_t alignment) 162 { 163 AdapterSuitablePoolCapacity(); 164 memMapTotalSize_ = 0; 165 size_t hugeObjectCapacity = std::min(capacity_ / 2, MAX_HUGE_OBJECT_CAPACITY); 166 MemMap memMap = PageMap(hugeObjectCapacity, PAGE_PROT_NONE, alignment); 167 PageRelease(memMap.GetMem(), memMap.GetSize()); 168 memMapFreeList_.Initialize(memMap); 169 } 170 Finalize()171 void Finalize() 172 { 173 memMapTotalSize_ = 0; 174 capacity_ = 0; 175 memMapFreeList_.Finalize(); 176 memMapPool_.Finalize(); 177 } 178 GetCapacity()179 size_t GetCapacity() 180 { 181 return capacity_; 182 } 183 IncreaseAndCheckReserved(size_t size)184 void IncreaseAndCheckReserved(size_t size) 185 { 186 if (reserved_ + size > capacity_) { 187 LOG_GC(ERROR) << "pool is empty, reserved = " << reserved_ << ", capacity_ = " 188 << capacity_ << ", size = " << size; 189 } 190 reserved_ += size; 191 LOG_GC(DEBUG) << "Ark IncreaseAndCheckReserved reserved = " << reserved_ << ", capacity_ = " << capacity_; 192 } 193 DecreaseReserved(size_t size)194 void DecreaseReserved(size_t size) 195 { 196 reserved_ -= size; 197 LOG_GC(DEBUG) << "Ark DecreaseReserved reserved = " << reserved_ << ", capacity_ = " << capacity_; 198 } 199 200 static MemMapAllocator *GetInstance(); 201 202 MemMap Allocate(size_t size, size_t alignment, bool regular, int prot); 203 204 void Free(void *mem, size_t size, bool isRegular); 205 206 private: 207 static constexpr size_t REGULAR_REGION_MMAP_SIZE = 4_MB; 208 209 void AdapterSuitablePoolCapacity(); 210 211 MemMapPool memMapPool_; 212 MemMapFreeList memMapFreeList_; 213 std::atomic_size_t memMapTotalSize_ {0}; 214 size_t capacity_ {0}; 215 size_t reserved_ {0}; 216 }; 217 } // namespace panda::ecmascript 218 #endif // ECMASCRIPT_MEM_MEM_MAP_ALLOCATOR_H 219