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