1 // AsmJit - Machine code generation for C++
2 //
3 //  * Official AsmJit Home Page: https://asmjit.com
4 //  * Official Github Repository: https://github.com/asmjit/asmjit
5 //
6 // Copyright (c) 2008-2020 The AsmJit Authors
7 //
8 // This software is provided 'as-is', without any express or implied
9 // warranty. In no event will the authors be held liable for any damages
10 // arising from the use of this software.
11 //
12 // Permission is granted to anyone to use this software for any purpose,
13 // including commercial applications, and to alter it and redistribute it
14 // freely, subject to the following restrictions:
15 //
16 // 1. The origin of this software must not be misrepresented; you must not
17 //    claim that you wrote the original software. If you use this software
18 //    in a product, an acknowledgment in the product documentation would be
19 //    appreciated but is not required.
20 // 2. Altered source versions must be plainly marked as such, and must not be
21 //    misrepresented as being the original software.
22 // 3. This notice may not be removed or altered from any source distribution.
23 
24 #ifndef ASMJIT_CORE_GLOBALS_H_INCLUDED
25 #define ASMJIT_CORE_GLOBALS_H_INCLUDED
26 
27 #include "../core/api-config.h"
28 
29 ASMJIT_BEGIN_NAMESPACE
30 
31 // ============================================================================
32 // [asmjit::Support]
33 // ============================================================================
34 
35 //! \cond INTERNAL
36 //! \addtogroup asmjit_utilities
37 //! \{
38 namespace Support {
39   //! Cast designed to cast between function and void* pointers.
40   template<typename Dst, typename Src>
ptr_cast_impl(Src p)41   static inline Dst ptr_cast_impl(Src p) noexcept { return (Dst)p; }
42 } // {Support}
43 
44 #if defined(ASMJIT_NO_STDCXX)
45 namespace Support {
operatorNew(size_t n)46   ASMJIT_INLINE void* operatorNew(size_t n) noexcept { return malloc(n); }
operatorDelete(void * p)47   ASMJIT_INLINE void operatorDelete(void* p) noexcept { if (p) free(p); }
48 } // {Support}
49 
50 #define ASMJIT_BASE_CLASS(TYPE)                                               \
51   ASMJIT_INLINE void* operator new(size_t n) noexcept {                       \
52     return Support::operatorNew(n);                                           \
53   }                                                                           \
54                                                                               \
55   ASMJIT_INLINE void  operator delete(void* p) noexcept {                     \
56     Support::operatorDelete(p);                                               \
57   }                                                                           \
58                                                                               \
59   ASMJIT_INLINE void* operator new(size_t, void* p) noexcept { return p; }    \
60   ASMJIT_INLINE void  operator delete(void*, void*) noexcept {}
61 #else
62 #define ASMJIT_BASE_CLASS(TYPE)
63 #endif
64 
65 //! \}
66 //! \endcond
67 
68 // ============================================================================
69 // [asmjit::Globals]
70 // ============================================================================
71 
72 //! \addtogroup asmjit_core
73 //! \{
74 
75 //! Contains typedefs, constants, and variables used globally by AsmJit.
76 namespace Globals {
77 
78 // ============================================================================
79 // [asmjit::Globals::<global>]
80 // ============================================================================
81 
82 //! Host memory allocator overhead.
83 static constexpr uint32_t kAllocOverhead = uint32_t(sizeof(intptr_t) * 4);
84 
85 //! Host memory allocator alignment.
86 static constexpr uint32_t kAllocAlignment = 8;
87 
88 //! Aggressive growing strategy threshold.
89 static constexpr uint32_t kGrowThreshold = 1024 * 1024 * 16;
90 
91 //! Maximum depth of RB-Tree is:
92 //!
93 //!   `2 * log2(n + 1)`
94 //!
95 //! Size of RB node is at least two pointers (without data),
96 //! so a theoretical architecture limit would be:
97 //!
98 //!   `2 * log2(addressableMemorySize / sizeof(Node) + 1)`
99 //!
100 //! Which yields 30 on 32-bit arch and 61 on 64-bit arch.
101 //! The final value was adjusted by +1 for safety reasons.
102 static constexpr uint32_t kMaxTreeHeight = (ASMJIT_ARCH_BITS == 32 ? 30 : 61) + 1;
103 
104 //! Maximum number of operands per a single instruction.
105 static constexpr uint32_t kMaxOpCount = 6;
106 
107 //! Maximum arguments of a function supported by the Compiler / Function API.
108 static constexpr uint32_t kMaxFuncArgs = 16;
109 
110 //! The number of values that can be assigned to a single function argument or
111 //! return value.
112 static constexpr uint32_t kMaxValuePack = 4;
113 
114 //! Maximum number of physical registers AsmJit can use per register group.
115 static constexpr uint32_t kMaxPhysRegs = 32;
116 
117 //! Maximum alignment.
118 static constexpr uint32_t kMaxAlignment = 64;
119 
120 //! Maximum label or symbol size in bytes.
121 static constexpr uint32_t kMaxLabelNameSize = 2048;
122 
123 //! Maximum section name size.
124 static constexpr uint32_t kMaxSectionNameSize = 35;
125 
126 //! Maximum size of comment.
127 static constexpr uint32_t kMaxCommentSize = 1024;
128 
129 //! Invalid identifier.
130 static constexpr uint32_t kInvalidId = 0xFFFFFFFFu;
131 
132 //! Returned by `indexOf()` and similar when working with containers that use 32-bit index/size.
133 static constexpr uint32_t kNotFound = 0xFFFFFFFFu;
134 
135 //! Invalid base address.
136 static constexpr uint64_t kNoBaseAddress = ~uint64_t(0);
137 
138 // ============================================================================
139 // [asmjit::Globals::ResetPolicy]
140 // ============================================================================
141 
142 //! Reset policy used by most `reset()` functions.
143 enum ResetPolicy : uint32_t {
144   //! Soft reset, doesn't deallocate memory (default).
145   kResetSoft = 0,
146   //! Hard reset, releases all memory used, if any.
147   kResetHard = 1
148 };
149 
150 // ============================================================================
151 // [asmjit::Globals::Link]
152 // ============================================================================
153 
154 enum Link : uint32_t {
155   kLinkLeft  = 0,
156   kLinkRight = 1,
157 
158   kLinkPrev  = 0,
159   kLinkNext  = 1,
160 
161   kLinkFirst = 0,
162   kLinkLast  = 1,
163 
164   kLinkCount = 2
165 };
166 
167 struct Init_ {};
168 struct NoInit_ {};
169 
170 static const constexpr Init_ Init {};
171 static const constexpr NoInit_ NoInit {};
172 
173 } // {Globals}
174 
175 // ============================================================================
176 // [asmjit::ByteOrder]
177 // ============================================================================
178 
179 //! Byte order.
180 namespace ByteOrder {
181   enum : uint32_t {
182     kLE      = 0,
183     kBE      = 1,
184     kNative  = ASMJIT_ARCH_LE ? kLE : kBE,
185     kSwapped = ASMJIT_ARCH_LE ? kBE : kLE
186   };
187 }
188 
189 // ============================================================================
190 // [asmjit::ptr_as_func / func_as_ptr]
191 // ============================================================================
192 
193 template<typename Func>
ptr_as_func(void * func)194 static inline Func ptr_as_func(void* func) noexcept { return Support::ptr_cast_impl<Func, void*>(func); }
195 
196 template<typename Func>
func_as_ptr(Func func)197 static inline void* func_as_ptr(Func func) noexcept { return Support::ptr_cast_impl<void*, Func>(func); }
198 
199 //! \}
200 
201 // ============================================================================
202 // [asmjit::Error]
203 // ============================================================================
204 
205 //! \addtogroup asmjit_error_handling
206 //! \{
207 
208 //! AsmJit error type (uint32_t).
209 typedef uint32_t Error;
210 
211 //! AsmJit error codes.
212 enum ErrorCode : uint32_t {
213   // @EnumValuesBegin{"enum": "ErrorCode"}@
214 
215   //! No error (success).
216   kErrorOk = 0,
217 
218   //! Out of memory.
219   kErrorOutOfMemory,
220 
221   //! Invalid argument.
222   kErrorInvalidArgument,
223 
224   //! Invalid state.
225   //!
226   //! If this error is returned it means that either you are doing something
227   //! wrong or AsmJit caught itself by doing something wrong. This error should
228   //! never be ignored.
229   kErrorInvalidState,
230 
231   //! Invalid or incompatible architecture.
232   kErrorInvalidArch,
233 
234   //! The object is not initialized.
235   kErrorNotInitialized,
236   //! The object is already initialized.
237   kErrorAlreadyInitialized,
238 
239   //! Built-in feature was disabled at compile time and it's not available.
240   kErrorFeatureNotEnabled,
241 
242   //! Too many handles (Windows) or file descriptors (Unix/Posix).
243   kErrorTooManyHandles,
244   //! Code generated is larger than allowed.
245   kErrorTooLarge,
246 
247   //! No code generated.
248   //!
249   //! Returned by runtime if the \ref CodeHolder contains no code.
250   kErrorNoCodeGenerated,
251 
252   //! Invalid directive.
253   kErrorInvalidDirective,
254   //! Attempt to use uninitialized label.
255   kErrorInvalidLabel,
256   //! Label index overflow - a single \ref BaseAssembler instance can hold
257   //! almost 2^32 (4 billion) labels. If there is an attempt to create more
258   //! labels then this error is returned.
259   kErrorTooManyLabels,
260   //! Label is already bound.
261   kErrorLabelAlreadyBound,
262   //! Label is already defined (named labels).
263   kErrorLabelAlreadyDefined,
264   //! Label name is too long.
265   kErrorLabelNameTooLong,
266   //! Label must always be local if it's anonymous (without a name).
267   kErrorInvalidLabelName,
268   //! Parent id passed to \ref CodeHolder::newNamedLabelEntry() was invalid.
269   kErrorInvalidParentLabel,
270   //! Parent id specified for a non-local (global) label.
271   kErrorNonLocalLabelCannotHaveParent,
272 
273   //! Invalid section.
274   kErrorInvalidSection,
275   //! Too many sections (section index overflow).
276   kErrorTooManySections,
277   //! Invalid section name (most probably too long).
278   kErrorInvalidSectionName,
279 
280   //! Relocation index overflow (too many relocations).
281   kErrorTooManyRelocations,
282   //! Invalid relocation entry.
283   kErrorInvalidRelocEntry,
284   //! Reloc entry contains address that is out of range (unencodable).
285   kErrorRelocOffsetOutOfRange,
286 
287   //! Invalid assignment to a register, function argument, or function return value.
288   kErrorInvalidAssignment,
289   //! Invalid instruction.
290   kErrorInvalidInstruction,
291   //! Invalid register type.
292   kErrorInvalidRegType,
293   //! Invalid register group.
294   kErrorInvalidRegGroup,
295   //! Invalid physical register id.
296   kErrorInvalidPhysId,
297   //! Invalid virtual register id.
298   kErrorInvalidVirtId,
299   //! Invalid element index (ARM).
300   kErrorInvalidElementIndex,
301   //! Invalid prefix combination (X86|X64).
302   kErrorInvalidPrefixCombination,
303   //! Invalid LOCK prefix (X86|X64).
304   kErrorInvalidLockPrefix,
305   //! Invalid XACQUIRE prefix (X86|X64).
306   kErrorInvalidXAcquirePrefix,
307   //! Invalid XRELEASE prefix (X86|X64).
308   kErrorInvalidXReleasePrefix,
309   //! Invalid REP prefix (X86|X64).
310   kErrorInvalidRepPrefix,
311   //! Invalid REX prefix (X86|X64).
312   kErrorInvalidRexPrefix,
313   //! Invalid {...} register (X86|X64).
314   kErrorInvalidExtraReg,
315   //! Invalid {k} use (not supported by the instruction) (X86|X64).
316   kErrorInvalidKMaskUse,
317   //! Invalid {k}{z} use (not supported by the instruction) (X86|X64).
318   kErrorInvalidKZeroUse,
319   //! Invalid broadcast - Currently only related to invalid use of AVX-512 {1tox} (X86|X64).
320   kErrorInvalidBroadcast,
321   //! Invalid 'embedded-rounding' {er} or 'suppress-all-exceptions' {sae} (AVX-512) (X86|X64).
322   kErrorInvalidEROrSAE,
323   //! Invalid address used (not encodable).
324   kErrorInvalidAddress,
325   //! Invalid index register used in memory address (not encodable).
326   kErrorInvalidAddressIndex,
327   //! Invalid address scale (not encodable).
328   kErrorInvalidAddressScale,
329   //! Invalid use of 64-bit address.
330   kErrorInvalidAddress64Bit,
331   //! Invalid use of 64-bit address that require 32-bit zero-extension (X64).
332   kErrorInvalidAddress64BitZeroExtension,
333   //! Invalid displacement (not encodable).
334   kErrorInvalidDisplacement,
335   //! Invalid segment (X86).
336   kErrorInvalidSegment,
337 
338   //! Invalid immediate (out of bounds on X86 and invalid pattern on ARM).
339   kErrorInvalidImmediate,
340 
341   //! Invalid operand size.
342   kErrorInvalidOperandSize,
343   //! Ambiguous operand size (memory has zero size while it's required to determine the operation type.
344   kErrorAmbiguousOperandSize,
345   //! Mismatching operand size (size of multiple operands doesn't match the operation size).
346   kErrorOperandSizeMismatch,
347 
348   //! Invalid option.
349   kErrorInvalidOption,
350   //! Option already defined.
351   kErrorOptionAlreadyDefined,
352 
353   //! Invalid TypeId.
354   kErrorInvalidTypeId,
355   //! Invalid use of a 8-bit GPB-HIGH register.
356   kErrorInvalidUseOfGpbHi,
357   //! Invalid use of a 64-bit GPQ register in 32-bit mode.
358   kErrorInvalidUseOfGpq,
359   //! Invalid use of an 80-bit float (\ref Type::kIdF80).
360   kErrorInvalidUseOfF80,
361   //! Some registers in the instruction muse be consecutive (some ARM and AVX512
362   //! neural-net instructions).
363   kErrorNotConsecutiveRegs,
364 
365   //! Illegal virtual register - reported by instruction validation.
366   kErrorIllegalVirtReg,
367   //! AsmJit cannot create more virtual registers.
368   kErrorTooManyVirtRegs,
369 
370   //! AsmJit requires a physical register, but no one is available.
371   kErrorNoMorePhysRegs,
372   //! A variable has been assigned more than once to a function argument (BaseCompiler).
373   kErrorOverlappedRegs,
374   //! Invalid register to hold stack arguments offset.
375   kErrorOverlappingStackRegWithRegArg,
376 
377   //! Unbound label cannot be evaluated by expression.
378   kErrorExpressionLabelNotBound,
379   //! Arithmetic overflow during expression evaluation.
380   kErrorExpressionOverflow,
381 
382   //! Failed to open anonymous memory handle or file descriptor.
383   kErrorFailedToOpenAnonymousMemory,
384 
385   // @EnumValuesEnd@
386 
387   //! Count of AsmJit error codes.
388   kErrorCount
389 };
390 
391 // ============================================================================
392 // [asmjit::DebugUtils]
393 // ============================================================================
394 
395 //! Debugging utilities.
396 namespace DebugUtils {
397 
398 //! \cond INTERNAL
399 //! Used to silence warnings about unused arguments or variables.
400 template<typename... Args>
unused(Args &&...)401 static ASMJIT_INLINE void unused(Args&&...) noexcept {}
402 //! \endcond
403 
404 //! Returns the error `err` passed.
405 //!
406 //! Provided for debugging purposes. Putting a breakpoint inside `errored` can
407 //! help with tracing the origin of any error reported / returned by AsmJit.
errored(Error err)408 static constexpr Error errored(Error err) noexcept { return err; }
409 
410 //! Returns a printable version of `asmjit::Error` code.
411 ASMJIT_API const char* errorAsString(Error err) noexcept;
412 
413 //! Called to output debugging message(s).
414 ASMJIT_API void debugOutput(const char* str) noexcept;
415 
416 //! Called on assertion failure.
417 //!
418 //! \param file Source file name where it happened.
419 //! \param line Line in the source file.
420 //! \param msg Message to display.
421 //!
422 //! If you have problems with assertion failures a breakpoint can be put
423 //! at \ref assertionFailed() function (asmjit/core/globals.cpp). A call stack
424 //! will be available when such assertion failure is triggered. AsmJit always
425 //! returns errors on failures, assertions are a last resort and usually mean
426 //! unrecoverable state due to out of range array access or totally invalid
427 //! arguments like nullptr where a valid pointer should be provided, etc...
428 ASMJIT_API void ASMJIT_NORETURN assertionFailed(const char* file, int line, const char* msg) noexcept;
429 
430 } // {DebugUtils}
431 
432 //! \def ASMJIT_ASSERT(...)
433 //!
434 //! AsmJit's own assert macro used in AsmJit code-base.
435 #if defined(ASMJIT_BUILD_DEBUG)
436 #define ASMJIT_ASSERT(...)                                                     \
437   do {                                                                         \
438     if (ASMJIT_LIKELY(__VA_ARGS__))                                            \
439       break;                                                                   \
440     ::asmjit::DebugUtils::assertionFailed(__FILE__, __LINE__, #__VA_ARGS__);   \
441   } while (0)
442 #else
443 #define ASMJIT_ASSERT(...) ((void)0)
444 #endif
445 
446 //! \def ASMJIT_PROPAGATE(...)
447 //!
448 //! Propagates a possible `Error` produced by `...` to the caller by returning
449 //! the error immediately. Used by AsmJit internally, but kept public for users
450 //! that want to use the same technique to propagate errors to the caller.
451 #define ASMJIT_PROPAGATE(...)               \
452   do {                                      \
453     ::asmjit::Error _err = __VA_ARGS__;     \
454     if (ASMJIT_UNLIKELY(_err))              \
455       return _err;                          \
456   } while (0)
457 
458 //! \}
459 
460 ASMJIT_END_NAMESPACE
461 
462 #endif // ASMJIT_CORE_GLOBALS_H_INCLUDED
463