asmjit 0.2.0 → 0.2.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (201) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile.lock +1 -1
  3. data/asmjit.gemspec +1 -1
  4. data/ext/asmjit/asmjit/.editorconfig +10 -0
  5. data/ext/asmjit/asmjit/.github/FUNDING.yml +1 -0
  6. data/ext/asmjit/asmjit/.github/workflows/build-config.json +47 -0
  7. data/ext/asmjit/asmjit/.github/workflows/build.yml +156 -0
  8. data/ext/asmjit/asmjit/.gitignore +6 -0
  9. data/ext/asmjit/asmjit/CMakeLists.txt +611 -0
  10. data/ext/asmjit/asmjit/LICENSE.md +17 -0
  11. data/ext/asmjit/asmjit/README.md +69 -0
  12. data/ext/asmjit/asmjit/src/asmjit/a64.h +62 -0
  13. data/ext/asmjit/asmjit/src/asmjit/arm/a64archtraits_p.h +81 -0
  14. data/ext/asmjit/asmjit/src/asmjit/arm/a64assembler.cpp +5115 -0
  15. data/ext/asmjit/asmjit/src/asmjit/arm/a64assembler.h +72 -0
  16. data/ext/asmjit/asmjit/src/asmjit/arm/a64builder.cpp +51 -0
  17. data/ext/asmjit/asmjit/src/asmjit/arm/a64builder.h +57 -0
  18. data/ext/asmjit/asmjit/src/asmjit/arm/a64compiler.cpp +60 -0
  19. data/ext/asmjit/asmjit/src/asmjit/arm/a64compiler.h +247 -0
  20. data/ext/asmjit/asmjit/src/asmjit/arm/a64emithelper.cpp +464 -0
  21. data/ext/asmjit/asmjit/src/asmjit/arm/a64emithelper_p.h +50 -0
  22. data/ext/asmjit/asmjit/src/asmjit/arm/a64emitter.h +1228 -0
  23. data/ext/asmjit/asmjit/src/asmjit/arm/a64formatter.cpp +298 -0
  24. data/ext/asmjit/asmjit/src/asmjit/arm/a64formatter_p.h +59 -0
  25. data/ext/asmjit/asmjit/src/asmjit/arm/a64func.cpp +189 -0
  26. data/ext/asmjit/asmjit/src/asmjit/arm/a64func_p.h +33 -0
  27. data/ext/asmjit/asmjit/src/asmjit/arm/a64globals.h +1894 -0
  28. data/ext/asmjit/asmjit/src/asmjit/arm/a64instapi.cpp +278 -0
  29. data/ext/asmjit/asmjit/src/asmjit/arm/a64instapi_p.h +41 -0
  30. data/ext/asmjit/asmjit/src/asmjit/arm/a64instdb.cpp +1957 -0
  31. data/ext/asmjit/asmjit/src/asmjit/arm/a64instdb.h +74 -0
  32. data/ext/asmjit/asmjit/src/asmjit/arm/a64instdb_p.h +876 -0
  33. data/ext/asmjit/asmjit/src/asmjit/arm/a64operand.cpp +85 -0
  34. data/ext/asmjit/asmjit/src/asmjit/arm/a64operand.h +312 -0
  35. data/ext/asmjit/asmjit/src/asmjit/arm/a64rapass.cpp +852 -0
  36. data/ext/asmjit/asmjit/src/asmjit/arm/a64rapass_p.h +105 -0
  37. data/ext/asmjit/asmjit/src/asmjit/arm/a64utils.h +179 -0
  38. data/ext/asmjit/asmjit/src/asmjit/arm/armformatter.cpp +143 -0
  39. data/ext/asmjit/asmjit/src/asmjit/arm/armformatter_p.h +44 -0
  40. data/ext/asmjit/asmjit/src/asmjit/arm/armglobals.h +21 -0
  41. data/ext/asmjit/asmjit/src/asmjit/arm/armoperand.h +621 -0
  42. data/ext/asmjit/asmjit/src/asmjit/arm.h +62 -0
  43. data/ext/asmjit/asmjit/src/asmjit/asmjit-scope-begin.h +17 -0
  44. data/ext/asmjit/asmjit/src/asmjit/asmjit-scope-end.h +9 -0
  45. data/ext/asmjit/asmjit/src/asmjit/asmjit.h +33 -0
  46. data/ext/asmjit/asmjit/src/asmjit/core/api-build_p.h +55 -0
  47. data/ext/asmjit/asmjit/src/asmjit/core/api-config.h +613 -0
  48. data/ext/asmjit/asmjit/src/asmjit/core/archcommons.h +229 -0
  49. data/ext/asmjit/asmjit/src/asmjit/core/archtraits.cpp +160 -0
  50. data/ext/asmjit/asmjit/src/asmjit/core/archtraits.h +290 -0
  51. data/ext/asmjit/asmjit/src/asmjit/core/assembler.cpp +406 -0
  52. data/ext/asmjit/asmjit/src/asmjit/core/assembler.h +129 -0
  53. data/ext/asmjit/asmjit/src/asmjit/core/builder.cpp +889 -0
  54. data/ext/asmjit/asmjit/src/asmjit/core/builder.h +1391 -0
  55. data/ext/asmjit/asmjit/src/asmjit/core/codebuffer.h +113 -0
  56. data/ext/asmjit/asmjit/src/asmjit/core/codeholder.cpp +1149 -0
  57. data/ext/asmjit/asmjit/src/asmjit/core/codeholder.h +1035 -0
  58. data/ext/asmjit/asmjit/src/asmjit/core/codewriter.cpp +175 -0
  59. data/ext/asmjit/asmjit/src/asmjit/core/codewriter_p.h +179 -0
  60. data/ext/asmjit/asmjit/src/asmjit/core/compiler.cpp +582 -0
  61. data/ext/asmjit/asmjit/src/asmjit/core/compiler.h +737 -0
  62. data/ext/asmjit/asmjit/src/asmjit/core/compilerdefs.h +173 -0
  63. data/ext/asmjit/asmjit/src/asmjit/core/constpool.cpp +363 -0
  64. data/ext/asmjit/asmjit/src/asmjit/core/constpool.h +250 -0
  65. data/ext/asmjit/asmjit/src/asmjit/core/cpuinfo.cpp +1162 -0
  66. data/ext/asmjit/asmjit/src/asmjit/core/cpuinfo.h +813 -0
  67. data/ext/asmjit/asmjit/src/asmjit/core/emithelper.cpp +323 -0
  68. data/ext/asmjit/asmjit/src/asmjit/core/emithelper_p.h +58 -0
  69. data/ext/asmjit/asmjit/src/asmjit/core/emitter.cpp +333 -0
  70. data/ext/asmjit/asmjit/src/asmjit/core/emitter.h +741 -0
  71. data/ext/asmjit/asmjit/src/asmjit/core/emitterutils.cpp +129 -0
  72. data/ext/asmjit/asmjit/src/asmjit/core/emitterutils_p.h +89 -0
  73. data/ext/asmjit/asmjit/src/asmjit/core/environment.cpp +46 -0
  74. data/ext/asmjit/asmjit/src/asmjit/core/environment.h +508 -0
  75. data/ext/asmjit/asmjit/src/asmjit/core/errorhandler.cpp +14 -0
  76. data/ext/asmjit/asmjit/src/asmjit/core/errorhandler.h +228 -0
  77. data/ext/asmjit/asmjit/src/asmjit/core/formatter.cpp +584 -0
  78. data/ext/asmjit/asmjit/src/asmjit/core/formatter.h +247 -0
  79. data/ext/asmjit/asmjit/src/asmjit/core/formatter_p.h +34 -0
  80. data/ext/asmjit/asmjit/src/asmjit/core/func.cpp +286 -0
  81. data/ext/asmjit/asmjit/src/asmjit/core/func.h +1445 -0
  82. data/ext/asmjit/asmjit/src/asmjit/core/funcargscontext.cpp +293 -0
  83. data/ext/asmjit/asmjit/src/asmjit/core/funcargscontext_p.h +199 -0
  84. data/ext/asmjit/asmjit/src/asmjit/core/globals.cpp +133 -0
  85. data/ext/asmjit/asmjit/src/asmjit/core/globals.h +393 -0
  86. data/ext/asmjit/asmjit/src/asmjit/core/inst.cpp +113 -0
  87. data/ext/asmjit/asmjit/src/asmjit/core/inst.h +772 -0
  88. data/ext/asmjit/asmjit/src/asmjit/core/jitallocator.cpp +1242 -0
  89. data/ext/asmjit/asmjit/src/asmjit/core/jitallocator.h +261 -0
  90. data/ext/asmjit/asmjit/src/asmjit/core/jitruntime.cpp +80 -0
  91. data/ext/asmjit/asmjit/src/asmjit/core/jitruntime.h +89 -0
  92. data/ext/asmjit/asmjit/src/asmjit/core/logger.cpp +69 -0
  93. data/ext/asmjit/asmjit/src/asmjit/core/logger.h +198 -0
  94. data/ext/asmjit/asmjit/src/asmjit/core/misc_p.h +33 -0
  95. data/ext/asmjit/asmjit/src/asmjit/core/operand.cpp +132 -0
  96. data/ext/asmjit/asmjit/src/asmjit/core/operand.h +1611 -0
  97. data/ext/asmjit/asmjit/src/asmjit/core/osutils.cpp +84 -0
  98. data/ext/asmjit/asmjit/src/asmjit/core/osutils.h +61 -0
  99. data/ext/asmjit/asmjit/src/asmjit/core/osutils_p.h +68 -0
  100. data/ext/asmjit/asmjit/src/asmjit/core/raassignment_p.h +418 -0
  101. data/ext/asmjit/asmjit/src/asmjit/core/rabuilders_p.h +612 -0
  102. data/ext/asmjit/asmjit/src/asmjit/core/radefs_p.h +1204 -0
  103. data/ext/asmjit/asmjit/src/asmjit/core/ralocal.cpp +1166 -0
  104. data/ext/asmjit/asmjit/src/asmjit/core/ralocal_p.h +254 -0
  105. data/ext/asmjit/asmjit/src/asmjit/core/rapass.cpp +1969 -0
  106. data/ext/asmjit/asmjit/src/asmjit/core/rapass_p.h +1183 -0
  107. data/ext/asmjit/asmjit/src/asmjit/core/rastack.cpp +184 -0
  108. data/ext/asmjit/asmjit/src/asmjit/core/rastack_p.h +171 -0
  109. data/ext/asmjit/asmjit/src/asmjit/core/string.cpp +559 -0
  110. data/ext/asmjit/asmjit/src/asmjit/core/string.h +372 -0
  111. data/ext/asmjit/asmjit/src/asmjit/core/support.cpp +494 -0
  112. data/ext/asmjit/asmjit/src/asmjit/core/support.h +1773 -0
  113. data/ext/asmjit/asmjit/src/asmjit/core/target.cpp +14 -0
  114. data/ext/asmjit/asmjit/src/asmjit/core/target.h +53 -0
  115. data/ext/asmjit/asmjit/src/asmjit/core/type.cpp +74 -0
  116. data/ext/asmjit/asmjit/src/asmjit/core/type.h +419 -0
  117. data/ext/asmjit/asmjit/src/asmjit/core/virtmem.cpp +722 -0
  118. data/ext/asmjit/asmjit/src/asmjit/core/virtmem.h +242 -0
  119. data/ext/asmjit/asmjit/src/asmjit/core/zone.cpp +353 -0
  120. data/ext/asmjit/asmjit/src/asmjit/core/zone.h +615 -0
  121. data/ext/asmjit/asmjit/src/asmjit/core/zonehash.cpp +309 -0
  122. data/ext/asmjit/asmjit/src/asmjit/core/zonehash.h +186 -0
  123. data/ext/asmjit/asmjit/src/asmjit/core/zonelist.cpp +163 -0
  124. data/ext/asmjit/asmjit/src/asmjit/core/zonelist.h +209 -0
  125. data/ext/asmjit/asmjit/src/asmjit/core/zonestack.cpp +176 -0
  126. data/ext/asmjit/asmjit/src/asmjit/core/zonestack.h +239 -0
  127. data/ext/asmjit/asmjit/src/asmjit/core/zonestring.h +120 -0
  128. data/ext/asmjit/asmjit/src/asmjit/core/zonetree.cpp +99 -0
  129. data/ext/asmjit/asmjit/src/asmjit/core/zonetree.h +380 -0
  130. data/ext/asmjit/asmjit/src/asmjit/core/zonevector.cpp +356 -0
  131. data/ext/asmjit/asmjit/src/asmjit/core/zonevector.h +690 -0
  132. data/ext/asmjit/asmjit/src/asmjit/core.h +1861 -0
  133. data/ext/asmjit/asmjit/src/asmjit/x86/x86archtraits_p.h +148 -0
  134. data/ext/asmjit/asmjit/src/asmjit/x86/x86assembler.cpp +5110 -0
  135. data/ext/asmjit/asmjit/src/asmjit/x86/x86assembler.h +685 -0
  136. data/ext/asmjit/asmjit/src/asmjit/x86/x86builder.cpp +52 -0
  137. data/ext/asmjit/asmjit/src/asmjit/x86/x86builder.h +351 -0
  138. data/ext/asmjit/asmjit/src/asmjit/x86/x86compiler.cpp +61 -0
  139. data/ext/asmjit/asmjit/src/asmjit/x86/x86compiler.h +721 -0
  140. data/ext/asmjit/asmjit/src/asmjit/x86/x86emithelper.cpp +619 -0
  141. data/ext/asmjit/asmjit/src/asmjit/x86/x86emithelper_p.h +60 -0
  142. data/ext/asmjit/asmjit/src/asmjit/x86/x86emitter.h +4315 -0
  143. data/ext/asmjit/asmjit/src/asmjit/x86/x86formatter.cpp +944 -0
  144. data/ext/asmjit/asmjit/src/asmjit/x86/x86formatter_p.h +58 -0
  145. data/ext/asmjit/asmjit/src/asmjit/x86/x86func.cpp +503 -0
  146. data/ext/asmjit/asmjit/src/asmjit/x86/x86func_p.h +33 -0
  147. data/ext/asmjit/asmjit/src/asmjit/x86/x86globals.h +2169 -0
  148. data/ext/asmjit/asmjit/src/asmjit/x86/x86instapi.cpp +1732 -0
  149. data/ext/asmjit/asmjit/src/asmjit/x86/x86instapi_p.h +41 -0
  150. data/ext/asmjit/asmjit/src/asmjit/x86/x86instdb.cpp +4427 -0
  151. data/ext/asmjit/asmjit/src/asmjit/x86/x86instdb.h +563 -0
  152. data/ext/asmjit/asmjit/src/asmjit/x86/x86instdb_p.h +311 -0
  153. data/ext/asmjit/asmjit/src/asmjit/x86/x86opcode_p.h +436 -0
  154. data/ext/asmjit/asmjit/src/asmjit/x86/x86operand.cpp +231 -0
  155. data/ext/asmjit/asmjit/src/asmjit/x86/x86operand.h +1085 -0
  156. data/ext/asmjit/asmjit/src/asmjit/x86/x86rapass.cpp +1509 -0
  157. data/ext/asmjit/asmjit/src/asmjit/x86/x86rapass_p.h +94 -0
  158. data/ext/asmjit/asmjit/src/asmjit/x86.h +93 -0
  159. data/ext/asmjit/asmjit/src/asmjit.natvis +245 -0
  160. data/ext/asmjit/asmjit/test/asmjit_test_assembler.cpp +84 -0
  161. data/ext/asmjit/asmjit/test/asmjit_test_assembler.h +85 -0
  162. data/ext/asmjit/asmjit/test/asmjit_test_assembler_a64.cpp +4006 -0
  163. data/ext/asmjit/asmjit/test/asmjit_test_assembler_x64.cpp +17833 -0
  164. data/ext/asmjit/asmjit/test/asmjit_test_assembler_x86.cpp +8300 -0
  165. data/ext/asmjit/asmjit/test/asmjit_test_compiler.cpp +253 -0
  166. data/ext/asmjit/asmjit/test/asmjit_test_compiler.h +73 -0
  167. data/ext/asmjit/asmjit/test/asmjit_test_compiler_a64.cpp +690 -0
  168. data/ext/asmjit/asmjit/test/asmjit_test_compiler_x86.cpp +4317 -0
  169. data/ext/asmjit/asmjit/test/asmjit_test_emitters.cpp +197 -0
  170. data/ext/asmjit/asmjit/test/asmjit_test_instinfo.cpp +181 -0
  171. data/ext/asmjit/asmjit/test/asmjit_test_misc.h +257 -0
  172. data/ext/asmjit/asmjit/test/asmjit_test_perf.cpp +62 -0
  173. data/ext/asmjit/asmjit/test/asmjit_test_perf.h +61 -0
  174. data/ext/asmjit/asmjit/test/asmjit_test_perf_a64.cpp +699 -0
  175. data/ext/asmjit/asmjit/test/asmjit_test_perf_x86.cpp +5032 -0
  176. data/ext/asmjit/asmjit/test/asmjit_test_unit.cpp +172 -0
  177. data/ext/asmjit/asmjit/test/asmjit_test_x86_sections.cpp +172 -0
  178. data/ext/asmjit/asmjit/test/asmjitutils.h +38 -0
  179. data/ext/asmjit/asmjit/test/broken.cpp +312 -0
  180. data/ext/asmjit/asmjit/test/broken.h +148 -0
  181. data/ext/asmjit/asmjit/test/cmdline.h +61 -0
  182. data/ext/asmjit/asmjit/test/performancetimer.h +41 -0
  183. data/ext/asmjit/asmjit/tools/configure-makefiles.sh +13 -0
  184. data/ext/asmjit/asmjit/tools/configure-ninja.sh +13 -0
  185. data/ext/asmjit/asmjit/tools/configure-sanitizers.sh +13 -0
  186. data/ext/asmjit/asmjit/tools/configure-vs2019-x64.bat +2 -0
  187. data/ext/asmjit/asmjit/tools/configure-vs2019-x86.bat +2 -0
  188. data/ext/asmjit/asmjit/tools/configure-vs2022-x64.bat +2 -0
  189. data/ext/asmjit/asmjit/tools/configure-vs2022-x86.bat +2 -0
  190. data/ext/asmjit/asmjit/tools/configure-xcode.sh +8 -0
  191. data/ext/asmjit/asmjit/tools/enumgen.js +417 -0
  192. data/ext/asmjit/asmjit/tools/enumgen.sh +3 -0
  193. data/ext/asmjit/asmjit/tools/tablegen-arm.js +365 -0
  194. data/ext/asmjit/asmjit/tools/tablegen-arm.sh +3 -0
  195. data/ext/asmjit/asmjit/tools/tablegen-x86.js +2638 -0
  196. data/ext/asmjit/asmjit/tools/tablegen-x86.sh +3 -0
  197. data/ext/asmjit/asmjit/tools/tablegen.js +947 -0
  198. data/ext/asmjit/asmjit/tools/tablegen.sh +4 -0
  199. data/ext/asmjit/asmjit.cc +18 -0
  200. data/lib/asmjit/version.rb +1 -1
  201. metadata +197 -2
@@ -0,0 +1,722 @@
1
+ // This file is part of AsmJit project <https://asmjit.com>
2
+ //
3
+ // See asmjit.h or LICENSE.md for license and copyright information
4
+ // SPDX-License-Identifier: Zlib
5
+
6
+ #include "../core/api-build_p.h"
7
+ #ifndef ASMJIT_NO_JIT
8
+
9
+ #include "../core/osutils.h"
10
+ #include "../core/string.h"
11
+ #include "../core/support.h"
12
+ #include "../core/virtmem.h"
13
+
14
+ #if !defined(_WIN32)
15
+ #include <errno.h>
16
+ #include <fcntl.h>
17
+ #include <sys/mman.h>
18
+ #include <sys/stat.h>
19
+ #include <sys/types.h>
20
+ #include <unistd.h>
21
+
22
+ // Linux has a `memfd_create` syscall that we would like to use, if available.
23
+ #if defined(__linux__)
24
+ #include <sys/syscall.h>
25
+ #endif
26
+
27
+ // Apple recently introduced MAP_JIT flag, which we want to use.
28
+ #if defined(__APPLE__)
29
+ #include <pthread.h>
30
+ #include <TargetConditionals.h>
31
+ #if TARGET_OS_OSX
32
+ #include <sys/utsname.h>
33
+ #include <libkern/OSCacheControl.h> // sys_icache_invalidate().
34
+ #endif
35
+ // Older SDK doesn't define `MAP_JIT`.
36
+ #ifndef MAP_JIT
37
+ #define MAP_JIT 0x800
38
+ #endif
39
+ #endif
40
+
41
+ // BSD/MAC: `MAP_ANONYMOUS` is not defined, `MAP_ANON` is.
42
+ #if !defined(MAP_ANONYMOUS)
43
+ #define MAP_ANONYMOUS MAP_ANON
44
+ #endif
45
+ #endif
46
+
47
+ #include <atomic>
48
+
49
+ #if defined(__APPLE__) || defined(__BIONIC__)
50
+ #define ASMJIT_VM_SHM_DETECT 0
51
+ #else
52
+ #define ASMJIT_VM_SHM_DETECT 1
53
+ #endif
54
+
55
+ // Android NDK doesn't provide `shm_open()` and `shm_unlink()`.
56
+ #if defined(__BIONIC__)
57
+ #define ASMJIT_VM_SHM_AVAILABLE 0
58
+ #else
59
+ #define ASMJIT_VM_SHM_AVAILABLE 1
60
+ #endif
61
+
62
+ #if defined(__APPLE__) && ASMJIT_ARCH_ARM >= 64
63
+ #define ASMJIT_HAS_PTHREAD_JIT_WRITE_PROTECT_NP
64
+ #endif
65
+
66
+ ASMJIT_BEGIN_SUB_NAMESPACE(VirtMem)
67
+
68
+ // Virtual Memory Utilities
69
+ // ========================
70
+
71
+ static const MemoryFlags dualMappingFilter[2] = {
72
+ MemoryFlags::kAccessWrite | MemoryFlags::kMMapMaxAccessWrite,
73
+ MemoryFlags::kAccessExecute | MemoryFlags::kMMapMaxAccessExecute
74
+ };
75
+
76
+ // Virtual Memory [Windows]
77
+ // ========================
78
+
79
+ #if defined(_WIN32)
80
+
81
+ struct ScopedHandle {
82
+ inline ScopedHandle() noexcept
83
+ : value(nullptr) {}
84
+
85
+ inline ~ScopedHandle() noexcept {
86
+ if (value != nullptr)
87
+ ::CloseHandle(value);
88
+ }
89
+
90
+ HANDLE value;
91
+ };
92
+
93
+ static void getVMInfo(Info& vmInfo) noexcept {
94
+ SYSTEM_INFO systemInfo;
95
+
96
+ ::GetSystemInfo(&systemInfo);
97
+ vmInfo.pageSize = Support::alignUpPowerOf2<uint32_t>(systemInfo.dwPageSize);
98
+ vmInfo.pageGranularity = systemInfo.dwAllocationGranularity;
99
+ }
100
+
101
+ // Returns windows-specific protectFlags from \ref MemoryFlags.
102
+ static DWORD protectFlagsFromMemoryFlags(MemoryFlags memoryFlags) noexcept {
103
+ DWORD protectFlags;
104
+
105
+ // READ|WRITE|EXECUTE.
106
+ if (Support::test(memoryFlags, MemoryFlags::kAccessExecute))
107
+ protectFlags = Support::test(memoryFlags, MemoryFlags::kAccessWrite) ? PAGE_EXECUTE_READWRITE : PAGE_EXECUTE_READ;
108
+ else if (Support::test(memoryFlags, MemoryFlags::kAccessRW))
109
+ protectFlags = Support::test(memoryFlags, MemoryFlags::kAccessWrite) ? PAGE_READWRITE : PAGE_READONLY;
110
+ else
111
+ protectFlags = PAGE_NOACCESS;
112
+
113
+ // Any other flags to consider?
114
+ return protectFlags;
115
+ }
116
+
117
+ static DWORD desiredAccessFromMemoryFlags(MemoryFlags memoryFlags) noexcept {
118
+ DWORD access = Support::test(memoryFlags, MemoryFlags::kAccessWrite) ? FILE_MAP_WRITE : FILE_MAP_READ;
119
+ if (Support::test(memoryFlags, MemoryFlags::kAccessExecute))
120
+ access |= FILE_MAP_EXECUTE;
121
+ return access;
122
+ }
123
+
124
+ static HardenedRuntimeFlags getHardenedRuntimeFlags() noexcept {
125
+ return HardenedRuntimeFlags::kNone;
126
+ }
127
+
128
+ Error alloc(void** p, size_t size, MemoryFlags memoryFlags) noexcept {
129
+ *p = nullptr;
130
+ if (size == 0)
131
+ return DebugUtils::errored(kErrorInvalidArgument);
132
+
133
+ DWORD protectFlags = protectFlagsFromMemoryFlags(memoryFlags);
134
+ void* result = ::VirtualAlloc(nullptr, size, MEM_COMMIT | MEM_RESERVE, protectFlags);
135
+
136
+ if (!result)
137
+ return DebugUtils::errored(kErrorOutOfMemory);
138
+
139
+ *p = result;
140
+ return kErrorOk;
141
+ }
142
+
143
+ Error release(void* p, size_t size) noexcept {
144
+ DebugUtils::unused(size);
145
+ if (ASMJIT_UNLIKELY(!::VirtualFree(p, 0, MEM_RELEASE)))
146
+ return DebugUtils::errored(kErrorInvalidArgument);
147
+ return kErrorOk;
148
+ }
149
+
150
+ Error protect(void* p, size_t size, MemoryFlags memoryFlags) noexcept {
151
+ DWORD protectFlags = protectFlagsFromMemoryFlags(memoryFlags);
152
+ DWORD oldFlags;
153
+
154
+ if (::VirtualProtect(p, size, protectFlags, &oldFlags))
155
+ return kErrorOk;
156
+
157
+ return DebugUtils::errored(kErrorInvalidArgument);
158
+ }
159
+
160
+ Error allocDualMapping(DualMapping* dm, size_t size, MemoryFlags memoryFlags) noexcept {
161
+ dm->rx = nullptr;
162
+ dm->rw = nullptr;
163
+
164
+ if (size == 0)
165
+ return DebugUtils::errored(kErrorInvalidArgument);
166
+
167
+ ScopedHandle handle;
168
+ handle.value = ::CreateFileMappingW(
169
+ INVALID_HANDLE_VALUE,
170
+ nullptr,
171
+ PAGE_EXECUTE_READWRITE,
172
+ (DWORD)(uint64_t(size) >> 32),
173
+ (DWORD)(size & 0xFFFFFFFFu),
174
+ nullptr);
175
+
176
+ if (ASMJIT_UNLIKELY(!handle.value))
177
+ return DebugUtils::errored(kErrorOutOfMemory);
178
+
179
+ void* ptr[2];
180
+ for (uint32_t i = 0; i < 2; i++) {
181
+ MemoryFlags accessFlags = memoryFlags & ~dualMappingFilter[i];
182
+ DWORD desiredAccess = desiredAccessFromMemoryFlags(accessFlags);
183
+ ptr[i] = ::MapViewOfFile(handle.value, desiredAccess, 0, 0, size);
184
+
185
+ if (ptr[i] == nullptr) {
186
+ if (i == 0)
187
+ ::UnmapViewOfFile(ptr[0]);
188
+ return DebugUtils::errored(kErrorOutOfMemory);
189
+ }
190
+ }
191
+
192
+ dm->rx = ptr[0];
193
+ dm->rw = ptr[1];
194
+ return kErrorOk;
195
+ }
196
+
197
+ Error releaseDualMapping(DualMapping* dm, size_t size) noexcept {
198
+ DebugUtils::unused(size);
199
+ bool failed = false;
200
+
201
+ if (!::UnmapViewOfFile(dm->rx))
202
+ failed = true;
203
+
204
+ if (dm->rx != dm->rw && !UnmapViewOfFile(dm->rw))
205
+ failed = true;
206
+
207
+ if (failed)
208
+ return DebugUtils::errored(kErrorInvalidArgument);
209
+
210
+ dm->rx = nullptr;
211
+ dm->rw = nullptr;
212
+ return kErrorOk;
213
+ }
214
+
215
+ #endif
216
+
217
+ // Virtual Memory [Posix]
218
+ // ======================
219
+
220
+ #if !defined(_WIN32)
221
+
222
+ static void getVMInfo(Info& vmInfo) noexcept {
223
+ uint32_t pageSize = uint32_t(::getpagesize());
224
+
225
+ vmInfo.pageSize = pageSize;
226
+ vmInfo.pageGranularity = Support::max<uint32_t>(pageSize, 65536);
227
+ }
228
+
229
+ #if !defined(SHM_ANON)
230
+ static const char* getTmpDir() noexcept {
231
+ const char* tmpDir = getenv("TMPDIR");
232
+ return tmpDir ? tmpDir : "/tmp";
233
+ }
234
+ #endif
235
+
236
+ // Translates libc errors specific to VirtualMemory mapping to `asmjit::Error`.
237
+ static Error asmjitErrorFromErrno(int e) noexcept {
238
+ switch (e) {
239
+ case EACCES:
240
+ case EAGAIN:
241
+ case ENODEV:
242
+ case EPERM:
243
+ return kErrorInvalidState;
244
+
245
+ case EFBIG:
246
+ case ENOMEM:
247
+ case EOVERFLOW:
248
+ return kErrorOutOfMemory;
249
+
250
+ case EMFILE:
251
+ case ENFILE:
252
+ return kErrorTooManyHandles;
253
+
254
+ default:
255
+ return kErrorInvalidArgument;
256
+ }
257
+ }
258
+
259
+ // Some operating systems don't allow /dev/shm to be executable. On Linux this happens when /dev/shm is mounted with
260
+ // 'noexec', which is enforced by systemd. Other operating systems like MacOS also restrict executable permissions
261
+ // regarding /dev/shm, so we use a runtime detection before attempting to allocate executable memory. Sometimes we
262
+ // don't need the detection as we know it would always result in `ShmStrategy::kTmpDir`.
263
+ enum class ShmStrategy : uint32_t {
264
+ kUnknown = 0,
265
+ kDevShm = 1,
266
+ kTmpDir = 2
267
+ };
268
+
269
+ class AnonymousMemory {
270
+ public:
271
+ enum FileType : uint32_t {
272
+ kFileTypeNone,
273
+ kFileTypeShm,
274
+ kFileTypeTmp
275
+ };
276
+
277
+ int _fd;
278
+ FileType _fileType;
279
+ StringTmp<128> _tmpName;
280
+
281
+ inline AnonymousMemory() noexcept
282
+ : _fd(-1),
283
+ _fileType(kFileTypeNone),
284
+ _tmpName() {}
285
+
286
+ inline ~AnonymousMemory() noexcept {
287
+ unlink();
288
+ close();
289
+ }
290
+
291
+ inline int fd() const noexcept { return _fd; }
292
+
293
+ Error open(bool preferTmpOverDevShm) noexcept {
294
+ #if defined(__linux__) && defined(__NR_memfd_create)
295
+ // Linux specific 'memfd_create' - if the syscall returns `ENOSYS` it means
296
+ // it's not available and we will never call it again (would be pointless).
297
+
298
+ // Zero initialized, if ever changed to '1' that would mean the syscall is not
299
+ // available and we must use `shm_open()` and `shm_unlink()`.
300
+ static volatile uint32_t memfd_create_not_supported;
301
+
302
+ if (!memfd_create_not_supported) {
303
+ _fd = (int)syscall(__NR_memfd_create, "vmem", 0);
304
+ if (ASMJIT_LIKELY(_fd >= 0))
305
+ return kErrorOk;
306
+
307
+ int e = errno;
308
+ if (e == ENOSYS)
309
+ memfd_create_not_supported = 1;
310
+ else
311
+ return DebugUtils::errored(asmjitErrorFromErrno(e));
312
+ }
313
+ #endif
314
+
315
+ #if defined(SHM_ANON)
316
+ // Originally FreeBSD extension, apparently works in other BSDs too.
317
+ DebugUtils::unused(preferTmpOverDevShm);
318
+ _fd = ::shm_open(SHM_ANON, O_RDWR | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR);
319
+
320
+ if (ASMJIT_LIKELY(_fd >= 0))
321
+ return kErrorOk;
322
+ else
323
+ return DebugUtils::errored(asmjitErrorFromErrno(errno));
324
+ #else
325
+ // POSIX API. We have to generate somehow a unique name. This is nothing cryptographic, just using a bit from
326
+ // the stack address to always have a different base for different threads (as threads have their own stack)
327
+ // and retries for avoiding collisions. We use `shm_open()` with flags that require creation of the file so we
328
+ // never open an existing shared memory.
329
+ static std::atomic<uint32_t> internalCounter;
330
+ const char* kShmFormat = "/shm-id-%016llX";
331
+
332
+ uint32_t kRetryCount = 100;
333
+ uint64_t bits = ((uintptr_t)(void*)this) & 0x55555555u;
334
+
335
+ for (uint32_t i = 0; i < kRetryCount; i++) {
336
+ bits -= uint64_t(OSUtils::getTickCount()) * 773703683;
337
+ bits = ((bits >> 14) ^ (bits << 6)) + uint64_t(++internalCounter) * 10619863;
338
+
339
+ bool useTmp = !ASMJIT_VM_SHM_DETECT || preferTmpOverDevShm;
340
+
341
+ if (useTmp) {
342
+ _tmpName.assign(getTmpDir());
343
+ _tmpName.appendFormat(kShmFormat, (unsigned long long)bits);
344
+ _fd = ::open(_tmpName.data(), O_RDWR | O_CREAT | O_EXCL, 0);
345
+ if (ASMJIT_LIKELY(_fd >= 0)) {
346
+ _fileType = kFileTypeTmp;
347
+ return kErrorOk;
348
+ }
349
+ }
350
+ #if ASMJIT_VM_SHM_AVAILABLE
351
+ else {
352
+ _tmpName.assignFormat(kShmFormat, (unsigned long long)bits);
353
+ _fd = ::shm_open(_tmpName.data(), O_RDWR | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR);
354
+ if (ASMJIT_LIKELY(_fd >= 0)) {
355
+ _fileType = kFileTypeShm;
356
+ return kErrorOk;
357
+ }
358
+ }
359
+ #endif
360
+
361
+ int e = errno;
362
+ if (e != EEXIST)
363
+ return DebugUtils::errored(asmjitErrorFromErrno(e));
364
+ }
365
+
366
+ return DebugUtils::errored(kErrorFailedToOpenAnonymousMemory);
367
+ #endif
368
+ }
369
+
370
+ void unlink() noexcept {
371
+ FileType type = _fileType;
372
+ _fileType = kFileTypeNone;
373
+
374
+ #if ASMJIT_VM_SHM_AVAILABLE
375
+ if (type == kFileTypeShm) {
376
+ ::shm_unlink(_tmpName.data());
377
+ return;
378
+ }
379
+ #endif
380
+
381
+ if (type == kFileTypeTmp) {
382
+ ::unlink(_tmpName.data());
383
+ return;
384
+ }
385
+ }
386
+
387
+ void close() noexcept {
388
+ if (_fd >= 0) {
389
+ ::close(_fd);
390
+ _fd = -1;
391
+ }
392
+ }
393
+
394
+ Error allocate(size_t size) noexcept {
395
+ // TODO: Improve this by using `posix_fallocate()` when available.
396
+ if (ftruncate(_fd, off_t(size)) != 0)
397
+ return DebugUtils::errored(asmjitErrorFromErrno(errno));
398
+
399
+ return kErrorOk;
400
+ }
401
+ };
402
+
403
+ // Returns `mmap()` protection flags from \ref MemoryFlags.
404
+ static int mmProtFromMemoryFlags(MemoryFlags memoryFlags) noexcept {
405
+ int protection = 0;
406
+ if (Support::test(memoryFlags, MemoryFlags::kAccessRead)) protection |= PROT_READ;
407
+ if (Support::test(memoryFlags, MemoryFlags::kAccessWrite)) protection |= PROT_READ | PROT_WRITE;
408
+ if (Support::test(memoryFlags, MemoryFlags::kAccessExecute)) protection |= PROT_READ | PROT_EXEC;
409
+ return protection;
410
+ }
411
+
412
+ #if defined(__APPLE__)
413
+ // Detects whether the current process is hardened, which means that pages that have WRITE and EXECUTABLE flags cannot
414
+ // be allocated without MAP_JIT flag.
415
+ static inline bool hasHardenedRuntimeMacOS() noexcept {
416
+ #if TARGET_OS_OSX && ASMJIT_ARCH_ARM >= 64
417
+ // MacOS on AArch64 has always hardened runtime enabled.
418
+ return true;
419
+ #else
420
+ static std::atomic<uint32_t> globalHardenedFlag;
421
+
422
+ enum HardenedFlag : uint32_t {
423
+ kHardenedFlagUnknown = 0,
424
+ kHardenedFlagDisabled = 1,
425
+ kHardenedFlagEnabled = 2
426
+ };
427
+
428
+ uint32_t flag = globalHardenedFlag.load();
429
+ if (flag == kHardenedFlagUnknown) {
430
+ size_t pageSize = ::getpagesize();
431
+
432
+ void* ptr = mmap(nullptr, pageSize, PROT_WRITE | PROT_EXEC, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
433
+ if (ptr == MAP_FAILED) {
434
+ flag = kHardenedFlagEnabled;
435
+ }
436
+ else {
437
+ flag = kHardenedFlagDisabled;
438
+ munmap(ptr, pageSize);
439
+ }
440
+ globalHardenedFlag.store(flag);
441
+ }
442
+
443
+ return flag == kHardenedFlagEnabled;
444
+ #endif
445
+ }
446
+
447
+ static inline bool hasMapJitSupportMacOS() noexcept {
448
+ #if TARGET_OS_OSX && ASMJIT_ARCH_ARM >= 64
449
+ // MacOS for 64-bit AArch architecture always uses hardened runtime. Some documentation can be found here:
450
+ // - https://developer.apple.com/documentation/apple_silicon/porting_just-in-time_compilers_to_apple_silicon
451
+ return true;
452
+ #elif TARGET_OS_OSX
453
+ // MAP_JIT flag required to run unsigned JIT code is only supported by kernel version 10.14+ (Mojave) and IOS.
454
+ static std::atomic<uint32_t> globalVersion;
455
+
456
+ int ver = globalVersion.load();
457
+ if (!ver) {
458
+ struct utsname osname {};
459
+ uname(&osname);
460
+ ver = atoi(osname.release);
461
+ globalVersion.store(ver);
462
+ }
463
+ return ver >= 18;
464
+ #else
465
+ // Assume it's available.
466
+ return true;
467
+ #endif
468
+ }
469
+ #endif // __APPLE__
470
+
471
+ // Detects whether the current process is hardened, which means that pages that have WRITE and EXECUTABLE flags
472
+ // cannot be normally allocated. On MacOS such allocation requires MAP_JIT flag.
473
+ static inline bool hasHardenedRuntime() noexcept {
474
+ #if defined(__APPLE__)
475
+ return hasHardenedRuntimeMacOS();
476
+ #else
477
+ return false;
478
+ #endif
479
+ }
480
+
481
+ // Detects whether MAP_JIT is available.
482
+ static inline bool hasMapJitSupport() noexcept {
483
+ #if defined(__APPLE__)
484
+ return hasMapJitSupportMacOS();
485
+ #else
486
+ return false;
487
+ #endif
488
+ }
489
+
490
+ // Returns either MAP_JIT or 0 based on `flags` and the host operating system.
491
+ static inline int mmMapJitFromMemoryFlags(MemoryFlags memoryFlags) noexcept {
492
+ #if defined(__APPLE__)
493
+ // Always use MAP_JIT flag if user asked for it (could be used for testing on non-hardened processes) and detect
494
+ // whether it must be used when the process is actually hardened (in that case it doesn't make sense to rely on
495
+ // user `memoryFlags`).
496
+ bool useMapJit = Support::test(memoryFlags, MemoryFlags::kMMapEnableMapJit) || hasHardenedRuntime();
497
+ if (useMapJit)
498
+ return hasMapJitSupport() ? int(MAP_JIT) : 0;
499
+ else
500
+ return 0;
501
+ #else
502
+ DebugUtils::unused(memoryFlags);
503
+ return 0;
504
+ #endif
505
+ }
506
+
507
+ // Returns BSD-specific `PROT_MAX()` flags.
508
+ static inline int mmMaxProtFromMemoryFlags(MemoryFlags memoryFlags) noexcept {
509
+ #if defined(PROT_MAX)
510
+ static constexpr uint32_t kMaxProtShift = Support::ConstCTZ<uint32_t(MemoryFlags::kMMapMaxAccessRead)>::value;
511
+
512
+ if (Support::test(memoryFlags, MemoryFlags::kMMapMaxAccessReadWrite | MemoryFlags::kMMapMaxAccessExecute))
513
+ return PROT_MAX(mmProtFromMemoryFlags((MemoryFlags)(uint32_t(memoryFlags) >> kMaxProtShift)));
514
+ else
515
+ return 0;
516
+ #else
517
+ DebugUtils::unused(memoryFlags);
518
+ return 0;
519
+ #endif
520
+ }
521
+
522
+ #if ASMJIT_VM_SHM_DETECT
523
+ static Error detectShmStrategy(ShmStrategy* strategyOut) noexcept {
524
+ AnonymousMemory anonMem;
525
+ Info vmInfo = info();
526
+
527
+ ASMJIT_PROPAGATE(anonMem.open(false));
528
+ ASMJIT_PROPAGATE(anonMem.allocate(vmInfo.pageSize));
529
+
530
+ void* ptr = mmap(nullptr, vmInfo.pageSize, PROT_READ | PROT_EXEC, MAP_SHARED, anonMem.fd(), 0);
531
+ if (ptr == MAP_FAILED) {
532
+ int e = errno;
533
+ if (e == EINVAL) {
534
+ *strategyOut = ShmStrategy::kTmpDir;
535
+ return kErrorOk;
536
+ }
537
+ return DebugUtils::errored(asmjitErrorFromErrno(e));
538
+ }
539
+ else {
540
+ munmap(ptr, vmInfo.pageSize);
541
+ *strategyOut = ShmStrategy::kDevShm;
542
+ return kErrorOk;
543
+ }
544
+ }
545
+ #endif
546
+
547
+ static Error getShmStrategy(ShmStrategy* strategyOut) noexcept {
548
+ #if ASMJIT_VM_SHM_DETECT
549
+ // Initially don't assume anything. It has to be tested whether '/dev/shm' was mounted with 'noexec' flag or not.
550
+ static std::atomic<uint32_t> globalShmStrategy;
551
+
552
+ ShmStrategy strategy = static_cast<ShmStrategy>(globalShmStrategy.load());
553
+ if (strategy == ShmStrategy::kUnknown) {
554
+ ASMJIT_PROPAGATE(detectShmStrategy(&strategy));
555
+ globalShmStrategy.store(static_cast<uint32_t>(strategy));
556
+ }
557
+
558
+ *strategyOut = strategy;
559
+ return kErrorOk;
560
+ #else
561
+ *strategyOut = ShmStrategy::kTmpDir;
562
+ return kErrorOk;
563
+ #endif
564
+ }
565
+
566
+ static HardenedRuntimeFlags getHardenedRuntimeFlags() noexcept {
567
+ HardenedRuntimeFlags hrFlags = HardenedRuntimeFlags::kNone;
568
+
569
+ if (hasHardenedRuntime())
570
+ hrFlags |= HardenedRuntimeFlags::kEnabled;
571
+
572
+ if (hasMapJitSupport())
573
+ hrFlags |= HardenedRuntimeFlags::kMapJit;
574
+
575
+ return hrFlags;
576
+ }
577
+
578
+ Error alloc(void** p, size_t size, MemoryFlags memoryFlags) noexcept {
579
+ *p = nullptr;
580
+ if (size == 0)
581
+ return DebugUtils::errored(kErrorInvalidArgument);
582
+
583
+ int protection = mmProtFromMemoryFlags(memoryFlags) | mmMaxProtFromMemoryFlags(memoryFlags);
584
+ int mmFlags = MAP_PRIVATE | MAP_ANONYMOUS | mmMapJitFromMemoryFlags(memoryFlags);
585
+
586
+ void* ptr = mmap(nullptr, size, protection, mmFlags, -1, 0);
587
+ if (ptr == MAP_FAILED)
588
+ return DebugUtils::errored(kErrorOutOfMemory);
589
+
590
+ *p = ptr;
591
+ return kErrorOk;
592
+ }
593
+
594
+ Error release(void* p, size_t size) noexcept {
595
+ if (ASMJIT_UNLIKELY(munmap(p, size) != 0))
596
+ return DebugUtils::errored(kErrorInvalidArgument);
597
+
598
+ return kErrorOk;
599
+ }
600
+
601
+
602
+ Error protect(void* p, size_t size, MemoryFlags memoryFlags) noexcept {
603
+ int protection = mmProtFromMemoryFlags(memoryFlags);
604
+ if (mprotect(p, size, protection) == 0)
605
+ return kErrorOk;
606
+
607
+ return DebugUtils::errored(kErrorInvalidArgument);
608
+ }
609
+
610
+ Error allocDualMapping(DualMapping* dm, size_t size, MemoryFlags memoryFlags) noexcept {
611
+ dm->rx = nullptr;
612
+ dm->rw = nullptr;
613
+
614
+ if (off_t(size) <= 0)
615
+ return DebugUtils::errored(size == 0 ? kErrorInvalidArgument : kErrorTooLarge);
616
+
617
+ bool preferTmpOverDevShm = Support::test(memoryFlags, MemoryFlags::kMappingPreferTmp);
618
+ if (!preferTmpOverDevShm) {
619
+ ShmStrategy strategy;
620
+ ASMJIT_PROPAGATE(getShmStrategy(&strategy));
621
+ preferTmpOverDevShm = (strategy == ShmStrategy::kTmpDir);
622
+ }
623
+
624
+ AnonymousMemory anonMem;
625
+ ASMJIT_PROPAGATE(anonMem.open(preferTmpOverDevShm));
626
+ ASMJIT_PROPAGATE(anonMem.allocate(size));
627
+
628
+ void* ptr[2];
629
+ for (uint32_t i = 0; i < 2; i++) {
630
+ MemoryFlags accessFlags = memoryFlags & ~dualMappingFilter[i];
631
+ int protection = mmProtFromMemoryFlags(accessFlags) | mmMaxProtFromMemoryFlags(accessFlags);
632
+
633
+ ptr[i] = mmap(nullptr, size, protection, MAP_SHARED, anonMem.fd(), 0);
634
+ if (ptr[i] == MAP_FAILED) {
635
+ // Get the error now before `munmap()` has a chance to clobber it.
636
+ int e = errno;
637
+ if (i == 1)
638
+ munmap(ptr[0], size);
639
+ return DebugUtils::errored(asmjitErrorFromErrno(e));
640
+ }
641
+ }
642
+
643
+ dm->rx = ptr[0];
644
+ dm->rw = ptr[1];
645
+ return kErrorOk;
646
+ }
647
+
648
+ Error releaseDualMapping(DualMapping* dm, size_t size) noexcept {
649
+ Error err = release(dm->rx, size);
650
+ if (dm->rx != dm->rw)
651
+ err |= release(dm->rw, size);
652
+
653
+ if (err)
654
+ return DebugUtils::errored(kErrorInvalidArgument);
655
+
656
+ dm->rx = nullptr;
657
+ dm->rw = nullptr;
658
+ return kErrorOk;
659
+ }
660
+ #endif
661
+
662
+ // Virtual Memory - Flush Instruction Cache
663
+ // ========================================
664
+
665
+ void flushInstructionCache(void* p, size_t size) noexcept {
666
+ #if ASMJIT_ARCH_X86
667
+ // X86/X86_64 architecture doesn't require to do anything to flush instruction cache.
668
+ DebugUtils::unused(p, size);
669
+ #elif defined(__APPLE__)
670
+ sys_icache_invalidate(p, size);
671
+ #elif defined(_WIN32)
672
+ // Windows has a built-in support in `kernel32.dll`.
673
+ FlushInstructionCache(GetCurrentProcess(), p, size);
674
+ #elif defined(__GNUC__)
675
+ char* start = static_cast<char*>(p);
676
+ char* end = start + size;
677
+ __builtin___clear_cache(start, end);
678
+ #else
679
+ #pragma message("asmjit::VirtMem::flushInstructionCache() doesn't have implementation for the target OS and compiler")
680
+ DebugUtils::unused(p, size);
681
+ #endif
682
+ }
683
+
684
+ // Virtual Memory - Memory Info
685
+ // ============================
686
+
687
+ Info info() noexcept {
688
+ static std::atomic<uint32_t> vmInfoInitialized;
689
+ static Info vmInfo;
690
+
691
+ if (!vmInfoInitialized.load()) {
692
+ Info localMemInfo;
693
+ getVMInfo(localMemInfo);
694
+
695
+ vmInfo = localMemInfo;
696
+ vmInfoInitialized.store(1u);
697
+ }
698
+
699
+ return vmInfo;
700
+ }
701
+
702
+ // Virtual Memory - Hardened Runtime Info
703
+ // ======================================
704
+
705
+ HardenedRuntimeInfo hardenedRuntimeInfo() noexcept {
706
+ return HardenedRuntimeInfo { getHardenedRuntimeFlags() };
707
+ }
708
+
709
+ // Virtual Memory - Project JIT Memory
710
+ // ===================================
711
+
712
+ void protectJitMemory(ProtectJitAccess access) noexcept {
713
+ #if defined(ASMJIT_HAS_PTHREAD_JIT_WRITE_PROTECT_NP)
714
+ pthread_jit_write_protect_np(static_cast<uint32_t>(access));
715
+ #else
716
+ DebugUtils::unused(access);
717
+ #endif
718
+ }
719
+
720
+ ASMJIT_END_SUB_NAMESPACE
721
+
722
+ #endif