Line data Source code
1 : /* +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2 : Copyright (c) 2008-2017, Petr Kobalicek
3 :
4 : This software is provided 'as-is', without any express or implied
5 : warranty. In no event will the authors be held liable for any damages
6 : arising from the use of this software.
7 :
8 : Permission is granted to anyone to use this software for any purpose,
9 : including commercial applications, and to alter it and redistribute it
10 : freely, subject to the following restrictions:
11 :
12 : 1. The origin of this software must not be misrepresented; you must not
13 : claim that you wrote the original software. If you use this software
14 : in a product, an acknowledgment in the product documentation would be
15 : appreciated but is not required.
16 : 2. Altered source versions must be plainly marked as such, and must not be
17 : misrepresented as being the original software.
18 : 3. This notice may not be removed or altered from any source distribution.
19 : +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */
20 : #ifdef __PLUMED_HAS_ASMJIT
21 : #pragma GCC diagnostic push
22 : #pragma GCC diagnostic ignored "-Wpedantic"
23 : // [AsmJit]
24 : // Complete x86/x64 JIT and Remote Assembler for C++.
25 : //
26 : // [License]
27 : // Zlib - See LICENSE.md file in the package.
28 :
29 : // [Export]
30 : #define ASMJIT_EXPORTS
31 :
32 : // [Dependencies]
33 : #include "./osutils.h"
34 : #include "./utils.h"
35 :
36 : #if ASMJIT_OS_POSIX
37 : # include <sys/types.h>
38 : # include <sys/mman.h>
39 : # include <time.h>
40 : # include <unistd.h>
41 : #endif // ASMJIT_OS_POSIX
42 :
43 : #if ASMJIT_OS_MAC
44 : # include <mach/mach_time.h>
45 : #endif // ASMJIT_OS_MAC
46 :
47 : #if ASMJIT_OS_WINDOWS
48 : # if defined(_MSC_VER) && _MSC_VER >= 1400
49 : # include <intrin.h>
50 : # else
51 : # define _InterlockedCompareExchange InterlockedCompareExchange
52 : # endif // _MSC_VER
53 : #endif // ASMJIT_OS_WINDOWS
54 :
55 : // [Api-Begin]
56 : #include "./asmjit_apibegin.h"
57 :
58 : namespace PLMD {
59 : namespace asmjit {
60 :
61 : // ============================================================================
62 : // [asmjit::OSUtils - Virtual Memory]
63 : // ============================================================================
64 :
65 : // Windows specific implementation using `VirtualAllocEx` and `VirtualFree`.
66 : #if ASMJIT_OS_WINDOWS
67 : static ASMJIT_NOINLINE const VMemInfo& OSUtils_GetVMemInfo() noexcept {
68 : static VMemInfo vmi;
69 :
70 : if (ASMJIT_UNLIKELY(!vmi.hCurrentProcess)) {
71 : SYSTEM_INFO info;
72 : ::GetSystemInfo(&info);
73 :
74 : vmi.pageSize = Utils::alignToPowerOf2<uint32_t>(info.dwPageSize);
75 : vmi.pageGranularity = info.dwAllocationGranularity;
76 : vmi.hCurrentProcess = ::GetCurrentProcess();
77 : }
78 :
79 : return vmi;
80 : };
81 :
82 : VMemInfo OSUtils::getVirtualMemoryInfo() noexcept { return OSUtils_GetVMemInfo(); }
83 :
84 : void* OSUtils::allocVirtualMemory(size_t size, size_t* allocated, uint32_t flags) noexcept {
85 : return allocProcessMemory(static_cast<HANDLE>(0), size, allocated, flags);
86 : }
87 :
88 : Error OSUtils::releaseVirtualMemory(void* p, size_t size) noexcept {
89 : return releaseProcessMemory(static_cast<HANDLE>(0), p, size);
90 : }
91 :
92 : void* OSUtils::allocProcessMemory(HANDLE hProcess, size_t size, size_t* allocated, uint32_t flags) noexcept {
93 : if (size == 0)
94 : return nullptr;
95 :
96 : const VMemInfo& vmi = OSUtils_GetVMemInfo();
97 : if (!hProcess) hProcess = vmi.hCurrentProcess;
98 :
99 : // VirtualAllocEx rounds the allocated size to a page size automatically,
100 : // but we need the `alignedSize` so we can store the real allocated size
101 : // into `allocated` output.
102 : size_t alignedSize = Utils::alignTo(size, vmi.pageSize);
103 :
104 : // Windows XP SP2 / Vista+ allow data-execution-prevention (DEP).
105 : DWORD protectFlags = 0;
106 :
107 : if (flags & kVMExecutable)
108 : protectFlags |= (flags & kVMWritable) ? PAGE_EXECUTE_READWRITE : PAGE_EXECUTE_READ;
109 : else
110 : protectFlags |= (flags & kVMWritable) ? PAGE_READWRITE : PAGE_READONLY;
111 :
112 : LPVOID mBase = ::VirtualAllocEx(hProcess, nullptr, alignedSize, MEM_COMMIT | MEM_RESERVE, protectFlags);
113 : if (ASMJIT_UNLIKELY(!mBase)) return nullptr;
114 :
115 : ASMJIT_ASSERT(Utils::isAligned<size_t>(reinterpret_cast<size_t>(mBase), vmi.pageSize));
116 : if (allocated) *allocated = alignedSize;
117 : return mBase;
118 : }
119 :
120 : Error OSUtils::releaseProcessMemory(HANDLE hProcess, void* p, size_t size) noexcept {
121 : const VMemInfo& vmi = OSUtils_GetVMemInfo();
122 : if (!hProcess) hProcess = vmi.hCurrentProcess;
123 :
124 : if (ASMJIT_UNLIKELY(!::VirtualFreeEx(hProcess, p, 0, MEM_RELEASE)))
125 : return DebugUtils::errored(kErrorInvalidState);
126 :
127 : return kErrorOk;
128 : }
129 : #endif // ASMJIT_OS_WINDOWS
130 :
131 : // Posix specific implementation using `mmap()` and `munmap()`.
132 : #if ASMJIT_OS_POSIX
133 :
134 : // Mac uses MAP_ANON instead of MAP_ANONYMOUS.
135 : #if !defined(MAP_ANONYMOUS)
136 : # define MAP_ANONYMOUS MAP_ANON
137 : #endif // MAP_ANONYMOUS
138 :
139 64252 : static const VMemInfo& OSUtils_GetVMemInfo() noexcept {
140 : static VMemInfo vmi;
141 64252 : if (ASMJIT_UNLIKELY(!vmi.pageSize)) {
142 260 : size_t pageSize = ::getpagesize();
143 260 : vmi.pageSize = pageSize;
144 520 : vmi.pageGranularity = std::max<size_t>(pageSize, 65536);
145 : }
146 64252 : return vmi;
147 : };
148 :
149 32141 : VMemInfo OSUtils::getVirtualMemoryInfo() noexcept { return OSUtils_GetVMemInfo(); }
150 :
151 32111 : void* OSUtils::allocVirtualMemory(size_t size, size_t* allocated, uint32_t flags) noexcept {
152 32111 : const VMemInfo& vmi = OSUtils_GetVMemInfo();
153 :
154 32111 : size_t alignedSize = Utils::alignTo<size_t>(size, vmi.pageSize);
155 : int protection = PROT_READ;
156 :
157 32111 : if (flags & kVMWritable ) protection |= PROT_WRITE;
158 32111 : if (flags & kVMExecutable) protection |= PROT_EXEC;
159 :
160 32111 : void* mbase = ::mmap(nullptr, alignedSize, protection, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
161 32111 : if (ASMJIT_UNLIKELY(mbase == MAP_FAILED)) return nullptr;
162 :
163 32111 : if (allocated) *allocated = alignedSize;
164 : return mbase;
165 : }
166 :
167 32111 : Error OSUtils::releaseVirtualMemory(void* p, size_t size) noexcept {
168 32111 : if (ASMJIT_UNLIKELY(::munmap(p, size) != 0))
169 : return DebugUtils::errored(kErrorInvalidState);
170 :
171 32111 : return kErrorOk;
172 : }
173 : #endif // ASMJIT_OS_POSIX
174 :
175 : // ============================================================================
176 : // [asmjit::OSUtils - GetTickCount]
177 : // ============================================================================
178 :
179 : #if ASMJIT_OS_WINDOWS
180 : static ASMJIT_INLINE uint32_t OSUtils_calcHiRes(const LARGE_INTEGER& now, double freq) noexcept {
181 : return static_cast<uint32_t>(
182 : (int64_t)(double(now.QuadPart) / freq) & 0xFFFFFFFF);
183 : }
184 :
185 : uint32_t OSUtils::getTickCount() noexcept {
186 : static volatile uint32_t _hiResTicks;
187 : static volatile double _hiResFreq;
188 :
189 : do {
190 : uint32_t hiResOk = _hiResTicks;
191 : LARGE_INTEGER qpf, now;
192 :
193 : // If for whatever reason this fails, bail to `GetTickCount()`.
194 : if (!::QueryPerformanceCounter(&now)) break;
195 :
196 : // Expected - if we ran through this at least once `hiResTicks` will be
197 : // either 1 or 0xFFFFFFFF. If it's '1' then the Hi-Res counter is available
198 : // and `QueryPerformanceCounter()` can be used.
199 : if (hiResOk == 1) return OSUtils_calcHiRes(now, _hiResFreq);
200 :
201 : // Hi-Res counter is not available, bail to `GetTickCount()`.
202 : if (hiResOk != 0) break;
203 :
204 : // Detect availability of Hi-Res counter, if not available, bail to `GetTickCount()`.
205 : if (!::QueryPerformanceFrequency(&qpf)) {
206 : _InterlockedCompareExchange((LONG*)&_hiResTicks, 0xFFFFFFFF, 0);
207 : break;
208 : }
209 :
210 : double freq = double(qpf.QuadPart) / 1000.0;
211 : _hiResFreq = freq;
212 :
213 : _InterlockedCompareExchange((LONG*)&_hiResTicks, 1, 0);
214 : return OSUtils_calcHiRes(now, freq);
215 : } while (0);
216 :
217 : return ::GetTickCount();
218 : }
219 : #elif ASMJIT_OS_MAC
220 : uint32_t OSUtils::getTickCount() noexcept {
221 : static mach_timebase_info_data_t _machTime;
222 :
223 : // See Apple's QA1398.
224 : if (ASMJIT_UNLIKELY(_machTime.denom == 0) || mach_timebase_info(&_machTime) != KERN_SUCCESS)
225 : return 0;
226 :
227 : // `mach_absolute_time()` returns nanoseconds, we want milliseconds.
228 : uint64_t t = mach_absolute_time() / 1000000;
229 :
230 : t = t * _machTime.numer / _machTime.denom;
231 : return static_cast<uint32_t>(t & 0xFFFFFFFFU);
232 : }
233 : #elif defined(_POSIX_MONOTONIC_CLOCK) && _POSIX_MONOTONIC_CLOCK >= 0
234 0 : uint32_t OSUtils::getTickCount() noexcept {
235 : struct timespec ts;
236 :
237 0 : if (ASMJIT_UNLIKELY(clock_gettime(CLOCK_MONOTONIC, &ts) != 0))
238 : return 0;
239 :
240 0 : uint64_t t = (uint64_t(ts.tv_sec ) * 1000) + (uint64_t(ts.tv_nsec) / 1000000);
241 0 : return static_cast<uint32_t>(t & 0xFFFFFFFFU);
242 : }
243 : #else
244 : #error "[asmjit] OSUtils::getTickCount() is not implemented for your target OS."
245 : uint32_t OSUtils::getTickCount() noexcept { return 0; }
246 : #endif
247 :
248 : } // asmjit namespace
249 : } // namespace PLMD
250 :
251 : // [Api-End]
252 : #include "./asmjit_apiend.h"
253 : #pragma GCC diagnostic pop
254 : #endif // __PLUMED_HAS_ASMJIT
|