koffi 3.0.1 → 3.1.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.
Files changed (50) hide show
  1. package/CHANGELOG.md +32 -3
  2. package/cnoke.cjs +2 -2
  3. package/doc/benchmarks.md +1 -1
  4. package/doc/callbacks.md +7 -26
  5. package/doc/{input.md → composites.md} +161 -147
  6. package/doc/contribute.md +3 -2
  7. package/doc/index.md +0 -14
  8. package/doc/{functions.md → load.md} +54 -113
  9. package/doc/migration.md +4 -7
  10. package/doc/misc.md +0 -103
  11. package/doc/output.md +5 -11
  12. package/doc/pointers.md +76 -17
  13. package/doc/primitives.md +151 -0
  14. package/doc/start.md +3 -13
  15. package/doc/types.md +88 -0
  16. package/doc/unions.md +0 -186
  17. package/doc/values.md +134 -0
  18. package/index.d.ts +375 -308
  19. package/lib/native/base/base.cc +66 -24
  20. package/lib/native/base/base.hh +55 -153
  21. package/package.json +16 -16
  22. package/src/koffi/CMakeLists.txt +20 -17
  23. package/src/koffi/index.cjs +30 -111
  24. package/src/koffi/index.js +22 -96
  25. package/src/koffi/indirect.cjs +30 -111
  26. package/src/koffi/indirect.js +24 -24
  27. package/src/koffi/src/abi/arm64.cc +48 -62
  28. package/src/koffi/src/abi/riscv64.cc +39 -57
  29. package/src/koffi/src/abi/x64sysv.cc +39 -57
  30. package/src/koffi/src/abi/x64win.cc +48 -65
  31. package/src/koffi/src/abi/x86.cc +47 -59
  32. package/src/koffi/src/call.cc +426 -209
  33. package/src/koffi/src/call.hh +7 -11
  34. package/src/koffi/src/ffi.cc +534 -303
  35. package/src/koffi/src/ffi.hh +71 -15
  36. package/src/koffi/src/parser.cc +5 -3
  37. package/src/koffi/src/parser.hh +2 -2
  38. package/src/koffi/src/static.cjs +122 -0
  39. package/src/koffi/src/static.js +125 -0
  40. package/src/koffi/src/type.cc +725 -0
  41. package/src/koffi/src/type.hh +71 -0
  42. package/src/koffi/src/util.cc +117 -1202
  43. package/src/koffi/src/util.hh +158 -156
  44. package/src/koffi/src/uv.cc +17 -11
  45. package/src/koffi/src/uv.hh +2 -1
  46. package/vendor/node-addon-api/README.md +1 -1
  47. package/vendor/node-addon-api/napi-inl.h +213 -35
  48. package/vendor/node-addon-api/napi.h +118 -7
  49. package/doc/variables.md +0 -102
  50. package/indirect.d.ts +0 -322
@@ -12,6 +12,34 @@ namespace K {
12
12
  // #define EXTERNAL_POINTERS
13
13
  // #define EXTERNAL_TYPES
14
14
 
15
+ #if defined(_MSC_VER)
16
+ #define FORCE_INLINE __forceinline
17
+ #else
18
+ #define FORCE_INLINE __attribute__((always_inline)) inline
19
+ #endif
20
+ #if defined(UNITY_BUILD)
21
+ #define INLINE_UNITY FORCE_INLINE
22
+ #else
23
+ #define INLINE_UNITY
24
+ #endif
25
+
26
+ #if defined(__GNUC__) || defined(__clang__)
27
+ #if __has_attribute(musttail) && __has_attribute(preserve_none)
28
+ #define MUST_TAIL __attribute__((musttail))
29
+ #define PRESERVE_NONE __attribute__((preserve_none))
30
+ #elif __has_attribute(musttail) && !defined(__clang__)
31
+ // GCC regalloc seems better, so the generated code is not too bad even without preserve_none
32
+ #define MUST_TAIL __attribute__((musttail))
33
+ #define PRESERVE_NONE
34
+ #endif
35
+ #endif
36
+
37
+ #define NAPI_OK(Call) \
38
+ do { \
39
+ napi_status _status = (Call); \
40
+ K_ASSERT(_status == napi_ok); \
41
+ } while (false)
42
+
15
43
  static const Size DefaultSyncStackSize = Mebibytes(1);
16
44
  static const Size DefaultSyncHeapSize = Mebibytes(2);
17
45
  static const Size DefaultAsyncStackSize = Kibibytes(128);
@@ -39,7 +67,7 @@ struct RecordMember;
39
67
  struct FunctionInfo;
40
68
  struct CallData;
41
69
 
42
- typedef void DisposeFunc (Napi::Env env, const TypeInfo *type, const void *ptr);
70
+ typedef void DisposeFunc (InstanceData *instance, const TypeInfo *type, const void *ptr);
43
71
 
44
72
  enum class TypeFlag {
45
73
  HasTypedArray = 1 << 0,
@@ -50,32 +78,42 @@ enum class TypeFlag {
50
78
  enum class ArrayHint {
51
79
  Array,
52
80
  Typed,
81
+ Buffer,
53
82
  String
54
83
  };
55
84
  static const char *const ArrayHintNames[] = {
56
85
  "Array",
57
86
  "Typed",
87
+ "Buffer",
58
88
  "String"
59
89
  };
60
90
 
61
91
  struct RecordMember {
62
92
  const char *name;
63
- napi_ref key;
64
93
  const TypeInfo *type;
65
94
  int32_t offset;
66
95
  Size countedby;
96
+
97
+ napi_ref key = nullptr;
98
+
99
+ #if defined(K_DEBUG)
100
+ ~RecordMember() { K_ASSERT(!key); }
101
+ #endif
67
102
  };
68
103
 
69
104
  struct TypeInfo {
70
- const char *name;
105
+ K_DELETE_COPY(TypeInfo)
106
+
107
+ InstanceData *instance = nullptr;
71
108
 
109
+ const char *name;
72
110
  alignas(8) PrimitiveKind primitive;
73
111
  int32_t size;
74
112
  int16_t align;
75
113
  uint16_t flags;
76
114
 
77
- DisposeFunc *dispose;
78
- Napi::FunctionReference dispose_ref;
115
+ DisposeFunc *dispose = nullptr;
116
+ napi_ref dispose_ref = nullptr;
79
117
 
80
118
  HeapArray<RecordMember> members; // Record or Union
81
119
  struct {
@@ -86,15 +124,23 @@ struct TypeInfo {
86
124
  ArrayHint hint; // Array only
87
125
  const char *countedby; // Pointer or array
88
126
 
89
- mutable Napi::FunctionReference construct; // Union only
90
- mutable Napi::ObjectReference defn;
127
+ mutable napi_ref construct = nullptr; // Union only
128
+ mutable napi_ref defn = nullptr;
91
129
 
92
- mutable const TypeInfo *reshaped;
130
+ mutable const TypeInfo *reshaped = nullptr;
131
+
132
+ TypeInfo() = default;
133
+ ~TypeInfo();
134
+
135
+ TypeInfo(TypeInfo &&other) = default;
136
+ TypeInfo &operator=(TypeInfo &&other) = default;
93
137
 
94
138
  K_HASHTABLE_HANDLER(TypeInfo, name);
95
139
  };
96
140
 
97
141
  struct LibraryHolder {
142
+ K_DELETE_COPY(LibraryHolder)
143
+
98
144
  void *module = nullptr; // HMODULE on Windows
99
145
  mutable int refcount = 1;
100
146
 
@@ -121,7 +167,7 @@ class LibraryHandle: public Napi::ObjectWrap<LibraryHandle> {
121
167
  LibraryHolder *lib = nullptr;
122
168
 
123
169
  public:
124
- static Napi::Function InitClass(Napi::Env env);
170
+ static Napi::Function InitClass(InstanceData *instance);
125
171
 
126
172
  LibraryHandle(const Napi::CallbackInfo &info);
127
173
 
@@ -166,7 +212,9 @@ struct ParameterInfo {
166
212
  // ABI-specific part
167
213
 
168
214
  #if defined(_M_X64)
169
- bool regular; // Used for structs and unions
215
+ struct {
216
+ bool regular; // Used for structs and unions
217
+ } abi;
170
218
  #elif defined(__x86_64__)
171
219
  struct {
172
220
  bool regular;
@@ -192,7 +240,9 @@ struct ReturnInfo {
192
240
  // ABI-specific part
193
241
 
194
242
  #if defined(_M_X64)
195
- bool regular;
243
+ struct {
244
+ bool regular;
245
+ } abi;
196
246
  #elif defined(__x86_64__)
197
247
  struct {
198
248
  AbiMethod method;
@@ -203,7 +253,9 @@ struct ReturnInfo {
203
253
  int offset;
204
254
  } abi;
205
255
  #elif defined(__i386__) || defined(_M_IX86)
206
- bool trivial;
256
+ struct {
257
+ bool regular;
258
+ } abi;
207
259
  #elif __riscv_xlen == 64 || defined(__loongarch64)
208
260
  struct {
209
261
  AbiMethod method;
@@ -322,8 +374,6 @@ struct InstanceData {
322
374
  // Variadic cache
323
375
  FunctionInfo *variadic_func = nullptr;
324
376
 
325
- napi_value (*translate_zero_call)(napi_env env, napi_callback_info info);
326
-
327
377
  std::thread::id main_thread_id;
328
378
  napi_threadsafe_function broker = nullptr;
329
379
 
@@ -389,15 +439,21 @@ struct SharedData {
389
439
  };
390
440
  static_assert(MaxTrampolines <= INT16_MAX);
391
441
 
442
+ extern const napi_type_tag LibraryHandleMarker;
443
+ extern const napi_type_tag TypeObjectMarker;
444
+ extern const napi_type_tag DirectionMarker;
445
+ extern const napi_type_tag UnionValueMarker;
446
+ extern const napi_type_tag CastMarker;
447
+
392
448
  extern SharedData shared;
393
449
 
394
450
  // Some Node-API functions are loaded dynamically to work around bugs or because they are recent
451
+ extern napi_status (NAPI_CDECL *node_api_delete_reference)(node_api_basic_env env, napi_ref ref);
395
452
  extern napi_status (NAPI_CDECL *node_api_get_buffer_info)(napi_env env, napi_value value, void **data, size_t *length);
396
453
  extern napi_status (NAPI_CDECL *node_api_create_property_key_utf8)(napi_env env, const char* str, size_t length, napi_value* result);
397
454
  extern napi_status (NAPI_CDECL *node_api_post_finalizer)(node_api_basic_env env, napi_finalize finalize_cb, void* finalize_data, void* finalize_hint);
398
455
  extern napi_status (NAPI_CDECL *node_api_create_object_with_properties)(napi_env env, napi_value prototype_or_null, const napi_value *property_names,
399
456
  const napi_value *property_values, size_t property_count, napi_value *result);
400
- extern napi_value (*translate_zero_call)(napi_env env, napi_callback_info info);
401
457
 
402
458
  InstanceMemory *AllocateMemory(InstanceData *instance, Size stack_size, Size heap_size);
403
459
  void ReleaseMemory(InstanceData *instance, InstanceMemory *mem);
@@ -2,8 +2,10 @@
2
2
  // SPDX-FileCopyrightText: 2026 Niels Martignène <niels.martignene@protonmail.com>
3
3
 
4
4
  #include "lib/native/base/base.hh"
5
+ #include "call.hh"
5
6
  #include "ffi.hh"
6
7
  #include "parser.hh"
8
+ #include "type.hh"
7
9
 
8
10
  #include <napi.h>
9
11
 
@@ -159,7 +161,7 @@ const TypeInfo *PrototypeParser::ParseType(int *out_directions)
159
161
 
160
162
  while (offset >= start) {
161
163
  Span<const char> str = MakeSpan(tokens[start].ptr, tokens[offset].end() - tokens[start].ptr);
162
- const TypeInfo *type = ResolveType(env, str);
164
+ const TypeInfo *type = ResolveType(instance, str);
163
165
 
164
166
  if (type) {
165
167
  offset++;
@@ -207,9 +209,9 @@ bool PrototypeParser::IsIdentifier(Span<const char> tok) const
207
209
  return IsAsciiAlpha(tok[0]) || tok[0] == '_';
208
210
  }
209
211
 
210
- bool ParsePrototype(Napi::Env env, const char *str, bool concrete, FunctionInfo *out_func)
212
+ bool ParsePrototype(InstanceData *instance, const char *str, bool concrete, FunctionInfo *out_func)
211
213
  {
212
- PrototypeParser parser(env);
214
+ PrototypeParser parser(instance);
213
215
  return parser.Parse(str, concrete, out_func);
214
216
  }
215
217
 
@@ -24,7 +24,7 @@ class PrototypeParser {
24
24
  bool valid;
25
25
 
26
26
  public:
27
- PrototypeParser(Napi::Env env) : env(env), instance(env.GetInstanceData<InstanceData>()) {}
27
+ PrototypeParser(InstanceData *instance) : env(instance->env), instance(instance) {}
28
28
 
29
29
  bool Parse(const char *str, bool concrete, FunctionInfo *out_func);
30
30
 
@@ -49,6 +49,6 @@ private:
49
49
  }
50
50
  };
51
51
 
52
- bool ParsePrototype(Napi::Env env, const char *str, bool concrete, FunctionInfo *out_func);
52
+ bool ParsePrototype(InstanceData *instance, const char *str, bool concrete, FunctionInfo *out_func);
53
53
 
54
54
  }
@@ -0,0 +1,122 @@
1
+ // SPDX-License-Identifier: MIT
2
+ // SPDX-FileCopyrightText: 2026 Niels Martignène <niels.martignene@protonmail.com>
3
+
4
+ function loadStatic(pkg) {
5
+ let native = null;
6
+
7
+ if (pkg == 'linux-arm64') {
8
+ try {
9
+ native = require('@koromix/koffi-linux-arm64');
10
+ } catch (err) {
11
+ // Go on
12
+ }
13
+ }
14
+
15
+ if (pkg == 'linux-ia32') {
16
+ try {
17
+ native = require('@koromix/koffi-linux-ia32');
18
+ } catch (err) {
19
+ // Go on
20
+ }
21
+ }
22
+
23
+ if (pkg == 'linux-x64') {
24
+ try {
25
+ native = require('@koromix/koffi-linux-x64');
26
+ } catch (err) {
27
+ // Go on
28
+ }
29
+ }
30
+
31
+ if (pkg == 'linux-riscv64') {
32
+ try {
33
+ native = require('@koromix/koffi-linux-riscv64');
34
+ } catch (err) {
35
+ // Go on
36
+ }
37
+ }
38
+
39
+ if (pkg == 'freebsd-ia32') {
40
+ try {
41
+ native = require('@koromix/koffi-freebsd-ia32');
42
+ } catch (err) {
43
+ // Go on
44
+ }
45
+ }
46
+
47
+ if (pkg == 'freebsd-x64') {
48
+ try {
49
+ native = require('@koromix/koffi-freebsd-x64');
50
+ } catch (err) {
51
+ // Go on
52
+ }
53
+ }
54
+
55
+ if (pkg == 'freebsd-arm64') {
56
+ try {
57
+ native = require('@koromix/koffi-freebsd-arm64');
58
+ } catch (err) {
59
+ // Go on
60
+ }
61
+ }
62
+
63
+ if (pkg == 'openbsd-ia32') {
64
+ try {
65
+ native = require('@koromix/koffi-openbsd-ia32');
66
+ } catch (err) {
67
+ // Go on
68
+ }
69
+ }
70
+
71
+ if (pkg == 'openbsd-x64') {
72
+ try {
73
+ native = require('@koromix/koffi-openbsd-x64');
74
+ } catch (err) {
75
+ // Go on
76
+ }
77
+ }
78
+
79
+ if (pkg == 'win32-ia32') {
80
+ try {
81
+ native = require('@koromix/koffi-win32-ia32');
82
+ } catch (err) {
83
+ // Go on
84
+ }
85
+ }
86
+
87
+ if (pkg == 'win32-x64') {
88
+ try {
89
+ native = require('@koromix/koffi-win32-x64');
90
+ } catch (err) {
91
+ // Go on
92
+ }
93
+ }
94
+
95
+ if (pkg == 'darwin-x64') {
96
+ try {
97
+ native = require('@koromix/koffi-darwin-x64');
98
+ } catch (err) {
99
+ // Go on
100
+ }
101
+ }
102
+
103
+ if (pkg == 'darwin-arm64') {
104
+ try {
105
+ native = require('@koromix/koffi-darwin-arm64');
106
+ } catch (err) {
107
+ // Go on
108
+ }
109
+ }
110
+
111
+ if (pkg == 'linux-loong64') {
112
+ try {
113
+ native = require('@koromix/koffi-linux-loong64');
114
+ } catch (err) {
115
+ // Go on
116
+ }
117
+ }
118
+
119
+ return native;
120
+ }
121
+
122
+ module.exports = { loadStatic };
@@ -0,0 +1,125 @@
1
+ // SPDX-License-Identifier: MIT
2
+ // SPDX-FileCopyrightText: 2026 Niels Martignène <niels.martignene@protonmail.com>
3
+
4
+ import { createRequire } from "node:module";
5
+ const require = createRequire(import.meta.url);
6
+
7
+ function loadStatic(pkg) {
8
+ let native = null;
9
+
10
+ if (pkg == 'linux-arm64') {
11
+ try {
12
+ native = require('@koromix/koffi-linux-arm64');
13
+ } catch (err) {
14
+ // Go on
15
+ }
16
+ }
17
+
18
+ if (pkg == 'linux-ia32') {
19
+ try {
20
+ native = require('@koromix/koffi-linux-ia32');
21
+ } catch (err) {
22
+ // Go on
23
+ }
24
+ }
25
+
26
+ if (pkg == 'linux-x64') {
27
+ try {
28
+ native = require('@koromix/koffi-linux-x64');
29
+ } catch (err) {
30
+ // Go on
31
+ }
32
+ }
33
+
34
+ if (pkg == 'linux-riscv64') {
35
+ try {
36
+ native = require('@koromix/koffi-linux-riscv64');
37
+ } catch (err) {
38
+ // Go on
39
+ }
40
+ }
41
+
42
+ if (pkg == 'freebsd-ia32') {
43
+ try {
44
+ native = require('@koromix/koffi-freebsd-ia32');
45
+ } catch (err) {
46
+ // Go on
47
+ }
48
+ }
49
+
50
+ if (pkg == 'freebsd-x64') {
51
+ try {
52
+ native = require('@koromix/koffi-freebsd-x64');
53
+ } catch (err) {
54
+ // Go on
55
+ }
56
+ }
57
+
58
+ if (pkg == 'freebsd-arm64') {
59
+ try {
60
+ native = require('@koromix/koffi-freebsd-arm64');
61
+ } catch (err) {
62
+ // Go on
63
+ }
64
+ }
65
+
66
+ if (pkg == 'openbsd-ia32') {
67
+ try {
68
+ native = require('@koromix/koffi-openbsd-ia32');
69
+ } catch (err) {
70
+ // Go on
71
+ }
72
+ }
73
+
74
+ if (pkg == 'openbsd-x64') {
75
+ try {
76
+ native = require('@koromix/koffi-openbsd-x64');
77
+ } catch (err) {
78
+ // Go on
79
+ }
80
+ }
81
+
82
+ if (pkg == 'win32-ia32') {
83
+ try {
84
+ native = require('@koromix/koffi-win32-ia32');
85
+ } catch (err) {
86
+ // Go on
87
+ }
88
+ }
89
+
90
+ if (pkg == 'win32-x64') {
91
+ try {
92
+ native = require('@koromix/koffi-win32-x64');
93
+ } catch (err) {
94
+ // Go on
95
+ }
96
+ }
97
+
98
+ if (pkg == 'darwin-x64') {
99
+ try {
100
+ native = require('@koromix/koffi-darwin-x64');
101
+ } catch (err) {
102
+ // Go on
103
+ }
104
+ }
105
+
106
+ if (pkg == 'darwin-arm64') {
107
+ try {
108
+ native = require('@koromix/koffi-darwin-arm64');
109
+ } catch (err) {
110
+ // Go on
111
+ }
112
+ }
113
+
114
+ if (pkg == 'linux-loong64') {
115
+ try {
116
+ native = require('@koromix/koffi-linux-loong64');
117
+ } catch (err) {
118
+ // Go on
119
+ }
120
+ }
121
+
122
+ return native;
123
+ }
124
+
125
+ export { loadStatic }