• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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