1 // [AsmJit]
2 // Machine Code Generation for C++.
3 //
4 // [License]
5 // Zlib - See LICENSE.md file in the package.
6
7 #define ASMJIT_EXPORTS
8
9 #include "../core/build.h"
10 #ifndef ASMJIT_NO_JIT
11
12 #include "../core/cpuinfo.h"
13 #include "../core/jitruntime.h"
14
15 ASMJIT_BEGIN_NAMESPACE
16
17 // ============================================================================
18 // [asmjit::JitRuntime - Utilities]
19 // ============================================================================
20
21 // Only useful on non-x86 architectures.
JitRuntime_flushInstructionCache(const void * p,size_t size)22 static inline void JitRuntime_flushInstructionCache(const void* p, size_t size) noexcept {
23 #if defined(_WIN32) && !ASMJIT_ARCH_X86
24 // Windows has a built-in support in `kernel32.dll`.
25 ::FlushInstructionCache(::GetCurrentProcess(), p, size);
26 #else
27 ASMJIT_UNUSED(p);
28 ASMJIT_UNUSED(size);
29 #endif
30 }
31
32 // X86 Target
33 // ----------
34 //
35 // - 32-bit - Linux, OSX, BSD, and apparently also Haiku guarantee 16-byte
36 // stack alignment. Other operating systems are assumed to have
37 // 4-byte alignment by default for safety reasons.
38 // - 64-bit - stack must be aligned to 16 bytes.
39 //
40 // ARM Target
41 // ----------
42 //
43 // - 32-bit - Stack must be aligned to 8 bytes.
44 // - 64-bit - Stack must be aligned to 16 bytes (hardware requirement).
JitRuntime_detectNaturalStackAlignment()45 static inline uint32_t JitRuntime_detectNaturalStackAlignment() noexcept {
46 #if ASMJIT_ARCH_BITS == 64 || \
47 defined(__APPLE__ ) || \
48 defined(__DragonFly__) || \
49 defined(__HAIKU__ ) || \
50 defined(__FreeBSD__ ) || \
51 defined(__NetBSD__ ) || \
52 defined(__OpenBSD__ ) || \
53 defined(__bsdi__ ) || \
54 defined(__linux__ )
55 return 16;
56 #elif ASMJIT_ARCH_ARM
57 return 8;
58 #else
59 return uint32_t(sizeof(uintptr_t));
60 #endif
61 }
62
63 // ============================================================================
64 // [asmjit::JitRuntime - Construction / Destruction]
65 // ============================================================================
66
JitRuntime(const JitAllocator::CreateParams * params)67 JitRuntime::JitRuntime(const JitAllocator::CreateParams* params) noexcept
68 : _allocator(params) {
69
70 // Setup target properties.
71 _targetType = kTargetJit;
72 _codeInfo._archInfo = CpuInfo::host().archInfo();
73 _codeInfo._stackAlignment = uint8_t(JitRuntime_detectNaturalStackAlignment());
74 _codeInfo._cdeclCallConv = CallConv::kIdHostCDecl;
75 _codeInfo._stdCallConv = CallConv::kIdHostStdCall;
76 _codeInfo._fastCallConv = CallConv::kIdHostFastCall;
77 }
~JitRuntime()78 JitRuntime::~JitRuntime() noexcept {}
79
80 // ============================================================================
81 // [asmjit::JitRuntime - Interface]
82 // ============================================================================
83
_add(void ** dst,CodeHolder * code)84 Error JitRuntime::_add(void** dst, CodeHolder* code) noexcept {
85 *dst = nullptr;
86
87 ASMJIT_PROPAGATE(code->flatten());
88 ASMJIT_PROPAGATE(code->resolveUnresolvedLinks());
89
90 size_t estimatedCodeSize = code->codeSize();
91 if (ASMJIT_UNLIKELY(estimatedCodeSize == 0))
92 return DebugUtils::errored(kErrorNoCodeGenerated);
93
94 uint8_t* ro;
95 uint8_t* rw;
96 ASMJIT_PROPAGATE(_allocator.alloc((void**)&ro, (void**)&rw, estimatedCodeSize));
97
98 // Relocate the code.
99 Error err = code->relocateToBase(uintptr_t((void*)ro));
100 if (ASMJIT_UNLIKELY(err)) {
101 _allocator.release(ro);
102 return err;
103 }
104
105 // Recalculate the final code size and shrink the memory we allocated for it
106 // in case that some relocations didn't require records in an address table.
107 size_t codeSize = code->codeSize();
108
109 for (Section* section : code->_sections) {
110 size_t offset = size_t(section->offset());
111 size_t bufferSize = size_t(section->bufferSize());
112 size_t virtualSize = size_t(section->virtualSize());
113
114 ASMJIT_ASSERT(offset + bufferSize <= codeSize);
115 memcpy(rw + offset, section->data(), bufferSize);
116
117 if (virtualSize > bufferSize) {
118 ASMJIT_ASSERT(offset + virtualSize <= codeSize);
119 memset(rw + offset + bufferSize, 0, virtualSize - bufferSize);
120 }
121 }
122
123 if (codeSize < estimatedCodeSize)
124 _allocator.shrink(ro, codeSize);
125
126 flush(ro, codeSize);
127 *dst = ro;
128
129 return kErrorOk;
130 }
131
_release(void * p)132 Error JitRuntime::_release(void* p) noexcept {
133 return _allocator.release(p);
134 }
135
flush(const void * p,size_t size)136 void JitRuntime::flush(const void* p, size_t size) noexcept {
137 JitRuntime_flushInstructionCache(p, size);
138 }
139
140 ASMJIT_END_NAMESPACE
141
142 #endif
143