@psnext/slingcli 2.4.20260526-1 → 2.4.20260527-2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (227) hide show
  1. package/bin/sling.js +4 -1
  2. package/node_modules/@aws-sdk/core/package.json +2 -2
  3. package/node_modules/@aws-sdk/credential-provider-env/package.json +2 -2
  4. package/node_modules/@aws-sdk/credential-provider-http/dist-cjs/fromHttp/fromHttp.js +12 -6
  5. package/node_modules/@aws-sdk/credential-provider-http/dist-es/fromHttp/fromHttp.js +12 -6
  6. package/node_modules/@aws-sdk/credential-provider-http/package.json +3 -2
  7. package/node_modules/@aws-sdk/credential-provider-ini/package.json +9 -9
  8. package/node_modules/@aws-sdk/credential-provider-login/package.json +3 -3
  9. package/node_modules/@aws-sdk/credential-provider-node/package.json +7 -7
  10. package/node_modules/@aws-sdk/credential-provider-process/package.json +2 -2
  11. package/node_modules/@aws-sdk/credential-provider-sso/node_modules/@aws-sdk/token-providers/package.json +3 -3
  12. package/node_modules/@aws-sdk/credential-provider-sso/package.json +4 -4
  13. package/node_modules/@aws-sdk/credential-provider-web-identity/package.json +3 -3
  14. package/node_modules/@aws-sdk/middleware-websocket/package.json +2 -2
  15. package/node_modules/@aws-sdk/nested-clients/dist-cjs/submodules/cognito-identity/index.js +1 -1
  16. package/node_modules/@aws-sdk/nested-clients/dist-cjs/submodules/signin/index.js +1 -1
  17. package/node_modules/@aws-sdk/nested-clients/dist-cjs/submodules/sso/index.js +1 -1
  18. package/node_modules/@aws-sdk/nested-clients/dist-cjs/submodules/sso-oidc/index.js +1 -1
  19. package/node_modules/@aws-sdk/nested-clients/dist-cjs/submodules/sts/index.js +1 -1
  20. package/node_modules/@aws-sdk/nested-clients/package.json +3 -3
  21. package/node_modules/@aws-sdk/signature-v4-multi-region/package.json +1 -2
  22. package/node_modules/@aws-sdk/xml-builder/package.json +2 -2
  23. package/node_modules/@earendil-works/pi-agent-core/dist/harness/compaction/compaction.js +18 -24
  24. package/node_modules/@earendil-works/pi-agent-core/package.json +2 -2
  25. package/node_modules/@earendil-works/pi-ai/dist/cli.js +14 -0
  26. package/node_modules/@earendil-works/pi-ai/dist/models.generated.js +73 -58
  27. package/node_modules/@earendil-works/pi-ai/dist/providers/amazon-bedrock.js +2 -1
  28. package/node_modules/@earendil-works/pi-ai/dist/providers/anthropic.js +8 -22
  29. package/node_modules/@earendil-works/pi-ai/dist/providers/azure-openai-responses.js +1 -1
  30. package/node_modules/@earendil-works/pi-ai/dist/providers/images/openrouter.js +1 -1
  31. package/node_modules/@earendil-works/pi-ai/dist/providers/openai-codex-responses.js +60 -40
  32. package/node_modules/@earendil-works/pi-ai/dist/providers/openai-completions.js +1 -1
  33. package/node_modules/@earendil-works/pi-ai/dist/providers/openai-responses.js +1 -1
  34. package/node_modules/@earendil-works/pi-ai/dist/utils/oauth/device-code.js +55 -0
  35. package/node_modules/@earendil-works/pi-ai/dist/utils/oauth/github-copilot.js +45 -69
  36. package/node_modules/@earendil-works/pi-ai/dist/utils/oauth/index.js +1 -0
  37. package/node_modules/@earendil-works/pi-ai/dist/utils/overflow.js +5 -2
  38. package/node_modules/@earendil-works/pi-ai/package.json +4 -3
  39. package/node_modules/@earendil-works/pi-coding-agent/dist/cli/file-processor.js +2 -3
  40. package/node_modules/@earendil-works/pi-coding-agent/dist/config.js +18 -12
  41. package/node_modules/@earendil-works/pi-coding-agent/dist/core/agent-session-runtime.js +2 -1
  42. package/node_modules/@earendil-works/pi-coding-agent/dist/core/agent-session-services.js +3 -2
  43. package/node_modules/@earendil-works/pi-coding-agent/dist/core/agent-session.js +8 -2
  44. package/node_modules/@earendil-works/pi-coding-agent/dist/core/auth-storage.js +2 -1
  45. package/node_modules/@earendil-works/pi-coding-agent/dist/core/compaction/compaction.js +18 -24
  46. package/node_modules/@earendil-works/pi-coding-agent/dist/core/export-html/index.js +8 -6
  47. package/node_modules/@earendil-works/pi-coding-agent/dist/core/export-html/template.js +6 -3
  48. package/node_modules/@earendil-works/pi-coding-agent/dist/core/extensions/loader.js +12 -29
  49. package/node_modules/@earendil-works/pi-coding-agent/dist/core/model-registry.js +5 -1
  50. package/node_modules/@earendil-works/pi-coding-agent/dist/core/output-guard.js +52 -22
  51. package/node_modules/@earendil-works/pi-coding-agent/dist/core/package-manager.js +63 -36
  52. package/node_modules/@earendil-works/pi-coding-agent/dist/core/prompt-templates.js +6 -20
  53. package/node_modules/@earendil-works/pi-coding-agent/dist/core/resource-loader.js +38 -31
  54. package/node_modules/@earendil-works/pi-coding-agent/dist/core/sdk.js +9 -4
  55. package/node_modules/@earendil-works/pi-coding-agent/dist/core/session-manager.js +32 -24
  56. package/node_modules/@earendil-works/pi-coding-agent/dist/core/settings-manager.js +6 -13
  57. package/node_modules/@earendil-works/pi-coding-agent/dist/core/skills.js +8 -22
  58. package/node_modules/@earendil-works/pi-coding-agent/dist/core/tools/bash.js +54 -53
  59. package/node_modules/@earendil-works/pi-coding-agent/dist/core/tools/edit-diff.js +8 -1
  60. package/node_modules/@earendil-works/pi-coding-agent/dist/core/tools/edit.js +44 -81
  61. package/node_modules/@earendil-works/pi-coding-agent/dist/core/tools/file-mutation-queue.js +27 -12
  62. package/node_modules/@earendil-works/pi-coding-agent/dist/core/tools/find.js +2 -3
  63. package/node_modules/@earendil-works/pi-coding-agent/dist/core/tools/grep.js +3 -3
  64. package/node_modules/@earendil-works/pi-coding-agent/dist/core/tools/ls.js +5 -5
  65. package/node_modules/@earendil-works/pi-coding-agent/dist/core/tools/output-accumulator.js +9 -3
  66. package/node_modules/@earendil-works/pi-coding-agent/dist/core/tools/path-utils.js +39 -21
  67. package/node_modules/@earendil-works/pi-coding-agent/dist/core/tools/read.js +9 -8
  68. package/node_modules/@earendil-works/pi-coding-agent/dist/core/tools/truncate.js +12 -2
  69. package/node_modules/@earendil-works/pi-coding-agent/dist/core/tools/write.js +20 -35
  70. package/node_modules/@earendil-works/pi-coding-agent/dist/main.js +5 -6
  71. package/node_modules/@earendil-works/pi-coding-agent/dist/modes/interactive/components/config-selector.js +1 -1
  72. package/node_modules/@earendil-works/pi-coding-agent/dist/modes/interactive/components/footer.js +14 -5
  73. package/node_modules/@earendil-works/pi-coding-agent/dist/modes/interactive/components/login-dialog.js +29 -4
  74. package/node_modules/@earendil-works/pi-coding-agent/dist/modes/interactive/components/user-message.js +1 -1
  75. package/node_modules/@earendil-works/pi-coding-agent/dist/modes/interactive/interactive-mode.js +4 -4
  76. package/node_modules/@earendil-works/pi-coding-agent/dist/modes/interactive/theme/theme.js +37 -28
  77. package/node_modules/@earendil-works/pi-coding-agent/dist/modes/rpc/rpc-client.js +64 -7
  78. package/node_modules/@earendil-works/pi-coding-agent/dist/modes/rpc/rpc-mode.js +15 -3
  79. package/node_modules/@earendil-works/pi-coding-agent/dist/utils/clipboard-native.js +14 -8
  80. package/node_modules/@earendil-works/pi-coding-agent/dist/utils/image-resize-core.js +124 -0
  81. package/node_modules/@earendil-works/pi-coding-agent/dist/utils/image-resize-worker.js +31 -0
  82. package/node_modules/@earendil-works/pi-coding-agent/dist/utils/image-resize.js +75 -115
  83. package/node_modules/@earendil-works/pi-coding-agent/dist/utils/paths.js +33 -7
  84. package/node_modules/@earendil-works/pi-coding-agent/npm-shrinkwrap.json +13 -26
  85. package/node_modules/@earendil-works/pi-coding-agent/package.json +6 -6
  86. package/node_modules/@earendil-works/pi-tui/dist/components/editor.js +40 -55
  87. package/node_modules/@earendil-works/pi-tui/dist/components/input.js +2 -2
  88. package/node_modules/@earendil-works/pi-tui/dist/components/markdown.js +12 -2
  89. package/node_modules/@earendil-works/pi-tui/dist/native-modifiers.js +53 -0
  90. package/node_modules/@earendil-works/pi-tui/dist/terminal-image.js +4 -1
  91. package/node_modules/@earendil-works/pi-tui/dist/terminal.js +38 -16
  92. package/node_modules/@earendil-works/pi-tui/dist/utils.js +19 -12
  93. package/node_modules/@earendil-works/pi-tui/native/darwin/prebuilds/darwin-arm64/darwin-modifiers.node +0 -0
  94. package/node_modules/@earendil-works/pi-tui/native/darwin/prebuilds/darwin-x64/darwin-modifiers.node +0 -0
  95. package/node_modules/@earendil-works/pi-tui/native/win32/prebuilds/win32-arm64/win32-console-mode.node +0 -0
  96. package/node_modules/@earendil-works/pi-tui/native/win32/prebuilds/win32-x64/win32-console-mode.node +0 -0
  97. package/node_modules/@earendil-works/pi-tui/package.json +3 -5
  98. package/node_modules/@smithy/node-http-handler/package.json +2 -2
  99. package/package.json +6 -6
  100. package/slingshot/index.js +246 -244
  101. package/node_modules/koffi/CHANGELOG.md +0 -1093
  102. package/node_modules/koffi/LICENSE.txt +0 -22
  103. package/node_modules/koffi/README.md +0 -43
  104. package/node_modules/koffi/build/koffi/darwin_arm64/koffi.node +0 -0
  105. package/node_modules/koffi/build/koffi/darwin_x64/koffi.node +0 -0
  106. package/node_modules/koffi/build/koffi/freebsd_arm64/koffi.node +0 -0
  107. package/node_modules/koffi/build/koffi/freebsd_ia32/koffi.node +0 -0
  108. package/node_modules/koffi/build/koffi/freebsd_x64/koffi.node +0 -0
  109. package/node_modules/koffi/build/koffi/linux_arm64/koffi.node +0 -0
  110. package/node_modules/koffi/build/koffi/linux_armhf/koffi.node +0 -0
  111. package/node_modules/koffi/build/koffi/linux_ia32/koffi.node +0 -0
  112. package/node_modules/koffi/build/koffi/linux_loong64/koffi.node +0 -0
  113. package/node_modules/koffi/build/koffi/linux_riscv64d/koffi.node +0 -0
  114. package/node_modules/koffi/build/koffi/linux_x64/koffi.node +0 -0
  115. package/node_modules/koffi/build/koffi/musl_arm64/koffi.node +0 -0
  116. package/node_modules/koffi/build/koffi/musl_x64/koffi.node +0 -0
  117. package/node_modules/koffi/build/koffi/openbsd_ia32/koffi.node +0 -0
  118. package/node_modules/koffi/build/koffi/openbsd_x64/koffi.node +0 -0
  119. package/node_modules/koffi/build/koffi/win32_arm64/koffi.exp +0 -0
  120. package/node_modules/koffi/build/koffi/win32_arm64/koffi.lib +0 -0
  121. package/node_modules/koffi/build/koffi/win32_arm64/koffi.node +0 -0
  122. package/node_modules/koffi/build/koffi/win32_ia32/koffi.exp +0 -0
  123. package/node_modules/koffi/build/koffi/win32_ia32/koffi.lib +0 -0
  124. package/node_modules/koffi/build/koffi/win32_ia32/koffi.node +0 -0
  125. package/node_modules/koffi/build/koffi/win32_x64/koffi.exp +0 -0
  126. package/node_modules/koffi/build/koffi/win32_x64/koffi.lib +0 -0
  127. package/node_modules/koffi/build/koffi/win32_x64/koffi.node +0 -0
  128. package/node_modules/koffi/doc/benchmarks.md +0 -126
  129. package/node_modules/koffi/doc/callbacks.md +0 -210
  130. package/node_modules/koffi/doc/contribute.md +0 -148
  131. package/node_modules/koffi/doc/functions.md +0 -250
  132. package/node_modules/koffi/doc/index.md +0 -61
  133. package/node_modules/koffi/doc/input.md +0 -471
  134. package/node_modules/koffi/doc/migration.md +0 -159
  135. package/node_modules/koffi/doc/misc.md +0 -180
  136. package/node_modules/koffi/doc/output.md +0 -305
  137. package/node_modules/koffi/doc/packaging.md +0 -88
  138. package/node_modules/koffi/doc/platforms.md +0 -36
  139. package/node_modules/koffi/doc/pointers.md +0 -328
  140. package/node_modules/koffi/doc/start.md +0 -118
  141. package/node_modules/koffi/doc/unions.md +0 -186
  142. package/node_modules/koffi/doc/variables.md +0 -102
  143. package/node_modules/koffi/index.d.ts +0 -288
  144. package/node_modules/koffi/index.js +0 -634
  145. package/node_modules/koffi/indirect.js +0 -533
  146. package/node_modules/koffi/lib/native/base/base.cc +0 -11015
  147. package/node_modules/koffi/lib/native/base/base.hh +0 -6003
  148. package/node_modules/koffi/lib/native/base/crc.inc +0 -2214
  149. package/node_modules/koffi/lib/native/base/crc_gen.py +0 -72
  150. package/node_modules/koffi/lib/native/base/mimetypes.inc +0 -1248
  151. package/node_modules/koffi/lib/native/base/mimetypes_gen.py +0 -58
  152. package/node_modules/koffi/lib/native/base/tower.cc +0 -821
  153. package/node_modules/koffi/lib/native/base/tower.hh +0 -81
  154. package/node_modules/koffi/lib/native/base/unicode.inc +0 -408
  155. package/node_modules/koffi/lib/native/base/unicode_gen.py +0 -152
  156. package/node_modules/koffi/package.json +0 -38
  157. package/node_modules/koffi/src/cnoke/LICENSE.txt +0 -22
  158. package/node_modules/koffi/src/cnoke/README.md +0 -99
  159. package/node_modules/koffi/src/cnoke/assets/FindCNoke.cmake +0 -127
  160. package/node_modules/koffi/src/cnoke/assets/toolchains.json +0 -126
  161. package/node_modules/koffi/src/cnoke/assets/win_delay_hook.c +0 -36
  162. package/node_modules/koffi/src/cnoke/cnoke.js +0 -170
  163. package/node_modules/koffi/src/cnoke/package.json +0 -24
  164. package/node_modules/koffi/src/cnoke/src/builder.js +0 -511
  165. package/node_modules/koffi/src/cnoke/src/index.js +0 -10
  166. package/node_modules/koffi/src/cnoke/src/tools.js +0 -407
  167. package/node_modules/koffi/src/koffi/CMakeLists.txt +0 -182
  168. package/node_modules/koffi/src/koffi/src/abi_arm32.cc +0 -1018
  169. package/node_modules/koffi/src/koffi/src/abi_arm32_asm.S +0 -169
  170. package/node_modules/koffi/src/koffi/src/abi_arm64.cc +0 -1295
  171. package/node_modules/koffi/src/koffi/src/abi_arm64_asm.S +0 -195
  172. package/node_modules/koffi/src/koffi/src/abi_arm64_asm.asm +0 -174
  173. package/node_modules/koffi/src/koffi/src/abi_loong64.cc +0 -5
  174. package/node_modules/koffi/src/koffi/src/abi_loong64_asm.S +0 -204
  175. package/node_modules/koffi/src/koffi/src/abi_riscv64.cc +0 -915
  176. package/node_modules/koffi/src/koffi/src/abi_riscv64_asm.S +0 -203
  177. package/node_modules/koffi/src/koffi/src/abi_x64_sysv.cc +0 -939
  178. package/node_modules/koffi/src/koffi/src/abi_x64_sysv_asm.S +0 -231
  179. package/node_modules/koffi/src/koffi/src/abi_x64_win.cc +0 -715
  180. package/node_modules/koffi/src/koffi/src/abi_x64_win_asm.S +0 -166
  181. package/node_modules/koffi/src/koffi/src/abi_x64_win_asm.asm +0 -192
  182. package/node_modules/koffi/src/koffi/src/abi_x86.cc +0 -860
  183. package/node_modules/koffi/src/koffi/src/abi_x86_asm.S +0 -193
  184. package/node_modules/koffi/src/koffi/src/abi_x86_asm.asm +0 -177
  185. package/node_modules/koffi/src/koffi/src/call.cc +0 -1326
  186. package/node_modules/koffi/src/koffi/src/call.hh +0 -179
  187. package/node_modules/koffi/src/koffi/src/errno.inc +0 -462
  188. package/node_modules/koffi/src/koffi/src/ffi.cc +0 -2702
  189. package/node_modules/koffi/src/koffi/src/ffi.hh +0 -354
  190. package/node_modules/koffi/src/koffi/src/init.js +0 -105
  191. package/node_modules/koffi/src/koffi/src/parser.cc +0 -220
  192. package/node_modules/koffi/src/koffi/src/parser.hh +0 -54
  193. package/node_modules/koffi/src/koffi/src/util.cc +0 -1807
  194. package/node_modules/koffi/src/koffi/src/util.hh +0 -221
  195. package/node_modules/koffi/src/koffi/src/uv.cc +0 -193
  196. package/node_modules/koffi/src/koffi/src/uv.def +0 -10
  197. package/node_modules/koffi/src/koffi/src/uv.hh +0 -40
  198. package/node_modules/koffi/src/koffi/src/win32.cc +0 -198
  199. package/node_modules/koffi/src/koffi/src/win32.hh +0 -119
  200. package/node_modules/koffi/src/koffi/tools/write_trampolines.js +0 -77
  201. package/node_modules/koffi/vendor/node-addon-api/LICENSE.md +0 -9
  202. package/node_modules/koffi/vendor/node-addon-api/README.md +0 -95
  203. package/node_modules/koffi/vendor/node-addon-api/napi-inl.deprecated.h +0 -186
  204. package/node_modules/koffi/vendor/node-addon-api/napi-inl.h +0 -7033
  205. package/node_modules/koffi/vendor/node-addon-api/napi.h +0 -3309
  206. package/node_modules/koffi/vendor/node-api-headers/LICENSE +0 -21
  207. package/node_modules/koffi/vendor/node-api-headers/README.md +0 -95
  208. package/node_modules/koffi/vendor/node-api-headers/def/js_native_api.def +0 -125
  209. package/node_modules/koffi/vendor/node-api-headers/def/node_api.def +0 -157
  210. package/node_modules/koffi/vendor/node-api-headers/include/js_native_api.h +0 -591
  211. package/node_modules/koffi/vendor/node-api-headers/include/js_native_api_types.h +0 -210
  212. package/node_modules/koffi/vendor/node-api-headers/include/node_api.h +0 -265
  213. package/node_modules/koffi/vendor/node-api-headers/include/node_api_types.h +0 -58
  214. package/node_modules/koffi/vendor/node-api-headers/include/uv/aix.h +0 -32
  215. package/node_modules/koffi/vendor/node-api-headers/include/uv/bsd.h +0 -34
  216. package/node_modules/koffi/vendor/node-api-headers/include/uv/darwin.h +0 -61
  217. package/node_modules/koffi/vendor/node-api-headers/include/uv/errno.h +0 -483
  218. package/node_modules/koffi/vendor/node-api-headers/include/uv/linux.h +0 -34
  219. package/node_modules/koffi/vendor/node-api-headers/include/uv/os390.h +0 -33
  220. package/node_modules/koffi/vendor/node-api-headers/include/uv/posix.h +0 -31
  221. package/node_modules/koffi/vendor/node-api-headers/include/uv/sunos.h +0 -44
  222. package/node_modules/koffi/vendor/node-api-headers/include/uv/threadpool.h +0 -37
  223. package/node_modules/koffi/vendor/node-api-headers/include/uv/tree.h +0 -521
  224. package/node_modules/koffi/vendor/node-api-headers/include/uv/unix.h +0 -512
  225. package/node_modules/koffi/vendor/node-api-headers/include/uv/version.h +0 -43
  226. package/node_modules/koffi/vendor/node-api-headers/include/uv/win.h +0 -698
  227. package/node_modules/koffi/vendor/node-api-headers/include/uv.h +0 -1990
@@ -1,2702 +0,0 @@
1
- // SPDX-License-Identifier: MIT
2
- // SPDX-FileCopyrightText: 2025 Niels Martignène <niels.martignene@protonmail.com>
3
-
4
- #include "lib/native/base/base.hh"
5
- #include "ffi.hh"
6
- #include "call.hh"
7
- #include "parser.hh"
8
- #include "util.hh"
9
- #include "uv.hh"
10
- #if defined(_WIN32)
11
- #include "win32.hh"
12
- #endif
13
- #include "errno.inc"
14
-
15
- #if defined(_WIN32)
16
- #if !defined(NOMINMAX)
17
- #define NOMINMAX
18
- #endif
19
- #if !defined(WIN32_LEAN_AND_MEAN)
20
- #define WIN32_LEAN_AND_MEAN
21
- #endif
22
- #include <windows.h>
23
- #include <ntsecapi.h>
24
- #else
25
- #include <dlfcn.h>
26
- #include <unistd.h>
27
- #include <sys/mman.h>
28
- #if !defined(MAP_STACK)
29
- #define MAP_STACK 0
30
- #endif
31
- #endif
32
- #include <wchar.h>
33
-
34
- #include <napi.h>
35
-
36
- namespace K {
37
-
38
- SharedData shared;
39
-
40
- static thread_local CallData *exec_call;
41
-
42
- extern "C" napi_value SwitchAndRelay(CallData *call, Size idx, uint8_t *sp, uint8_t *saved_sp, Span<uint8_t> *new_stack);
43
-
44
- static bool ChangeSize(const char *name, Napi::Value value, Size min_size, Size max_size, Size *out_size)
45
- {
46
- Napi::Env env = value.Env();
47
-
48
- if (!value.IsNumber()) {
49
- InstanceData *instance = env.GetInstanceData<InstanceData>();
50
-
51
- ThrowError<Napi::TypeError>(env, "Unexpected %1 value for '%2', expected number", GetValueType(instance, value), name);
52
- return false;
53
- }
54
-
55
- int64_t size = value.As<Napi::Number>().Int64Value();
56
-
57
- if (size < min_size || size > max_size) {
58
- ThrowError<Napi::Error>(env, "Setting '%1' must be between %2 and %3", name, FmtMemSize(min_size), FmtMemSize(max_size));
59
- return false;
60
- }
61
-
62
- *out_size = (Size)size;
63
- return true;
64
- }
65
-
66
- static bool ChangeMemorySize(const char *name, Napi::Value value, Size *out_size)
67
- {
68
- const Size MinSize = Kibibytes(1);
69
- const Size MaxSize = Mebibytes(16);
70
-
71
- return ChangeSize(name, value, MinSize, MaxSize, out_size);
72
- }
73
-
74
- static bool ChangeAsyncLimit(const char *name, Napi::Value value, int max, int *out_limit)
75
- {
76
- Napi::Env env = value.Env();
77
-
78
- if (!value.IsNumber()) {
79
- InstanceData *instance = env.GetInstanceData<InstanceData>();
80
-
81
- ThrowError<Napi::TypeError>(env, "Unexpected %1 value for '%2', expected number", GetValueType(instance, value), name);
82
- return false;
83
- }
84
-
85
- int64_t n = value.As<Napi::Number>().Int64Value();
86
-
87
- if (n < 0 || n > max) {
88
- ThrowError<Napi::Error>(env, "Setting '%1' must be between 0 and %2", name, max);
89
- return false;
90
- }
91
-
92
- *out_limit = (int)n;
93
- return true;
94
- }
95
-
96
- static Napi::Value GetSetConfig(const Napi::CallbackInfo &info)
97
- {
98
- Napi::Env env = info.Env();
99
- InstanceData *instance = env.GetInstanceData<InstanceData>();
100
-
101
- if (info.Length()) {
102
- if (instance->memories.len) {
103
- ThrowError<Napi::Error>(env, "Cannot change Koffi configuration once a library has been loaded");
104
- return env.Null();
105
- }
106
-
107
- if (!info[0].IsObject()) {
108
- ThrowError<Napi::TypeError>(env, "Unexpected %1 value for config, expected object", GetValueType(instance, info[0]));
109
- return env.Null();
110
- }
111
-
112
- decltype(instance->config) new_config = instance->config;
113
- int max_async_calls = new_config.resident_async_pools + new_config.max_temporaries;
114
-
115
- Napi::Object obj = info[0].As<Napi::Object>();
116
- Napi::Array keys = GetOwnPropertyNames(obj);
117
-
118
- for (uint32_t i = 0; i < keys.Length(); i++) {
119
- std::string key = keys.Get(i).As<Napi::String>();
120
- Napi::Value value = obj[key];
121
-
122
- if (key == "sync_stack_size") {
123
- if (!ChangeMemorySize(key.c_str(), value, &new_config.sync_stack_size))
124
- return env.Null();
125
- } else if (key == "sync_heap_size") {
126
- if (!ChangeMemorySize(key.c_str(), value, &new_config.sync_heap_size))
127
- return env.Null();
128
- } else if (key == "async_stack_size") {
129
- if (!ChangeMemorySize(key.c_str(), value, &new_config.async_stack_size))
130
- return env.Null();
131
- } else if (key == "async_heap_size") {
132
- if (!ChangeMemorySize(key.c_str(), value, &new_config.async_heap_size))
133
- return env.Null();
134
- } else if (key == "resident_async_pools") {
135
- if (!ChangeAsyncLimit(key.c_str(), value, K_LEN(instance->memories.data) - 1, &new_config.resident_async_pools))
136
- return env.Null();
137
- } else if (key == "max_async_calls") {
138
- if (!ChangeAsyncLimit(key.c_str(), value, MaxAsyncCalls, &max_async_calls))
139
- return env.Null();
140
- } else if (key == "max_type_size") {
141
- if (!ChangeSize(key.c_str(), value, 32, Mebibytes(512), &new_config.max_type_size))
142
- return env.Null();
143
- } else {
144
- ThrowError<Napi::Error>(env, "Unexpected config member '%1'", key.c_str());
145
- return env.Null();
146
- }
147
- }
148
-
149
- if (max_async_calls < new_config.resident_async_pools) {
150
- ThrowError<Napi::Error>(env, "Setting max_async_calls must be >= to resident_async_pools");
151
- return env.Null();
152
- }
153
-
154
- new_config.max_temporaries = max_async_calls - new_config.resident_async_pools;
155
- instance->config = new_config;
156
- }
157
-
158
- Napi::Object obj = Napi::Object::New(env);
159
-
160
- obj.Set("sync_stack_size", instance->config.sync_stack_size);
161
- obj.Set("sync_heap_size", instance->config.sync_heap_size);
162
- obj.Set("async_stack_size", instance->config.async_stack_size);
163
- obj.Set("async_heap_size", instance->config.async_heap_size);
164
- obj.Set("resident_async_pools", instance->config.resident_async_pools);
165
- obj.Set("max_async_calls", instance->config.resident_async_pools + instance->config.max_temporaries);
166
- obj.Set("max_type_size", instance->config.max_type_size);
167
-
168
- return obj;
169
- }
170
-
171
- static Napi::Value GetStats(const Napi::CallbackInfo &info)
172
- {
173
- Napi::Env env = info.Env();
174
- InstanceData *instance = env.GetInstanceData<InstanceData>();
175
-
176
- Napi::Object obj = Napi::Object::New(env);
177
-
178
- obj.Set("disposed", instance->stats.disposed);
179
-
180
- return obj;
181
- }
182
-
183
- static inline bool CheckAlignment(int64_t align)
184
- {
185
- bool valid = (align > 0) && (align <= 8 && !(align & (align - 1)));
186
- return valid;
187
- }
188
-
189
- static bool IsNameValid(const char *name)
190
- {
191
- if (!IsXidStart(name[0]))
192
- return false;
193
-
194
- for (Size i = 1; name[i]; i++) {
195
- if (!IsXidContinue(name[i])) [[unlikely]]
196
- return false;
197
- }
198
-
199
- return true;
200
- }
201
-
202
- static bool MapType(Napi::Env env, InstanceData *instance, const TypeInfo *type, const char *name)
203
- {
204
- if (!IsNameValid(name)) {
205
- ThrowError<Napi::Error>(env, "Invalid type name '%1'", name);
206
- return false;
207
- }
208
-
209
- bool inserted;
210
- instance->types_map.InsertOrGet(name, type, &inserted);
211
-
212
- if (!inserted) {
213
- ThrowError<Napi::Error>(env, "Duplicate type name '%1'", name);
214
- return false;
215
- }
216
-
217
- return true;
218
- }
219
-
220
- static Napi::Value CreateStructType(const Napi::CallbackInfo &info, bool pad)
221
- {
222
- Napi::Env env = info.Env();
223
- InstanceData *instance = env.GetInstanceData<InstanceData>();
224
-
225
- if (info.Length() < 1) {
226
- ThrowError<Napi::TypeError>(env, "Expected 1 or 2 arguments, got %1", info.Length());
227
- return env.Null();
228
- }
229
-
230
- bool skip = (info.Length() > 1);
231
- bool named = skip && !IsNullOrUndefined(info[0]);
232
- bool redefine = named && CheckValueTag(info[0], &TypeInfoMarker);
233
-
234
- if (named && !info[0].IsString() && !redefine) {
235
- ThrowError<Napi::TypeError>(env, "Unexpected %1 value for name, expected string", GetValueType(instance, info[0]));
236
- return env.Null();
237
- }
238
- if (!IsObject(info[skip])) {
239
- ThrowError<Napi::TypeError>(env, "Unexpected %1 value for members, expected object", GetValueType(instance, info[1]));
240
- return env.Null();
241
- }
242
-
243
- Napi::String name = info[0].As<Napi::String>();
244
- Napi::Object obj = info[skip].As<Napi::Object>();
245
- Napi::Array keys = GetOwnPropertyNames(obj);
246
-
247
- K_DEFER_NC(err_guard, count = instance->types.count) {
248
- Size start = count + !skip;
249
-
250
- for (Size i = start; i < instance->types.count; i++) {
251
- const TypeInfo *it = &instance->types[i];
252
- const TypeInfo **ptr = instance->types_map.Find(it->name);
253
-
254
- if (ptr && *ptr == it) {
255
- instance->types_map.Remove(ptr);
256
- }
257
- }
258
-
259
- instance->types.RemoveFrom(count);
260
- };
261
-
262
- TypeInfo *type = instance->types.AppendDefault();
263
- TypeInfo *replace = nullptr;
264
-
265
- if (redefine) {
266
- Napi::External<TypeInfo> external = name.As<Napi::External<TypeInfo>>();
267
- const TypeInfo *raw = external.Data();
268
-
269
- replace = (TypeInfo *)AlignDown(raw, 4);
270
- type->name = replace->name;
271
-
272
- if (replace->primitive != PrimitiveKind::Void || replace == instance->void_type) {
273
- ThrowError<Napi::TypeError>(env, "Cannot redefine non-opaque type %1", replace->name);
274
- return env.Null();
275
- }
276
- } else if (named) {
277
- type->name = DuplicateString(name.Utf8Value().c_str(), &instance->str_alloc).ptr;
278
-
279
- if (!MapType(env, instance, type, type->name))
280
- return env.Null();
281
- } else {
282
- type->name = Fmt(&instance->str_alloc, "<anonymous_%1>", instance->types.count).ptr;
283
- }
284
-
285
- type->primitive = PrimitiveKind::Record;
286
- type->align = 1;
287
- type->flags = (int)TypeFlag::IsIncomplete;
288
-
289
- HashSet<const char *> members;
290
- int64_t size = 0;
291
-
292
- for (uint32_t i = 0; i < keys.Length(); i++) {
293
- RecordMember member = {};
294
-
295
- std::string key = keys.Get(i).As<Napi::String>();
296
- Napi::Value value = obj[key];
297
- int16_t align = 0;
298
-
299
- member.name = DuplicateString(key.c_str(), &instance->str_alloc).ptr;
300
-
301
- if (value.IsArray()) {
302
- Napi::Array array = value.As<Napi::Array>();
303
-
304
- if (array.Length() != 2 || !array.Get(0u).IsNumber()) {
305
- ThrowError<Napi::Error>(env, "Member specifier array must contain alignement value and type");
306
- return env.Null();
307
- }
308
-
309
- int64_t align64 = array.Get(0u).As<Napi::Number>().Int64Value();
310
-
311
- if (!CheckAlignment(align64)) {
312
- ThrowError<Napi::Error>(env, "Alignment of member '%1' must be 1, 2, 4 or 8", member.name);
313
- return env.Null();
314
- }
315
-
316
- value = array[1u];
317
- align = (int16_t)align64;
318
- }
319
-
320
- member.type = ResolveType(value);
321
- if (!member.type)
322
- return env.Null();
323
- if (!CanStoreType(member.type)) {
324
- ThrowError<Napi::TypeError>(env, "Type %1 cannot be used as a member (maybe try %1 *)", member.type->name);
325
- return env.Null();
326
- }
327
-
328
- if (!align) {
329
- align = pad ? member.type->align : 1;
330
- }
331
- member.offset = (int32_t)AlignLen(size, align);
332
-
333
- size = member.offset + member.type->size;
334
- type->align = std::max(type->align, align);
335
-
336
- member.countedby = -1;
337
-
338
- if (size > instance->config.max_type_size) {
339
- ThrowError<Napi::Error>(env, "Struct '%1' size is too high (max = %2)", type->name, FmtMemSize(size));
340
- return env.Null();
341
- }
342
-
343
- if (TestStr(member.name, "_"))
344
- continue;
345
-
346
- if (!IsNameValid(member.name)) {
347
- ThrowError<Napi::Error>(env, "Invalid member name '%1'", member.name);
348
- return env.Null();
349
- }
350
-
351
- bool inserted;
352
- members.InsertOrGet(member.name, &inserted);
353
-
354
- if (!inserted) {
355
- ThrowError<Napi::Error>(env, "Duplicate member '%1' in struct '%2'", member.name, type->name);
356
- return env.Null();
357
- }
358
-
359
- type->members.Append(member);
360
- }
361
-
362
- for (Size i = 0; i < type->members.len; i++) {
363
- RecordMember *member = &type->members[i];
364
- const char *countedby = member->type->countedby;
365
-
366
- if (countedby) {
367
- const RecordMember *by = std::find_if(type->members.begin(), type->members.end(),
368
- [&](const RecordMember &member) { return TestStr(member.name, countedby); });
369
-
370
- if (by == type->members.end()) {
371
- ThrowError<Napi::Error>(env, "Record type %1 does not have member '%2'", type->name, countedby);
372
- return env.Null();
373
- }
374
- if (!IsInteger(by->type)) {
375
- ThrowError<Napi::Error>(env, "Dynamic length member %1 is not an integer", countedby);
376
- return env.Null();
377
- }
378
- if (member->type->primitive == PrimitiveKind::Array && i < type->members.len - 1) {
379
- ThrowError<Napi::Error>(env, "Flexible array '%1' is not the last member of struct", member->name);
380
- return env.Null();
381
- }
382
-
383
- member->countedby = by - type->members.ptr;
384
- }
385
- }
386
-
387
- size = (int32_t)AlignLen(size, type->align);
388
- if (!size) {
389
- ThrowError<Napi::Error>(env, "Empty struct '%1' is not allowed in C", type->name);
390
- return env.Null();
391
- }
392
- type->size = (int32_t)size;
393
-
394
- type->flags &= ~(int)TypeFlag::IsIncomplete;
395
- err_guard.Disable();
396
-
397
- if (replace) {
398
- std::swap(*type, *replace);
399
- type = replace;
400
- }
401
-
402
- return WrapType(env, type);
403
- }
404
-
405
- static Napi::Value CreatePaddedStructType(const Napi::CallbackInfo &info)
406
- {
407
- return CreateStructType(info, true);
408
- }
409
-
410
- static Napi::Value CreatePackedStructType(const Napi::CallbackInfo &info)
411
- {
412
- return CreateStructType(info, false);
413
- }
414
-
415
- static Napi::Value CreateUnionType(const Napi::CallbackInfo &info)
416
- {
417
- Napi::Env env = info.Env();
418
- InstanceData *instance = env.GetInstanceData<InstanceData>();
419
-
420
- if (info.Length() < 1) {
421
- ThrowError<Napi::TypeError>(env, "Expected 1 or 2 arguments, got %1", info.Length());
422
- return env.Null();
423
- }
424
-
425
- bool skip = (info.Length() > 1);
426
- bool named = skip && !IsNullOrUndefined(info[0]);
427
- bool redefine = named && CheckValueTag(info[0], &TypeInfoMarker);
428
-
429
- if (named && !info[0].IsString() && !redefine) {
430
- ThrowError<Napi::TypeError>(env, "Unexpected %1 value for name, expected string", GetValueType(instance, info[0]));
431
- return env.Null();
432
- }
433
- if (!IsObject(info[skip])) {
434
- ThrowError<Napi::TypeError>(env, "Unexpected %1 value for members, expected object", GetValueType(instance, info[1]));
435
- return env.Null();
436
- }
437
-
438
- Napi::String name = info[0].As<Napi::String>();
439
- Napi::Object obj = info[skip].As<Napi::Object>();
440
- Napi::Array keys = GetOwnPropertyNames(obj);
441
-
442
- K_DEFER_NC(err_guard, count = instance->types.count) {
443
- Size start = count + !skip;
444
-
445
- for (Size i = start; i < instance->types.count; i++) {
446
- const TypeInfo *it = &instance->types[i];
447
- const TypeInfo **ptr = instance->types_map.Find(it->name);
448
-
449
- if (ptr && *ptr == it) {
450
- instance->types_map.Remove(ptr);
451
- }
452
- }
453
-
454
- instance->types.RemoveFrom(count);
455
- };
456
-
457
- TypeInfo *type = instance->types.AppendDefault();
458
- TypeInfo *replace = nullptr;
459
-
460
- if (redefine) {
461
- Napi::External<TypeInfo> external = name.As<Napi::External<TypeInfo>>();
462
- const TypeInfo *raw = external.Data();
463
-
464
- replace = (TypeInfo *)AlignDown(raw, 4);
465
- type->name = replace->name;
466
-
467
- if (replace->primitive != PrimitiveKind::Void || replace == instance->void_type) {
468
- ThrowError<Napi::TypeError>(env, "Cannot redefine non-opaque type %1", replace->name);
469
- return env.Null();
470
- }
471
- } else if (named) {
472
- type->name = DuplicateString(name.Utf8Value().c_str(), &instance->str_alloc).ptr;
473
-
474
- if (!MapType(env, instance, type, type->name))
475
- return env.Null();
476
- } else {
477
- type->name = Fmt(&instance->str_alloc, "<anonymous_%1>", instance->types.count).ptr;
478
- }
479
-
480
- type->primitive = PrimitiveKind::Union;
481
- type->align = 1;
482
- type->flags = (int)TypeFlag::IsIncomplete;
483
-
484
- HashSet<const char *> members;
485
- int32_t size = 0;
486
-
487
- for (uint32_t i = 0; i < keys.Length(); i++) {
488
- RecordMember member = {};
489
-
490
- std::string key = keys.Get(i).As<Napi::String>();
491
- Napi::Value value = obj[key];
492
- int16_t align = 0;
493
-
494
- member.name = DuplicateString(key.c_str(), &instance->str_alloc).ptr;
495
-
496
- if (value.IsArray()) {
497
- Napi::Array array = value.As<Napi::Array>();
498
-
499
- if (array.Length() != 2 || !array.Get(0u).IsNumber()) {
500
- ThrowError<Napi::Error>(env, "Member specifier array must contain alignement value and type");
501
- return env.Null();
502
- }
503
-
504
- int64_t align64 = array.Get(0u).As<Napi::Number>().Int64Value();
505
-
506
- if (!CheckAlignment(align64)) {
507
- ThrowError<Napi::Error>(env, "Alignment of member '%1' must be 1, 2, 4 or 8", member.name);
508
- return env.Null();
509
- }
510
-
511
- value = array[1u];
512
- align = (int16_t)align64;
513
- }
514
-
515
- member.type = ResolveType(value);
516
- if (!member.type)
517
- return env.Null();
518
- if (!CanStoreType(member.type)) {
519
- ThrowError<Napi::TypeError>(env, "Type %1 cannot be used as a member (maybe try %1 *)", member.type->name);
520
- return env.Null();
521
- }
522
- if (member.type->countedby) {
523
- ThrowError<Napi::TypeError>(env, "Cannot use dynamic-length array or pointer inside of union");
524
- return env.Null();
525
- }
526
-
527
- align = align ? align : member.type->align;
528
- size = std::max(size, member.type->size);
529
- type->align = std::max(type->align, align);
530
-
531
- member.countedby = -1;
532
-
533
- if (TestStr(member.name, "_"))
534
- continue;
535
-
536
- if (!IsNameValid(member.name)) {
537
- ThrowError<Napi::Error>(env, "Invalid member name '%1'", member.name);
538
- return env.Null();
539
- }
540
-
541
- bool inserted;
542
- members.InsertOrGet(member.name, &inserted);
543
-
544
- if (!inserted) {
545
- ThrowError<Napi::Error>(env, "Duplicate member '%1' in union '%2'", member.name, type->name);
546
- return env.Null();
547
- }
548
-
549
- type->members.Append(member);
550
- }
551
-
552
- size = (int32_t)AlignLen(size, type->align);
553
- if (!size) {
554
- ThrowError<Napi::Error>(env, "Empty union '%1' is not allowed in C", type->name);
555
- return env.Null();
556
- }
557
- type->size = (int32_t)size;
558
-
559
- type->flags &= ~(int)TypeFlag::IsIncomplete;
560
- err_guard.Disable();
561
-
562
- // Union constructor
563
- Napi::Function constructor = MagicUnion::InitClass(env, type);
564
- type->construct.Reset(constructor, 1);
565
-
566
- if (replace) {
567
- std::swap(*type, *replace);
568
- type = replace;
569
- }
570
-
571
- return WrapType(env, type);
572
- }
573
-
574
- Napi::Value InstantiateUnion(const Napi::CallbackInfo &info)
575
- {
576
- Napi::Env env = info.Env();
577
-
578
- if (!info.IsConstructCall()) {
579
- ThrowError<Napi::TypeError>(env, "This function is a constructor and must be called with new");
580
- return env.Null();
581
- }
582
- if (info.Length() < 1) {
583
- ThrowError<Napi::TypeError>(env, "Expected 1 argument, got %1", info.Length());
584
- return env.Null();
585
- }
586
-
587
- const TypeInfo *type = ResolveType(info[0]);
588
- if (!type)
589
- return env.Null();
590
- if (type->primitive != PrimitiveKind::Union) {
591
- ThrowError<Napi::TypeError>(env, "Expected union type, got %1", PrimitiveKindNames[(int)type->primitive]);
592
- return env.Null();
593
- }
594
-
595
- Napi::Object wrapper = type->construct.New({}).As<Napi::Object>();
596
- SetValueTag(wrapper, &MagicUnionMarker);
597
-
598
- return wrapper;
599
- }
600
-
601
- static Napi::Value CreateOpaqueType(const Napi::CallbackInfo &info)
602
- {
603
- Napi::Env env = info.Env();
604
- InstanceData *instance = env.GetInstanceData<InstanceData>();
605
-
606
- bool named = (info.Length() >= 1) && !IsNullOrUndefined(info[0]);
607
-
608
- if (named && !info[0].IsString()) {
609
- ThrowError<Napi::TypeError>(env, "Unexpected %1 value for name, expected string", GetValueType(instance, info[0]));
610
- return env.Null();
611
- }
612
-
613
- Napi::String name = info[0].As<Napi::String>();
614
-
615
- TypeInfo *type = instance->types.AppendDefault();
616
- K_DEFER_N(err_guard) { instance->types.RemoveLast(1); };
617
-
618
- type->name = named ? DuplicateString(name.Utf8Value().c_str(), &instance->str_alloc).ptr
619
- : Fmt(&instance->str_alloc, "<anonymous_%1>", instance->types.count).ptr;
620
-
621
- type->primitive = PrimitiveKind::Void;
622
- type->size = 0;
623
- type->align = 0;
624
-
625
- // If the insert succeeds, we cannot fail anymore
626
- if (named && !MapType(env, instance, type, type->name))
627
- return env.Null();
628
- err_guard.Disable();
629
-
630
- return WrapType(env, type);
631
- }
632
-
633
- static Napi::Value CreatePointerType(const Napi::CallbackInfo &info)
634
- {
635
- Napi::Env env = info.Env();
636
- InstanceData *instance = env.GetInstanceData<InstanceData>();
637
-
638
- if (info.Length() < 1) {
639
- ThrowError<Napi::TypeError>(env, "Expected 1 to 3 arguments, got %1", info.Length());
640
- return env.Null();
641
- }
642
-
643
- bool skip = (info.Length() > 1) && !info[1].IsNumber();
644
- bool named = skip && !IsNullOrUndefined(info[0]);
645
-
646
- if (named && !info[0].IsString()) {
647
- ThrowError<Napi::TypeError>(env, "Unexpected %1 value for name, expected string", GetValueType(instance, info[0]));
648
- return env.Null();
649
- }
650
-
651
- std::string name = named ? info[0].As<Napi::String>() : std::string();
652
-
653
- const TypeInfo *ref = ResolveType(info[skip]);
654
- if (!ref)
655
- return env.Null();
656
-
657
- Napi::Value countedby;
658
- int count = 1;
659
-
660
- if (info.Length() >= 2u + skip) {
661
- if (info[1 + skip].IsString()) {
662
- countedby = info[1 + skip];
663
- } else if (info[1 + skip].IsNumber()) {
664
- count = info[1 + skip].As<Napi::Number>();
665
-
666
- if (count < 1 || count > 4) {
667
- ThrowError<Napi::TypeError>(env, "Value of count must be between 1 and 4");
668
- return env.Null();
669
- }
670
- } else {
671
- ThrowError<Napi::TypeError>(env, "Unexpected %1 value for count, expected number", GetValueType(instance, info[1 + skip]));
672
- return env.Null();
673
- }
674
- }
675
-
676
- TypeInfo *type = MakePointerType(instance, ref, count);
677
- K_ASSERT(type);
678
-
679
- if (named || !countedby.IsEmpty()) {
680
- TypeInfo *copy = instance->types.AppendDefault();
681
- K_DEFER_N(err_guard) { instance->types.RemoveLast(1); };
682
-
683
- memcpy((void *)copy, type, K_SIZE(*type));
684
- copy->name = named ? DuplicateString(name.c_str(), &instance->str_alloc).ptr : copy->name;
685
-
686
- if (!countedby.IsEmpty()) {
687
- Napi::String str = countedby.As<Napi::String>();
688
- copy->countedby = DuplicateString(str.Utf8Value().c_str(), &instance->str_alloc).ptr;
689
- }
690
-
691
- // If the insert succeeds, we cannot fail anymore
692
- if (named && !MapType(env, instance, copy, copy->name))
693
- return env.Null();
694
- err_guard.Disable();
695
-
696
- type = copy;
697
- }
698
-
699
- return WrapType(env, type);
700
- }
701
-
702
- static Napi::Value EncodePointerDirection(const Napi::CallbackInfo &info, int directions)
703
- {
704
- K_ASSERT(directions >= 1 && directions <= 3);
705
-
706
- Napi::Env env = info.Env();
707
-
708
- if (info.Length() < 1) {
709
- ThrowError<Napi::TypeError>(env, "Expected 1 argument, got %1", info.Length());
710
- return env.Null();
711
- }
712
-
713
- const TypeInfo *type = ResolveType(info[0]);
714
- if (!type)
715
- return env.Null();
716
-
717
- if (type->primitive != PrimitiveKind::Pointer &&
718
- type->primitive != PrimitiveKind::String &&
719
- type->primitive != PrimitiveKind::String16 &&
720
- type->primitive != PrimitiveKind::String32) {
721
- ThrowError<Napi::TypeError>(env, "Unexpected %1 type, expected pointer or string type", type->name);
722
- return env.Null();
723
- }
724
-
725
- // Embed direction in unused pointer bits
726
- const TypeInfo *marked = (const TypeInfo *)((uint8_t *)type + directions - 1);
727
-
728
- return WrapType(env, marked);
729
- }
730
-
731
- static Napi::Value MarkIn(const Napi::CallbackInfo &info)
732
- {
733
- return EncodePointerDirection(info, 1);
734
- }
735
-
736
- static Napi::Value MarkOut(const Napi::CallbackInfo &info)
737
- {
738
- return EncodePointerDirection(info, 2);
739
- }
740
-
741
- static Napi::Value MarkInOut(const Napi::CallbackInfo &info)
742
- {
743
- return EncodePointerDirection(info, 3);
744
- }
745
-
746
- static Napi::Value CreateDisposableType(const Napi::CallbackInfo &info)
747
- {
748
- Napi::Env env = info.Env();
749
- InstanceData *instance = env.GetInstanceData<InstanceData>();
750
-
751
- if (info.Length() < 1) {
752
- ThrowError<Napi::TypeError>(env, "Expected 1 or 2 arguments, got %1", info.Length());
753
- return env.Null();
754
- }
755
-
756
- bool skip = (info.Length() > 1) && !info[1].IsFunction();
757
- bool named = skip && !IsNullOrUndefined(info[0]);
758
-
759
- if (named && !info[0].IsString()) {
760
- ThrowError<Napi::TypeError>(env, "Unexpected %1 value for name, expected string", GetValueType(instance, info[0]));
761
- return env.Null();
762
- }
763
-
764
- Napi::String name = info[0].As<Napi::String>();
765
-
766
- const TypeInfo *src = ResolveType(info[skip]);
767
- if (!src)
768
- return env.Null();
769
- if (src->primitive != PrimitiveKind::Pointer &&
770
- src->primitive != PrimitiveKind::String &&
771
- src->primitive != PrimitiveKind::String16 &&
772
- src->primitive != PrimitiveKind::String32) {
773
- ThrowError<Napi::TypeError>(env, "Unexpected %1 type, expected pointer or string type", src->name);
774
- return env.Null();
775
- }
776
- if (src->dispose) {
777
- ThrowError<Napi::TypeError>(env, "Cannot use disposable type '%1' to create new disposable", src->name);
778
- return env.Null();
779
- }
780
-
781
- DisposeFunc *dispose;
782
- Napi::Function dispose_func;
783
- if (info.Length() >= 2u + skip && !IsNullOrUndefined(info[1 + skip])) {
784
- Napi::Function func = info[1 + skip].As<Napi::Function>();
785
-
786
- if (!func.IsFunction()) {
787
- ThrowError<Napi::TypeError>(env, "Unexpected %1 value for func, expected function", GetValueType(instance, func));
788
- return env.Null();
789
- }
790
-
791
- dispose = [](Napi::Env env, const TypeInfo *type, const void *ptr) {
792
- InstanceData *instance = env.GetInstanceData<InstanceData>();
793
- const Napi::FunctionReference &ref = type->dispose_ref;
794
-
795
- Napi::External<void> external = Napi::External<void>::New(env, (void *)ptr);
796
- SetValueTag(external, type->ref.marker);
797
-
798
- Napi::Value self = env.Null();
799
- napi_value args[] = {
800
- external
801
- };
802
-
803
- ref.Call(self, K_LEN(args), args);
804
- instance->stats.disposed++;
805
- };
806
- dispose_func = func;
807
- } else {
808
- dispose = [](Napi::Env env, const TypeInfo *, const void *ptr) {
809
- InstanceData *instance = env.GetInstanceData<InstanceData>();
810
-
811
- free((void *)ptr);
812
- instance->stats.disposed++;
813
- };
814
- }
815
-
816
- TypeInfo *type = instance->types.AppendDefault();
817
- K_DEFER_N(err_guard) { instance->types.RemoveLast(1); };
818
-
819
- memcpy((void *)type, (const void *)src, K_SIZE(*src));
820
- type->members.allocator = GetNullAllocator();
821
-
822
- type->name = named ? DuplicateString(name.Utf8Value().c_str(), &instance->str_alloc).ptr
823
- : Fmt(&instance->str_alloc, "<anonymous_%1>", instance->types.count).ptr;
824
-
825
- type->dispose = dispose;
826
- type->dispose_ref = Napi::Persistent(dispose_func);
827
-
828
- // If the insert succeeds, we cannot fail anymore
829
- if (named && !MapType(env, instance, type, type->name))
830
- return env.Null();
831
- err_guard.Disable();
832
-
833
- return WrapType(env, type);
834
- }
835
-
836
- static inline bool GetExternalPointer(Napi::Env env, Napi::Value value, void **out_ptr)
837
- {
838
- InstanceData *instance = env.GetInstanceData<InstanceData>();
839
-
840
- if (IsNullOrUndefined(value)) {
841
- *out_ptr = 0;
842
- return true;
843
- } else if (IsRawBuffer(value)) {
844
- Span<uint8_t> buffer = GetRawBuffer(value);
845
-
846
- *out_ptr = buffer.ptr;
847
- return true;
848
- } else if (value.IsExternal() && !CheckValueTag(value, &TypeInfoMarker) &&
849
- !CheckValueTag(value, &CastMarker) &&
850
- !CheckValueTag(value, &MagicUnionMarker)) {
851
- Napi::External<void> external = value.As<Napi::External<void>>();
852
- void *ptr = external.Data();
853
-
854
- *out_ptr = ptr;
855
- return true;
856
- } else {
857
- ThrowError<Napi::TypeError>(env, "Unexpected %1 value for ptr, expected external pointer", GetValueType(instance, value));
858
- return false;
859
- }
860
- }
861
-
862
- static Napi::Value CallAlloc(const Napi::CallbackInfo &info)
863
- {
864
- Napi::Env env = info.Env();
865
- InstanceData *instance = env.GetInstanceData<InstanceData>();
866
-
867
- if (info.Length() < 2) {
868
- ThrowError<Napi::TypeError>(env, "Expected 2 arguments, got %1", info.Length());
869
- return env.Null();
870
- }
871
- if (!info[1].IsNumber()) {
872
- ThrowError<Napi::TypeError>(env, "Unexpected %1 value for length, expected number", GetValueType(instance, info[1]));
873
- return env.Null();
874
- }
875
-
876
- const TypeInfo *type = ResolveType(info[0]);
877
- if (!type)
878
- return env.Null();
879
-
880
- if (!type->size) [[unlikely]] {
881
- ThrowError<Napi::TypeError>(env, "Cannot allocate memory for zero-sized type %1", type->name);
882
- return env.Null();
883
- }
884
-
885
- int32_t len = info[1].As<Napi::Number>();
886
-
887
- if (len <= 0) [[unlikely]] {
888
- ThrowError<Napi::Error>(env, "Size must be greater than 0");
889
- return env.Null();
890
- }
891
- if (len > INT32_MAX / type->size) [[unlikely]] {
892
- ThrowError<Napi::Error>(env, "Cannot allocate more than %1 objects of type %2", INT32_MAX / type->size, type->name);
893
- return env.Null();
894
- }
895
-
896
- void *ptr = calloc((size_t)len, (size_t)type->size);
897
-
898
- if (!ptr) [[unlikely]] {
899
- Size size = (Size)(len * type->size);
900
-
901
- ThrowError<Napi::Error>(env, "Failed to allocate %1 of memory", FmtMemSize((Size)size));
902
- return env.Null();
903
- }
904
-
905
- Napi::External<void> external = Napi::External<void>::New(env, ptr);
906
- SetValueTag(external, type);
907
-
908
- return external;
909
- }
910
-
911
- static Napi::Value CallFree(const Napi::CallbackInfo &info)
912
- {
913
- Napi::Env env = info.Env();
914
-
915
- if (info.Length() < 1) {
916
- ThrowError<Napi::TypeError>(env, "Expected 1 argument, got %1", info.Length());
917
- return env.Null();
918
- }
919
-
920
- void *ptr = nullptr;
921
- if (!GetExternalPointer(env, info[0], &ptr))
922
- return env.Null();
923
-
924
- free(ptr);
925
-
926
- return env.Undefined();
927
- }
928
-
929
- static Napi::Value GetOrSetErrNo(const Napi::CallbackInfo &info)
930
- {
931
- Napi::Env env = info.Env();
932
- InstanceData *instance = env.GetInstanceData<InstanceData>();
933
-
934
- if (info.Length() >= 1) {
935
- Napi::Number value = info[0].As<Napi::Number>();
936
-
937
- if (!value.IsNumber()) {
938
- ThrowError<Napi::TypeError>(env, "Unexpected %1 value for errno, expected integer", GetValueType(instance, value));
939
- return env.Null();
940
- }
941
-
942
- errno = value;
943
- }
944
-
945
- Napi::Number ret = Napi::Number::New(env, errno);
946
- return ret;
947
- }
948
-
949
- static Napi::Value CreateArrayType(const Napi::CallbackInfo &info)
950
- {
951
- Napi::Env env = info.Env();
952
- InstanceData *instance = env.GetInstanceData<InstanceData>();
953
-
954
- if (info.Length() < 2) {
955
- ThrowError<Napi::TypeError>(env, "Expected 2 to 4 arguments, got %1", info.Length());
956
- return env.Null();
957
- }
958
-
959
- const TypeInfo *ref = ResolveType(info[0]);
960
- if (!ref)
961
- return env.Null();
962
-
963
- bool dynamic = (info.Length() >= 3) && info[1].IsString();
964
-
965
- if (dynamic && !info[1].IsString()) {
966
- ThrowError<Napi::TypeError>(env, "Unexpected %1 value for countedBy, expected string", GetValueType(instance, info[1]));
967
- return env.Null();
968
- }
969
- if (!info[1 + dynamic].IsNumber()) {
970
- if (info.Length() == 2 && info[1].IsString()) {
971
- ThrowError<Napi::TypeError>(env, "Missing maxLen argument");
972
- } else {
973
- ThrowError<Napi::TypeError>(env, "Unexpected %1 value for %2, expected integer", GetValueType(instance, info[1]), dynamic ? "maxLen" : "len");
974
- }
975
- return env.Null();
976
- }
977
-
978
- int64_t len = info[1 + dynamic].As<Napi::Number>().Int64Value();
979
-
980
- if (len <= 0) {
981
- ThrowError<Napi::TypeError>(env, "Array length must be positive and non-zero");
982
- return env.Null();
983
- }
984
- if (len > instance->config.max_type_size / ref->size) {
985
- ThrowError<Napi::TypeError>(env, "Array length is too high (max = %1)", instance->config.max_type_size / ref->size);
986
- return env.Null();
987
- }
988
-
989
- TypeInfo *type = nullptr;
990
-
991
- if (info.Length() >= 3u + dynamic && !IsNullOrUndefined(info[2 + dynamic])) {
992
- if (!info[2 + dynamic].IsString()) {
993
- ThrowError<Napi::TypeError>(env, "Unexpected %1 value for hint, expected string", GetValueType(instance, info[2]));
994
- return env.Null();
995
- }
996
-
997
- std::string str = info[2 + dynamic].As<Napi::String>();
998
- ArrayHint hint = {};
999
-
1000
- if (str == "Typed" || str == "typed") {
1001
- if (!(ref->flags & (int)TypeFlag::HasTypedArray)) {
1002
- ThrowError<Napi::Error>(env, "Array hint 'Typed' cannot be used with type %1", ref->name);
1003
- return env.Null();
1004
- }
1005
-
1006
- hint = ArrayHint::Typed;
1007
- } else if (str == "Array" || str == "array") {
1008
- hint = ArrayHint::Array;
1009
- } else if (str == "String" || str == "string") {
1010
- if (ref->primitive != PrimitiveKind::Int8 && ref->primitive != PrimitiveKind::Int16) {
1011
- ThrowError<Napi::Error>(env, "Array hint 'String' can only be used with 8 and 16-bit signed integer types");
1012
- return env.Null();
1013
- }
1014
-
1015
- hint = ArrayHint::String;
1016
- } else {
1017
- ThrowError<Napi::Error>(env, "Array conversion hint must be 'Typed', 'Array' or 'String'");
1018
- return env.Null();
1019
- }
1020
-
1021
- type = MakeArrayType(instance, ref, len, hint);
1022
- } else {
1023
- type = MakeArrayType(instance, ref, len);
1024
- }
1025
-
1026
- if (dynamic) {
1027
- Napi::String str = info[1].As<Napi::String>();
1028
- type->countedby = DuplicateString(str.Utf8Value().c_str(), &instance->str_alloc).ptr;
1029
- }
1030
-
1031
- return WrapType(env, type);
1032
- }
1033
-
1034
- static bool ParseClassicFunction(const Napi::CallbackInfo &info, bool concrete, FunctionInfo *out_func)
1035
- {
1036
- K_ASSERT(info.Length() >= 2);
1037
-
1038
- Napi::Env env = info.Env();
1039
- InstanceData *instance = env.GetInstanceData<InstanceData>();
1040
-
1041
- Napi::String name = info[0u].As<Napi::String>();
1042
- Napi::Value ret = info[1u];
1043
- Napi::Array parameters = info[2u].As<Napi::Array>();
1044
-
1045
- // Detect optional call convention
1046
- if (name.IsString() && DetectCallConvention(name.Utf8Value().c_str(), &out_func->convention)) {
1047
- if (info.Length() < 3) {
1048
- ThrowError<Napi::TypeError>(env, "Expected 3 or 4 arguments, got %1", info.Length());
1049
- return false;
1050
- }
1051
-
1052
- name = info[1u].As<Napi::String>();
1053
- ret = info[2u];
1054
- parameters = (info.Length() >= 4 ? info[3u] : env.Null()).As<Napi::Array>();
1055
- }
1056
-
1057
- bool named = parameters.IsArray();
1058
-
1059
- if (named) {
1060
- #if defined(_WIN32)
1061
- if (name.IsNumber()) {
1062
- out_func->ordinal_name = name.As<Napi::Number>().Int32Value();
1063
- name = name.ToString();
1064
- }
1065
- #endif
1066
- if (!name.IsString()) {
1067
- if (!concrete && IsNullOrUndefined(name)) {
1068
- named = false;
1069
- } else {
1070
- ThrowError<Napi::TypeError>(env, "Unexpected %1 value for name, expected string or integer", GetValueType(instance, name));
1071
- return false;
1072
- }
1073
- }
1074
- } else {
1075
- parameters = ret.As<Napi::Array>();
1076
- ret = name;
1077
- }
1078
-
1079
- // Leave anonymous naming responsibility to caller
1080
- out_func->name = named ? DuplicateString(name.Utf8Value().c_str(), &instance->str_alloc).ptr : nullptr;
1081
-
1082
- out_func->ret.type = ResolveType(ret);
1083
- if (!out_func->ret.type)
1084
- return false;
1085
- if (!CanReturnType(out_func->ret.type)) {
1086
- ThrowError<Napi::TypeError>(env, "You are not allowed to directly return %1 values (maybe try %1 *)", out_func->ret.type->name);
1087
- return false;
1088
- }
1089
-
1090
- if (!parameters.IsArray()) {
1091
- ThrowError<Napi::TypeError>(env, "Unexpected %1 value for parameters of '%2', expected an array", GetValueType(instance, parameters), out_func->name);
1092
- return false;
1093
- }
1094
-
1095
- uint32_t parameters_len = parameters.Length();
1096
-
1097
- if (parameters_len) {
1098
- Napi::String str = parameters.Get(parameters_len - 1).As<Napi::String>();
1099
-
1100
- if (str.IsString() && str.Utf8Value() == "...") {
1101
- out_func->variadic = true;
1102
- parameters_len--;
1103
- }
1104
- }
1105
-
1106
- for (uint32_t j = 0; j < parameters_len; j++) {
1107
- ParameterInfo param = {};
1108
-
1109
- param.type = ResolveType(parameters[j], &param.directions);
1110
-
1111
- if (!param.type)
1112
- return false;
1113
- if (!CanPassType(param.type, param.directions)) {
1114
- ThrowError<Napi::TypeError>(env, "Type %1 cannot be used as a parameter", param.type->name);
1115
- return false;
1116
- }
1117
- if (out_func->parameters.len >= MaxParameters) {
1118
- ThrowError<Napi::TypeError>(env, "Functions cannot have more than %1 parameters", MaxParameters);
1119
- return false;
1120
- }
1121
- if ((param.directions & 2) && ++out_func->out_parameters >= MaxParameters) {
1122
- ThrowError<Napi::TypeError>(env, "Functions cannot have more than %1 output parameters", MaxParameters);
1123
- return false;
1124
- }
1125
-
1126
- param.offset = (int8_t)j;
1127
-
1128
- out_func->parameters.Append(param);
1129
- }
1130
-
1131
- out_func->required_parameters = (int8_t)out_func->parameters.len;
1132
-
1133
- return true;
1134
- }
1135
-
1136
- static Napi::Value CreateFunctionType(const Napi::CallbackInfo &info)
1137
- {
1138
- Napi::Env env = info.Env();
1139
- InstanceData *instance = env.GetInstanceData<InstanceData>();
1140
-
1141
- FunctionInfo *func = instance->callbacks.AppendDefault();
1142
- TypeInfo *type = instance->types.AppendDefault();
1143
-
1144
- K_DEFER_N(err_guard) {
1145
- instance->callbacks.RemoveLast(1);
1146
- instance->types.RemoveLast(1);
1147
- };
1148
-
1149
- if (info.Length() >= 2) {
1150
- if (!ParseClassicFunction(info, false, func))
1151
- return env.Null();
1152
- } else if (info.Length() >= 1) {
1153
- if (!info[0].IsString()) {
1154
- ThrowError<Napi::TypeError>(env, "Unexpected %1 value for prototype, expected string", GetValueType(instance, info[0]));
1155
- return env.Null();
1156
- }
1157
-
1158
- std::string proto = info[0u].As<Napi::String>();
1159
- if (!ParsePrototype(env, proto.c_str(), false, func))
1160
- return env.Null();
1161
- } else {
1162
- ThrowError<Napi::TypeError>(env, "Expected 1 to 4 arguments, got %1", info.Length());
1163
- return env.Null();
1164
- }
1165
-
1166
- bool named = func->name;
1167
-
1168
- if (!named) {
1169
- func->name = Fmt(&instance->str_alloc, "<anonymous_%1>", instance->types.count).ptr;
1170
- }
1171
-
1172
- if (!AnalyseFunction(env, instance, func))
1173
- return env.Null();
1174
-
1175
- // Adjust parameter offsets for koffi.call()
1176
- for (ParameterInfo &param: func->parameters) {
1177
- param.offset += 2;
1178
- }
1179
- func->required_parameters += 2;
1180
-
1181
- type->name = func->name;
1182
-
1183
- type->primitive = PrimitiveKind::Prototype;
1184
- type->align = alignof(void *);
1185
- type->size = K_SIZE(void *);
1186
- type->ref.proto = func;
1187
-
1188
- // If the insert succeeds, we cannot fail anymore
1189
- if (named && !MapType(env, instance, type, type->name))
1190
- return env.Null();
1191
- err_guard.Disable();
1192
-
1193
- return WrapType(env, type);
1194
- }
1195
-
1196
- static Napi::Value CreateTypeAlias(const Napi::CallbackInfo &info)
1197
- {
1198
- Napi::Env env = info.Env();
1199
- InstanceData *instance = env.GetInstanceData<InstanceData>();
1200
-
1201
- if (info.Length() < 2) {
1202
- ThrowError<Napi::TypeError>(env, "Expected 2 arguments, got %1", info.Length());
1203
- return env.Null();
1204
- }
1205
- if (!info[0].IsString()) {
1206
- ThrowError<Napi::TypeError>(env, "Unexpected %1 value for name, expected string", GetValueType(instance, info[0]));
1207
- return env.Null();
1208
- }
1209
-
1210
- std::string name = info[0].As<Napi::String>();
1211
- const char *alias = DuplicateString(name.c_str(), &instance->str_alloc).ptr;
1212
-
1213
- const TypeInfo *type = ResolveType(info[1]);
1214
- if (!type)
1215
- return env.Null();
1216
-
1217
- // Alias the type
1218
- if (!MapType(env, instance, type, alias))
1219
- return env.Null();
1220
-
1221
- return WrapType(env, type);
1222
- }
1223
-
1224
- static Napi::Value GetTypeSize(const Napi::CallbackInfo &info)
1225
- {
1226
- Napi::Env env = info.Env();
1227
-
1228
- if (info.Length() < 1) {
1229
- ThrowError<Napi::TypeError>(env, "Expected 1 argument, got %1", info.Length());
1230
- return env.Null();
1231
- }
1232
-
1233
- const TypeInfo *type = ResolveType(info[0]);
1234
- if (!type)
1235
- return env.Null();
1236
-
1237
- return Napi::Number::New(env, type->size);
1238
- }
1239
-
1240
- static Napi::Value GetTypeAlign(const Napi::CallbackInfo &info)
1241
- {
1242
- Napi::Env env = info.Env();
1243
-
1244
- if (info.Length() < 1) {
1245
- ThrowError<Napi::TypeError>(env, "Expected 1 argument, got %1", info.Length());
1246
- return env.Null();
1247
- }
1248
-
1249
- const TypeInfo *type = ResolveType(info[0]);
1250
- if (!type)
1251
- return env.Null();
1252
-
1253
- return Napi::Number::New(env, type->align);
1254
- }
1255
-
1256
- static Napi::Value GetMemberOffset(const Napi::CallbackInfo &info)
1257
- {
1258
- Napi::Env env = info.Env();
1259
- InstanceData *instance = env.GetInstanceData<InstanceData>();
1260
-
1261
- if (info.Length() < 2) {
1262
- ThrowError<Napi::TypeError>(env, "Expected 2 arguments, got %1", info.Length());
1263
- return env.Null();
1264
- }
1265
- if (!info[1].IsString()) {
1266
- ThrowError<Napi::TypeError>(env, "Unexpected %1 value for member, expected string", GetValueType(instance, info[1]));
1267
- return env.Null();
1268
- }
1269
-
1270
- const TypeInfo *type = ResolveType(info[0]);
1271
- if (!type)
1272
- return env.Null();
1273
- if (type->primitive != PrimitiveKind::Record) {
1274
- ThrowError<Napi::TypeError>(env, "The offsetof() function can only be used with record types");
1275
- return env.Null();
1276
- }
1277
-
1278
- std::string name = info[1].As<Napi::String>();
1279
-
1280
- const RecordMember *member = std::find_if(type->members.begin(), type->members.end(),
1281
- [&](const RecordMember &member) { return TestStr(member.name, name.c_str()); });
1282
- if (member == type->members.end()) {
1283
- ThrowError<Napi::Error>(env, "Record type %1 does not have member '%2'", type->name, name.c_str());
1284
- return env.Null();
1285
- }
1286
-
1287
- return Napi::Number::New(env, member->offset);
1288
- }
1289
-
1290
- static Napi::Value GetResolvedType(const Napi::CallbackInfo &info)
1291
- {
1292
- Napi::Env env = info.Env();
1293
-
1294
- if (info.Length() < 1) {
1295
- ThrowError<Napi::TypeError>(env, "Expected 1 argument, got %1", info.Length());
1296
- return env.Null();
1297
- }
1298
-
1299
- const TypeInfo *type = ResolveType(info[0]);
1300
- if (!type)
1301
- return env.Null();
1302
-
1303
- return WrapType(env, type);
1304
- }
1305
-
1306
- static Napi::Value GetTypeDefinition(const Napi::CallbackInfo &info)
1307
- {
1308
- Napi::Env env = info.Env();
1309
-
1310
- if (info.Length() < 1) {
1311
- ThrowError<Napi::TypeError>(env, "Expected 1 argument, got %1", info.Length());
1312
- return env.Null();
1313
- }
1314
-
1315
- const TypeInfo *type = ResolveType(info[0]);
1316
- if (!type)
1317
- return env.Null();
1318
-
1319
- if (type->defn.IsEmpty()) {
1320
- Napi::Object defn = Napi::Object::New(env);
1321
-
1322
- defn.Set("name", Napi::String::New(env, type->name));
1323
- defn.Set("primitive", PrimitiveKindNames[(int)type->primitive]);
1324
- defn.Set("size", Napi::Number::New(env, (double)type->size));
1325
- defn.Set("alignment", Napi::Number::New(env, (double)type->align));
1326
- defn.Set("disposable", Napi::Boolean::New(env, !!type->dispose));
1327
-
1328
- switch (type->primitive) {
1329
- case PrimitiveKind::Void:
1330
- case PrimitiveKind::Bool:
1331
- case PrimitiveKind::Int8:
1332
- case PrimitiveKind::UInt8:
1333
- case PrimitiveKind::Int16:
1334
- case PrimitiveKind::Int16S:
1335
- case PrimitiveKind::UInt16:
1336
- case PrimitiveKind::UInt16S:
1337
- case PrimitiveKind::Int32:
1338
- case PrimitiveKind::Int32S:
1339
- case PrimitiveKind::UInt32:
1340
- case PrimitiveKind::UInt32S:
1341
- case PrimitiveKind::Int64:
1342
- case PrimitiveKind::Int64S:
1343
- case PrimitiveKind::UInt64:
1344
- case PrimitiveKind::UInt64S:
1345
- case PrimitiveKind::String:
1346
- case PrimitiveKind::String16:
1347
- case PrimitiveKind::String32:
1348
- case PrimitiveKind::Float32:
1349
- case PrimitiveKind::Float64:
1350
- case PrimitiveKind::Prototype:
1351
- case PrimitiveKind::Callback: {} break;
1352
-
1353
- case PrimitiveKind::Array: {
1354
- uint32_t len = type->size / type->ref.type->size;
1355
- defn.Set("length", Napi::Number::New(env, (double)len));
1356
- defn.Set("hint", ArrayHintNames[(int)type->hint]);
1357
- } [[fallthrough]];
1358
- case PrimitiveKind::Pointer: {
1359
- Napi::Value value = WrapType(env, type->ref.type);
1360
- defn.Set("ref", value);
1361
- } break;
1362
- case PrimitiveKind::Record:
1363
- case PrimitiveKind::Union: {
1364
- Napi::Object members = Napi::Object::New(env);
1365
-
1366
- for (const RecordMember &member: type->members) {
1367
- Napi::Object obj = Napi::Object::New(env);
1368
-
1369
- obj.Set("name", member.name);
1370
- obj.Set("type", WrapType(env, member.type));
1371
- obj.Set("offset", member.offset);
1372
- if (member.countedby >= 0) {
1373
- obj.Set("countedBy", type->members[member.countedby].name);
1374
- }
1375
-
1376
- members.Set(member.name, obj);
1377
- }
1378
-
1379
- defn.Set("members", members);
1380
- } break;
1381
- }
1382
-
1383
- defn.Freeze();
1384
- type->defn.Reset(defn, 1);
1385
- }
1386
-
1387
- return type->defn.Value();
1388
- }
1389
-
1390
- InstanceMemory *AllocateMemory(InstanceData *instance, Size stack_size, Size heap_size)
1391
- {
1392
- std::lock_guard<std::mutex> lock(instance->mem_mutex);
1393
-
1394
- for (Size i = 1; i < instance->memories.len; i++) {
1395
- InstanceMemory *mem = instance->memories[i];
1396
-
1397
- if (!mem->busy) {
1398
- mem->busy = true;
1399
- return mem;
1400
- }
1401
- }
1402
-
1403
- bool temporary = (instance->memories.len > instance->config.resident_async_pools);
1404
-
1405
- if (temporary && instance->temporaries > instance->config.max_temporaries)
1406
- return nullptr;
1407
-
1408
- InstanceMemory *mem = new InstanceMemory();
1409
- K_DEFER_N(mem_guard) { delete mem; };
1410
-
1411
- stack_size = AlignLen(stack_size, Kibibytes(64));
1412
-
1413
- #if defined(_WIN32)
1414
- // Allocate stack memory
1415
- mem->stack.len = stack_size;
1416
- mem->stack.ptr = (uint8_t *)VirtualAlloc(nullptr, mem->stack.len, MEM_RESERVE | MEM_COMMIT, PAGE_READWRITE);
1417
-
1418
- K_CRITICAL(mem->stack.ptr, "Failed to allocate %1 of memory", mem->stack.len);
1419
- #else
1420
- mem->stack.len = stack_size;
1421
- mem->stack.ptr = (uint8_t *)mmap(nullptr, mem->stack.len, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON | MAP_STACK, -1, 0);
1422
-
1423
- K_CRITICAL(mem->stack.ptr, "Failed to allocate %1 of memory", mem->stack.len);
1424
- #endif
1425
-
1426
- #if defined(__OpenBSD__)
1427
- // Make sure the SP points inside the MAP_STACK area, or (void) functions may crash on OpenBSD i386
1428
- mem->stack.len -= 16;
1429
- #endif
1430
-
1431
- // Keep real stack limits intact, in case we need them
1432
- mem->stack0 = mem->stack;
1433
-
1434
- #if defined(_WIN32) && !defined(_WIN64)
1435
- mem->stack.len -= K_SIZE(SehFrame);
1436
-
1437
- // Prepare at the top SEH frame record
1438
- {
1439
- SehFrame *seh = (SehFrame *)mem->stack.end();
1440
-
1441
- seh->Next = (void *)-1;
1442
- seh->Handler = (void *)SehHandler;
1443
- }
1444
- #endif
1445
-
1446
- mem->heap.len = heap_size;
1447
- #if defined(_WIN32)
1448
- mem->heap.ptr = (uint8_t *)VirtualAlloc(nullptr, mem->heap.len, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
1449
- #else
1450
- mem->heap.ptr = (uint8_t *)mmap(nullptr, mem->heap.len, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0);
1451
- #endif
1452
- K_CRITICAL(mem->heap.ptr, "Failed to allocate %1 of memory", mem->heap.len);
1453
-
1454
- if (temporary) {
1455
- instance->temporaries++;
1456
- mem->temporary = true;
1457
- } else {
1458
- instance->memories.Append(mem);
1459
- mem->temporary = false;
1460
- }
1461
-
1462
- mem->busy = true;
1463
-
1464
- mem_guard.Disable();
1465
- return mem;
1466
- }
1467
-
1468
- void ReleaseMemory(InstanceData *instance, InstanceMemory *mem)
1469
- {
1470
- if (--mem->depth)
1471
- return;
1472
-
1473
- // The first InstanceMemory is used for sync calls, no need to manage the async stuff
1474
- if (mem == instance->memories[0])
1475
- return;
1476
-
1477
- std::lock_guard<std::mutex> lock(instance->mem_mutex);
1478
-
1479
- if (mem->temporary) {
1480
- instance->temporaries--;
1481
- delete mem;
1482
- } else {
1483
- mem->busy = false;
1484
- }
1485
- }
1486
-
1487
- static Napi::Value TranslateNormalCall(const FunctionInfo *func, void *native,
1488
- const Napi::CallbackInfo &info)
1489
- {
1490
- Napi::Env env = info.Env();
1491
- InstanceData *instance = env.GetInstanceData<InstanceData>();
1492
-
1493
- if (info.Length() < (uint32_t)func->required_parameters) [[unlikely]] {
1494
- ThrowError<Napi::TypeError>(env, "Expected %1 arguments, got %2", func->parameters.len, info.Length());
1495
- return env.Null();
1496
- }
1497
-
1498
- InstanceMemory *mem = instance->memories[0];
1499
- CallData call(env, instance, mem);
1500
-
1501
- if (!call.Prepare(func, info)) [[unlikely]]
1502
- return env.Null();
1503
-
1504
- if (instance->debug) {
1505
- call.DumpForward(func);
1506
- }
1507
-
1508
- // Execute call
1509
- {
1510
- K_DEFER_C(prev_call = exec_call) { exec_call = prev_call; };
1511
- exec_call = &call;
1512
-
1513
- call.Execute(func, native);
1514
- }
1515
-
1516
- return call.Complete(func);
1517
- }
1518
-
1519
- Napi::Value TranslateNormalCall(const Napi::CallbackInfo &info)
1520
- {
1521
- FunctionInfo *func = (FunctionInfo *)info.Data();
1522
- return TranslateNormalCall(func, func->native, info);
1523
- }
1524
-
1525
- static Napi::Value TranslateVariadicCall(const FunctionInfo *func, void *native,
1526
- const Napi::CallbackInfo &info)
1527
- {
1528
- Napi::Env env = info.Env();
1529
- InstanceData *instance = env.GetInstanceData<InstanceData>();
1530
-
1531
- FunctionInfo copy;
1532
- memcpy((void *)&copy, func, K_SIZE(*func));
1533
- copy.lib = nullptr;
1534
-
1535
- // This makes variadic calls non-reentrant
1536
- K_DEFER_C(len = copy.parameters.len) {
1537
- copy.parameters.RemoveFrom(len);
1538
- copy.parameters.Leak();
1539
- };
1540
-
1541
- if (info.Length() < (uint32_t)copy.required_parameters) [[unlikely]] {
1542
- ThrowError<Napi::TypeError>(env, "Expected %1 arguments or more, got %2", copy.parameters.len, info.Length());
1543
- return env.Null();
1544
- }
1545
- if ((info.Length() - copy.required_parameters) % 2) [[unlikely]] {
1546
- ThrowError<Napi::Error>(env, "Missing value argument for variadic call");
1547
- return env.Null();
1548
- }
1549
-
1550
- for (Size i = copy.required_parameters; i < (Size)info.Length(); i += 2) {
1551
- ParameterInfo param = {};
1552
-
1553
- param.type = ResolveType(info[(uint32_t)i], &param.directions);
1554
-
1555
- if (!param.type) [[unlikely]]
1556
- return env.Null();
1557
- if (!CanPassType(param.type, param.directions)) [[unlikely]] {
1558
- ThrowError<Napi::TypeError>(env, "Type %1 cannot be used as a parameter", param.type->name);
1559
- return env.Null();
1560
- }
1561
- if (copy.parameters.len >= MaxParameters) [[unlikely]] {
1562
- ThrowError<Napi::TypeError>(env, "Functions cannot have more than %1 parameters", MaxParameters);
1563
- return env.Null();
1564
- }
1565
- if ((param.directions & 2) && ++copy.out_parameters >= MaxParameters) [[unlikely]] {
1566
- ThrowError<Napi::TypeError>(env, "Functions cannot have more than %1 output parameters", MaxParameters);
1567
- return env.Null();
1568
- }
1569
-
1570
- param.variadic = true;
1571
- param.offset = (int8_t)(i + 1);
1572
-
1573
- copy.parameters.Append(param);
1574
- }
1575
-
1576
- if (!AnalyseFunction(env, instance, &copy)) [[unlikely]]
1577
- return env.Null();
1578
-
1579
- InstanceMemory *mem = instance->memories[0];
1580
- CallData call(env, instance, mem);
1581
-
1582
- if (!call.Prepare(&copy, info)) [[unlikely]]
1583
- return env.Null();
1584
-
1585
- if (instance->debug) {
1586
- call.DumpForward(&copy);
1587
- }
1588
-
1589
- // Execute call
1590
- {
1591
- K_DEFER_C(prev_call = exec_call) { exec_call = prev_call; };
1592
- exec_call = &call;
1593
-
1594
- call.Execute(&copy, native);
1595
- }
1596
-
1597
- return call.Complete(&copy);
1598
- }
1599
-
1600
- Napi::Value TranslateVariadicCall(const Napi::CallbackInfo &info)
1601
- {
1602
- FunctionInfo *func = (FunctionInfo *)info.Data();
1603
- return TranslateVariadicCall(func, func->native, info);
1604
- }
1605
-
1606
- class AsyncCall: public Napi::AsyncWorker {
1607
- Napi::Env env;
1608
-
1609
- const FunctionInfo *func;
1610
- void *native;
1611
-
1612
- CallData call;
1613
- bool prepared = false;
1614
-
1615
- public:
1616
- AsyncCall(Napi::Env env, InstanceData *instance, const FunctionInfo *func,
1617
- void *native, InstanceMemory *mem, Napi::Function &callback)
1618
- : Napi::AsyncWorker(callback), env(env), func(func->Ref()), native(native),
1619
- call(env, instance, mem) {}
1620
- ~AsyncCall() { func->Unref(); }
1621
-
1622
- bool Prepare(const Napi::CallbackInfo &info) {
1623
- prepared = call.Prepare(func, info);
1624
-
1625
- if (!prepared) {
1626
- Napi::Error err = env.GetAndClearPendingException();
1627
- SetError(err.Message());
1628
- }
1629
-
1630
- return prepared;
1631
- }
1632
- void DumpForward() { call.DumpForward(func); }
1633
-
1634
- void Execute() override;
1635
- void OnOK() override;
1636
- };
1637
-
1638
- void AsyncCall::Execute()
1639
- {
1640
- if (prepared) {
1641
- K_DEFER_C(prev_call = exec_call) { exec_call = prev_call; };
1642
- exec_call = &call;
1643
-
1644
- call.Execute(func, native);
1645
- }
1646
- }
1647
-
1648
- void AsyncCall::OnOK()
1649
- {
1650
- K_ASSERT(prepared);
1651
-
1652
- Napi::FunctionReference &callback = Callback();
1653
-
1654
- Napi::Value self = env.Null();
1655
- napi_value args[] = {
1656
- env.Null(),
1657
- call.Complete(func)
1658
- };
1659
-
1660
- callback.Call(self, K_LEN(args), args);
1661
- }
1662
-
1663
- static Napi::Value TranslateAsyncCall(const FunctionInfo *func, void *native,
1664
- const Napi::CallbackInfo &info)
1665
- {
1666
- K_ASSERT(!func->variadic);
1667
-
1668
- Napi::Env env = info.Env();
1669
- InstanceData *instance = env.GetInstanceData<InstanceData>();
1670
-
1671
- if (info.Length() <= (uint32_t)func->required_parameters) {
1672
- ThrowError<Napi::TypeError>(env, "Expected %1 arguments, got %2", func->parameters.len + 1, info.Length());
1673
- return env.Null();
1674
- }
1675
-
1676
- Napi::Function callback = info[(uint32_t)func->required_parameters].As<Napi::Function>();
1677
-
1678
- if (!callback.IsFunction()) {
1679
- ThrowError<Napi::TypeError>(env, "Expected callback function as last argument, got %1", GetValueType(instance, callback));
1680
- return env.Null();
1681
- }
1682
-
1683
- InstanceMemory *mem = AllocateMemory(instance, instance->config.async_stack_size, instance->config.async_heap_size);
1684
- if (!mem) [[unlikely]] {
1685
- ThrowError<Napi::Error>(env, "Too many asynchronous calls are running");
1686
- return env.Null();
1687
- }
1688
- AsyncCall *async = new AsyncCall(env, instance, func, native, mem, callback);
1689
-
1690
- if (async->Prepare(info) && instance->debug) {
1691
- async->DumpForward();
1692
- }
1693
- async->Queue();
1694
-
1695
- return env.Undefined();
1696
- }
1697
-
1698
- Napi::Value TranslateAsyncCall(const Napi::CallbackInfo &info)
1699
- {
1700
- FunctionInfo *func = (FunctionInfo *)info.Data();
1701
- return TranslateAsyncCall(func, func->native, info);
1702
- }
1703
-
1704
- extern "C" void RelayCallback(Size idx, uint8_t *sp)
1705
- {
1706
- CallData *call = exec_call;
1707
-
1708
- // Try the fast path first: we are on the main thread and we are running a native call through Koffi.
1709
- // It should be easy, but in this case we are running on the custom Koffi stack, which will trip up
1710
- // Node and V8. So we need to switch back to the normal/main stack.
1711
- if (call && std::this_thread::get_id() == call->instance->main_thread_id) {
1712
- SwitchAndRelay(call, idx, sp, call->old_sp, &call->mem->stack);
1713
- return;
1714
- }
1715
-
1716
- // Otherwise, we need to allocate memory to perform the callback.
1717
- // Since the necessary machinery live in CallData, just use a temporary instance.
1718
- // In some cases we would reuse the existing call (exec_call may be not null),
1719
- // but it is rare so let's ignore this for simplicity.
1720
-
1721
- TrampolineInfo *trampoline = &shared.trampolines[idx];
1722
- Napi::Env env = trampoline->func.Env();
1723
- InstanceData *instance = env.GetInstanceData<InstanceData>();
1724
-
1725
- InstanceMemory *mem = AllocateMemory(instance, instance->config.async_stack_size, instance->config.async_heap_size);
1726
- if (!mem) [[unlikely]] {
1727
- ThrowError<Napi::Error>(env, "Too many asynchronous calls are running");
1728
- return;
1729
- }
1730
-
1731
- if (std::this_thread::get_id() == instance->main_thread_id) {
1732
- CallData call(env, instance, mem);
1733
-
1734
- Napi::HandleScope scope(env);
1735
- call.Relay(idx, sp);
1736
- } else {
1737
- CallData call(env, instance, mem);
1738
- call.RelayAsync(idx, sp);
1739
- }
1740
- }
1741
-
1742
- extern "C" void RelayDirect(CallData *call, Size idx, uint8_t *sp)
1743
- {
1744
- TrampolineInfo *trampoline = &shared.trampolines[idx];
1745
- Napi::Env env = trampoline->func.Env();
1746
-
1747
- #if defined(_WIN32)
1748
- TEB *teb = GetTEB();
1749
- InstanceData *instance = trampoline->instance;
1750
-
1751
- // Restore previous stack limits at the end
1752
- K_DEFER_C(base = teb->StackBase,
1753
- limit = teb->StackLimit,
1754
- dealloc = teb->DeallocationStack) {
1755
- teb->StackBase = base;
1756
- teb->StackLimit = limit;
1757
- teb->DeallocationStack = dealloc;
1758
- };
1759
-
1760
- // Adjust stack limits so SEH works correctly
1761
- teb->StackBase = instance->main_stack_max;
1762
- teb->StackLimit = instance->main_stack_min;
1763
- teb->DeallocationStack = instance->main_stack_min;
1764
- #endif
1765
-
1766
- if (env.IsExceptionPending()) [[unlikely]]
1767
- return;
1768
- if (!trampoline->used) [[unlikely]] {
1769
- ThrowError<Napi::Error>(env, "Cannot use non-registered callback beyond FFI call");
1770
- return;
1771
- }
1772
-
1773
- Napi::HandleScope scope(call->env);
1774
- call->Relay(idx, sp);
1775
- }
1776
-
1777
- static Napi::Value FindLibraryFunction(const Napi::CallbackInfo &info)
1778
- {
1779
- Napi::Env env = info.Env();
1780
- InstanceData *instance = env.GetInstanceData<InstanceData>();
1781
- LibraryHolder *lib = (LibraryHolder *)info.Data();
1782
-
1783
- FunctionInfo *func = new FunctionInfo();
1784
- K_DEFER { func->Unref(); };
1785
-
1786
- func->lib = lib->Ref();
1787
-
1788
- if (info.Length() >= 2) {
1789
- if (!ParseClassicFunction(info, true, func))
1790
- return env.Null();
1791
- } else if (info.Length() >= 1) {
1792
- if (!info[0].IsString()) {
1793
- ThrowError<Napi::TypeError>(env, "Unexpected %1 value for prototype, expected string", GetValueType(instance, info[0]));
1794
- return env.Null();
1795
- }
1796
-
1797
- std::string proto = info[0u].As<Napi::String>();
1798
- if (!ParsePrototype(env, proto.c_str(), true, func))
1799
- return env.Null();
1800
- } else {
1801
- ThrowError<Napi::TypeError>(env, "Expected 1 to 4 arguments, got %1", info.Length());
1802
- return env.Null();
1803
- }
1804
-
1805
- if (func->convention != CallConvention::Cdecl && func->variadic) {
1806
- LogError("Call convention '%1' does not support variadic functions, ignoring",
1807
- CallConventionNames[(int)func->convention]);
1808
- func->convention = CallConvention::Cdecl;
1809
- }
1810
-
1811
- if (!AnalyseFunction(env, instance, func))
1812
- return env.Null();
1813
- if (func->variadic) {
1814
- // Minimize reallocations
1815
- func->parameters.Grow(32);
1816
- }
1817
-
1818
- #if defined(_WIN32)
1819
- if (func->ordinal_name < 0) {
1820
- if (func->decorated_name) {
1821
- func->native = (void *)GetProcAddress((HMODULE)lib->module, func->decorated_name);
1822
- }
1823
- if (!func->native) {
1824
- func->native = (void *)GetProcAddress((HMODULE)lib->module, func->name);
1825
- }
1826
- } else {
1827
- uint16_t ordinal = (uint16_t)func->ordinal_name;
1828
-
1829
- func->decorated_name = nullptr;
1830
- func->native = (void *)GetProcAddress((HMODULE)lib->module, (LPCSTR)(size_t)ordinal);
1831
- }
1832
- #else
1833
- if (func->decorated_name) {
1834
- func->native = dlsym(lib->module, func->decorated_name);
1835
- }
1836
- if (!func->native) {
1837
- func->native = dlsym(lib->module, func->name);
1838
- }
1839
- #endif
1840
- if (!func->native) {
1841
- ThrowError<Napi::Error>(env, "Cannot find function '%1' in shared library", func->name);
1842
- return env.Null();
1843
- }
1844
-
1845
- Napi::Function wrapper = WrapFunction(env, func);
1846
- return wrapper;
1847
- }
1848
-
1849
- static Napi::Value FindSymbol(const Napi::CallbackInfo &info)
1850
- {
1851
- Napi::Env env = info.Env();
1852
- InstanceData *instance = env.GetInstanceData<InstanceData>();
1853
- LibraryHolder *lib = (LibraryHolder *)info.Data();
1854
-
1855
- if (info.Length() < 2) {
1856
- ThrowError<Napi::TypeError>(env, "Expected 2, got %1", info.Length());
1857
- return env.Null();
1858
- }
1859
- if (!info[0].IsString()) {
1860
- ThrowError<Napi::TypeError>(env, "Unexpected %1 value for name, expected string", GetValueType(instance, info[0]));
1861
- return env.Null();
1862
- }
1863
-
1864
- std::string name = info[0].As<Napi::String>();
1865
-
1866
- const TypeInfo *type = ResolveType(info[1]);
1867
- if (!type)
1868
- return env.Null();
1869
-
1870
- #if defined(_WIN32)
1871
- void *ptr = (void *)GetProcAddress((HMODULE)lib->module, name.c_str());
1872
- #else
1873
- void *ptr = (void *)dlsym(lib->module, name.c_str());
1874
- #endif
1875
- if (!ptr) {
1876
- ThrowError<Napi::Error>(env, "Cannot find symbol '%1' in shared library", name.c_str());
1877
- return env.Null();
1878
- }
1879
-
1880
- Napi::External<void> external = Napi::External<void>::New(env, ptr);
1881
- SetValueTag(external, &type);
1882
-
1883
- return external;
1884
- }
1885
-
1886
- static Napi::Value UnloadLibrary(const Napi::CallbackInfo &info)
1887
- {
1888
- Napi::Env env = info.Env();
1889
- LibraryHolder *lib = (LibraryHolder *)info.Data();
1890
-
1891
- lib->Unload();
1892
-
1893
- return env.Undefined();
1894
- }
1895
-
1896
- static Napi::Value LoadSharedLibrary(const Napi::CallbackInfo &info)
1897
- {
1898
- Napi::Env env = info.Env();
1899
- InstanceData *instance = env.GetInstanceData<InstanceData>();
1900
-
1901
- if (info.Length() < 1) {
1902
- ThrowError<Napi::TypeError>(env, "Expected 1 or 2 arguments, got %1", info.Length());
1903
- return env.Null();
1904
- }
1905
- if (!info[0].IsString() && !IsNullOrUndefined(info[0])) {
1906
- ThrowError<Napi::TypeError>(env, "Unexpected %1 value for filename, expected string or null", GetValueType(instance, info[0]));
1907
- return env.Null();
1908
- }
1909
- if (info.Length() >= 2 && !IsObject(info[1])) {
1910
- ThrowError<Napi::TypeError>(env, "Unexpected %1 value for options, expected object", GetValueType(instance, info[1]));
1911
- return env.Null();
1912
- }
1913
-
1914
- #if !defined(_WIN32)
1915
- int flags = 0;
1916
-
1917
- if (info.Length() >= 2) {
1918
- Napi::Object options = info[1].As<Napi::Object>();
1919
-
1920
- flags |= options.Get("lazy").ToBoolean() ? RTLD_LAZY : RTLD_NOW;
1921
- flags |= options.Get("global").ToBoolean() ? RTLD_GLOBAL : RTLD_LOCAL;
1922
- #if defined(RTLD_DEEPBIND)
1923
- flags |= options.Get("deep").ToBoolean() ? RTLD_DEEPBIND : 0;
1924
- #endif
1925
- } else {
1926
- flags = RTLD_NOW | RTLD_LOCAL;
1927
- }
1928
- #endif
1929
-
1930
- if (!instance->memories.len) {
1931
- AllocateMemory(instance, instance->config.sync_stack_size, instance->config.sync_heap_size);
1932
- K_ASSERT(instance->memories.len == 1);
1933
- }
1934
-
1935
- // Load shared library
1936
- void *module = nullptr;
1937
- #if defined(_WIN32)
1938
- if (info[0].IsString()) {
1939
- std::string filename = info[0].As<Napi::String>();
1940
- module = LoadWindowsLibrary(env, filename.c_str());
1941
-
1942
- if (!module)
1943
- return env.Null();
1944
- } else {
1945
- module = GetModuleHandle(nullptr);
1946
- K_ASSERT(module);
1947
- }
1948
- #else
1949
- if (info[0].IsString()) {
1950
- std::string filename = info[0].As<Napi::String>();
1951
- module = dlopen(filename.c_str(), flags);
1952
-
1953
- if (!module) {
1954
- const char *msg = dlerror();
1955
-
1956
- if (StartsWith(msg, filename.c_str())) {
1957
- msg += filename.length();
1958
-
1959
- while (strchr(": ", msg[0]) && msg[0]) {
1960
- msg++;
1961
- }
1962
- }
1963
-
1964
- ThrowError<Napi::Error>(env, "Failed to load shared library: %1", msg);
1965
- return env.Null();
1966
- }
1967
- } else {
1968
- module = RTLD_DEFAULT;
1969
- }
1970
- #endif
1971
-
1972
- LibraryHolder *lib = new LibraryHolder(module);
1973
- K_DEFER { lib->Unref(); };
1974
-
1975
- Napi::Object obj = Napi::Object::New(env);
1976
-
1977
- #define ADD_METHOD(Name, Call) \
1978
- do { \
1979
- const auto wrapper = [](const Napi::CallbackInfo &info) { return Call; }; \
1980
- Napi::Function func = Napi::Function::New(env, wrapper, (Name), (void *)lib->Ref()); \
1981
- func.AddFinalizer([](Napi::Env, LibraryHolder *lib) { lib->Unref(); }, lib); \
1982
- obj.Set((Name), func); \
1983
- } while (false)
1984
-
1985
- ADD_METHOD("func", FindLibraryFunction(info));
1986
- ADD_METHOD("symbol", FindSymbol(info));
1987
-
1988
- // We can't unref the library after unload, obviously
1989
- obj.Set("unload", Napi::Function::New(env, UnloadLibrary, "unload", (void *)lib->Ref()));
1990
-
1991
- #undef ADD_METHOD
1992
-
1993
- return obj;
1994
- }
1995
-
1996
- static Napi::Value RegisterCallback(const Napi::CallbackInfo &info)
1997
- {
1998
- Napi::Env env = info.Env();
1999
- InstanceData *instance = env.GetInstanceData<InstanceData>();
2000
-
2001
- if (!InitAsyncBroker(env, instance)) [[unlikely]]
2002
- return env.Null();
2003
-
2004
- bool has_recv = (info.Length() >= 3 && info[1].IsFunction());
2005
-
2006
- if (info.Length() < 2u + has_recv) {
2007
- ThrowError<Napi::TypeError>(env, "Expected 2 or 3 arguments, got %1", info.Length());
2008
- return env.Null();
2009
- }
2010
- if (!info[0u + has_recv].IsFunction()) {
2011
- ThrowError<Napi::TypeError>(env, "Unexpected %1 value for func, expected function", GetValueType(instance, info[0 + has_recv]));
2012
- return env.Null();
2013
- }
2014
-
2015
- Napi::Value recv = has_recv ? info[0] : env.Undefined();
2016
- Napi::Function func = info[0u + has_recv].As<Napi::Function>();
2017
-
2018
- const TypeInfo *type = ResolveType(info[1u + has_recv]);
2019
- if (!type)
2020
- return env.Null();
2021
- if (type->primitive != PrimitiveKind::Callback) {
2022
- ThrowError<Napi::TypeError>(env, "Unexpected %1 type, expected <callback> * type", type->name);
2023
- return env.Null();
2024
- }
2025
-
2026
- int16_t idx;
2027
- {
2028
- std::lock_guard<std::mutex> lock(shared.mutex);
2029
-
2030
- if (!shared.available.len) [[unlikely]] {
2031
- ThrowError<Napi::Error>(env, "Too many callbacks are in use (max = %1)", MaxTrampolines);
2032
- return env.Null();
2033
- }
2034
-
2035
- idx = shared.available.data[--shared.available.len];
2036
- }
2037
-
2038
- TrampolineInfo *trampoline = &shared.trampolines[idx];
2039
-
2040
- trampoline->instance = instance;
2041
- trampoline->proto = type->ref.proto;
2042
- trampoline->func.Reset(func, 1);
2043
- if (!IsNullOrUndefined(recv)) {
2044
- trampoline->recv.Reset(recv, 1);
2045
- } else {
2046
- trampoline->recv.Reset();
2047
- }
2048
- trampoline->used = true;
2049
-
2050
- void *ptr = GetTrampoline(idx);
2051
-
2052
- Napi::External<void> external = Napi::External<void>::New(env, ptr);
2053
- SetValueTag(external, type->ref.marker);
2054
-
2055
- // Cache index for fast unregistration
2056
- instance->trampolines_map.Set(ptr, idx);
2057
-
2058
- return external;
2059
- }
2060
-
2061
- static Napi::Value UnregisterCallback(const Napi::CallbackInfo &info)
2062
- {
2063
- Napi::Env env = info.Env();
2064
- InstanceData *instance = env.GetInstanceData<InstanceData>();
2065
-
2066
- if (info.Length() < 1) {
2067
- ThrowError<Napi::TypeError>(env, "Expected 1 argument, got %1", info.Length());
2068
- return env.Null();
2069
- }
2070
- if (!info[0].IsExternal()) {
2071
- ThrowError<Napi::TypeError>(env, "Unexpected %1 value for id, expected registered callback", GetValueType(instance, info[0]));
2072
- return env.Null();
2073
- }
2074
-
2075
- Napi::External<void> external = info[0].As<Napi::External<void>>();
2076
- void *ptr = external.Data();
2077
-
2078
- int16_t idx;
2079
- {
2080
- int16_t *it = instance->trampolines_map.Find(ptr);
2081
-
2082
- if (!it) [[unlikely]] {
2083
- ThrowError<Napi::Error>(env, "Could not find matching registered callback");
2084
- return env.Null();
2085
- }
2086
-
2087
- idx = *it;
2088
- instance->trampolines_map.Remove(it);
2089
- }
2090
-
2091
- // Release shared trampoline safely
2092
- {
2093
- std::lock_guard<std::mutex> lock(shared.mutex);
2094
-
2095
- TrampolineInfo *trampoline = &shared.trampolines[idx];
2096
- K_ASSERT(!trampoline->func.IsEmpty());
2097
-
2098
- trampoline->func.Reset();
2099
- trampoline->recv.Reset();
2100
- trampoline->used = false;
2101
-
2102
- shared.available.Append(idx);
2103
- }
2104
-
2105
- return env.Undefined();
2106
- }
2107
-
2108
- static Napi::Value CastValue(const Napi::CallbackInfo &info)
2109
- {
2110
- Napi::Env env = info.Env();
2111
-
2112
- if (info.Length() < 2) [[unlikely]] {
2113
- ThrowError<Napi::TypeError>(env, "Expected 2 arguments, got %1", info.Length());
2114
- return env.Null();
2115
- }
2116
-
2117
- Napi::Value value = info[0];
2118
-
2119
- const TypeInfo *type = ResolveType(info[1]);
2120
- if (!type) [[unlikely]]
2121
- return env.Null();
2122
- if (type->primitive != PrimitiveKind::Pointer &&
2123
- type->primitive != PrimitiveKind::Callback &&
2124
- type->primitive != PrimitiveKind::String &&
2125
- type->primitive != PrimitiveKind::String16 &&
2126
- type->primitive != PrimitiveKind::String32) [[unlikely]] {
2127
- ThrowError<Napi::TypeError>(env, "Only pointer or string types can be used for casting");
2128
- return env.Null();
2129
- }
2130
-
2131
- ValueCast *cast = new ValueCast;
2132
-
2133
- cast->ref.Reset(value, 1);
2134
- cast->type = type;
2135
-
2136
- Napi::External<ValueCast> external = Napi::External<ValueCast>::New(env, cast, [](Napi::Env, ValueCast *cast) { delete cast; });
2137
- SetValueTag(external, &CastMarker);
2138
-
2139
- return external;
2140
- }
2141
-
2142
- static Napi::Value DecodeValue(const Napi::CallbackInfo &info)
2143
- {
2144
- Napi::Env env = info.Env();
2145
-
2146
- bool has_offset = (info.Length() >= 2 && info[1].IsNumber());
2147
- bool has_len = (info.Length() >= 3u + has_offset && info[2 + has_offset].IsNumber());
2148
-
2149
- if (info.Length() < 2u + has_offset) [[unlikely]] {
2150
- ThrowError<Napi::TypeError>(env, "Expected %1 to 4 arguments, got %2", 2 + has_offset, info.Length());
2151
- return env.Null();
2152
- }
2153
-
2154
- const TypeInfo *type = ResolveType(info[1u + has_offset]);
2155
- if (!type) [[unlikely]]
2156
- return env.Null();
2157
-
2158
- Napi::Value value = info[0];
2159
- int64_t offset = has_offset ? info[1].As<Napi::Number>().Int64Value() : 0;
2160
-
2161
- if (has_len) {
2162
- Size len = info[2 + has_offset].As<Napi::Number>();
2163
-
2164
- Napi::Value ret = Decode(value, offset, type, &len);
2165
- return ret;
2166
- } else {
2167
- Napi::Value ret = Decode(value, offset, type);
2168
- return ret;
2169
- }
2170
- }
2171
-
2172
- static Napi::Value GetPointerAddress(const Napi::CallbackInfo &info)
2173
- {
2174
- Napi::Env env = info.Env();
2175
-
2176
- if (info.Length() < 1) {
2177
- ThrowError<Napi::TypeError>(env, "Expected 1 argument, got %1", info.Length());
2178
- return env.Null();
2179
- }
2180
-
2181
- void *ptr = nullptr;
2182
- if (!GetExternalPointer(env, info[0], &ptr))
2183
- return env.Null();
2184
-
2185
- uint64_t ptr64 = (uint64_t)(uintptr_t)ptr;
2186
- Napi::BigInt bigint = Napi::BigInt::New(env, ptr64);
2187
-
2188
- return bigint;
2189
- }
2190
-
2191
- static Napi::Value CallPointerSync(const Napi::CallbackInfo &info)
2192
- {
2193
- Napi::Env env = info.Env();
2194
- InstanceData *instance = env.GetInstanceData<InstanceData>();
2195
-
2196
- if (info.Length() < 2) [[unlikely]] {
2197
- ThrowError<Napi::TypeError>(env, "Expected 2 or more arguments, got %1", info.Length());
2198
- return env.Null();
2199
- }
2200
-
2201
- void *ptr = nullptr;
2202
- if (!GetExternalPointer(env, info[0], &ptr)) [[unlikely]]
2203
- return env.Null();
2204
-
2205
- const TypeInfo *type = ResolveType(info[1]);
2206
- if (!type) [[unlikely]]
2207
- return env.Null();
2208
- if (type->primitive != PrimitiveKind::Prototype) [[unlikely]] {
2209
- ThrowError<Napi::TypeError>(env, "Unexpected %1 value for type, expected function type", GetValueType(instance, info[1]));
2210
- return env.Null();
2211
- }
2212
-
2213
- const FunctionInfo *proto = type->ref.proto;
2214
-
2215
- return proto->variadic ? TranslateVariadicCall(proto, ptr, info)
2216
- : TranslateNormalCall(proto, ptr, info);
2217
- }
2218
-
2219
- static Napi::Value EncodeValue(const Napi::CallbackInfo &info)
2220
- {
2221
- Napi::Env env = info.Env();
2222
-
2223
- bool has_offset = (info.Length() >= 2 && info[1].IsNumber());
2224
- bool has_len = (info.Length() >= 4u + has_offset && info[3 + has_offset].IsNumber());
2225
-
2226
- if (info.Length() < 3u + has_offset) [[unlikely]] {
2227
- ThrowError<Napi::TypeError>(env, "Expected %1 to 5 arguments, got %2", 3 + has_offset, info.Length());
2228
- return env.Null();
2229
- }
2230
-
2231
- const TypeInfo *type = ResolveType(info[1u + has_offset]);
2232
- if (!type) [[unlikely]]
2233
- return env.Null();
2234
-
2235
- Napi::Value ref = info[0];
2236
- int64_t offset = has_offset ? info[1].As<Napi::Number>().Int64Value() : 0;
2237
- Napi::Value value = info[2 + has_offset];
2238
-
2239
- if (has_len) {
2240
- Size len = info[3 + has_offset].As<Napi::Number>();
2241
-
2242
- if (!Encode(ref, offset, value, type, &len))
2243
- return env.Null();
2244
- } else {
2245
- if (!Encode(ref, offset, value, type))
2246
- return env.Null();
2247
- }
2248
-
2249
- return env.Undefined();
2250
- }
2251
-
2252
- static Napi::Value CreateView(const Napi::CallbackInfo &info)
2253
- {
2254
- Napi::Env env = info.Env();
2255
- InstanceData *instance = env.GetInstanceData<InstanceData>();
2256
-
2257
- if (info.Length() < 1) {
2258
- ThrowError<Napi::TypeError>(env, "Expected 2 arguments, got %1", info.Length());
2259
- return env.Null();
2260
- }
2261
- if (!info[1].IsNumber()) {
2262
- ThrowError<Napi::TypeError>(env, "Unexpected %1 value for length, expected integer", GetValueType(instance, info[1]));
2263
- return env.Null();
2264
- }
2265
-
2266
- void *ptr = nullptr;
2267
- if (!GetExternalPointer(env, info[0], &ptr))
2268
- return env.Null();
2269
- Size len = (Size)info[1].As<Napi::Number>().Int64Value();
2270
-
2271
- if (len < 0) {
2272
- ThrowError<Napi::TypeError>(env, "Array length must be positive and non-zero");
2273
- return env.Null();
2274
- }
2275
-
2276
- if (len) {
2277
- Napi::ArrayBuffer view = Napi::ArrayBuffer::New(env, ptr, (size_t)len);
2278
-
2279
- if (!view.ByteLength()) {
2280
- ThrowError<Napi::Error>(env, "This runtime does not support external buffers");
2281
- return env.Null();
2282
- }
2283
-
2284
- return view;
2285
- } else {
2286
- return Napi::ArrayBuffer::New(env, 0);
2287
- }
2288
- }
2289
-
2290
- static Napi::Value ResetKoffi(const Napi::CallbackInfo &info)
2291
- {
2292
- Napi::Env env = info.Env();
2293
- InstanceData *instance = env.GetInstanceData<InstanceData>();
2294
-
2295
- if (instance->broker) {
2296
- napi_release_threadsafe_function(instance->broker, napi_tsfn_abort);
2297
- instance->broker = nullptr;
2298
- }
2299
-
2300
- instance->types.RemoveFrom(instance->base_types_count);
2301
-
2302
- {
2303
- HashSet<const void *> base_types;
2304
- HashMap<const char *, const TypeInfo *> new_map;
2305
-
2306
- for (const TypeInfo &type: instance->types) {
2307
- base_types.Set(&type);
2308
- }
2309
-
2310
- for (const auto &bucket: instance->types_map.table) {
2311
- if (base_types.Find(bucket.value)) {
2312
- new_map.Set(bucket.key, bucket.value);
2313
- }
2314
- }
2315
-
2316
- std::swap(instance->types_map, new_map);
2317
- }
2318
-
2319
- instance->callbacks.Clear();
2320
-
2321
- return env.Undefined();
2322
- }
2323
-
2324
- void LibraryHolder::Unload()
2325
- {
2326
- #if defined(_WIN32)
2327
- if (module && module != GetModuleHandle(nullptr)) {
2328
- FreeLibrary((HMODULE)module);
2329
- }
2330
- #else
2331
- if (module && module != RTLD_DEFAULT) {
2332
- dlclose(module);
2333
- }
2334
- #endif
2335
-
2336
- module = nullptr;
2337
- }
2338
-
2339
- const LibraryHolder *LibraryHolder::Ref() const
2340
- {
2341
- refcount++;
2342
- return this;
2343
- }
2344
-
2345
- void LibraryHolder::Unref() const
2346
- {
2347
- if (!--refcount) {
2348
- delete this;
2349
- }
2350
- }
2351
-
2352
- FunctionInfo::~FunctionInfo()
2353
- {
2354
- if (lib) {
2355
- lib->Unref();
2356
- }
2357
- }
2358
-
2359
- const FunctionInfo *FunctionInfo::Ref() const
2360
- {
2361
- refcount++;
2362
- return this;
2363
- }
2364
-
2365
- void FunctionInfo::Unref() const
2366
- {
2367
- if (!--refcount) {
2368
- delete this;
2369
- }
2370
- }
2371
-
2372
- InstanceMemory::~InstanceMemory()
2373
- {
2374
- #if defined(_WIN32)
2375
- if (stack.ptr) {
2376
- VirtualFree(stack.ptr, 0, MEM_RELEASE);
2377
- }
2378
- if (heap.ptr) {
2379
- VirtualFree(heap.ptr, 0, MEM_RELEASE);
2380
- }
2381
- #else
2382
- if (stack.ptr) {
2383
- munmap(stack.ptr, stack.len);
2384
- }
2385
- if (heap.ptr) {
2386
- munmap(heap.ptr, heap.len);
2387
- }
2388
- #endif
2389
- }
2390
-
2391
- bool InitAsyncBroker(Napi::Env env, InstanceData *instance)
2392
- {
2393
- if (!instance->broker) {
2394
- if (napi_create_threadsafe_function(env, nullptr, nullptr,
2395
- Napi::String::New(env, "Koffi Async Callback Broker"),
2396
- 0, 1, nullptr, nullptr, nullptr,
2397
- PerformAsyncRelay, &instance->broker) != napi_ok) {
2398
- LogError("Failed to create async callback broker");
2399
- return false;
2400
- }
2401
- napi_unref_threadsafe_function(env, instance->broker);
2402
- }
2403
-
2404
- return true;
2405
- }
2406
-
2407
- static void RegisterPrimitiveType(Napi::Env env, Napi::Object map, std::initializer_list<const char *> names,
2408
- PrimitiveKind primitive, int32_t size, int16_t align, const char *ref = nullptr)
2409
- {
2410
- K_ASSERT(names.size() > 0);
2411
- K_ASSERT(align <= size);
2412
-
2413
- InstanceData *instance = env.GetInstanceData<InstanceData>();
2414
-
2415
- TypeInfo *type = instance->types.AppendDefault();
2416
-
2417
- type->name = *names.begin();
2418
-
2419
- type->primitive = primitive;
2420
- type->size = size;
2421
- type->align = align;
2422
-
2423
- if (IsInteger(type) || IsFloat(type)) {
2424
- type->flags |= (int)TypeFlag::HasTypedArray;
2425
- }
2426
- if (TestStr(type->name, "char") ||
2427
- TestStr(type->name, "char16") || TestStr(type->name, "char16_t") ||
2428
- TestStr(type->name, "char32") || TestStr(type->name, "char32_t") ||
2429
- TestStr(type->name, "wchar") || TestStr(type->name, "wchar_t")) {
2430
- type->flags |= (int)TypeFlag::IsCharLike;
2431
- }
2432
-
2433
- if (ref) {
2434
- const TypeInfo *marker = instance->types_map.FindValue(ref, nullptr);
2435
- K_ASSERT(marker);
2436
-
2437
- type->ref.marker = marker;
2438
- }
2439
-
2440
- Napi::Value wrapper = WrapType(env, type);
2441
-
2442
- for (const char *name: names) {
2443
- bool inserted;
2444
- instance->types_map.InsertOrGet(name, type, &inserted);
2445
- K_ASSERT(inserted);
2446
-
2447
- if (!EndsWith(name, "*")) {
2448
- map.Set(name, wrapper);
2449
- }
2450
- }
2451
- }
2452
-
2453
- static inline PrimitiveKind GetSignPrimitive(Size len, bool sign)
2454
- {
2455
- switch (len) {
2456
- case 1: return sign ? PrimitiveKind::Int8 : PrimitiveKind::UInt8;
2457
- case 2: return sign ? PrimitiveKind::Int16 : PrimitiveKind::UInt16;
2458
- case 4: return sign ? PrimitiveKind::Int32 : PrimitiveKind::UInt32;
2459
- case 8: return sign ? PrimitiveKind::Int64 : PrimitiveKind::UInt64;
2460
- }
2461
-
2462
- K_UNREACHABLE();
2463
- }
2464
-
2465
- static inline PrimitiveKind GetLittleEndianPrimitive(PrimitiveKind kind)
2466
- {
2467
- #if defined(K_BIG_ENDIAN)
2468
- return (PrimitiveKind)((int)kind + 1);
2469
- #else
2470
- return kind;
2471
- #endif
2472
- }
2473
-
2474
- static inline PrimitiveKind GetBigEndianPrimitive(PrimitiveKind kind)
2475
- {
2476
- #if defined(K_BIG_ENDIAN)
2477
- return kind;
2478
- #else
2479
- return (PrimitiveKind)((int)kind + 1);
2480
- #endif
2481
- }
2482
-
2483
- static InstanceData *CreateInstance()
2484
- {
2485
- InstanceData *instance = new InstanceData();
2486
- K_DEFER_N(err_guard) { delete instance; };
2487
-
2488
- instance->main_thread_id = std::this_thread::get_id();
2489
-
2490
- instance->debug = GetDebugFlag("DUMP_CALLS");
2491
-
2492
- #if defined(_WIN32)
2493
- TEB *teb = GetTEB();
2494
-
2495
- instance->main_stack_max = teb->StackBase;
2496
- instance->main_stack_min = teb->DeallocationStack;
2497
- #endif
2498
-
2499
- err_guard.Disable();
2500
- return instance;
2501
- }
2502
-
2503
- static Napi::Object InitModule(Napi::Env env, Napi::Object exports)
2504
- {
2505
- InstanceData *instance = CreateInstance();
2506
- K_CRITICAL(instance, "Failed to initialize Koffi");
2507
-
2508
- env.SetInstanceData(instance);
2509
-
2510
- exports.Set("config", Napi::Function::New(env, GetSetConfig, "config"));
2511
- exports.Set("stats", Napi::Function::New(env, GetStats, "stats"));
2512
-
2513
- exports.Set("struct", Napi::Function::New(env, CreatePaddedStructType, "struct"));
2514
- exports.Set("pack", Napi::Function::New(env, CreatePackedStructType, "pack"));
2515
- exports.Set("union", Napi::Function::New(env, CreateUnionType, "union"));
2516
- exports.Set("Union", Napi::Function::New(env, InstantiateUnion, "Union"));
2517
- exports.Set("opaque", Napi::Function::New(env, CreateOpaqueType, "opaque"));
2518
- exports.Set("pointer", Napi::Function::New(env, CreatePointerType, "pointer"));
2519
- exports.Set("array", Napi::Function::New(env, CreateArrayType, "array"));
2520
- exports.Set("proto", Napi::Function::New(env, CreateFunctionType, "proto"));
2521
- exports.Set("alias", Napi::Function::New(env, CreateTypeAlias, "alias"));
2522
-
2523
- exports.Set("sizeof", Napi::Function::New(env, GetTypeSize, "sizeof"));
2524
- exports.Set("alignof", Napi::Function::New(env, GetTypeAlign, "alignof"));
2525
- exports.Set("offsetof", Napi::Function::New(env, GetMemberOffset, "offsetof"));
2526
- exports.Set("resolve", Napi::Function::New(env, GetResolvedType, "resolve"));
2527
- exports.Set("introspect", Napi::Function::New(env, GetTypeDefinition, "introspect"));
2528
-
2529
- exports.Set("load", Napi::Function::New(env, LoadSharedLibrary, "load"));
2530
-
2531
- exports.Set("in", Napi::Function::New(env, MarkIn, "in"));
2532
- exports.Set("out", Napi::Function::New(env, MarkOut, "out"));
2533
- exports.Set("inout", Napi::Function::New(env, MarkInOut, "inout"));
2534
-
2535
- exports.Set("disposable", Napi::Function::New(env, CreateDisposableType, "disposable"));
2536
- exports.Set("alloc", Napi::Function::New(env, CallAlloc, "alloc"));
2537
- exports.Set("free", Napi::Function::New(env, CallFree, "free"));
2538
-
2539
- exports.Set("register", Napi::Function::New(env, RegisterCallback, "register"));
2540
- exports.Set("unregister", Napi::Function::New(env, UnregisterCallback, "unregister"));
2541
-
2542
- exports.Set("as", Napi::Function::New(env, CastValue, "as"));
2543
- exports.Set("decode", Napi::Function::New(env, DecodeValue, "decode"));
2544
- exports.Set("address", Napi::Function::New(env, GetPointerAddress, "address"));
2545
- exports.Set("call", Napi::Function::New(env, CallPointerSync, "call"));
2546
- exports.Set("encode", Napi::Function::New(env, EncodeValue, "encode"));
2547
- exports.Set("view", Napi::Function::New(env, CreateView, "view"));
2548
-
2549
- exports.Set("reset", Napi::Function::New(env, ResetKoffi, "reset"));
2550
-
2551
- exports.Set("errno", Napi::Function::New(env, GetOrSetErrNo, "errno"));
2552
-
2553
- // Export useful OS info
2554
- {
2555
- Napi::Object os = Napi::Object::New(env);
2556
- exports.Set("os", os);
2557
-
2558
- Napi::Object codes = Napi::Object::New(env);
2559
-
2560
- for (const ErrnoCodeInfo &info: ErrnoCodes) {
2561
- codes.Set(info.name, Napi::Number::New(env, info.value));
2562
- }
2563
-
2564
- os.Set("errno", codes);
2565
- }
2566
-
2567
- #if defined(_WIN32)
2568
- exports.Set("extension", Napi::String::New(env, ".dll"));
2569
- #elif defined(__APPLE__)
2570
- exports.Set("extension", Napi::String::New(env, ".dylib"));
2571
- #else
2572
- exports.Set("extension", Napi::String::New(env, ".so"));
2573
- #endif
2574
-
2575
- // Init base types
2576
- {
2577
- Napi::Object types = Napi::Object::New(env);
2578
- exports.Set("types", types);
2579
-
2580
- RegisterPrimitiveType(env, types, {"void"}, PrimitiveKind::Void, 0, 0);
2581
- RegisterPrimitiveType(env, types, {"bool"}, PrimitiveKind::Bool, K_SIZE(bool), alignof(bool));
2582
- RegisterPrimitiveType(env, types, {"int8_t", "int8"}, PrimitiveKind::Int8, 1, 1);
2583
- RegisterPrimitiveType(env, types, {"uint8_t", "uint8"}, PrimitiveKind::UInt8, 1, 1);
2584
- RegisterPrimitiveType(env, types, {"char"}, PrimitiveKind::Int8, 1, 1);
2585
- RegisterPrimitiveType(env, types, {"unsigned char", "uchar"}, PrimitiveKind::UInt8, 1, 1);
2586
- RegisterPrimitiveType(env, types, {"char16_t", "char16"}, PrimitiveKind::Int16, 2, 2);
2587
- RegisterPrimitiveType(env, types, {"char32_t", "char32"}, PrimitiveKind::Int32, 4, 4);
2588
- if (K_SIZE(wchar_t) == 2) {
2589
- RegisterPrimitiveType(env, types, {"wchar_t", "wchar"}, PrimitiveKind::Int16, 2, 2);
2590
- } else if (K_SIZE(wchar_t) == 4) {
2591
- RegisterPrimitiveType(env, types, {"wchar_t", "wchar"}, PrimitiveKind::Int32, 4, 4);
2592
- }
2593
- RegisterPrimitiveType(env, types, {"int16_t", "int16"}, PrimitiveKind::Int16, 2, 2);
2594
- RegisterPrimitiveType(env, types, {"int16_le_t", "int16_le"}, GetLittleEndianPrimitive(PrimitiveKind::Int16), 2, 2);
2595
- RegisterPrimitiveType(env, types, {"int16_be_t", "int16_be"}, GetBigEndianPrimitive(PrimitiveKind::Int16), 2, 2);
2596
- RegisterPrimitiveType(env, types, {"uint16_t", "uint16"}, PrimitiveKind::UInt16, 2, 2);
2597
- RegisterPrimitiveType(env, types, {"uint16_le_t", "uint16_le"}, GetLittleEndianPrimitive(PrimitiveKind::UInt16), 2, 2);
2598
- RegisterPrimitiveType(env, types, {"uint16_be_t", "uint16_be"}, GetBigEndianPrimitive(PrimitiveKind::UInt16), 2, 2);
2599
- RegisterPrimitiveType(env, types, {"short"}, PrimitiveKind::Int16, 2, 2);
2600
- RegisterPrimitiveType(env, types, {"unsigned short", "ushort"}, PrimitiveKind::UInt16, 2, 2);
2601
- RegisterPrimitiveType(env, types, {"int32_t", "int32"}, PrimitiveKind::Int32, 4, 4);
2602
- RegisterPrimitiveType(env, types, {"int32_le_t", "int32_le"}, GetLittleEndianPrimitive(PrimitiveKind::Int32), 4, 4);
2603
- RegisterPrimitiveType(env, types, {"int32_be_t", "int32_be"}, GetBigEndianPrimitive(PrimitiveKind::Int32), 4, 4);
2604
- RegisterPrimitiveType(env, types, {"uint32_t", "uint32"}, PrimitiveKind::UInt32, 4, 4);
2605
- RegisterPrimitiveType(env, types, {"uint32_le_t", "uint32_le"}, GetLittleEndianPrimitive(PrimitiveKind::UInt32), 4, 4);
2606
- RegisterPrimitiveType(env, types, {"uint32_be_t", "uint32_be"}, GetBigEndianPrimitive(PrimitiveKind::UInt32), 4, 4);
2607
- RegisterPrimitiveType(env, types, {"int"}, PrimitiveKind::Int32, 4, 4);
2608
- RegisterPrimitiveType(env, types, {"unsigned int", "uint"}, PrimitiveKind::UInt32, 4, 4);
2609
- RegisterPrimitiveType(env, types, {"int64_t", "int64"}, PrimitiveKind::Int64, 8, alignof(int64_t));
2610
- RegisterPrimitiveType(env, types, {"int64_le_t", "int64_le"}, GetLittleEndianPrimitive(PrimitiveKind::Int64), 8, alignof(int64_t));
2611
- RegisterPrimitiveType(env, types, {"int64_be_t", "int64_be"}, GetBigEndianPrimitive(PrimitiveKind::Int64), 8, alignof(int64_t));
2612
- RegisterPrimitiveType(env, types, {"uint64_t", "uint64"}, PrimitiveKind::UInt64, 8, alignof(int64_t));
2613
- RegisterPrimitiveType(env, types, {"uint64_le_t", "uint64_le"}, GetLittleEndianPrimitive(PrimitiveKind::UInt64), 8, alignof(int64_t));
2614
- RegisterPrimitiveType(env, types, {"uint64_be_t", "uint64_be"}, GetBigEndianPrimitive(PrimitiveKind::UInt64), 8, alignof(int64_t));
2615
- RegisterPrimitiveType(env, types, {"intptr_t", "intptr"}, GetSignPrimitive(K_SIZE(intptr_t), true), K_SIZE(intptr_t), alignof(intptr_t));
2616
- RegisterPrimitiveType(env, types, {"uintptr_t", "uintptr"}, GetSignPrimitive(K_SIZE(intptr_t), false), K_SIZE(intptr_t), alignof(intptr_t));
2617
- RegisterPrimitiveType(env, types, {"size_t"}, GetSignPrimitive(K_SIZE(size_t), false), K_SIZE(size_t), alignof(size_t));
2618
- RegisterPrimitiveType(env, types, {"long"}, GetSignPrimitive(K_SIZE(long), true), K_SIZE(long), alignof(long));
2619
- RegisterPrimitiveType(env, types, {"unsigned long", "ulong"}, GetSignPrimitive(K_SIZE(long), false), K_SIZE(long), alignof(long));
2620
- RegisterPrimitiveType(env, types, {"long long", "longlong"}, PrimitiveKind::Int64, K_SIZE(int64_t), alignof(int64_t));
2621
- RegisterPrimitiveType(env, types, {"unsigned long long", "ulonglong"}, PrimitiveKind::UInt64, K_SIZE(uint64_t), alignof(uint64_t));
2622
- RegisterPrimitiveType(env, types, {"float", "float32"}, PrimitiveKind::Float32, 4, alignof(float));
2623
- RegisterPrimitiveType(env, types, {"double", "float64"}, PrimitiveKind::Float64, 8, alignof(double));
2624
- RegisterPrimitiveType(env, types, {"char *", "str", "string"}, PrimitiveKind::String, K_SIZE(void *), alignof(void *), "char");
2625
- RegisterPrimitiveType(env, types, {"char16_t *", "char16 *", "str16", "string16"}, PrimitiveKind::String16, K_SIZE(void *), alignof(void *), "char16_t");
2626
- RegisterPrimitiveType(env, types, {"char32_t *", "char32 *", "str32", "string32"}, PrimitiveKind::String32, K_SIZE(void *), alignof(void *), "char32_t");
2627
- if (K_SIZE(wchar_t) == 2) {
2628
- RegisterPrimitiveType(env, types, {"wchar_t *", "wchar *"}, PrimitiveKind::String16, K_SIZE(void *), alignof(void *), "wchar_t");
2629
- } else if (K_SIZE(wchar_t) == 4) {
2630
- RegisterPrimitiveType(env, types, {"wchar_t *", "wchar *"}, PrimitiveKind::String32, K_SIZE(void *), alignof(void *), "wchar_t");
2631
- }
2632
-
2633
- instance->void_type = instance->types_map.FindValue("void", nullptr);
2634
- instance->char_type = instance->types_map.FindValue("char", nullptr);
2635
- instance->char16_type = instance->types_map.FindValue("char16", nullptr);
2636
- instance->char32_type = instance->types_map.FindValue("char32", nullptr);
2637
- instance->str_type = instance->types_map.FindValue("char *", nullptr);
2638
- instance->str16_type = instance->types_map.FindValue("char16_t *", nullptr);
2639
- instance->str32_type = instance->types_map.FindValue("char32_t *", nullptr);
2640
-
2641
- Napi::Symbol symbol = Napi::Symbol::New(env, "active");
2642
- instance->active_symbol.Reset(symbol, 1);
2643
-
2644
- instance->base_types_count = instance->types.count;
2645
- }
2646
-
2647
- // Expose internal Node stuff
2648
- {
2649
- Napi::Object node = Napi::Object::New(env);
2650
- exports.Set("node", node);
2651
-
2652
- Napi::External<void> external = Napi::External<void>::New(env, (napi_env)env);
2653
- SetValueTag(external, instance->void_type);
2654
-
2655
- node.Set("env", external);
2656
-
2657
- node.Set("poll", Napi::Function::New(env, &Poll, "poll"));
2658
- node.Set("PollHandle", PollHandle::Define(env));
2659
- }
2660
-
2661
- exports.Set("version", Napi::String::New(env, K_STRINGIFY(VERSION)));
2662
-
2663
- napi_add_env_cleanup_hook(env, [](void *udata) {
2664
- InstanceData *instance = (InstanceData *)udata;
2665
-
2666
- if (instance->broker) {
2667
- // This deadlocks if we try to do this when the module is destroyed, when
2668
- // the InstanceData destructor runs, so run in the env cleanup hook instead,
2669
- // where it seems to go okay.
2670
- napi_release_threadsafe_function(instance->broker, napi_tsfn_abort);
2671
- }
2672
- }, instance);
2673
-
2674
- return exports;
2675
- }
2676
-
2677
- InstanceData::~InstanceData()
2678
- {
2679
- for (InstanceMemory *mem: memories) {
2680
- delete mem;
2681
- }
2682
-
2683
- // Clean-up leftover trampoline references
2684
- {
2685
- std::lock_guard<std::mutex> lock(shared.mutex);
2686
-
2687
- for (int16_t idx = 0; idx < MaxTrampolines; idx++) {
2688
- TrampolineInfo *trampoline = &shared.trampolines[idx];
2689
-
2690
- if (trampoline->instance == this) {
2691
- trampoline->instance = nullptr;
2692
- trampoline->func.Reset();
2693
- trampoline->recv.Reset();
2694
- trampoline->used = false;
2695
- }
2696
- }
2697
- }
2698
- }
2699
-
2700
- NODE_API_MODULE(koffi, InitModule);
2701
-
2702
- }