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 class PUBLIC_API NativeAreaAllocator { 29 public: 30 NativeAreaAllocator() = default; ~NativeAreaAllocator()31 virtual ~NativeAreaAllocator() 32 { 33 if (cachedArea_ != nullptr) { 34 FreeArea(cachedArea_); 35 cachedArea_ = nullptr; 36 } 37 } 38 39 Area *AllocateArea(size_t capacity); 40 void FreeArea(Area *area); 41 void Free(void *mem, size_t size); 42 void *AllocateBuffer(size_t size); 43 void FreeBuffer(void *mem); 44 45 static void FreeBufferFunc(void* buffer, void* data); 46 47 template<class T> FreeObjectFunc(void * buffer,void * data)48 static void FreeObjectFunc(void* buffer, void* data) 49 { 50 if (buffer == nullptr || data == nullptr) { 51 return; 52 } 53 NativeAreaAllocator* allocator = reinterpret_cast<NativeAreaAllocator*>(data); 54 allocator->Delete<T>(static_cast<T *>(buffer)); 55 } 56 57 // implemented by AllocateBuffer 58 template<typename T, typename... Args> New(Args &&...args)59 std::enable_if_t<!std::is_array_v<T>, T *> New(Args &&... args) 60 { 61 void *p = AllocateBuffer(sizeof(T)); 62 if (UNLIKELY(p == nullptr)) { 63 return nullptr; 64 } 65 new (p) T(std::forward<Args>(args)...); // NOLINT(bugprone-throw-keyword-missing) 66 return reinterpret_cast<T *>(p); 67 } 68 69 template<class T> Delete(T * ptr)70 void Delete(T *ptr) 71 { 72 if (ptr == nullptr) { 73 return; 74 } 75 // NOLINTNEXTLINE(readability-braces-around-statements,bugprone-suspicious-semicolon) 76 if constexpr (std::is_class_v<T>) { 77 ptr->~T(); 78 } 79 FreeBuffer(ptr); 80 } 81 IncreaseNativeMemoryUsage(size_t bytes)82 void IncreaseNativeMemoryUsage(size_t bytes) 83 { 84 size_t current = nativeMemoryUsage_.fetch_add(bytes, std::memory_order_relaxed) + bytes; 85 size_t max = maxNativeMemoryUsage_.load(std::memory_order_relaxed); 86 while (current > max && !maxNativeMemoryUsage_.compare_exchange_weak(max, current, std::memory_order_relaxed)) { 87 } 88 } 89 DecreaseNativeMemoryUsage(size_t bytes)90 void DecreaseNativeMemoryUsage(size_t bytes) 91 { 92 nativeMemoryUsage_.fetch_sub(bytes, std::memory_order_relaxed); 93 } 94 GetNativeMemoryUsage()95 size_t GetNativeMemoryUsage() const 96 { 97 return nativeMemoryUsage_.load(std::memory_order_relaxed); 98 } 99 GetMaxNativeMemoryUsage()100 size_t GetMaxNativeMemoryUsage() const 101 { 102 return maxNativeMemoryUsage_.load(std::memory_order_relaxed); 103 } 104 Allocate(size_t size)105 void *Allocate(size_t size) 106 { 107 if (size == 0) { 108 LOG_ECMA_MEM(FATAL) << "size must have a size bigger than 0"; 109 UNREACHABLE(); 110 } 111 // NOLINTNEXTLINE(cppcoreguidelines-no-malloc) 112 void *ptr = malloc(size); 113 if (ptr == nullptr) { 114 LOG_ECMA_MEM(FATAL) << "malloc failed"; 115 UNREACHABLE(); 116 } 117 IncreaseNativeMemoryUsage(size); 118 return ptr; 119 } 120 AllocateSpace(size_t capacity)121 static inline Area *AllocateSpace(size_t capacity) 122 { 123 size_t headerSize = sizeof(Area); 124 if (capacity < headerSize) { 125 LOG_ECMA_MEM(FATAL) << "capacity must have a size not less than sizeof Area."; 126 UNREACHABLE(); 127 } 128 // NOLINTNEXTLINE(cppcoreguidelines-no-malloc) 129 void *mem = malloc(capacity); 130 if (mem == nullptr) { 131 LOG_ECMA_MEM(FATAL) << "malloc failed"; 132 UNREACHABLE(); 133 } 134 // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic) 135 uintptr_t begin = reinterpret_cast<uintptr_t>(mem) + headerSize; 136 capacity -= headerSize; 137 return new (mem) Area(begin, capacity); 138 } 139 FreeSpace(Area * area)140 static inline void FreeSpace(Area *area) 141 { 142 if (area == nullptr) { 143 return; 144 } 145 // NOLINTNEXTLINE(cppcoreguidelines-no-malloc) 146 free(reinterpret_cast<std::byte *>(area)); 147 } 148 149 private: 150 NO_COPY_SEMANTIC(NativeAreaAllocator); 151 NO_MOVE_SEMANTIC(NativeAreaAllocator); 152 153 Area *cachedArea_ {nullptr}; 154 std::atomic<size_t> nativeMemoryUsage_ {0}; 155 std::atomic<size_t> maxNativeMemoryUsage_ {0}; 156 }; 157 } // namespace panda::ecmascript 158 159 #endif // ECMASCRIPT_MEM_NATIVE_AREA_ALLOCATOR_H 160