@psnext/slingcli 2.4.20260525-4 → 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 (243) 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 +78 -63
  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/node_modules/undici/lib/api/api-request.js +1 -1
  100. package/node_modules/undici/lib/cache/sqlite-cache-store.js +3 -3
  101. package/node_modules/undici/lib/core/connect.js +16 -0
  102. package/node_modules/undici/lib/core/request.js +17 -2
  103. package/node_modules/undici/lib/core/socks5-client.js +10 -5
  104. package/node_modules/undici/lib/core/socks5-utils.js +17 -22
  105. package/node_modules/undici/lib/dispatcher/client-h1.js +64 -20
  106. package/node_modules/undici/lib/dispatcher/client.js +6 -2
  107. package/node_modules/undici/lib/dispatcher/h2c-client.js +1 -1
  108. package/node_modules/undici/lib/mock/mock-call-history.js +15 -15
  109. package/node_modules/undici/lib/util/cache.js +8 -7
  110. package/node_modules/undici/lib/web/fetch/formdata-parser.js +17 -6
  111. package/node_modules/undici/lib/web/fetch/index.js +5 -2
  112. package/node_modules/undici/lib/web/webidl/index.js +5 -5
  113. package/node_modules/undici/lib/web/websocket/stream/websocketstream.js +1 -7
  114. package/node_modules/undici/package.json +1 -1
  115. package/package.json +6 -6
  116. package/slingshot/index.js +269 -266
  117. package/node_modules/koffi/CHANGELOG.md +0 -1093
  118. package/node_modules/koffi/LICENSE.txt +0 -22
  119. package/node_modules/koffi/README.md +0 -43
  120. package/node_modules/koffi/build/koffi/darwin_arm64/koffi.node +0 -0
  121. package/node_modules/koffi/build/koffi/darwin_x64/koffi.node +0 -0
  122. package/node_modules/koffi/build/koffi/freebsd_arm64/koffi.node +0 -0
  123. package/node_modules/koffi/build/koffi/freebsd_ia32/koffi.node +0 -0
  124. package/node_modules/koffi/build/koffi/freebsd_x64/koffi.node +0 -0
  125. package/node_modules/koffi/build/koffi/linux_arm64/koffi.node +0 -0
  126. package/node_modules/koffi/build/koffi/linux_armhf/koffi.node +0 -0
  127. package/node_modules/koffi/build/koffi/linux_ia32/koffi.node +0 -0
  128. package/node_modules/koffi/build/koffi/linux_loong64/koffi.node +0 -0
  129. package/node_modules/koffi/build/koffi/linux_riscv64d/koffi.node +0 -0
  130. package/node_modules/koffi/build/koffi/linux_x64/koffi.node +0 -0
  131. package/node_modules/koffi/build/koffi/musl_arm64/koffi.node +0 -0
  132. package/node_modules/koffi/build/koffi/musl_x64/koffi.node +0 -0
  133. package/node_modules/koffi/build/koffi/openbsd_ia32/koffi.node +0 -0
  134. package/node_modules/koffi/build/koffi/openbsd_x64/koffi.node +0 -0
  135. package/node_modules/koffi/build/koffi/win32_arm64/koffi.exp +0 -0
  136. package/node_modules/koffi/build/koffi/win32_arm64/koffi.lib +0 -0
  137. package/node_modules/koffi/build/koffi/win32_arm64/koffi.node +0 -0
  138. package/node_modules/koffi/build/koffi/win32_ia32/koffi.exp +0 -0
  139. package/node_modules/koffi/build/koffi/win32_ia32/koffi.lib +0 -0
  140. package/node_modules/koffi/build/koffi/win32_ia32/koffi.node +0 -0
  141. package/node_modules/koffi/build/koffi/win32_x64/koffi.exp +0 -0
  142. package/node_modules/koffi/build/koffi/win32_x64/koffi.lib +0 -0
  143. package/node_modules/koffi/build/koffi/win32_x64/koffi.node +0 -0
  144. package/node_modules/koffi/doc/benchmarks.md +0 -126
  145. package/node_modules/koffi/doc/callbacks.md +0 -210
  146. package/node_modules/koffi/doc/contribute.md +0 -148
  147. package/node_modules/koffi/doc/functions.md +0 -250
  148. package/node_modules/koffi/doc/index.md +0 -61
  149. package/node_modules/koffi/doc/input.md +0 -471
  150. package/node_modules/koffi/doc/migration.md +0 -159
  151. package/node_modules/koffi/doc/misc.md +0 -180
  152. package/node_modules/koffi/doc/output.md +0 -305
  153. package/node_modules/koffi/doc/packaging.md +0 -88
  154. package/node_modules/koffi/doc/platforms.md +0 -36
  155. package/node_modules/koffi/doc/pointers.md +0 -328
  156. package/node_modules/koffi/doc/start.md +0 -118
  157. package/node_modules/koffi/doc/unions.md +0 -186
  158. package/node_modules/koffi/doc/variables.md +0 -102
  159. package/node_modules/koffi/index.d.ts +0 -288
  160. package/node_modules/koffi/index.js +0 -634
  161. package/node_modules/koffi/indirect.js +0 -533
  162. package/node_modules/koffi/lib/native/base/base.cc +0 -11015
  163. package/node_modules/koffi/lib/native/base/base.hh +0 -6003
  164. package/node_modules/koffi/lib/native/base/crc.inc +0 -2214
  165. package/node_modules/koffi/lib/native/base/crc_gen.py +0 -72
  166. package/node_modules/koffi/lib/native/base/mimetypes.inc +0 -1248
  167. package/node_modules/koffi/lib/native/base/mimetypes_gen.py +0 -58
  168. package/node_modules/koffi/lib/native/base/tower.cc +0 -821
  169. package/node_modules/koffi/lib/native/base/tower.hh +0 -81
  170. package/node_modules/koffi/lib/native/base/unicode.inc +0 -408
  171. package/node_modules/koffi/lib/native/base/unicode_gen.py +0 -152
  172. package/node_modules/koffi/package.json +0 -38
  173. package/node_modules/koffi/src/cnoke/LICENSE.txt +0 -22
  174. package/node_modules/koffi/src/cnoke/README.md +0 -99
  175. package/node_modules/koffi/src/cnoke/assets/FindCNoke.cmake +0 -127
  176. package/node_modules/koffi/src/cnoke/assets/toolchains.json +0 -126
  177. package/node_modules/koffi/src/cnoke/assets/win_delay_hook.c +0 -36
  178. package/node_modules/koffi/src/cnoke/cnoke.js +0 -170
  179. package/node_modules/koffi/src/cnoke/package.json +0 -24
  180. package/node_modules/koffi/src/cnoke/src/builder.js +0 -511
  181. package/node_modules/koffi/src/cnoke/src/index.js +0 -10
  182. package/node_modules/koffi/src/cnoke/src/tools.js +0 -407
  183. package/node_modules/koffi/src/koffi/CMakeLists.txt +0 -182
  184. package/node_modules/koffi/src/koffi/src/abi_arm32.cc +0 -1018
  185. package/node_modules/koffi/src/koffi/src/abi_arm32_asm.S +0 -169
  186. package/node_modules/koffi/src/koffi/src/abi_arm64.cc +0 -1295
  187. package/node_modules/koffi/src/koffi/src/abi_arm64_asm.S +0 -195
  188. package/node_modules/koffi/src/koffi/src/abi_arm64_asm.asm +0 -174
  189. package/node_modules/koffi/src/koffi/src/abi_loong64.cc +0 -5
  190. package/node_modules/koffi/src/koffi/src/abi_loong64_asm.S +0 -204
  191. package/node_modules/koffi/src/koffi/src/abi_riscv64.cc +0 -915
  192. package/node_modules/koffi/src/koffi/src/abi_riscv64_asm.S +0 -203
  193. package/node_modules/koffi/src/koffi/src/abi_x64_sysv.cc +0 -939
  194. package/node_modules/koffi/src/koffi/src/abi_x64_sysv_asm.S +0 -231
  195. package/node_modules/koffi/src/koffi/src/abi_x64_win.cc +0 -715
  196. package/node_modules/koffi/src/koffi/src/abi_x64_win_asm.S +0 -166
  197. package/node_modules/koffi/src/koffi/src/abi_x64_win_asm.asm +0 -192
  198. package/node_modules/koffi/src/koffi/src/abi_x86.cc +0 -860
  199. package/node_modules/koffi/src/koffi/src/abi_x86_asm.S +0 -193
  200. package/node_modules/koffi/src/koffi/src/abi_x86_asm.asm +0 -177
  201. package/node_modules/koffi/src/koffi/src/call.cc +0 -1326
  202. package/node_modules/koffi/src/koffi/src/call.hh +0 -179
  203. package/node_modules/koffi/src/koffi/src/errno.inc +0 -462
  204. package/node_modules/koffi/src/koffi/src/ffi.cc +0 -2702
  205. package/node_modules/koffi/src/koffi/src/ffi.hh +0 -354
  206. package/node_modules/koffi/src/koffi/src/init.js +0 -105
  207. package/node_modules/koffi/src/koffi/src/parser.cc +0 -220
  208. package/node_modules/koffi/src/koffi/src/parser.hh +0 -54
  209. package/node_modules/koffi/src/koffi/src/util.cc +0 -1807
  210. package/node_modules/koffi/src/koffi/src/util.hh +0 -221
  211. package/node_modules/koffi/src/koffi/src/uv.cc +0 -193
  212. package/node_modules/koffi/src/koffi/src/uv.def +0 -10
  213. package/node_modules/koffi/src/koffi/src/uv.hh +0 -40
  214. package/node_modules/koffi/src/koffi/src/win32.cc +0 -198
  215. package/node_modules/koffi/src/koffi/src/win32.hh +0 -119
  216. package/node_modules/koffi/src/koffi/tools/write_trampolines.js +0 -77
  217. package/node_modules/koffi/vendor/node-addon-api/LICENSE.md +0 -9
  218. package/node_modules/koffi/vendor/node-addon-api/README.md +0 -95
  219. package/node_modules/koffi/vendor/node-addon-api/napi-inl.deprecated.h +0 -186
  220. package/node_modules/koffi/vendor/node-addon-api/napi-inl.h +0 -7033
  221. package/node_modules/koffi/vendor/node-addon-api/napi.h +0 -3309
  222. package/node_modules/koffi/vendor/node-api-headers/LICENSE +0 -21
  223. package/node_modules/koffi/vendor/node-api-headers/README.md +0 -95
  224. package/node_modules/koffi/vendor/node-api-headers/def/js_native_api.def +0 -125
  225. package/node_modules/koffi/vendor/node-api-headers/def/node_api.def +0 -157
  226. package/node_modules/koffi/vendor/node-api-headers/include/js_native_api.h +0 -591
  227. package/node_modules/koffi/vendor/node-api-headers/include/js_native_api_types.h +0 -210
  228. package/node_modules/koffi/vendor/node-api-headers/include/node_api.h +0 -265
  229. package/node_modules/koffi/vendor/node-api-headers/include/node_api_types.h +0 -58
  230. package/node_modules/koffi/vendor/node-api-headers/include/uv/aix.h +0 -32
  231. package/node_modules/koffi/vendor/node-api-headers/include/uv/bsd.h +0 -34
  232. package/node_modules/koffi/vendor/node-api-headers/include/uv/darwin.h +0 -61
  233. package/node_modules/koffi/vendor/node-api-headers/include/uv/errno.h +0 -483
  234. package/node_modules/koffi/vendor/node-api-headers/include/uv/linux.h +0 -34
  235. package/node_modules/koffi/vendor/node-api-headers/include/uv/os390.h +0 -33
  236. package/node_modules/koffi/vendor/node-api-headers/include/uv/posix.h +0 -31
  237. package/node_modules/koffi/vendor/node-api-headers/include/uv/sunos.h +0 -44
  238. package/node_modules/koffi/vendor/node-api-headers/include/uv/threadpool.h +0 -37
  239. package/node_modules/koffi/vendor/node-api-headers/include/uv/tree.h +0 -521
  240. package/node_modules/koffi/vendor/node-api-headers/include/uv/unix.h +0 -512
  241. package/node_modules/koffi/vendor/node-api-headers/include/uv/version.h +0 -43
  242. package/node_modules/koffi/vendor/node-api-headers/include/uv/win.h +0 -698
  243. package/node_modules/koffi/vendor/node-api-headers/include/uv.h +0 -1990
@@ -1,1326 +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 "call.hh"
6
- #include "ffi.hh"
7
- #include "util.hh"
8
-
9
- #include <napi.h>
10
-
11
- namespace K {
12
-
13
- struct RelayContext {
14
- CallData *call;
15
-
16
- Size idx;
17
- uint8_t *sp;
18
-
19
- std::mutex mutex = {};
20
- std::condition_variable cv = {};
21
- bool done = false;
22
- };
23
-
24
- extern "C" void *FindTrampolineStart();
25
- extern "C" void *FindTrampolineEnd();
26
-
27
- static const uint8_t *TrampolineStart = (const uint8_t *)FindTrampolineStart();
28
- static const Size TrampolineSize = ((const uint8_t *)FindTrampolineEnd() - TrampolineStart) / MaxTrampolines;
29
-
30
- CallData::CallData(Napi::Env env, InstanceData *instance, InstanceMemory *mem)
31
- : env(env), instance(instance),
32
- mem(mem), old_stack_mem(mem->stack), old_heap_mem(mem->heap)
33
- {
34
- mem->depth++;
35
-
36
- K_ASSERT(AlignUp(mem->stack.ptr, 16) == mem->stack.ptr);
37
- }
38
-
39
- CallData::~CallData()
40
- {
41
- if (!instance)
42
- return;
43
-
44
- Dispose();
45
- }
46
-
47
- void CallData::Dispose()
48
- {
49
- for (const OutArgument &out: out_arguments) {
50
- napi_delete_reference(env, out.ref);
51
- }
52
-
53
- mem->stack = old_stack_mem;
54
- mem->heap = old_heap_mem;
55
-
56
- if (used_trampolines.len) {
57
- std::lock_guard<std::mutex> lock(shared.mutex);
58
-
59
- for (Size i = used_trampolines.len - 1; i >= 0; i--) {
60
- int16_t idx = used_trampolines[i];
61
- TrampolineInfo *trampoline = &shared.trampolines[idx];
62
-
63
- K_ASSERT(trampoline->instance == instance);
64
- K_ASSERT(!trampoline->func.IsEmpty());
65
-
66
- trampoline->func.Reset();
67
- trampoline->recv.Reset();
68
- trampoline->used = false;
69
-
70
- shared.available.Append(idx);
71
- }
72
- }
73
-
74
- ReleaseMemory(instance, mem);
75
-
76
- instance = nullptr;
77
- }
78
-
79
- void CallData::RelayAsync(Size idx, uint8_t *sp)
80
- {
81
- // JS/V8 is single-threaded, and runs on main_thread_id. Forward the call
82
- // to the JS event loop.
83
-
84
- RelayContext ctx = {
85
- .call = this,
86
- .idx = idx,
87
- .sp = sp
88
- };
89
-
90
- napi_call_threadsafe_function(instance->broker, &ctx, napi_tsfn_blocking);
91
-
92
- // Wait until it executes
93
- std::unique_lock<std::mutex> lock(ctx.mutex);
94
- while (!ctx.done) {
95
- ctx.cv.wait(lock);
96
- }
97
- }
98
-
99
- bool CallData::PushString(Napi::Value value, int directions, const char **out_str)
100
- {
101
- // Fast path
102
- if (value.IsString()) {
103
- if (directions & 2) [[unlikely]] {
104
- ThrowError<Napi::TypeError>(env, "Unexpected %1 value, expected [string]", GetValueType(instance, value));
105
- return false;
106
- }
107
-
108
- PushStringValue(value, out_str);
109
- return true;
110
- }
111
-
112
- return PushPointer(value, instance->str_type, directions, (void **)out_str);
113
- }
114
-
115
- bool CallData::PushString16(Napi::Value value, int directions, const char16_t **out_str16)
116
- {
117
- // Fast path
118
- if (value.IsString()) {
119
- if (directions & 2) [[unlikely]] {
120
- ThrowError<Napi::TypeError>(env, "Unexpected %1 value, expected [string]", GetValueType(instance, value));
121
- return false;
122
- }
123
-
124
- PushString16Value(value, out_str16);
125
- return true;
126
- }
127
-
128
- return PushPointer(value, instance->str16_type, directions, (void **)out_str16);
129
- }
130
-
131
- bool CallData::PushString32(Napi::Value value, int directions, const char32_t **out_str32)
132
- {
133
- // Fast path
134
- if (value.IsString()) {
135
- if (directions & 2) [[unlikely]] {
136
- ThrowError<Napi::TypeError>(env, "Unexpected %1 value, expected [string]", GetValueType(instance, value));
137
- return false;
138
- }
139
-
140
- PushString32Value(value, out_str32);
141
- return true;
142
- }
143
-
144
- return PushPointer(value, instance->str32_type, directions, (void **)out_str32);
145
- }
146
-
147
- Size CallData::PushStringValue(Napi::Value value, const char **out_str)
148
- {
149
- Span<char> buf;
150
- size_t len = 0;
151
- napi_status status;
152
-
153
- buf.ptr = (char *)mem->heap.ptr;
154
- buf.len = mem->heap.len;
155
-
156
- status = napi_get_value_string_utf8(env, value, buf.ptr, (size_t)buf.len, &len);
157
- K_ASSERT(status == napi_ok);
158
-
159
- len++;
160
-
161
- // V8 can truncate the string and return a length that is less than the real string
162
- // length in several cases, such as when it flattens string ropes.
163
- // This was the cause of a truncation bug (see https://github.com/Koromix/koffi/issues/266),
164
- // which went unnoticed for a long time.
165
- // We don't want to query the length beforehand, because it's slow. Instead, check that the
166
- // returned lengfth is much shorter than the available buffer capacity, and if so, we know
167
- // we're okay because V8 flattens strings ~32 KiB at a time.
168
-
169
- if ((Size)len < buf.len - Kibibytes(64)) [[likely]] {
170
- mem->heap.ptr += (Size)len;
171
- mem->heap.len -= (Size)len;
172
- } else {
173
- status = napi_get_value_string_utf8(env, value, nullptr, 0, &len);
174
- K_ASSERT(status == napi_ok);
175
-
176
- len++;
177
- buf = AllocateSpan<char>(&alloc, (Size)len);
178
-
179
- status = napi_get_value_string_utf8(env, value, buf.ptr, (size_t)buf.len, &len);
180
- K_ASSERT(status == napi_ok);
181
-
182
- len++;
183
- }
184
-
185
- *out_str = buf.ptr;
186
- return (Size)len;
187
- }
188
-
189
- Size CallData::PushString16Value(Napi::Value value, const char16_t **out_str16)
190
- {
191
- Span<char16_t> buf;
192
- size_t len = 0;
193
- napi_status status;
194
-
195
- mem->heap.ptr = AlignUp(mem->heap.ptr, 2);
196
- buf.ptr = (char16_t *)mem->heap.ptr;
197
- buf.len = mem->heap.len / 2;
198
-
199
- status = napi_get_value_string_utf16(env, value, buf.ptr, (size_t)buf.len, &len);
200
- K_ASSERT(status == napi_ok);
201
-
202
- len++;
203
-
204
- if ((Size)len < buf.len - Kibibytes(64) / 2) [[likely]] {
205
- mem->heap.ptr += (Size)len * 2;
206
- mem->heap.len -= (Size)len * 2;
207
- } else {
208
- status = napi_get_value_string_utf16(env, value, nullptr, 0, &len);
209
- K_ASSERT(status == napi_ok);
210
-
211
- len++;
212
- buf = AllocateSpan<char16_t>(&alloc, (Size)len);
213
-
214
- status = napi_get_value_string_utf16(env, value, buf.ptr, (size_t)buf.len, &len);
215
- K_ASSERT(status == napi_ok);
216
-
217
- len++;
218
- }
219
-
220
- *out_str16 = buf.ptr;
221
- return (Size)len;
222
- }
223
-
224
- Size CallData::PushString32Value(Napi::Value value, const char32_t **out_str32)
225
- {
226
- static const char32_t ReplacementChar = 0x0000FFFD;
227
-
228
- Span<char32_t> buf;
229
-
230
- Span<const char16_t> buf16;
231
- buf16.len = PushString16Value(value, &buf16.ptr);
232
- if (buf16.len < 0) [[unlikely]]
233
- return -1;
234
-
235
- mem->heap.ptr = AlignUp(mem->heap.ptr, 4);
236
- buf.ptr = (char32_t *)mem->heap.ptr;
237
- buf.len = mem->heap.len / 4;
238
-
239
- if (buf16.len < buf.len) [[likely]] {
240
- mem->heap.ptr += buf16.len * 4;
241
- mem->heap.len -= buf16.len * 4;
242
- } else {
243
- buf = AllocateSpan<char32_t>(&alloc, buf16.len);
244
- }
245
-
246
- Size j = 0;
247
- for (Size i = 0; i < buf16.len; i++) {
248
- char32_t uc = buf16[i];
249
-
250
- if (uc >= 0xD800 && uc <= 0xDBFF) {
251
- if (++i < buf16.len) {
252
- char16_t uc2 = buf16.ptr[i];
253
-
254
- if (uc2 >= 0xDC00 && uc2 <= 0xDFFF) [[likely]] {
255
- uc = ((uc - 0xD800) << 10) + (uc2 - 0xDC00) + 0x10000u;
256
- } else {
257
- uc = ReplacementChar;
258
- }
259
- } else {
260
- uc = ReplacementChar;
261
- }
262
- } else if (uc >= 0xDC00 && uc <= 0xDFFF) [[unlikely]] {
263
- uc = ReplacementChar;
264
- }
265
-
266
- buf[j++] = uc;
267
- }
268
-
269
- *out_str32 = buf.ptr;
270
- return j;
271
- }
272
-
273
- bool CallData::PushObject(Napi::Object obj, const TypeInfo *type, uint8_t *origin)
274
- {
275
- K_ASSERT(IsObject(obj));
276
- K_ASSERT(type->primitive == PrimitiveKind::Record ||
277
- type->primitive == PrimitiveKind::Union);
278
-
279
- Span<const RecordMember> members = {};
280
-
281
- if (type->primitive == PrimitiveKind::Record) {
282
- members = type->members;
283
- } else if (type->primitive == PrimitiveKind::Union) {
284
- if (CheckValueTag(obj, &MagicUnionMarker)) {
285
- MagicUnion *u = MagicUnion::Unwrap(obj);
286
- const uint8_t *raw = u->GetRaw();
287
-
288
- if (u->GetType() != type) [[unlikely]] {
289
- ThrowError<Napi::TypeError>(env, "Expected union type %1, got %2", type->name, u->GetType()->name);
290
- return false;
291
- }
292
-
293
- // Fast path: encoded value already exists, just copy!
294
- if (raw) {
295
- memcpy(origin, raw, type->size);
296
- return true;
297
- }
298
-
299
- members.ptr = u->GetMember();
300
- members.len = 1;
301
-
302
- if (!members.ptr) [[unlikely]] {
303
- ThrowError<Napi::Error>(env, "Cannot use ambiguous empty union");
304
- return false;
305
- }
306
- } else {
307
- Napi::Array properties = GetOwnPropertyNames(obj);
308
-
309
- if (properties.Length() != 1 || !properties.Get(0u).IsString()) [[unlikely]] {
310
- ThrowError<Napi::Error>(env, "Expected object with single property name for union");
311
- return false;
312
- }
313
-
314
- std::string property = properties.Get(0u).As<Napi::String>();
315
-
316
- members.ptr = std::find_if(type->members.begin(), type->members.end(),
317
- [&](const RecordMember &member) { return TestStr(property.c_str(), member.name); });
318
- members.len = 1;
319
-
320
- if (members.ptr == type->members.end()) [[unlikely]] {
321
- ThrowError<Napi::Error>(env, "Unknown member %1 in union type %2", property.c_str(), type->name);
322
- return false;
323
- }
324
- }
325
- } else {
326
- K_UNREACHABLE();
327
- }
328
-
329
- MemSet(origin, 0, type->size);
330
-
331
- for (Size i = 0; i < members.len; i++) {
332
- const RecordMember &member = members[i];
333
- Napi::Value value = obj.Get(member.name);
334
-
335
- if (member.countedby >= 0) {
336
- const char *countedby = members[member.countedby].name;
337
-
338
- if (!CheckDynamicLength(obj, member.type->ref.type->size, countedby, value)) [[unlikely]]
339
- return false;
340
- }
341
-
342
- if (value.IsUndefined())
343
- continue;
344
-
345
- uint8_t *dest = origin + member.offset;
346
-
347
- switch (member.type->primitive) {
348
- case PrimitiveKind::Void: { K_UNREACHABLE(); } break;
349
-
350
- case PrimitiveKind::Bool: {
351
- if (!value.IsBoolean()) [[unlikely]] {
352
- ThrowError<Napi::TypeError>(env, "Unexpected %1 value, expected boolean", GetValueType(instance, value));
353
- return false;
354
- }
355
-
356
- bool b = value.As<Napi::Boolean>();
357
- *(bool *)dest = b;
358
- } break;
359
- case PrimitiveKind::Int8: {
360
- if (!value.IsNumber() && !value.IsBigInt()) [[unlikely]] {
361
- ThrowError<Napi::TypeError>(env, "Unexpected %1 value, expected number", GetValueType(instance, value));
362
- return false;
363
- }
364
-
365
- int8_t v = GetNumber<int8_t>(value);
366
- *(int8_t *)dest = v;
367
- } break;
368
- case PrimitiveKind::UInt8: {
369
- if (!value.IsNumber() && !value.IsBigInt()) [[unlikely]] {
370
- ThrowError<Napi::TypeError>(env, "Unexpected %1 value, expected number", GetValueType(instance, value));
371
- return false;
372
- }
373
-
374
- uint8_t v = GetNumber<uint8_t>(value);
375
- *(uint8_t *)dest = v;
376
- } break;
377
- case PrimitiveKind::Int16: {
378
- if (!value.IsNumber() && !value.IsBigInt()) [[unlikely]] {
379
- ThrowError<Napi::TypeError>(env, "Unexpected %1 value, expected number", GetValueType(instance, value));
380
- return false;
381
- }
382
-
383
- int16_t v = GetNumber<int16_t>(value);
384
- *(int16_t *)dest = v;
385
- } break;
386
- case PrimitiveKind::Int16S: {
387
- if (!value.IsNumber() && !value.IsBigInt()) [[unlikely]] {
388
- ThrowError<Napi::TypeError>(env, "Unexpected %1 value, expected number", GetValueType(instance, value));
389
- return false;
390
- }
391
-
392
- int16_t v = GetNumber<int16_t>(value);
393
- *(int16_t *)dest = ReverseBytes(v);
394
- } break;
395
- case PrimitiveKind::UInt16: {
396
- if (!value.IsNumber() && !value.IsBigInt()) [[unlikely]] {
397
- ThrowError<Napi::TypeError>(env, "Unexpected %1 value, expected number", GetValueType(instance, value));
398
- return false;
399
- }
400
-
401
- uint16_t v = GetNumber<uint16_t>(value);
402
- *(uint16_t *)dest = v;
403
- } break;
404
- case PrimitiveKind::UInt16S: {
405
- if (!value.IsNumber() && !value.IsBigInt()) [[unlikely]] {
406
- ThrowError<Napi::TypeError>(env, "Unexpected %1 value, expected number", GetValueType(instance, value));
407
- return false;
408
- }
409
-
410
- uint16_t v = GetNumber<uint16_t>(value);
411
- *(uint16_t *)dest = ReverseBytes(v);
412
- } break;
413
- case PrimitiveKind::Int32: {
414
- if (!value.IsNumber() && !value.IsBigInt()) [[unlikely]] {
415
- ThrowError<Napi::TypeError>(env, "Unexpected %1 value, expected number", GetValueType(instance, value));
416
- return false;
417
- }
418
-
419
- int32_t v = GetNumber<int32_t>(value);
420
- *(int32_t *)dest = v;
421
- } break;
422
- case PrimitiveKind::Int32S: {
423
- if (!value.IsNumber() && !value.IsBigInt()) [[unlikely]] {
424
- ThrowError<Napi::TypeError>(env, "Unexpected %1 value, expected number", GetValueType(instance, value));
425
- return false;
426
- }
427
-
428
- int32_t v = GetNumber<int32_t>(value);
429
- *(int32_t *)dest = ReverseBytes(v);
430
- } break;
431
- case PrimitiveKind::UInt32: {
432
- if (!value.IsNumber() && !value.IsBigInt()) [[unlikely]] {
433
- ThrowError<Napi::TypeError>(env, "Unexpected %1 value, expected number", GetValueType(instance, value));
434
- return false;
435
- }
436
-
437
- uint32_t v = GetNumber<uint32_t>(value);
438
- *(uint32_t *)dest = v;
439
- } break;
440
- case PrimitiveKind::UInt32S: {
441
- if (!value.IsNumber() && !value.IsBigInt()) [[unlikely]] {
442
- ThrowError<Napi::TypeError>(env, "Unexpected %1 value, expected number", GetValueType(instance, value));
443
- return false;
444
- }
445
-
446
- uint32_t v = GetNumber<uint32_t>(value);
447
- *(uint32_t *)dest = ReverseBytes(v);
448
- } break;
449
- case PrimitiveKind::Int64: {
450
- if (!value.IsNumber() && !value.IsBigInt()) [[unlikely]] {
451
- ThrowError<Napi::TypeError>(env, "Unexpected %1 value, expected number", GetValueType(instance, value));
452
- return false;
453
- }
454
-
455
- int64_t v = GetNumber<int64_t>(value);
456
- *(int64_t *)dest = v;
457
- } break;
458
- case PrimitiveKind::Int64S: {
459
- if (!value.IsNumber() && !value.IsBigInt()) [[unlikely]] {
460
- ThrowError<Napi::TypeError>(env, "Unexpected %1 value, expected number", GetValueType(instance, value));
461
- return false;
462
- }
463
-
464
- int64_t v = GetNumber<int64_t>(value);
465
- *(int64_t *)dest = ReverseBytes(v);
466
- } break;
467
- case PrimitiveKind::UInt64: {
468
- if (!value.IsNumber() && !value.IsBigInt()) [[unlikely]] {
469
- ThrowError<Napi::TypeError>(env, "Unexpected %1 value, expected number", GetValueType(instance, value));
470
- return false;
471
- }
472
-
473
- uint64_t v = GetNumber<uint64_t>(value);
474
- *(uint64_t *)dest = v;
475
- } break;
476
- case PrimitiveKind::UInt64S: {
477
- if (!value.IsNumber() && !value.IsBigInt()) [[unlikely]] {
478
- ThrowError<Napi::TypeError>(env, "Unexpected %1 value, expected number", GetValueType(instance, value));
479
- return false;
480
- }
481
-
482
- uint64_t v = GetNumber<uint64_t>(value);
483
- *(uint64_t *)dest = ReverseBytes(v);
484
- } break;
485
- case PrimitiveKind::String: {
486
- const char *str;
487
- if (!PushString(value, 1, &str)) [[unlikely]]
488
- return false;
489
-
490
- *(const char **)dest = str;
491
- } break;
492
- case PrimitiveKind::String16: {
493
- const char16_t *str16;
494
- if (!PushString16(value, 1, &str16)) [[unlikely]]
495
- return false;
496
-
497
- *(const char16_t **)dest = str16;
498
- } break;
499
- case PrimitiveKind::String32: {
500
- const char32_t *str32;
501
- if (!PushString32(value, 1, &str32)) [[unlikely]]
502
- return false;
503
-
504
- *(const char32_t **)dest = str32;
505
- } break;
506
- case PrimitiveKind::Pointer: {
507
- void *ptr;
508
- if (!PushPointer(value, member.type, 1, &ptr)) [[unlikely]]
509
- return false;
510
-
511
- *(void **)dest = ptr;
512
- } break;
513
- case PrimitiveKind::Record:
514
- case PrimitiveKind::Union: {
515
- if (!IsObject(value)) [[unlikely]] {
516
- ThrowError<Napi::TypeError>(env, "Unexpected %1 value, expected object", GetValueType(instance, value));
517
- return false;
518
- }
519
-
520
- Napi::Object obj2 = value.As<Napi::Object>();
521
- if (!PushObject(obj2, member.type, dest))
522
- return false;
523
- } break;
524
- case PrimitiveKind::Array: {
525
- if (value.IsArray()) {
526
- Napi::Array array = value.As<Napi::Array>();
527
- if (!PushNormalArray(array, member.type, member.type->size, dest))
528
- return false;
529
- } else if (IsRawBuffer(value)) {
530
- Span<const uint8_t> buffer = GetRawBuffer(value);
531
- PushBuffer(buffer, member.type, dest);
532
- } else if (value.IsString()) {
533
- if (!PushStringArray(value, member.type, dest))
534
- return false;
535
- } else {
536
- ThrowError<Napi::TypeError>(env, "Unexpected %1 value, expected array", GetValueType(instance, value));
537
- return false;
538
- }
539
- } break;
540
- case PrimitiveKind::Float32: {
541
- if (!value.IsNumber() && !value.IsBigInt()) [[unlikely]] {
542
- ThrowError<Napi::TypeError>(env, "Unexpected %1 value, expected number", GetValueType(instance, value));
543
- return false;
544
- }
545
-
546
- float f = GetNumber<float>(value);
547
- *(float *)dest = f;
548
- } break;
549
- case PrimitiveKind::Float64: {
550
- if (!value.IsNumber() && !value.IsBigInt()) [[unlikely]] {
551
- ThrowError<Napi::TypeError>(env, "Unexpected %1 value, expected number", GetValueType(instance, value));
552
- return false;
553
- }
554
-
555
- double d = GetNumber<double>(value);
556
- *(double *)dest = d;
557
- } break;
558
- case PrimitiveKind::Callback: {
559
- void *ptr;
560
- if (!PushCallback(value, member.type, &ptr))
561
- return false;
562
-
563
- *(void **)dest = ptr;
564
- } break;
565
-
566
- case PrimitiveKind::Prototype: { K_UNREACHABLE(); } break;
567
- }
568
- }
569
-
570
- return true;
571
- }
572
-
573
- bool CallData::PushNormalArray(Napi::Array array, const TypeInfo *type, Size size, uint8_t *origin)
574
- {
575
- K_ASSERT(array.IsArray());
576
-
577
- const TypeInfo *ref = type->ref.type;
578
- Size len = (Size)array.Length();
579
- Size available = len * ref->size;
580
-
581
- if (available > size) {
582
- len = size / ref->size;
583
- } else {
584
- MemSet(origin + available, 0, size - available);
585
- }
586
-
587
- Size offset = 0;
588
-
589
- #define PUSH_ARRAY(Check, Expected, GetCode) \
590
- do { \
591
- for (Size i = 0; i < len; i++) { \
592
- Napi::Value value = array[(uint32_t)i]; \
593
- \
594
- offset = AlignLen(offset, ref->align); \
595
- uint8_t *dest = origin + offset; \
596
- \
597
- if (!(Check)) [[unlikely]] { \
598
- ThrowError<Napi::TypeError>(env, "Unexpected %1 value, expected %2", GetValueType(instance, value), (Expected)); \
599
- return false; \
600
- } \
601
- \
602
- GetCode \
603
- \
604
- offset += ref->size; \
605
- } \
606
- } while (false)
607
-
608
- switch (ref->primitive) {
609
- case PrimitiveKind::Void: {
610
- ThrowError<Napi::TypeError>(env, "Ambigous parameter type %1, use koffi.as(value, type)", type->name); \
611
- return false;
612
- } break;
613
-
614
- case PrimitiveKind::Bool: {
615
- PUSH_ARRAY(value.IsBoolean(), "boolean", {
616
- bool b = value.As<Napi::Boolean>();
617
- *(bool *)dest = b;
618
- });
619
- } break;
620
- case PrimitiveKind::Int8: {
621
- PUSH_ARRAY(value.IsNumber() || value.IsBigInt(), "number", {
622
- int8_t v = GetNumber<int8_t>(value);
623
- *(int8_t *)dest = v;
624
- });
625
- } break;
626
- case PrimitiveKind::UInt8: {
627
- PUSH_ARRAY(value.IsNumber() || value.IsBigInt(), "number", {
628
- uint8_t v = GetNumber<uint8_t>(value);
629
- *(uint8_t *)dest = v;
630
- });
631
- } break;
632
- case PrimitiveKind::Int16: {
633
- PUSH_ARRAY(value.IsNumber() || value.IsBigInt(), "number", {
634
- int16_t v = GetNumber<int16_t>(value);
635
- *(int16_t *)dest = v;
636
- });
637
- } break;
638
- case PrimitiveKind::Int16S: {
639
- PUSH_ARRAY(value.IsNumber() || value.IsBigInt(), "number", {
640
- int16_t v = GetNumber<int16_t>(value);
641
- *(int16_t *)dest = ReverseBytes(v);
642
- });
643
- } break;
644
- case PrimitiveKind::UInt16: {
645
- PUSH_ARRAY(value.IsNumber() || value.IsBigInt(), "number", {
646
- uint16_t v = GetNumber<uint16_t>(value);
647
- *(uint16_t *)dest = v;
648
- });
649
- } break;
650
- case PrimitiveKind::UInt16S: {
651
- PUSH_ARRAY(value.IsNumber() || value.IsBigInt(), "number", {
652
- uint16_t v = GetNumber<uint16_t>(value);
653
- *(uint16_t *)dest = ReverseBytes(v);
654
- });
655
- } break;
656
- case PrimitiveKind::Int32: {
657
- PUSH_ARRAY(value.IsNumber() || value.IsBigInt(), "number", {
658
- int32_t v = GetNumber<int32_t>(value);
659
- *(int32_t *)dest = v;
660
- });
661
- } break;
662
- case PrimitiveKind::Int32S: {
663
- PUSH_ARRAY(value.IsNumber() || value.IsBigInt(), "number", {
664
- int32_t v = GetNumber<int32_t>(value);
665
- *(int32_t *)dest = ReverseBytes(v);
666
- });
667
- } break;
668
- case PrimitiveKind::UInt32: {
669
- PUSH_ARRAY(value.IsNumber() || value.IsBigInt(), "number", {
670
- uint32_t v = GetNumber<uint32_t>(value);
671
- *(uint32_t *)dest = v;
672
- });
673
- } break;
674
- case PrimitiveKind::UInt32S: {
675
- PUSH_ARRAY(value.IsNumber() || value.IsBigInt(), "number", {
676
- uint32_t v = GetNumber<uint32_t>(value);
677
- *(uint32_t *)dest = ReverseBytes(v);
678
- });
679
- } break;
680
- case PrimitiveKind::Int64: {
681
- PUSH_ARRAY(value.IsNumber() || value.IsBigInt(), "number", {
682
- int64_t v = GetNumber<int64_t>(value);
683
- *(int64_t *)dest = v;
684
- });
685
- } break;
686
- case PrimitiveKind::Int64S: {
687
- PUSH_ARRAY(value.IsNumber() || value.IsBigInt(), "number", {
688
- int64_t v = GetNumber<int64_t>(value);
689
- *(int64_t *)dest = ReverseBytes(v);
690
- });
691
- } break;
692
- case PrimitiveKind::UInt64: {
693
- PUSH_ARRAY(value.IsNumber() || value.IsBigInt(), "number", {
694
- uint64_t v = GetNumber<uint64_t>(value);
695
- *(uint64_t *)dest = v;
696
- });
697
- } break;
698
- case PrimitiveKind::UInt64S: {
699
- PUSH_ARRAY(value.IsNumber() || value.IsBigInt(), "number", {
700
- uint64_t v = GetNumber<uint64_t>(value);
701
- *(uint64_t *)dest = ReverseBytes(v);
702
- });
703
- } break;
704
- case PrimitiveKind::String: {
705
- PUSH_ARRAY(true, "string", {
706
- const char *str;
707
- if (!PushString(value, 1, &str)) [[unlikely]]
708
- return false;
709
-
710
- *(const char **)dest = str;
711
- });
712
- } break;
713
- case PrimitiveKind::String16: {
714
- PUSH_ARRAY(true, "string", {
715
- const char16_t *str16;
716
- if (!PushString16(value, 1, &str16)) [[unlikely]]
717
- return false;
718
-
719
- *(const char16_t **)dest = str16;
720
- });
721
- } break;
722
- case PrimitiveKind::String32: {
723
- PUSH_ARRAY(true, "string", {
724
- const char32_t *str32;
725
- if (!PushString32(value, 1, &str32)) [[unlikely]]
726
- return false;
727
-
728
- *(const char32_t **)dest = str32;
729
- });
730
- } break;
731
- case PrimitiveKind::Pointer: {
732
- PUSH_ARRAY(true, ref->name, {
733
- void *ptr;
734
- if (!PushPointer(value, ref, 1, &ptr)) [[unlikely]]
735
- return false;
736
-
737
- *(const void **)dest = ptr;
738
- });
739
- } break;
740
- case PrimitiveKind::Record:
741
- case PrimitiveKind::Union: {
742
- PUSH_ARRAY(IsObject(value), "object", {
743
- Napi::Object obj2 = value.As<Napi::Object>();
744
- if (!PushObject(obj2, ref, dest))
745
- return false;
746
- });
747
- } break;
748
- case PrimitiveKind::Array: {
749
- for (Size i = 0; i < len; i++) {
750
- Napi::Value value = array[(uint32_t)i];
751
-
752
- offset = AlignLen(offset, ref->align);
753
-
754
- uint8_t *dest = origin + offset;
755
-
756
- if (value.IsArray()) {
757
- Napi::Array array2 = value.As<Napi::Array>();
758
- if (!PushNormalArray(array2, ref, (Size)ref->size, dest))
759
- return false;
760
- } else if (IsRawBuffer(value)) {
761
- Span<const uint8_t> buffer = GetRawBuffer(value);
762
- PushBuffer(buffer, ref, dest);
763
- } else if (value.IsString()) {
764
- if (!PushStringArray(value, ref, dest))
765
- return false;
766
- } else {
767
- ThrowError<Napi::TypeError>(env, "Unexpected %1 value, expected array", GetValueType(instance, value));
768
- return false;
769
- }
770
-
771
- offset += ref->size;
772
- }
773
- } break;
774
- case PrimitiveKind::Float32: {
775
- PUSH_ARRAY(value.IsNumber() || value.IsBigInt(), "number", {
776
- float f = GetNumber<float>(value);
777
- *(float *)dest = f;
778
- });
779
- } break;
780
- case PrimitiveKind::Float64: {
781
- PUSH_ARRAY(value.IsNumber() || value.IsBigInt(), "number", {
782
- double d = GetNumber<double>(value);
783
- *(double *)dest = d;
784
- });
785
- } break;
786
- case PrimitiveKind::Callback: {
787
- for (Size i = 0; i < len; i++) {
788
- Napi::Value value = array[(uint32_t)i];
789
-
790
- offset = AlignLen(offset, ref->align);
791
-
792
- uint8_t *dest = origin + offset;
793
-
794
- void *ptr;
795
- if (!PushCallback(value, ref, &ptr))
796
- return false;
797
-
798
- *(void **)dest = ptr;
799
-
800
- offset += ref->size;
801
- }
802
- } break;
803
-
804
- case PrimitiveKind::Prototype: { K_UNREACHABLE(); } break;
805
- }
806
-
807
- #undef PUSH_ARRAY
808
-
809
- return true;
810
- }
811
-
812
- void CallData::PushBuffer(Span<const uint8_t> buffer, const TypeInfo *type, uint8_t *origin)
813
- {
814
- buffer.len = std::min(buffer.len, (Size)type->size);
815
-
816
- // Go fast brrrrrrr :)
817
- MemCpy(origin, buffer.ptr, buffer.len);
818
- MemSet(origin + buffer.len, 0, (Size)type->size - buffer.len);
819
-
820
- #define SWAP(CType) \
821
- do { \
822
- CType *data = (CType *)origin; \
823
- Size len = buffer.len / K_SIZE(CType); \
824
- \
825
- for (Size i = 0; i < len; i++) { \
826
- data[i] = ReverseBytes(data[i]); \
827
- } \
828
- } while (false)
829
-
830
- if (type->primitive == PrimitiveKind::Array || type->primitive == PrimitiveKind::Pointer) {
831
- const TypeInfo *ref = type->ref.type;
832
-
833
- if (ref->primitive == PrimitiveKind::Int16S || ref->primitive == PrimitiveKind::UInt16S) {
834
- SWAP(uint16_t);
835
- } else if (ref->primitive == PrimitiveKind::Int32S || ref->primitive == PrimitiveKind::UInt32S) {
836
- SWAP(uint32_t);
837
- } else if (ref->primitive == PrimitiveKind::Int64S || ref->primitive == PrimitiveKind::UInt64S) {
838
- SWAP(uint64_t);
839
- }
840
- }
841
-
842
- #undef SWAP
843
- }
844
-
845
- bool CallData::PushStringArray(Napi::Value obj, const TypeInfo *type, uint8_t *origin)
846
- {
847
- K_ASSERT(obj.IsString());
848
- K_ASSERT(type->primitive == PrimitiveKind::Array);
849
-
850
- size_t encoded = 0;
851
-
852
- switch (type->ref.type->primitive) {
853
- case PrimitiveKind::Int8: {
854
- napi_status status = napi_get_value_string_utf8(env, obj, (char *)origin, type->size, &encoded);
855
- K_ASSERT(status == napi_ok);
856
- } break;
857
- case PrimitiveKind::Int16: {
858
- napi_status status = napi_get_value_string_utf16(env, obj, (char16_t *)origin, type->size / 2, &encoded);
859
- K_ASSERT(status == napi_ok);
860
-
861
- encoded *= 2;
862
- } break;
863
-
864
- default: {
865
- ThrowError<Napi::TypeError>(env, "Strings cannot be converted to %1 array", type->ref.type->name);
866
- return false;
867
- } break;
868
- }
869
-
870
- MemSet(origin + encoded, 0, type->size - encoded);
871
-
872
- return true;
873
- }
874
-
875
- bool CallData::PushPointer(Napi::Value value, const TypeInfo *type, int directions, void **out_ptr)
876
- {
877
- if (CheckValueTag(value, &CastMarker)) {
878
- Napi::External<ValueCast> external = value.As<Napi::External<ValueCast>>();
879
- ValueCast *cast = external.Data();
880
-
881
- value = cast->ref.Value();
882
- type = cast->type;
883
- }
884
-
885
- const TypeInfo *ref = type->ref.type;
886
-
887
- switch (value.Type()) {
888
- case napi_undefined:
889
- case napi_null: {
890
- *out_ptr = nullptr;
891
- return true;
892
- } break;
893
-
894
- case napi_external: {
895
- K_ASSERT(type->primitive == PrimitiveKind::Pointer ||
896
- type->primitive == PrimitiveKind::String ||
897
- type->primitive == PrimitiveKind::String16 ||
898
- type->primitive == PrimitiveKind::String32);
899
-
900
- if (!CheckValueTag(value, type->ref.marker) &&
901
- !CheckValueTag(value, instance->void_type) &&
902
- ref != instance->void_type) [[unlikely]]
903
- goto unexpected;
904
-
905
- *out_ptr = value.As<Napi::External<uint8_t>>().Data();
906
- return true;
907
- } break;
908
-
909
- case napi_object: {
910
- uint8_t *ptr = nullptr;
911
-
912
- OutArgument::Kind out_kind;
913
- Size out_max_len = -1;
914
-
915
- if (value.IsArray()) {
916
- Napi::Array array = value.As<Napi::Array>();
917
- Size len = PushIndirectString(array, ref, &ptr);
918
-
919
- if (len >= 0) {
920
- if (!ref->size && ref != instance->void_type) [[unlikely]] {
921
- ThrowError<Napi::TypeError>(env, "Cannot pass [string] value to %1", type->name);
922
- return false;
923
- }
924
-
925
- switch (ref->size) {
926
- default: { out_kind = OutArgument::Kind::String; } break;
927
- case 2: { out_kind = OutArgument::Kind::String16; } break;
928
- case 4: { out_kind = OutArgument::Kind::String32; } break;
929
- }
930
- out_max_len = len;
931
- } else {
932
- if (!ref->size) [[unlikely]] {
933
- ThrowError<Napi::TypeError>(env, "Cannot pass %1 value to %2, use koffi.as()",
934
- ref != instance->void_type ? "opaque" : "ambiguous", type->name);
935
- return false;
936
- }
937
-
938
- Size len = (Size)array.Length();
939
- Size size = len * ref->size;
940
-
941
- ptr = AllocHeap(size, 16);
942
-
943
- if (directions & 1) {
944
- if (!PushNormalArray(array, type, size, ptr))
945
- return false;
946
- } else {
947
- MemSet(ptr, 0, size);
948
- }
949
-
950
- out_kind = OutArgument::Kind::Array;
951
- }
952
- } else if (IsRawBuffer(value)) {
953
- Span<uint8_t> buffer = GetRawBuffer(value);
954
-
955
- // We can fast path
956
- ptr = buffer.ptr;
957
- directions = 1;
958
-
959
- out_kind = OutArgument::Kind::Buffer;
960
- } else if (ref->primitive == PrimitiveKind::Record ||
961
- ref->primitive == PrimitiveKind::Union) [[likely]] {
962
- Napi::Object obj = value.As<Napi::Object>();
963
- K_ASSERT(IsObject(value));
964
-
965
- ptr = AllocHeap(ref->size, 16);
966
-
967
- if (ref->primitive == PrimitiveKind::Union &&
968
- (directions & 2) && !CheckValueTag(obj, &MagicUnionMarker)) [[unlikely]] {
969
- ThrowError<Napi::TypeError>(env, "Unexpected %1 value, expected union value", GetValueType(instance, obj));
970
- return false;
971
- }
972
-
973
- if (directions & 1) {
974
- if (!PushObject(obj, ref, ptr))
975
- return false;
976
- } else {
977
- MemSet(ptr, 0, ref->size);
978
- }
979
-
980
- out_kind = OutArgument::Kind::Object;
981
- } else {
982
- goto unexpected;
983
- }
984
-
985
- if (directions & 2) {
986
- OutArgument *out = out_arguments.AppendDefault();
987
-
988
- napi_status status = napi_create_reference(env, value, 1, &out->ref);
989
- K_ASSERT(status == napi_ok);
990
-
991
- out->kind = out_kind;
992
- out->ptr = ptr;
993
- out->type = ref;
994
- out->max_len = out_max_len;
995
- }
996
-
997
- *out_ptr = ptr;
998
- return true;
999
- } break;
1000
-
1001
- case napi_string: {
1002
- K_ASSERT(type->primitive == PrimitiveKind::Pointer);
1003
-
1004
- if (directions & 2) [[unlikely]]
1005
- goto unexpected;
1006
-
1007
- if (ref == instance->void_type) {
1008
- PushStringValue(value, (const char **)out_ptr);
1009
- return true;
1010
- } else if (ref->primitive == PrimitiveKind::Int8) {
1011
- PushStringValue(value, (const char **)out_ptr);
1012
- return true;
1013
- } else if (ref->primitive == PrimitiveKind::Int16) {
1014
- PushString16Value(value, (const char16_t **)out_ptr);
1015
- return true;
1016
- } else if (ref->primitive == PrimitiveKind::Int32) {
1017
- PushString32Value(value, (const char32_t **)out_ptr);
1018
- return true;
1019
- } else {
1020
- goto unexpected;
1021
- }
1022
- } break;
1023
-
1024
- case napi_function: {
1025
- if (type->primitive != PrimitiveKind::Callback) [[unlikely]] {
1026
- ThrowError<Napi::TypeError>(env, "Cannot pass function to type %1", type->name);
1027
- return false;
1028
- }
1029
-
1030
- Napi::Function func = value.As<Napi::Function>();
1031
-
1032
- void *ptr = ReserveTrampoline(type->ref.proto, func);
1033
- if (!ptr) [[unlikely]]
1034
- return false;
1035
-
1036
- *out_ptr = (void *)ptr;
1037
- return true;
1038
- } break;
1039
-
1040
- case napi_number: {
1041
- Napi::Number number = value.As<Napi::Number>();
1042
- intptr_t ptr = (intptr_t)number.Int32Value();
1043
-
1044
- *out_ptr = (void *)ptr;
1045
- return true;
1046
- } break;
1047
-
1048
- case napi_bigint: {
1049
- Napi::BigInt bigint = value.As<Napi::BigInt>();
1050
-
1051
- bool lossless;
1052
- intptr_t ptr = (intptr_t)bigint.Int64Value(&lossless);
1053
-
1054
- *out_ptr = (void *)ptr;
1055
- return true;
1056
- } break;
1057
-
1058
- default: {} break;
1059
- }
1060
-
1061
- unexpected:
1062
- ThrowError<Napi::TypeError>(env, "Unexpected %1 value, expected %2", GetValueType(instance, value), type->name);
1063
- return false;
1064
- }
1065
-
1066
- bool CallData::PushCallback(Napi::Value value, const TypeInfo *type, void **out_ptr)
1067
- {
1068
- if (value.IsFunction()) {
1069
- Napi::Function func = value.As<Napi::Function>();
1070
-
1071
- void *ptr = ReserveTrampoline(type->ref.proto, func);
1072
- if (!ptr) [[unlikely]]
1073
- return false;
1074
-
1075
- *out_ptr = ptr;
1076
- } else if (CheckValueTag(value, type->ref.marker)) {
1077
- *out_ptr = value.As<Napi::External<void>>().Data();
1078
- } else if (CheckValueTag(value, &CastMarker)) {
1079
- Napi::External<ValueCast> external = value.As<Napi::External<ValueCast>>();
1080
- ValueCast *cast = external.Data();
1081
-
1082
- value = cast->ref.Value();
1083
-
1084
- if (!value.IsExternal() || cast->type != type)
1085
- goto unexpected;
1086
-
1087
- *out_ptr = value.As<Napi::External<void>>().Data();
1088
- } else if (IsNullOrUndefined(value)) {
1089
- *out_ptr = nullptr;
1090
- } else {
1091
- goto unexpected;
1092
- }
1093
-
1094
- return true;
1095
-
1096
- unexpected:
1097
- ThrowError<Napi::TypeError>(env, "Unexpected %1 value, expected %2", GetValueType(instance, value), type->name);
1098
- return false;
1099
- }
1100
-
1101
- Size CallData::PushIndirectString(Napi::Array array, const TypeInfo *ref, uint8_t **out_ptr)
1102
- {
1103
- if (array.Length() != 1)
1104
- return -1;
1105
-
1106
- Napi::Value value = array[0u];
1107
-
1108
- if (!value.IsString())
1109
- return -1;
1110
-
1111
- if (ref == instance->void_type) {
1112
- return PushStringValue(value, (const char **)out_ptr);
1113
- } else if (ref->primitive == PrimitiveKind::Int8) {
1114
- return PushStringValue(value, (const char **)out_ptr);
1115
- } else if (ref->primitive == PrimitiveKind::Int16) {
1116
- return PushString16Value(value, (const char16_t **)out_ptr);
1117
- } else if (ref->primitive == PrimitiveKind::Int32) {
1118
- return PushString32Value(value, (const char32_t **)out_ptr);
1119
- } else {
1120
- return -1;
1121
- }
1122
- }
1123
-
1124
- void *CallData::ReserveTrampoline(const FunctionInfo *proto, Napi::Function func)
1125
- {
1126
- if (!InitAsyncBroker(env, instance)) [[unlikely]]
1127
- return nullptr;
1128
-
1129
- int16_t idx;
1130
- {
1131
- std::lock_guard<std::mutex> lock(shared.mutex);
1132
-
1133
- if (!shared.available.len) [[unlikely]] {
1134
- ThrowError<Napi::Error>(env, "Too many callbacks are in use (max = %1)", MaxTrampolines);
1135
- return env.Null();
1136
- }
1137
- if (!used_trampolines.Available()) [[unlikely]] {
1138
- ThrowError<Napi::Error>(env, "This call uses too many temporary callbacks (max = %1)", K_LEN(used_trampolines.data));
1139
- return env.Null();
1140
- }
1141
-
1142
- idx = shared.available.data[--shared.available.len];
1143
- used_trampolines.Append(idx);
1144
- }
1145
-
1146
- TrampolineInfo *trampoline = &shared.trampolines[idx];
1147
-
1148
- trampoline->instance = instance;
1149
- trampoline->proto = proto;
1150
- trampoline->func.Reset(func, 1);
1151
- trampoline->recv.Reset();
1152
- trampoline->used = true;
1153
-
1154
- void *ptr = GetTrampoline(idx);
1155
-
1156
- return ptr;
1157
- }
1158
-
1159
- void CallData::DumpForward(const FunctionInfo *func) const
1160
- {
1161
- PrintLn(StdErr, "%!..+---- %1 (%2) ----%!0", func->name, CallConventionNames[(int)func->convention]);
1162
-
1163
- if (func->parameters.len) {
1164
- PrintLn(StdErr, "Parameters:");
1165
- for (Size i = 0; i < func->parameters.len; i++) {
1166
- const ParameterInfo &param = func->parameters[i];
1167
- PrintLn(StdErr, " %1 = %2 (%3)", i, param.type->name, FmtMemSize(param.type->size));
1168
- }
1169
- }
1170
- PrintLn(StdErr, "Return: %1 (%2)", func->ret.type->name, FmtMemSize(func->ret.type->size));
1171
-
1172
- Span<const uint8_t> stack = MakeSpan(mem->stack.end(), old_stack_mem.end() - mem->stack.end());
1173
- Span<const uint8_t> heap = MakeSpan(old_heap_mem.ptr, mem->heap.ptr - old_heap_mem.ptr);
1174
-
1175
- DumpMemory("Stack", stack);
1176
- DumpMemory("Heap", heap);
1177
- }
1178
-
1179
- bool CallData::CheckDynamicLength(Napi::Object obj, Size element, const char *countedby, Napi::Value value)
1180
- {
1181
- int64_t expected = -1;
1182
- int64_t size = -1;
1183
-
1184
- // Get expected size
1185
- {
1186
- Napi::Value by = obj.Get(countedby);
1187
-
1188
- if (!by.IsNumber() && !by.IsBigInt()) [[unlikely]] {
1189
- ThrowError<Napi::Error>(env, "Unexpected %1 value for dynamic length, expected number", GetValueType(instance, by));
1190
- return false;
1191
- }
1192
-
1193
- // If we get anywhere near overflow there are other problems to worry about.
1194
- // So let's not worry about that.
1195
- expected = GetNumber<int64_t>(by) * element;
1196
- }
1197
-
1198
- // Get actual size
1199
- if (value.IsArray()) {
1200
- Napi::Array array = value.As<Napi::Array>();
1201
- size = array.Length() * element;
1202
- } else if (value.IsTypedArray()) {
1203
- Napi::TypedArray typed = value.As<Napi::TypedArray>();
1204
- size = typed.ByteLength();
1205
- } else if (value.IsArrayBuffer()) {
1206
- Napi::ArrayBuffer buffer = value.As<Napi::ArrayBuffer>();
1207
- size = buffer.ByteLength();
1208
- } else if (!IsNullOrUndefined(value)) {
1209
- size = element;
1210
- } else {
1211
- size = 0;
1212
- }
1213
-
1214
- if (size != expected) {
1215
- ThrowError<Napi::Error>(env, "Mismatched dynamic length between '%1' and actual array", countedby);
1216
- return false;
1217
- }
1218
-
1219
- return true;
1220
- }
1221
-
1222
- static inline Napi::Value GetReferenceValue(Napi::Env env, napi_ref ref)
1223
- {
1224
- napi_value value;
1225
-
1226
- napi_status status = napi_get_reference_value(env, ref, &value);
1227
- K_ASSERT(status == napi_ok);
1228
-
1229
- return Napi::Value(env, value);
1230
- }
1231
-
1232
- void CallData::PopOutArguments()
1233
- {
1234
- for (const OutArgument &out: out_arguments) {
1235
- Napi::Value value = GetReferenceValue(env, out.ref);
1236
- K_ASSERT(!value.IsEmpty());
1237
-
1238
- switch (out.kind) {
1239
- case OutArgument::Kind::Array: {
1240
- K_ASSERT(value.IsArray());
1241
-
1242
- Napi::Array array(env, value);
1243
- DecodeNormalArray(array, out.ptr, out.type);
1244
- } break;
1245
-
1246
- case OutArgument::Kind::Buffer: {
1247
- K_ASSERT(IsRawBuffer(value));
1248
-
1249
- Span<uint8_t> buffer = GetRawBuffer(value);
1250
- DecodeBuffer(buffer, out.ptr, out.type);
1251
- } break;
1252
-
1253
- case OutArgument::Kind::String: {
1254
- Napi::Array array(env, value);
1255
-
1256
- K_ASSERT(array.IsArray());
1257
- K_ASSERT(array.Length() == 1);
1258
-
1259
- Size len = strnlen((const char *)out.ptr, out.max_len);
1260
- Napi::String str = Napi::String::New(env, (const char *)out.ptr, len);
1261
-
1262
- array.Set(0u, str);
1263
- } break;
1264
-
1265
- case OutArgument::Kind::String16: {
1266
- Napi::Array array(env, value);
1267
-
1268
- K_ASSERT(array.IsArray());
1269
- K_ASSERT(array.Length() == 1);
1270
-
1271
- Size len = NullTerminatedLength((const char16_t *)out.ptr, out.max_len);
1272
- Napi::String str = Napi::String::New(env, (const char16_t *)out.ptr, len);
1273
-
1274
- array.Set(0u, str);
1275
- } break;
1276
-
1277
- case OutArgument::Kind::String32: {
1278
- Napi::Array array(env, value);
1279
-
1280
- K_ASSERT(array.IsArray());
1281
- K_ASSERT(array.Length() == 1);
1282
-
1283
- Size len = NullTerminatedLength((const char32_t *)out.ptr, out.max_len);
1284
- Napi::String str = MakeStringFromUTF32(env, (const char32_t *)out.ptr, len);
1285
-
1286
- array.Set(0u, str);
1287
- } break;
1288
-
1289
- case OutArgument::Kind::Object: {
1290
- Napi::Object obj = value.As<Napi::Object>();
1291
-
1292
- if (CheckValueTag(value, &MagicUnionMarker)) {
1293
- MagicUnion *u = MagicUnion::Unwrap(obj);
1294
- u->SetRaw(out.ptr);
1295
- } else {
1296
- DecodeObject(obj, out.ptr, out.type);
1297
- }
1298
- } break;
1299
- }
1300
- }
1301
- }
1302
-
1303
- void PerformAsyncRelay(napi_env, napi_value, void *, void *udata)
1304
- {
1305
- RelayContext *ctx = (RelayContext *)udata;
1306
- CallData *call = ctx->call;
1307
-
1308
- call->Relay(ctx->idx, ctx->sp);
1309
-
1310
- // This CallData was created artificially just to perform the callback. Which means the
1311
- // creator may not run on the main thread, and cannot properly destroy it, because some
1312
- // members are managed by Node.
1313
- call->Dispose();
1314
-
1315
- // We're done!
1316
- std::lock_guard<std::mutex> lock(ctx->mutex);
1317
- ctx->done = true;
1318
- ctx->cv.notify_one();
1319
- }
1320
-
1321
- void *GetTrampoline(int idx)
1322
- {
1323
- return (void *)(TrampolineStart + TrampolineSize * idx);
1324
- }
1325
-
1326
- }