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_NATIVE_AREA_ALLOCATOR_H 17 #define ECMASCRIPT_MEM_NATIVE_AREA_ALLOCATOR_H 18 19 #include <atomic> 20 #include <cstddef> 21 22 #include "ecmascript/common.h" 23 #include "ecmascript/log_wrapper.h" 24 #include "ecmascript/mem/mem.h" 25 #include "ecmascript/mem/area.h" 26 27 namespace panda::ecmascript { 28 enum class NativeFlag : uint32_t { 29 NO_DIV, 30 ARRAY_BUFFER, 31 REGEXP_BTYECODE, 32 CHUNK_MEM, 33 }; 34 35 class PUBLIC_API NativeAreaAllocator { 36 public: 37 NativeAreaAllocator() = default; ~NativeAreaAllocator()38 virtual ~NativeAreaAllocator() 39 { 40 if (cachedArea_ != nullptr) { 41 FreeArea(cachedArea_); 42 cachedArea_ = nullptr; 43 } 44 } 45 46 Area *AllocateArea(size_t capacity); 47 void FreeArea(Area *area); 48 void Free(void *mem, size_t size); 49 void *AllocateBuffer(size_t size); 50 void FreeBuffer(void *mem); 51 void *NativeAreaPageMap(size_t size); 52 void NativeAreaPageUnmap(void *mem, size_t size); 53 54 static void FreeBufferFunc(void *env, void* buffer, void* data); 55 56 template<class T> FreeObjectFunc(void * env,void * buffer,void * data)57 static void FreeObjectFunc([[maybe_unused]] void *env, void* buffer, void* data) 58 { 59 if (buffer == nullptr || data == nullptr) { 60 return; 61 } 62 NativeAreaAllocator* allocator = reinterpret_cast<NativeAreaAllocator*>(data); 63 allocator->Delete<T>(static_cast<T *>(buffer)); 64 } 65 66 // implemented by AllocateBuffer 67 template<typename T, typename... Args> New(Args &&...args)68 std::enable_if_t<!std::is_array_v<T>, T *> New(Args &&... args) 69 { 70 void *p = AllocateBuffer(sizeof(T)); 71 if (UNLIKELY(p == nullptr)) { 72 return nullptr; 73 } 74 new (p) T(std::forward<Args>(args)...); // NOLINT(bugprone-throw-keyword-missing) 75 return reinterpret_cast<T *>(p); 76 } 77 78 template<class T> Delete(T * ptr)79 void Delete(T *ptr) 80 { 81 if (ptr == nullptr) { 82 return; 83 } 84 // NOLINTNEXTLINE(readability-braces-around-statements,bugprone-suspicious-semicolon) 85 if constexpr (std::is_class_v<T>) { 86 ptr->~T(); 87 } 88 FreeBuffer(ptr); 89 } 90 IncreaseNativeMemoryUsage(size_t bytes)91 void IncreaseNativeMemoryUsage(size_t bytes) 92 { 93 size_t current = nativeMemoryUsage_.fetch_add(bytes, std::memory_order_relaxed) + bytes; 94 size_t max = maxNativeMemoryUsage_.load(std::memory_order_relaxed); 95 while (current > max && !maxNativeMemoryUsage_.compare_exchange_weak(max, current, std::memory_order_relaxed)) { 96 } 97 } 98 DecreaseNativeMemoryUsage(size_t bytes)99 void DecreaseNativeMemoryUsage(size_t bytes) 100 { 101 nativeMemoryUsage_.fetch_sub(bytes, std::memory_order_relaxed); 102 } 103 GetNativeMemoryUsage()104 size_t GetNativeMemoryUsage() const 105 { 106 return nativeMemoryUsage_.load(std::memory_order_relaxed); 107 } 108 GetMaxNativeMemoryUsage()109 size_t GetMaxNativeMemoryUsage() const 110 { 111 return maxNativeMemoryUsage_.load(std::memory_order_relaxed); 112 } 113 GetArrayBufferNativeSize()114 size_t GetArrayBufferNativeSize() const 115 { 116 return arrayBufferNativeSize_; 117 } 118 GetRegExpNativeSize()119 size_t GetRegExpNativeSize() const 120 { 121 return regExpNativeSize_; 122 } 123 GetChunkNativeSize()124 size_t GetChunkNativeSize() const 125 { 126 return chunkNativeSize_; 127 } 128 IncreaseNativeSizeStats(size_t size,NativeFlag flag)129 inline void IncreaseNativeSizeStats(size_t size, NativeFlag flag) 130 { 131 if (size == 0) { 132 return; 133 } 134 switch (flag) { 135 case NativeFlag::ARRAY_BUFFER: 136 arrayBufferNativeSize_ += size; 137 break; 138 case NativeFlag::REGEXP_BTYECODE: 139 regExpNativeSize_ += size; 140 break; 141 case NativeFlag::CHUNK_MEM: 142 chunkNativeSize_ += size; 143 break; 144 default: 145 break; 146 } 147 } 148 DecreaseNativeSizeStats(size_t size,NativeFlag flag)149 inline void DecreaseNativeSizeStats(size_t size, NativeFlag flag) 150 { 151 if (size == 0) { 152 return; 153 } 154 switch (flag) { 155 case NativeFlag::ARRAY_BUFFER: 156 arrayBufferNativeSize_ -= size; 157 break; 158 case NativeFlag::REGEXP_BTYECODE: 159 regExpNativeSize_ -= size; 160 break; 161 case NativeFlag::CHUNK_MEM: 162 chunkNativeSize_ -= size; 163 break; 164 default: 165 break; 166 } 167 } 168 ModifyNativeSizeStats(size_t preSize,size_t nextSize,NativeFlag flag)169 void ModifyNativeSizeStats(size_t preSize, size_t nextSize, NativeFlag flag) { 170 if (flag == NativeFlag::NO_DIV) { 171 return; 172 } 173 DecreaseNativeSizeStats(preSize, flag); 174 IncreaseNativeSizeStats(nextSize, flag); 175 } 176 Allocate(size_t size)177 void *Allocate(size_t size) 178 { 179 if (size == 0) { 180 LOG_ECMA_MEM(FATAL) << "size must have a size bigger than 0"; 181 UNREACHABLE(); 182 } 183 // NOLINTNEXTLINE(cppcoreguidelines-no-malloc) 184 void *ptr = malloc(size); 185 if (ptr == nullptr) { 186 LOG_ECMA_MEM(FATAL) << "malloc failed"; 187 UNREACHABLE(); 188 } 189 IncreaseNativeMemoryUsage(size); 190 return ptr; 191 } 192 AllocateSpace(size_t capacity)193 static inline Area *AllocateSpace(size_t capacity) 194 { 195 size_t headerSize = sizeof(Area); 196 if (capacity < headerSize) { 197 LOG_ECMA_MEM(FATAL) << "capacity must have a size not less than sizeof Area."; 198 UNREACHABLE(); 199 } 200 // NOLINTNEXTLINE(cppcoreguidelines-no-malloc) 201 void *mem = malloc(capacity); 202 if (mem == nullptr) { 203 LOG_ECMA_MEM(FATAL) << "malloc failed"; 204 UNREACHABLE(); 205 } 206 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) 207 uintptr_t begin = reinterpret_cast<uintptr_t>(mem) + headerSize; 208 capacity -= headerSize; 209 return new (mem) Area(begin, capacity); 210 } 211 FreeSpace(Area * area)212 static inline void FreeSpace(Area *area) 213 { 214 if (area == nullptr) { 215 return; 216 } 217 // NOLINTNEXTLINE(cppcoreguidelines-no-malloc) 218 free(reinterpret_cast<std::byte *>(area)); 219 } 220 221 private: 222 NO_COPY_SEMANTIC(NativeAreaAllocator); 223 NO_MOVE_SEMANTIC(NativeAreaAllocator); 224 225 Area *cachedArea_ {nullptr}; 226 std::atomic<size_t> nativeMemoryUsage_ {0}; 227 std::atomic<size_t> maxNativeMemoryUsage_ {0}; 228 // native area size stats 229 size_t arrayBufferNativeSize_ {0}; 230 size_t regExpNativeSize_ {0}; 231 size_t chunkNativeSize_ {0}; 232 }; 233 } // namespace panda::ecmascript 234 235 #endif // ECMASCRIPT_MEM_NATIVE_AREA_ALLOCATOR_H 236