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