koffi 2.6.12 → 2.7.0
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/CHANGELOG.md +8 -0
- package/build/koffi/darwin_arm64/koffi.node +0 -0
- package/build/koffi/darwin_x64/koffi.node +0 -0
- package/build/koffi/freebsd_arm64/koffi.node +0 -0
- package/build/koffi/freebsd_ia32/koffi.node +0 -0
- package/build/koffi/freebsd_x64/koffi.node +0 -0
- package/build/koffi/linux_arm32hf/koffi.node +0 -0
- package/build/koffi/linux_arm64/koffi.node +0 -0
- package/build/koffi/linux_ia32/koffi.node +0 -0
- package/build/koffi/linux_riscv64hf64/koffi.node +0 -0
- package/build/koffi/linux_x64/koffi.node +0 -0
- package/build/koffi/openbsd_ia32/koffi.node +0 -0
- package/build/koffi/openbsd_x64/koffi.node +0 -0
- package/build/koffi/win32_arm64/koffi.node +0 -0
- package/build/koffi/win32_ia32/koffi.node +0 -0
- package/build/koffi/win32_x64/koffi.node +0 -0
- package/doc/callbacks.md +19 -0
- package/doc/functions.md +15 -7
- package/doc/start.md +2 -2
- package/index.d.ts +11 -11
- package/index.js +11 -2
- package/indirect.js +11 -2
- package/package.json +2 -2
- package/src/core/libcc/libcc.cc +5 -6
- package/src/core/libcc/libcc.hh +2 -2
- package/src/koffi/src/ffi.cc +40 -34
- package/src/koffi/src/ffi.hh +3 -0
- package/src/koffi/src/parser.cc +1 -9
- package/src/koffi/src/util.cc +19 -0
- package/src/koffi/src/util.hh +2 -0
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,14 @@
|
|
|
2
2
|
|
|
3
3
|
## Version history
|
|
4
4
|
|
|
5
|
+
### Koffi 2.7
|
|
6
|
+
|
|
7
|
+
#### Koffi 2.7.0 (2023-12-21)
|
|
8
|
+
|
|
9
|
+
- Support alternative [callback calling convention](callbacks.md#callback-types) in classic syntax
|
|
10
|
+
- Change syntax for [calling conventions](functions.md#calling-conventions) with classic syntax
|
|
11
|
+
- Drop unused "internal" property from Koffi
|
|
12
|
+
|
|
5
13
|
### Koffi 2.6
|
|
6
14
|
|
|
7
15
|
#### Koffi 2.6.12 (2023-12-11)
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
package/doc/callbacks.md
CHANGED
|
@@ -8,6 +8,8 @@ The function `koffi.proto()` was introduced in Koffi 2.4, it was called `koffi.c
|
|
|
8
8
|
|
|
9
9
|
## Callback types
|
|
10
10
|
|
|
11
|
+
*Changed in Koffi 2.7*
|
|
12
|
+
|
|
11
13
|
In order to pass a JS function to a C function expecting a callback, you must first create a callback type with the expected return type and parameters. The syntax is similar to the one used to load functions from a shared library.
|
|
12
14
|
|
|
13
15
|
```js
|
|
@@ -21,6 +23,23 @@ const ExampleCallback = koffi.proto('ExampleCallback', 'void', ['int']);
|
|
|
21
23
|
const AddDoubleFloat = koffi.proto('double AddDoubleFloat(double d, float f)');
|
|
22
24
|
```
|
|
23
25
|
|
|
26
|
+
For alternative [calling conventions](functions.md#calling-conventions) (such as `stdcall` on Windows x86 32-bit), you can specify as the first argument with the classic syntax, or after the return type in prototype strings, like this:
|
|
27
|
+
|
|
28
|
+
```js
|
|
29
|
+
const HANDLE = koffi.pointer('HANDLE', koffi.opaque());
|
|
30
|
+
const HWND = koffi.alias('HWND', HANDLE);
|
|
31
|
+
|
|
32
|
+
// These two declarations work the same, and use the __stdcall convention on Windows x86
|
|
33
|
+
const EnumWindowsProc = koffi.proto('bool __stdcall EnumWindowsProc (HWND hwnd, long lParam)');
|
|
34
|
+
const EnumWindowsProc = koffi.proto('__stdcall', 'EnumWindowsProc', 'bool', ['HWND', 'long']);
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
```{warning}
|
|
38
|
+
You have to make sure you **get the calling convention right** (such as specifying __stdcall for a Windows API callback), or your code will crash on Windows 32-bit.
|
|
39
|
+
|
|
40
|
+
Before Koffi 2.7, it was *impossible to use an alternative callback calling convention with the classic syntax*. Use a prototype string or *upgrade to Koffi 2.7* to solve this limitation.
|
|
41
|
+
```
|
|
42
|
+
|
|
24
43
|
Once your callback type is declared, you can use a pointer to it in struct definitions, as function parameters and/or return types, or to call/decode function pointers.
|
|
25
44
|
|
|
26
45
|
```{note}
|
package/doc/functions.md
CHANGED
|
@@ -83,19 +83,27 @@ On x86 platforms, only the Cdecl convention can be used for variadic functions.
|
|
|
83
83
|
|
|
84
84
|
### Calling conventions
|
|
85
85
|
|
|
86
|
+
*Changed in Koffi 2.7*
|
|
87
|
+
|
|
86
88
|
By default, calling a C function happens synchronously.
|
|
87
89
|
|
|
88
90
|
Most architectures only support one procedure call standard per process. The 32-bit x86 platform is an exception to this, and Koffi supports several x86 conventions:
|
|
89
91
|
|
|
90
|
-
Convention | Classic form
|
|
91
|
-
------------- |
|
|
92
|
-
**Cdecl** | `koffi.
|
|
93
|
-
**Stdcall** | `koffi.
|
|
94
|
-
**Fastcall** | `koffi.
|
|
95
|
-
**Thiscall** | `koffi.
|
|
92
|
+
Convention | Classic form | Prototype form | Description
|
|
93
|
+
------------- | --------------------------------------------- | -------------- | -------------------------------------------------------------------
|
|
94
|
+
**Cdecl** | `koffi.func(name, ret, params)` | _(default)_ | This is the default convention, and the only one on other platforms
|
|
95
|
+
**Stdcall** | `koffi.func('__stdcall', name, ret, params)` | __stdcall | This convention is used extensively within the Win32 API
|
|
96
|
+
**Fastcall** | `koffi.func('__fastcall', name, ret, params)` | __fastcall | Rarely used, uses ECX and EDX for first two parameters
|
|
97
|
+
**Thiscall** | `koffi.func('__thiscall', name, ret, params)` | __thiscall | Rarely used, uses ECX for first parameter
|
|
96
98
|
|
|
97
99
|
You can safely use these on non-x86 platforms, they are simply ignored.
|
|
98
100
|
|
|
101
|
+
```{note}
|
|
102
|
+
Support for specifying the convention as the first argument of the classic form was introduced in Koffi 2.7.
|
|
103
|
+
|
|
104
|
+
In earlier versions, you had to use `koffi.stdcall()` and similar functions. These functions are still supported but deprecated, and will be removed in Koffi 3.0.
|
|
105
|
+
```
|
|
106
|
+
|
|
99
107
|
Below you can find a small example showing how to use a non-default calling convention, with the two syntaxes:
|
|
100
108
|
|
|
101
109
|
```js
|
|
@@ -105,7 +113,7 @@ const koffi = require('koffi');
|
|
|
105
113
|
const lib = koffi.load('user32.dll');
|
|
106
114
|
|
|
107
115
|
// The following two declarations are equivalent, and use stdcall on x86 (and the default ABI on other platforms)
|
|
108
|
-
const MessageBoxA_1 = lib.
|
|
116
|
+
const MessageBoxA_1 = lib.func('__stdcall', 'MessageBoxA', 'int', ['void *', 'str', 'str', 'uint']);
|
|
109
117
|
const MessageBoxA_2 = lib.func('int __stdcall MessageBoxA(void *hwnd, str text, str caption, uint type)');
|
|
110
118
|
```
|
|
111
119
|
|
package/doc/start.md
CHANGED
|
@@ -99,8 +99,8 @@ const IDYES = 6;
|
|
|
99
99
|
const IDNO = 7;
|
|
100
100
|
|
|
101
101
|
// Find functions
|
|
102
|
-
const MessageBoxA = lib.
|
|
103
|
-
const MessageBoxW = lib.
|
|
102
|
+
const MessageBoxA = lib.func('__stdcall', 'MessageBoxA', 'int', ['void *', 'str', 'str', 'uint']);
|
|
103
|
+
const MessageBoxW = lib.func('__stdcall', 'MessageBoxW', 'int', ['void *', 'str16', 'str16', 'uint']);
|
|
104
104
|
|
|
105
105
|
let ret = MessageBoxA(null, 'Do you want another message box?', 'Koffi', MB_YESNO | MB_ICONQUESTION);
|
|
106
106
|
if (ret == IDYES)
|
package/index.d.ts
CHANGED
|
@@ -67,18 +67,16 @@ declare module 'koffi' {
|
|
|
67
67
|
export interface IKoffiLib {
|
|
68
68
|
func(definition: string): KoffiFunction;
|
|
69
69
|
func(name: string, result: TypeSpec, arguments: TypeSpec[]): KoffiFunction;
|
|
70
|
+
func(convention: string, name: string, result: TypeSpec, arguments: TypeSpec[]): KoffiFunction;
|
|
70
71
|
|
|
71
|
-
cdecl(definition: string): KoffiFunction;
|
|
72
|
-
cdecl(name: string, result: TypeSpec, arguments: TypeSpec[]): KoffiFunction;
|
|
73
|
-
|
|
74
|
-
stdcall(
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
thiscall(definition: string): KoffiFunction;
|
|
81
|
-
thiscall(name: string, result: TypeSpec, arguments: TypeSpec[]): KoffiFunction;
|
|
72
|
+
/** @deprecated */ cdecl(definition: string): KoffiFunction;
|
|
73
|
+
/** @deprecated */ cdecl(name: string, result: TypeSpec, arguments: TypeSpec[]): KoffiFunction;
|
|
74
|
+
/** @deprecated */ stdcall(definition: string): KoffiFunction;
|
|
75
|
+
/** @deprecated */ stdcall(name: string, result: TypeSpec, arguments: TypeSpec[]): KoffiFunction;
|
|
76
|
+
/** @deprecated */ fastcall(definition: string): KoffiFunction;
|
|
77
|
+
/** @deprecated */ fastcall(name: string, result: TypeSpec, arguments: TypeSpec[]): KoffiFunction;
|
|
78
|
+
/** @deprecated */ thiscall(definition: string): KoffiFunction;
|
|
79
|
+
/** @deprecated */ thiscall(name: string, result: TypeSpec, arguments: TypeSpec[]): KoffiFunction;
|
|
82
80
|
|
|
83
81
|
symbol(name: string, type: TypeSpec): any;
|
|
84
82
|
|
|
@@ -118,8 +116,10 @@ declare module 'koffi' {
|
|
|
118
116
|
|
|
119
117
|
export function proto(definition: string): IKoffiCType;
|
|
120
118
|
export function proto(name: string, result: TypeSpec, arguments: TypeSpec[]): IKoffiCType;
|
|
119
|
+
export function proto(convention: string, name: string, result: TypeSpec, arguments: TypeSpec[]): IKoffiCType;
|
|
121
120
|
/** @deprecated */ export function callback(definition: string): IKoffiCType;
|
|
122
121
|
/** @deprecated */ export function callback(name: string, result: TypeSpec, arguments: TypeSpec[]): IKoffiCType;
|
|
122
|
+
/** @deprecated */ export function callback(convention: string, name: string, result: TypeSpec, arguments: TypeSpec[]): IKoffiCType;
|
|
123
123
|
|
|
124
124
|
export function register(callback: Function, type: TypeSpec): IKoffiRegisteredCallback;
|
|
125
125
|
export function register(thisValue: any, callback: Function, type: TypeSpec): IKoffiRegisteredCallback;
|
package/index.js
CHANGED
|
@@ -378,8 +378,8 @@ var require_package = __commonJS({
|
|
|
378
378
|
"build/dist/src/koffi/package.json"(exports2, module2) {
|
|
379
379
|
module2.exports = {
|
|
380
380
|
name: "koffi",
|
|
381
|
-
version: "2.
|
|
382
|
-
stable: "2.
|
|
381
|
+
version: "2.7.0",
|
|
382
|
+
stable: "2.7.0",
|
|
383
383
|
description: "Fast and simple C FFI (foreign function interface) for Node.js",
|
|
384
384
|
keywords: [
|
|
385
385
|
"foreign",
|
|
@@ -557,3 +557,12 @@ module.exports = {
|
|
|
557
557
|
handle: util.deprecate(native.opaque, "The koffi.handle() function was deprecated in Koffi 2.1, use koffi.opaque() instead", "KOFFI001"),
|
|
558
558
|
callback: util.deprecate(native.proto, "The koffi.callback() function was deprecated in Koffi 2.4, use koffi.proto() instead", "KOFFI002")
|
|
559
559
|
};
|
|
560
|
+
var load = module.exports.load;
|
|
561
|
+
module.exports.load = (...args) => {
|
|
562
|
+
let lib = load(...args);
|
|
563
|
+
lib.cdecl = util.deprecate((...args2) => lib.func("__cdecl", ...args2), "The koffi.stdcall() function was deprecated in Koffi 2.7, use koffi.func(...) instead", "KOFFI003");
|
|
564
|
+
lib.stdcall = util.deprecate((...args2) => lib.func("__stdcall", ...args2), 'The koffi.stdcall() function was deprecated in Koffi 2.7, use koffi.func("__stdcall", ...) instead', "KOFFI004");
|
|
565
|
+
lib.fastcall = util.deprecate((...args2) => lib.func("__fastcall", ...args2), 'The koffi.fastcall() function was deprecated in Koffi 2.7, use koffi.func("__fastcall", ...) instead', "KOFFI005");
|
|
566
|
+
lib.thiscall = util.deprecate((...args2) => lib.func("__thiscall", ...args2), 'The koffi.thiscall() function was deprecated in Koffi 2.7, use koffi.func("__thiscall", ...) instead', "KOFFI006");
|
|
567
|
+
return lib;
|
|
568
|
+
};
|
package/indirect.js
CHANGED
|
@@ -378,8 +378,8 @@ var require_package = __commonJS({
|
|
|
378
378
|
"build/dist/src/koffi/package.json"(exports2, module2) {
|
|
379
379
|
module2.exports = {
|
|
380
380
|
name: "koffi",
|
|
381
|
-
version: "2.
|
|
382
|
-
stable: "2.
|
|
381
|
+
version: "2.7.0",
|
|
382
|
+
stable: "2.7.0",
|
|
383
383
|
description: "Fast and simple C FFI (foreign function interface) for Node.js",
|
|
384
384
|
keywords: [
|
|
385
385
|
"foreign",
|
|
@@ -477,3 +477,12 @@ module.exports = {
|
|
|
477
477
|
handle: util.deprecate(native.opaque, "The koffi.handle() function was deprecated in Koffi 2.1, use koffi.opaque() instead", "KOFFI001"),
|
|
478
478
|
callback: util.deprecate(native.proto, "The koffi.callback() function was deprecated in Koffi 2.4, use koffi.proto() instead", "KOFFI002")
|
|
479
479
|
};
|
|
480
|
+
var load = module.exports.load;
|
|
481
|
+
module.exports.load = (...args) => {
|
|
482
|
+
let lib = load(...args);
|
|
483
|
+
lib.cdecl = util.deprecate((...args2) => lib.func("__cdecl", ...args2), "The koffi.stdcall() function was deprecated in Koffi 2.7, use koffi.func(...) instead", "KOFFI003");
|
|
484
|
+
lib.stdcall = util.deprecate((...args2) => lib.func("__stdcall", ...args2), 'The koffi.stdcall() function was deprecated in Koffi 2.7, use koffi.func("__stdcall", ...) instead', "KOFFI004");
|
|
485
|
+
lib.fastcall = util.deprecate((...args2) => lib.func("__fastcall", ...args2), 'The koffi.fastcall() function was deprecated in Koffi 2.7, use koffi.func("__fastcall", ...) instead', "KOFFI005");
|
|
486
|
+
lib.thiscall = util.deprecate((...args2) => lib.func("__thiscall", ...args2), 'The koffi.thiscall() function was deprecated in Koffi 2.7, use koffi.func("__thiscall", ...) instead', "KOFFI006");
|
|
487
|
+
return lib;
|
|
488
|
+
};
|
package/package.json
CHANGED
package/src/core/libcc/libcc.cc
CHANGED
|
@@ -5599,7 +5599,6 @@ public:
|
|
|
5599
5599
|
AsyncPool(int threads, bool leak);
|
|
5600
5600
|
|
|
5601
5601
|
int GetWorkerCount() const { return (int)workers.len; }
|
|
5602
|
-
int CountPendingTasks() const { return pending_tasks; }
|
|
5603
5602
|
|
|
5604
5603
|
void RegisterAsync();
|
|
5605
5604
|
void UnregisterAsync();
|
|
@@ -5673,11 +5672,6 @@ bool Async::Sync()
|
|
|
5673
5672
|
return success;
|
|
5674
5673
|
}
|
|
5675
5674
|
|
|
5676
|
-
int Async::CountPendingTasks()
|
|
5677
|
-
{
|
|
5678
|
-
return pool->CountPendingTasks();
|
|
5679
|
-
}
|
|
5680
|
-
|
|
5681
5675
|
bool Async::IsTaskRunning()
|
|
5682
5676
|
{
|
|
5683
5677
|
return async_running_task;
|
|
@@ -5806,6 +5800,11 @@ void AsyncPool::AddTask(Async *async, const std::function<bool()> &func)
|
|
|
5806
5800
|
pending_cv.notify_all();
|
|
5807
5801
|
sync_cv.notify_all();
|
|
5808
5802
|
}
|
|
5803
|
+
|
|
5804
|
+
// Limit queue size (back pressure)
|
|
5805
|
+
while (pending_tasks >= RG_ASYNC_MAX_PENDING_TASKS) {
|
|
5806
|
+
RunTasks(0);
|
|
5807
|
+
}
|
|
5809
5808
|
}
|
|
5810
5809
|
|
|
5811
5810
|
void AsyncPool::RunWorker(int worker_idx)
|
package/src/core/libcc/libcc.hh
CHANGED
|
@@ -93,6 +93,8 @@ namespace RG {
|
|
|
93
93
|
|
|
94
94
|
#define RG_ASYNC_MAX_THREADS 2048
|
|
95
95
|
#define RG_ASYNC_MAX_IDLE_TIME 10000
|
|
96
|
+
#define RG_ASYNC_MAX_PENDING_TASKS 1024
|
|
97
|
+
|
|
96
98
|
#define RG_FIBER_DEFAULT_STACK_SIZE Kibibytes(128)
|
|
97
99
|
|
|
98
100
|
// ------------------------------------------------------------------------
|
|
@@ -4265,8 +4267,6 @@ public:
|
|
|
4265
4267
|
void Run(const std::function<bool()> &f);
|
|
4266
4268
|
bool Sync();
|
|
4267
4269
|
|
|
4268
|
-
int CountPendingTasks();
|
|
4269
|
-
|
|
4270
4270
|
static bool IsTaskRunning();
|
|
4271
4271
|
static int GetWorkerIdx();
|
|
4272
4272
|
static int GetWorkerCount();
|
package/src/koffi/src/ffi.cc
CHANGED
|
@@ -880,35 +880,50 @@ static Napi::Value CreateArrayType(const Napi::CallbackInfo &info)
|
|
|
880
880
|
return WrapType(env, instance, type);
|
|
881
881
|
}
|
|
882
882
|
|
|
883
|
-
static bool ParseClassicFunction(
|
|
884
|
-
Napi::Array parameters, FunctionInfo *func)
|
|
883
|
+
static bool ParseClassicFunction(const Napi::CallbackInfo &info, FunctionInfo *out_func)
|
|
885
884
|
{
|
|
885
|
+
Napi::Env env = info.Env();
|
|
886
886
|
InstanceData *instance = env.GetInstanceData<InstanceData>();
|
|
887
887
|
|
|
888
|
+
Napi::String name = info[0u].As<Napi::String>();
|
|
889
|
+
Napi::Value ret = info[1u];
|
|
890
|
+
Napi::Array parameters = info[2u].As<Napi::Array>();
|
|
891
|
+
|
|
892
|
+
// Detect optional call convention
|
|
893
|
+
if (name.IsString() && DetectCallConvention(name.Utf8Value().c_str(), &out_func->convention)) {
|
|
894
|
+
if (info.Length() < 4) {
|
|
895
|
+
ThrowError<Napi::TypeError>(env, "Expected 4 arguments, got %1", info.Length());
|
|
896
|
+
return false;
|
|
897
|
+
}
|
|
898
|
+
|
|
899
|
+
name = info[1u].As<Napi::String>();
|
|
900
|
+
ret = info[2u];
|
|
901
|
+
parameters = info[3u].As<Napi::Array>();
|
|
902
|
+
}
|
|
903
|
+
|
|
888
904
|
#ifdef _WIN32
|
|
889
|
-
if (
|
|
890
|
-
|
|
891
|
-
|
|
905
|
+
if (name.IsNumber()) {
|
|
906
|
+
out_func->ordinal_name = name.As<Napi::Number>().Int32Value();
|
|
907
|
+
name = name.ToString();
|
|
892
908
|
}
|
|
893
|
-
#
|
|
909
|
+
#endif
|
|
894
910
|
if (!name.IsString()) {
|
|
895
|
-
ThrowError<Napi::TypeError>(env, "Unexpected %1 value for name, expected string", GetValueType(instance, name));
|
|
911
|
+
ThrowError<Napi::TypeError>(env, "Unexpected %1 value for name, expected string or integer", GetValueType(instance, name));
|
|
896
912
|
return false;
|
|
897
913
|
}
|
|
898
|
-
#endif
|
|
899
914
|
|
|
900
|
-
|
|
915
|
+
out_func->name = DuplicateString(name.ToString().Utf8Value().c_str(), &instance->str_alloc).ptr;
|
|
901
916
|
|
|
902
|
-
|
|
903
|
-
if (!
|
|
917
|
+
out_func->ret.type = ResolveType(ret);
|
|
918
|
+
if (!out_func->ret.type)
|
|
904
919
|
return false;
|
|
905
|
-
if (!CanReturnType(
|
|
906
|
-
ThrowError<Napi::TypeError>(env, "You are not allowed to directly return %1 values (maybe try %1 *)",
|
|
920
|
+
if (!CanReturnType(out_func->ret.type)) {
|
|
921
|
+
ThrowError<Napi::TypeError>(env, "You are not allowed to directly return %1 values (maybe try %1 *)", out_func->ret.type->name);
|
|
907
922
|
return false;
|
|
908
923
|
}
|
|
909
924
|
|
|
910
925
|
if (!parameters.IsArray()) {
|
|
911
|
-
ThrowError<Napi::TypeError>(env, "Unexpected %1 value for parameters of '%2', expected an array", GetValueType(instance, parameters),
|
|
926
|
+
ThrowError<Napi::TypeError>(env, "Unexpected %1 value for parameters of '%2', expected an array", GetValueType(instance, parameters), out_func->name);
|
|
912
927
|
return false;
|
|
913
928
|
}
|
|
914
929
|
|
|
@@ -918,7 +933,7 @@ static bool ParseClassicFunction(Napi::Env env, Napi::String name, Napi::Value r
|
|
|
918
933
|
Napi::String str = parameters.Get(parameters_len - 1).As<Napi::String>();
|
|
919
934
|
|
|
920
935
|
if (str.IsString() && str.Utf8Value() == "...") {
|
|
921
|
-
|
|
936
|
+
out_func->variadic = true;
|
|
922
937
|
parameters_len--;
|
|
923
938
|
}
|
|
924
939
|
}
|
|
@@ -934,21 +949,21 @@ static bool ParseClassicFunction(Napi::Env env, Napi::String name, Napi::Value r
|
|
|
934
949
|
ThrowError<Napi::TypeError>(env, "Type %1 cannot be used as a parameter", param.type->name);
|
|
935
950
|
return false;
|
|
936
951
|
}
|
|
937
|
-
if (
|
|
952
|
+
if (out_func->parameters.len >= MaxParameters) {
|
|
938
953
|
ThrowError<Napi::TypeError>(env, "Functions cannot have more than %1 parameters", MaxParameters);
|
|
939
954
|
return false;
|
|
940
955
|
}
|
|
941
|
-
if ((param.directions & 2) && ++
|
|
956
|
+
if ((param.directions & 2) && ++out_func->out_parameters >= MaxParameters) {
|
|
942
957
|
ThrowError<Napi::TypeError>(env, "Functions cannot have more than %1 output parameters", MaxParameters);
|
|
943
958
|
return false;
|
|
944
959
|
}
|
|
945
960
|
|
|
946
961
|
param.offset = (int8_t)j;
|
|
947
962
|
|
|
948
|
-
|
|
963
|
+
out_func->parameters.Append(param);
|
|
949
964
|
}
|
|
950
965
|
|
|
951
|
-
|
|
966
|
+
out_func->required_parameters = (int8_t)out_func->parameters.len;
|
|
952
967
|
|
|
953
968
|
return true;
|
|
954
969
|
}
|
|
@@ -962,7 +977,7 @@ static Napi::Value CreateFunctionType(const Napi::CallbackInfo &info)
|
|
|
962
977
|
RG_DEFER_N(err_guard) { instance->callbacks.RemoveLast(1); };
|
|
963
978
|
|
|
964
979
|
if (info.Length() >= 3) {
|
|
965
|
-
if (!ParseClassicFunction(
|
|
980
|
+
if (!ParseClassicFunction(info, func))
|
|
966
981
|
return env.Null();
|
|
967
982
|
} else if (info.Length() >= 1) {
|
|
968
983
|
if (!info[0].IsString()) {
|
|
@@ -1519,7 +1534,7 @@ extern "C" void RelayCallback(Size idx, uint8_t *own_sp, uint8_t *caller_sp, Bac
|
|
|
1519
1534
|
}
|
|
1520
1535
|
}
|
|
1521
1536
|
|
|
1522
|
-
static Napi::Value FindLibraryFunction(const Napi::CallbackInfo &info
|
|
1537
|
+
static Napi::Value FindLibraryFunction(const Napi::CallbackInfo &info)
|
|
1523
1538
|
{
|
|
1524
1539
|
Napi::Env env = info.Env();
|
|
1525
1540
|
InstanceData *instance = env.GetInstanceData<InstanceData>();
|
|
@@ -1529,10 +1544,9 @@ static Napi::Value FindLibraryFunction(const Napi::CallbackInfo &info, CallConve
|
|
|
1529
1544
|
RG_DEFER { func->Unref(); };
|
|
1530
1545
|
|
|
1531
1546
|
func->lib = lib->Ref();
|
|
1532
|
-
func->convention = convention;
|
|
1533
1547
|
|
|
1534
1548
|
if (info.Length() >= 3) {
|
|
1535
|
-
if (!ParseClassicFunction(
|
|
1549
|
+
if (!ParseClassicFunction(info, func))
|
|
1536
1550
|
return env.Null();
|
|
1537
1551
|
} else if (info.Length() >= 1) {
|
|
1538
1552
|
if (!info[0].IsString()) {
|
|
@@ -1562,7 +1576,7 @@ static Napi::Value FindLibraryFunction(const Napi::CallbackInfo &info, CallConve
|
|
|
1562
1576
|
}
|
|
1563
1577
|
|
|
1564
1578
|
#ifdef _WIN32
|
|
1565
|
-
if (
|
|
1579
|
+
if (func->ordinal_name < 0) {
|
|
1566
1580
|
if (func->decorated_name) {
|
|
1567
1581
|
func->native = (void *)GetProcAddress((HMODULE)lib->module, func->decorated_name);
|
|
1568
1582
|
}
|
|
@@ -1570,7 +1584,7 @@ static Napi::Value FindLibraryFunction(const Napi::CallbackInfo &info, CallConve
|
|
|
1570
1584
|
func->native = (void *)GetProcAddress((HMODULE)lib->module, func->name);
|
|
1571
1585
|
}
|
|
1572
1586
|
} else {
|
|
1573
|
-
uint16_t ordinal = (uint16_t)
|
|
1587
|
+
uint16_t ordinal = (uint16_t)func->ordinal_name;
|
|
1574
1588
|
|
|
1575
1589
|
func->decorated_name = nullptr;
|
|
1576
1590
|
func->native = (void *)GetProcAddress((HMODULE)lib->module, (LPCSTR)(size_t)ordinal);
|
|
@@ -1720,20 +1734,13 @@ static Napi::Value LoadSharedLibrary(const Napi::CallbackInfo &info)
|
|
|
1720
1734
|
func.AddFinalizer([](Napi::Env, LibraryHolder *lib) { lib->Unref(); }, lib); \
|
|
1721
1735
|
obj.Set((Name), func); \
|
|
1722
1736
|
} while (false)
|
|
1723
|
-
#define ADD_CONVENTION(Name, Value) ADD_METHOD((Name), FindLibraryFunction(info, Value))
|
|
1724
|
-
|
|
1725
|
-
ADD_CONVENTION("func", CallConvention::Cdecl);
|
|
1726
|
-
ADD_CONVENTION("cdecl", CallConvention::Cdecl);
|
|
1727
|
-
ADD_CONVENTION("stdcall", CallConvention::Stdcall);
|
|
1728
|
-
ADD_CONVENTION("fastcall", CallConvention::Fastcall);
|
|
1729
|
-
ADD_CONVENTION("thiscall", CallConvention::Thiscall);
|
|
1730
1737
|
|
|
1738
|
+
ADD_METHOD("func", FindLibraryFunction(info));
|
|
1731
1739
|
ADD_METHOD("symbol", FindSymbol(info));
|
|
1732
1740
|
|
|
1733
1741
|
// We can't unref the library after unload, obviously
|
|
1734
1742
|
obj.Set("unload", Napi::Function::New(env, UnloadLibrary, "unload", (void *)lib->Ref()));
|
|
1735
1743
|
|
|
1736
|
-
#undef ADD_CONVENTION
|
|
1737
1744
|
#undef ADD_METHOD
|
|
1738
1745
|
|
|
1739
1746
|
return obj;
|
|
@@ -2326,7 +2333,6 @@ static Napi::Object InitModule(Napi::Env env, Napi::Object exports)
|
|
|
2326
2333
|
Napi::Object types = InitBaseTypes(env);
|
|
2327
2334
|
exports.Set("types", types);
|
|
2328
2335
|
|
|
2329
|
-
exports.Set("internal", Napi::Boolean::New(env, false));
|
|
2330
2336
|
exports.Set("version", Napi::String::New(env, RG_STRINGIFY(VERSION)));
|
|
2331
2337
|
|
|
2332
2338
|
return exports;
|
package/src/koffi/src/ffi.hh
CHANGED
package/src/koffi/src/parser.cc
CHANGED
|
@@ -40,15 +40,7 @@ bool PrototypeParser::Parse(const char *str, FunctionInfo *out_func)
|
|
|
40
40
|
MarkError("You are not allowed to directly return %1 values (maybe try %1 *)", out_func->ret.type->name);
|
|
41
41
|
return false;
|
|
42
42
|
}
|
|
43
|
-
|
|
44
|
-
out_func->convention = CallConvention::Cdecl;
|
|
45
|
-
} else if (Match("__stdcall")) {
|
|
46
|
-
out_func->convention = CallConvention::Stdcall;
|
|
47
|
-
} else if (Match("__fastcall")) {
|
|
48
|
-
out_func->convention = CallConvention::Fastcall;
|
|
49
|
-
} else if (Match("__thiscall")) {
|
|
50
|
-
out_func->convention = CallConvention::Thiscall;
|
|
51
|
-
}
|
|
43
|
+
offset += (offset < tokens.len && DetectCallConvention(tokens[offset], &out_func->convention));
|
|
52
44
|
out_func->name = ParseIdentifier();
|
|
53
45
|
|
|
54
46
|
Consume("(");
|
package/src/koffi/src/util.cc
CHANGED
|
@@ -1508,6 +1508,25 @@ Napi::Function WrapFunction(Napi::Env env, const FunctionInfo *func)
|
|
|
1508
1508
|
return wrapper;
|
|
1509
1509
|
}
|
|
1510
1510
|
|
|
1511
|
+
bool DetectCallConvention(Span<const char> name, CallConvention *out_convention)
|
|
1512
|
+
{
|
|
1513
|
+
if (name == "__cdecl") {
|
|
1514
|
+
*out_convention = CallConvention::Cdecl;
|
|
1515
|
+
return true;
|
|
1516
|
+
} else if (name == "__stdcall") {
|
|
1517
|
+
*out_convention = CallConvention::Stdcall;
|
|
1518
|
+
return true;
|
|
1519
|
+
} else if (name == "__fastcall") {
|
|
1520
|
+
*out_convention = CallConvention::Fastcall;
|
|
1521
|
+
return true;
|
|
1522
|
+
} else if (name == "__thiscall") {
|
|
1523
|
+
*out_convention = CallConvention::Thiscall;
|
|
1524
|
+
return true;
|
|
1525
|
+
} else {
|
|
1526
|
+
return false;
|
|
1527
|
+
}
|
|
1528
|
+
}
|
|
1529
|
+
|
|
1511
1530
|
static int AnalyseFlatRec(const TypeInfo *type, int offset, int count, FunctionRef<void(const TypeInfo *type, int offset, int count)> func)
|
|
1512
1531
|
{
|
|
1513
1532
|
if (type->primitive == PrimitiveKind::Record) {
|
package/src/koffi/src/util.hh
CHANGED
|
@@ -208,6 +208,8 @@ static inline Napi::Array GetOwnPropertyNames(Napi::Object obj)
|
|
|
208
208
|
|
|
209
209
|
Napi::Function WrapFunction(Napi::Env env, const FunctionInfo *func);
|
|
210
210
|
|
|
211
|
+
bool DetectCallConvention(Span<const char> name, CallConvention *out_convention);
|
|
212
|
+
|
|
211
213
|
int AnalyseFlat(const TypeInfo *type, FunctionRef<void(const TypeInfo *type, int offset, int count)> func);
|
|
212
214
|
|
|
213
215
|
void DumpMemory(const char *type, Span<const uint8_t> bytes);
|