@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,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
- }