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