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#include "ecmascript/mem/native_area_allocator.h"
17
18#include "ecmascript/platform/os.h"
19
20#if ECMASCRIPT_ENABLE_ZAP_MEM
21#include "securec.h"
22#endif
23namespace panda::ecmascript {
24Area *NativeAreaAllocator::AllocateArea(size_t capacity)
25{
26    size_t headerSize = sizeof(Area);
27    if (capacity < headerSize) { // LOCV_EXCL_BR_LINE
28        LOG_ECMA_MEM(FATAL) << "capacity must have a size not less than sizeof Area.";
29        UNREACHABLE();
30    }
31    if (cachedArea_ != nullptr && capacity <= cachedArea_->GetSize()) {
32        auto result = cachedArea_;
33        cachedArea_ = nullptr;
34        return result;
35    }
36    // NOLINTNEXTLINE(cppcoreguidelines-no-malloc)
37    void *mem = malloc(capacity);
38    if (mem == nullptr) { // LOCV_EXCL_BR_LINE
39        LOG_ECMA_MEM(FATAL) << "malloc failed, current alloc size = " << capacity
40                            << ", total allocated size = " << nativeMemoryUsage_.load(std::memory_order_relaxed);
41        UNREACHABLE();
42    }
43#if ECMASCRIPT_ENABLE_ZAP_MEM
44    if (memset_s(mem, capacity, 0, capacity) != EOK) { // LOCV_EXCL_BR_LINE
45        LOG_FULL(FATAL) << "memset_s failed";
46        UNREACHABLE();
47    }
48#endif
49    IncreaseNativeMemoryUsage(capacity);
50    // NOLINTNEXTLINE(cppcoreguidelines-pro-bounds-pointer-arithmetic)
51    uintptr_t begin = reinterpret_cast<uintptr_t>(mem) + headerSize;
52    capacity -= headerSize;
53    return new (mem) Area(begin, capacity);
54}
55
56void NativeAreaAllocator::FreeArea(Area *area)
57{
58    if (area == nullptr) {
59        return;
60    }
61    if (cachedArea_ == nullptr && area->GetSize() <= MAX_CACHED_CHUNK_AREA_SIZE) {
62        cachedArea_ = area;
63        return;
64    }
65    auto size = area->GetSize() + sizeof(Area);
66    DecreaseNativeMemoryUsage(size);
67#if ECMASCRIPT_ENABLE_ZAP_MEM
68    if (memset_s(area, size, INVALID_VALUE, size) != EOK) { // LOCV_EXCL_BR_LINE
69        LOG_FULL(FATAL) << "memset_s failed";
70        UNREACHABLE();
71    }
72#endif
73    // NOLINTNEXTLINE(cppcoreguidelines-no-malloc)
74    free(reinterpret_cast<std::byte *>(area));
75}
76
77void NativeAreaAllocator::Free(void *mem, size_t size)
78{
79    if (mem == nullptr) {
80        return;
81    }
82    DecreaseNativeMemoryUsage(size);
83#if ECMASCRIPT_ENABLE_ZAP_MEM
84    if (memset_s(mem, size, INVALID_VALUE, size) != EOK) { // LOCV_EXCL_BR_LINE
85        LOG_FULL(FATAL) << "memset_s failed";
86        UNREACHABLE();
87    }
88#endif
89    // NOLINTNEXTLINE(cppcoreguidelines-no-malloc)
90    free(mem);
91}
92
93void *NativeAreaAllocator::AllocateBuffer(size_t size)
94{
95    if (size == 0) { // LOCV_EXCL_BR_LINE
96        LOG_ECMA_MEM(FATAL) << "size must have a size bigger than 0";
97        UNREACHABLE();
98    }
99    // NOLINTNEXTLINE(cppcoreguidelines-no-malloc)
100    void *ptr = malloc(size);
101    if (ptr == nullptr) { // LOCV_EXCL_BR_LINE
102        LOG_ECMA_MEM(FATAL) << "malloc failed, current alloc size = " << size
103                            << ", total allocated size = " << nativeMemoryUsage_.load(std::memory_order_relaxed);
104        UNREACHABLE();
105    }
106#if ECMASCRIPT_ENABLE_ZAP_MEM
107    if (memset_s(ptr, size, INVALID_VALUE, size) != EOK) { // LOCV_EXCL_BR_LINE
108        LOG_FULL(FATAL) << "memset_s failed";
109        UNREACHABLE();
110    }
111#endif
112    IncreaseNativeMemoryUsage(MallocUsableSize(ptr));
113    return ptr;
114}
115
116void NativeAreaAllocator::FreeBuffer(void *mem)
117{
118    if (mem == nullptr) {
119        return;
120    }
121    size_t size = MallocUsableSize(mem);
122    DecreaseNativeMemoryUsage(size);
123
124#if ECMASCRIPT_ENABLE_ZAP_MEM
125    if (memset_s(mem, size, INVALID_VALUE, size) != EOK) { // LOCV_EXCL_BR_LINE
126        LOG_FULL(FATAL) << "memset_s failed";
127        UNREACHABLE();
128    }
129#endif
130    // NOLINTNEXTLINE(cppcoreguidelines-no-malloc)
131    free(mem);
132}
133
134void NativeAreaAllocator::FreeBufferFunc([[maybe_unused]] void *env, void *buffer, void *data)
135{
136    if (buffer == nullptr || data == nullptr) {
137        return;
138    }
139    NativeAreaAllocator* allocator = reinterpret_cast<NativeAreaAllocator*>(data);
140    allocator->FreeBuffer(buffer);
141}
142}  // namespace panda::ecmascript
143