/src/WasmEdge/lib/system/allocator.cpp
Line | Count | Source |
1 | | // SPDX-License-Identifier: Apache-2.0 |
2 | | // SPDX-FileCopyrightText: Copyright The WasmEdge Authors |
3 | | |
4 | | #include "system/allocator.h" |
5 | | |
6 | | #include "common/config.h" |
7 | | #include "common/defines.h" |
8 | | #include "common/errcode.h" |
9 | | |
10 | | #if WASMEDGE_OS_WINDOWS |
11 | | #include "system/winapi.h" |
12 | | #elif defined(HAVE_MMAP) && defined(__x86_64__) || defined(__aarch64__) || \ |
13 | | defined(__arm__) || (defined(__riscv) && __riscv_xlen == 64) || \ |
14 | | defined(__s390x__) |
15 | | #include <sys/mman.h> |
16 | | #else |
17 | | #include <cctype> |
18 | | #include <cstdlib> |
19 | | #include <cstring> |
20 | | #endif |
21 | | |
22 | | namespace WasmEdge { |
23 | | |
24 | | namespace { |
25 | | static inline constexpr const uint64_t kPageSize = UINT64_C(65536); |
26 | | |
27 | | #if WASMEDGE_OS_WINDOWS || defined(HAVE_MMAP) && defined(__x86_64__) || \ |
28 | | defined(__aarch64__) || (defined(__riscv) && __riscv_xlen == 64) || \ |
29 | | defined(__s390x__) |
30 | | // Only define these two constants on the supported platform to avoid |
31 | | // -Wunused-const-variable error when applying -Werror. |
32 | | static inline constexpr const uint64_t k4G = UINT64_C(0x100000000); |
33 | | static inline constexpr const uint64_t k12G = UINT64_C(0x300000000); |
34 | | #endif |
35 | | |
36 | | } // namespace |
37 | | |
38 | 0 | WASMEDGE_EXPORT uint8_t *Allocator::allocate(uint64_t PageCount) noexcept { |
39 | | #if WASMEDGE_OS_WINDOWS |
40 | | auto Reserved = reinterpret_cast<uint8_t *>(winapi::VirtualAlloc( |
41 | | nullptr, k12G, winapi::MEM_RESERVE_, winapi::PAGE_NOACCESS_)); |
42 | | if (Reserved == nullptr) { |
43 | | return nullptr; |
44 | | } |
45 | | if (PageCount == 0) { |
46 | | return Reserved + k4G; |
47 | | } |
48 | | auto Pointer = resize(Reserved + k4G, 0, PageCount); |
49 | | if (Pointer == nullptr) { |
50 | | return nullptr; |
51 | | } |
52 | | return Pointer; |
53 | | #elif defined(HAVE_MMAP) && defined(__x86_64__) || defined(__aarch64__) || \ |
54 | | (defined(__riscv) && __riscv_xlen == 64) || defined(__s390x__) |
55 | | auto Reserved = reinterpret_cast<uint8_t *>( |
56 | 0 | mmap(nullptr, k12G, PROT_NONE, |
57 | 0 | MAP_PRIVATE | MAP_ANONYMOUS | MAP_NORESERVE, -1, 0)); |
58 | 0 | if (Reserved == MAP_FAILED) { |
59 | 0 | return nullptr; |
60 | 0 | } |
61 | 0 | if (PageCount == 0) { |
62 | 0 | return Reserved + k4G; |
63 | 0 | } |
64 | 0 | auto Pointer = resize(Reserved + k4G, 0, PageCount); |
65 | 0 | if (Pointer == nullptr) { |
66 | 0 | return nullptr; |
67 | 0 | } |
68 | 0 | return Pointer; |
69 | | #else |
70 | | auto Result = reinterpret_cast<uint8_t *>(std::malloc(kPageSize * PageCount)); |
71 | | if (Result == nullptr) { |
72 | | return nullptr; |
73 | | } |
74 | | std::memset(Result, 0, kPageSize * PageCount); |
75 | | return Result; |
76 | | #endif |
77 | 0 | } |
78 | | |
79 | | WASMEDGE_EXPORT uint8_t *Allocator::resize(uint8_t *Pointer, |
80 | | uint64_t OldPageCount, |
81 | 0 | uint64_t NewPageCount) noexcept { |
82 | 0 | assuming(NewPageCount > OldPageCount); |
83 | | #if WASMEDGE_OS_WINDOWS |
84 | | if (winapi::VirtualAlloc(Pointer + OldPageCount * kPageSize, |
85 | | (NewPageCount - OldPageCount) * kPageSize, |
86 | | winapi::MEM_COMMIT_, |
87 | | winapi::PAGE_READWRITE_) == nullptr) { |
88 | | return nullptr; |
89 | | } |
90 | | return Pointer; |
91 | | #elif defined(HAVE_MMAP) && (defined(__x86_64__) || defined(__aarch64__) || \ |
92 | | (defined(__riscv) && __riscv_xlen == 64)) || \ |
93 | | defined(__s390x__) |
94 | 0 | if (mmap(Pointer + OldPageCount * kPageSize, |
95 | 0 | (NewPageCount - OldPageCount) * kPageSize, PROT_READ | PROT_WRITE, |
96 | 0 | MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED, -1, 0) == MAP_FAILED) { |
97 | 0 | return nullptr; |
98 | 0 | } |
99 | 0 | return Pointer; |
100 | | #else |
101 | | auto Result = reinterpret_cast<uint8_t *>( |
102 | | std::realloc(Pointer, NewPageCount * kPageSize)); |
103 | | if (Result == nullptr) { |
104 | | return nullptr; |
105 | | } |
106 | | std::memset(Result + OldPageCount * kPageSize, 0, |
107 | | (NewPageCount - OldPageCount) * kPageSize); |
108 | | return Result; |
109 | | #endif |
110 | 0 | } |
111 | | |
112 | | WASMEDGE_EXPORT uint8_t *Allocator::shrink(uint8_t *Pointer, |
113 | | uint64_t OldPageCount, |
114 | 0 | uint64_t NewPageCount) noexcept { |
115 | 0 | assuming(NewPageCount < OldPageCount); |
116 | | #if WASMEDGE_OS_WINDOWS |
117 | | if (!winapi::VirtualFree(Pointer + NewPageCount * kPageSize, |
118 | | (OldPageCount - NewPageCount) * kPageSize, |
119 | | winapi::MEM_DECOMMIT_)) { |
120 | | return nullptr; |
121 | | } |
122 | | return Pointer; |
123 | | #elif defined(HAVE_MMAP) && (defined(__x86_64__) || defined(__aarch64__) || \ |
124 | | (defined(__riscv) && __riscv_xlen == 64)) || \ |
125 | | defined(__s390x__) |
126 | 0 | if (mmap(Pointer + NewPageCount * kPageSize, |
127 | 0 | (OldPageCount - NewPageCount) * kPageSize, PROT_NONE, |
128 | 0 | MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED | MAP_NORESERVE, -1, |
129 | 0 | 0) == MAP_FAILED) { |
130 | 0 | return nullptr; |
131 | 0 | } |
132 | 0 | return Pointer; |
133 | | #else |
134 | | return reinterpret_cast<uint8_t *>( |
135 | | std::realloc(Pointer, NewPageCount == 0 ? 1 : NewPageCount * kPageSize)); |
136 | | #endif |
137 | 0 | } |
138 | | |
139 | 0 | WASMEDGE_EXPORT void Allocator::release(uint8_t *Pointer, uint64_t) noexcept { |
140 | | #if WASMEDGE_OS_WINDOWS |
141 | | winapi::VirtualFree(Pointer - k4G, 0, winapi::MEM_RELEASE_); |
142 | | #elif defined(HAVE_MMAP) && (defined(__x86_64__) || defined(__aarch64__) || \ |
143 | | (defined(__riscv) && __riscv_xlen == 64)) || \ |
144 | | defined(__s390x__) |
145 | 0 | if (Pointer == nullptr) { |
146 | 0 | return; |
147 | 0 | } |
148 | 0 | munmap(Pointer - k4G, k12G); |
149 | | #else |
150 | | return std::free(Pointer); |
151 | | #endif |
152 | 0 | } |
153 | | |
154 | 0 | uint8_t *Allocator::allocate_chunk(uint64_t Size) noexcept { |
155 | | #if WASMEDGE_OS_WINDOWS |
156 | | if (auto Pointer = winapi::VirtualAlloc(nullptr, Size, winapi::MEM_COMMIT_, |
157 | | winapi::PAGE_READWRITE_); |
158 | | unlikely(Pointer == nullptr)) { |
159 | | return nullptr; |
160 | | } else { |
161 | | return reinterpret_cast<uint8_t *>(Pointer); |
162 | | } |
163 | | #elif defined(HAVE_MMAP) |
164 | 0 | if (auto Pointer = mmap(nullptr, Size, PROT_READ | PROT_WRITE, |
165 | 0 | MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); |
166 | 0 | unlikely(Pointer == MAP_FAILED)) { |
167 | 0 | return nullptr; |
168 | 0 | } else { |
169 | 0 | return reinterpret_cast<uint8_t *>(Pointer); |
170 | 0 | } |
171 | | #else |
172 | | return std::malloc(Size); |
173 | | #endif |
174 | 0 | } |
175 | | |
176 | | void Allocator::release_chunk(uint8_t *Pointer, |
177 | 0 | uint64_t Size [[maybe_unused]]) noexcept { |
178 | | #if WASMEDGE_OS_WINDOWS |
179 | | winapi::VirtualFree(Pointer, 0, winapi::MEM_RELEASE_); |
180 | | #elif defined(HAVE_MMAP) |
181 | | munmap(Pointer, Size); |
182 | | #else |
183 | | return std::free(Pointer); |
184 | | #endif |
185 | 0 | } |
186 | | |
187 | 0 | bool Allocator::set_chunk_executable(uint8_t *Pointer, uint64_t Size) noexcept { |
188 | | #if WASMEDGE_OS_WINDOWS |
189 | | winapi::DWORD_ OldPerm; |
190 | | return winapi::VirtualProtect(Pointer, Size, winapi::PAGE_EXECUTE_READ_, |
191 | | &OldPerm) != 0; |
192 | | #elif defined(HAVE_MMAP) |
193 | 0 | return mprotect(Pointer, Size, PROT_EXEC | PROT_READ) == 0; |
194 | | #else |
195 | | return true; |
196 | | #endif |
197 | 0 | } |
198 | | |
199 | 0 | bool Allocator::set_chunk_readable(uint8_t *Pointer, uint64_t Size) noexcept { |
200 | | #if WASMEDGE_OS_WINDOWS |
201 | | winapi::DWORD_ OldPerm; |
202 | | return winapi::VirtualProtect(Pointer, Size, winapi::PAGE_READONLY_, |
203 | | &OldPerm) != 0; |
204 | | #elif defined(HAVE_MMAP) |
205 | 0 | return mprotect(Pointer, Size, PROT_READ) == 0; |
206 | | #else |
207 | | return true; |
208 | | #endif |
209 | 0 | } |
210 | | |
211 | | bool Allocator::set_chunk_readable_writable(uint8_t *Pointer, |
212 | 0 | uint64_t Size) noexcept { |
213 | | #if WASMEDGE_OS_WINDOWS |
214 | | winapi::DWORD_ OldPerm; |
215 | | return winapi::VirtualProtect(Pointer, Size, winapi::PAGE_READWRITE_, |
216 | | &OldPerm) != 0; |
217 | | #elif defined(HAVE_MMAP) |
218 | 0 | return mprotect(Pointer, Size, PROT_READ | PROT_WRITE) == 0; |
219 | | #else |
220 | | return true; |
221 | | #endif |
222 | 0 | } |
223 | | |
224 | | } // namespace WasmEdge |