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