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 "./assembler.h"
34 #include "./cpuinfo.h"
35 #include "./runtime.h"
36 
37 // [Api-Begin]
38 #include "./asmjit_apibegin.h"
39 
40 namespace PLMD {
41 namespace asmjit {
42 
hostFlushInstructionCache(const void * p,size_t size)43 static ASMJIT_INLINE void hostFlushInstructionCache(const void* p, size_t size) noexcept {
44   // Only useful on non-x86 architectures.
45 #if !ASMJIT_ARCH_X86 && !ASMJIT_ARCH_X64
46 # if ASMJIT_OS_WINDOWS
47   // Windows has a built-in support in kernel32.dll.
48   ::FlushInstructionCache(_memMgr.getProcessHandle(), p, size);
49 # endif // ASMJIT_OS_WINDOWS
50 #else
51   ASMJIT_UNUSED(p);
52   ASMJIT_UNUSED(size);
53 #endif // !ASMJIT_ARCH_X86 && !ASMJIT_ARCH_X64
54 }
55 
hostDetectNaturalStackAlignment()56 static ASMJIT_INLINE uint32_t hostDetectNaturalStackAlignment() noexcept {
57   // Alignment is assumed to match the pointer-size by default.
58   uint32_t alignment = sizeof(intptr_t);
59 
60   // X86 & X64
61   // ---------
62   //
63   //   - 32-bit X86 requires stack to be aligned to 4 bytes. Modern Linux, Mac
64   //     and UNIX guarantees 16-byte stack alignment even on 32-bit. I'm not
65   //     sure about all other UNIX operating systems, because 16-byte alignment
66   //!    is addition to an older specification.
67   //   - 64-bit X86 requires stack to be aligned to at least 16 bytes.
68 #if ASMJIT_ARCH_X86 || ASMJIT_ARCH_X64
69   int kIsModernOS = ASMJIT_OS_LINUX  || // Linux & ANDROID.
70                     ASMJIT_OS_MAC    || // OSX and iOS.
71                     ASMJIT_OS_BSD    ;  // BSD variants.
72   alignment = ASMJIT_ARCH_X64 || kIsModernOS ? 16 : 4;
73 #endif
74 
75   // ARM32 & ARM64
76   // -------------
77   //
78   //   - 32-bit ARM requires stack to be aligned to 8 bytes.
79   //   - 64-bit ARM requires stack to be aligned to 16 bytes.
80 #if ASMJIT_ARCH_ARM32 || ASMJIT_ARCH_ARM64
81   alignment = ASMJIT_ARCH_ARM32 ? 8 : 16;
82 #endif
83 
84   return alignment;
85 }
86 
87 
88 // ============================================================================
89 // [asmjit::Runtime - Construction / Destruction]
90 // ============================================================================
91 
Runtime()92 Runtime::Runtime() noexcept
93   : _codeInfo(),
94     _runtimeType(kRuntimeNone),
95     _allocType(VMemMgr::kAllocFreeable) {}
~Runtime()96 Runtime::~Runtime() noexcept {}
97 
98 // ============================================================================
99 // [asmjit::HostRuntime - Construction / Destruction]
100 // ============================================================================
101 
HostRuntime()102 HostRuntime::HostRuntime() noexcept {
103   _runtimeType = kRuntimeJit;
104 
105   // Setup the CodeInfo of this Runtime.
106   _codeInfo._archInfo       = CpuInfo::getHost().getArchInfo();
107   _codeInfo._stackAlignment = static_cast<uint8_t>(hostDetectNaturalStackAlignment());
108   _codeInfo._cdeclCallConv  = CallConv::kIdHostCDecl;
109   _codeInfo._stdCallConv    = CallConv::kIdHostStdCall;
110   _codeInfo._fastCallConv   = CallConv::kIdHostFastCall;
111 }
~HostRuntime()112 HostRuntime::~HostRuntime() noexcept {}
113 
114 // ============================================================================
115 // [asmjit::HostRuntime - Interface]
116 // ============================================================================
117 
flush(const void * p,size_t size)118 void HostRuntime::flush(const void* p, size_t size) noexcept {
119   hostFlushInstructionCache(p, size);
120 }
121 
122 // ============================================================================
123 // [asmjit::JitRuntime - Construction / Destruction]
124 // ============================================================================
125 
JitRuntime()126 JitRuntime::JitRuntime() noexcept {}
~JitRuntime()127 JitRuntime::~JitRuntime() noexcept {}
128 
129 // ============================================================================
130 // [asmjit::JitRuntime - Interface]
131 // ============================================================================
132 
_add(void ** dst,CodeHolder * code)133 Error JitRuntime::_add(void** dst, CodeHolder* code) noexcept {
134   size_t codeSize = code->getCodeSize();
135   if (ASMJIT_UNLIKELY(codeSize == 0)) {
136     *dst = nullptr;
137     return DebugUtils::errored(kErrorNoCodeGenerated);
138   }
139 
140   void* p = _memMgr.alloc(codeSize, getAllocType());
141   if (ASMJIT_UNLIKELY(!p)) {
142     *dst = nullptr;
143     return DebugUtils::errored(kErrorNoVirtualMemory);
144   }
145 
146   // Relocate the code and release the unused memory back to `VMemMgr`.
147   size_t relocSize = code->relocate(p);
148   if (ASMJIT_UNLIKELY(relocSize == 0)) {
149     *dst = nullptr;
150     _memMgr.release(p);
151     return DebugUtils::errored(kErrorInvalidState);
152   }
153 
154   if (relocSize < codeSize)
155     _memMgr.shrink(p, relocSize);
156 
157   flush(p, relocSize);
158   *dst = p;
159 
160   return kErrorOk;
161 }
162 
_release(void * p)163 Error JitRuntime::_release(void* p) noexcept {
164   return _memMgr.release(p);
165 }
166 
167 } // asmjit namespace
168 } // namespace PLMD
169 
170 // [Api-End]
171 #include "./asmjit_apiend.h"
172 #pragma GCC diagnostic pop
173 #endif // __PLUMED_HAS_ASMJIT
174